db.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. /*!
  2. \file db/driver/postgres/db.c
  3. \brief DBMI - Low Level PostgreSQL database driver - open/close database.
  4. This program is free software under the GNU General Public License
  5. (>=v2). Read the file COPYING that comes with GRASS for details.
  6. \author Radim Blazek
  7. \author Create/drop database by Martin Landa <landa.martin gmail.com>
  8. */
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <grass/dbmi.h>
  12. #include <grass/gis.h>
  13. #include <grass/glocale.h>
  14. #include "globals.h"
  15. #include "proto.h"
  16. static void notice_processor(void *arg, const char *message)
  17. {
  18. /* print notice messages only on verbose level */
  19. if (G_verbose() > G_verbose_std()) {
  20. fprintf(stderr, "%s", message);
  21. }
  22. }
  23. static int create_delete_db();
  24. int db__driver_open_database(dbHandle * handle)
  25. {
  26. char buf[500];
  27. const char *name, *schema, *user, *password;
  28. dbConnection connection;
  29. PGCONN pgconn;
  30. PGresult *res;
  31. int row;
  32. db_get_connection(&connection);
  33. name = db_get_handle_dbname(handle);
  34. /* if name is empty use connection.databaseName */
  35. if (strlen(name) == 0)
  36. name = connection.databaseName;
  37. G_debug(3,
  38. "db_driver_open_database(): driver=pg database definition = '%s'",
  39. name);
  40. if (parse_conn(name, &pgconn) == DB_FAILED) {
  41. db_d_report_error();
  42. return DB_FAILED;
  43. }
  44. G_debug(3,
  45. "db_driver_open_database(): host = %s, port = %s, options = %s, tty = %s, "
  46. "dbname = %s, user = %s, password = %s, "
  47. "schema = %s", pgconn.host, pgconn.port, pgconn.options,
  48. pgconn.tty, pgconn.dbname, pgconn.user, pgconn.password,
  49. pgconn.schema);
  50. db_get_login("pg", name, &user, &password);
  51. pg_conn = PQsetdbLogin(pgconn.host, pgconn.port, pgconn.options, pgconn.tty,
  52. pgconn.dbname, user, password);
  53. if (PQstatus(pg_conn) == CONNECTION_BAD) {
  54. db_d_append_error("%s\n%s",
  55. _("Connection failed."),
  56. PQerrorMessage(pg_conn));
  57. db_d_report_error();
  58. PQfinish(pg_conn);
  59. return DB_FAILED;
  60. }
  61. /* set schema */
  62. schema = db_get_handle_dbschema(handle);
  63. /* Cannot use default schema because link to table can point to
  64. different database */
  65. /*
  66. if ( schema )
  67. schema = connection.schemaName;
  68. */
  69. if (pgconn.schema) {
  70. schema = pgconn.schema;
  71. }
  72. /* set path to the schema */
  73. if (schema && strlen(schema) > 0) {
  74. sprintf(buf, "set search_path to %s", schema);
  75. res = PQexec(pg_conn, buf);
  76. if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) {
  77. db_d_append_error("%s %s",
  78. _("Unable to set schema:"),
  79. schema);
  80. db_d_report_error();
  81. PQclear(res);
  82. return DB_FAILED;
  83. }
  84. }
  85. /* read internal codes */
  86. res = PQexec(pg_conn,
  87. "select oid, typname from pg_type where typname in ( "
  88. "'bit', 'int2', 'int4', 'int8', 'serial', 'oid', "
  89. "'float4', 'float8', 'numeric', "
  90. "'char', 'bpchar', 'varchar', 'text', "
  91. "'time', 'date', 'timestamp', "
  92. "'bool', 'geometry', 'topogeometry') order by oid");
  93. if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) {
  94. db_d_append_error(_("Unable to select data types"));
  95. db_d_report_error();
  96. PQclear(res);
  97. return DB_FAILED;
  98. }
  99. pg_ntypes = PQntuples(res);
  100. pg_types = G_realloc(pg_types, 2 * pg_ntypes * sizeof(int));
  101. for (row = 0; row < pg_ntypes; row++) {
  102. int pgtype, type;
  103. pgtype = atoi(PQgetvalue(res, row, 0));
  104. pg_types[row][0] = pgtype;
  105. G_debug(3, "row = %d value = %s", row, PQgetvalue(res, row, 1));
  106. if (strcmp(PQgetvalue(res, row, 1), "bit") == 0)
  107. type = PG_TYPE_BIT;
  108. else if (strcmp(PQgetvalue(res, row, 1), "int2") == 0)
  109. type = PG_TYPE_INT2;
  110. else if (strcmp(PQgetvalue(res, row, 1), "int4") == 0)
  111. type = PG_TYPE_INT4;
  112. else if (strcmp(PQgetvalue(res, row, 1), "int8") == 0)
  113. type = PG_TYPE_INT8;
  114. else if (strcmp(PQgetvalue(res, row, 1), "serial") == 0)
  115. type = PG_TYPE_SERIAL;
  116. else if (strcmp(PQgetvalue(res, row, 1), "oid") == 0)
  117. type = PG_TYPE_OID;
  118. else if (strcmp(PQgetvalue(res, row, 1), "float4") == 0)
  119. type = PG_TYPE_FLOAT4;
  120. else if (strcmp(PQgetvalue(res, row, 1), "float8") == 0)
  121. type = PG_TYPE_FLOAT8;
  122. else if (strcmp(PQgetvalue(res, row, 1), "numeric") == 0)
  123. type = PG_TYPE_NUMERIC;
  124. else if (strcmp(PQgetvalue(res, row, 1), "char") == 0)
  125. type = PG_TYPE_CHAR;
  126. else if (strcmp(PQgetvalue(res, row, 1), "bpchar") == 0)
  127. type = PG_TYPE_BPCHAR;
  128. else if (strcmp(PQgetvalue(res, row, 1), "varchar") == 0)
  129. type = PG_TYPE_VARCHAR;
  130. else if (strcmp(PQgetvalue(res, row, 1), "text") == 0)
  131. type = PG_TYPE_TEXT;
  132. else if (strcmp(PQgetvalue(res, row, 1), "date") == 0)
  133. type = PG_TYPE_DATE;
  134. else if (strcmp(PQgetvalue(res, row, 1), "time") == 0)
  135. type = PG_TYPE_TIME;
  136. else if (strcmp(PQgetvalue(res, row, 1), "timestamp") == 0)
  137. type = PG_TYPE_TIMESTAMP;
  138. else if (strcmp(PQgetvalue(res, row, 1), "bool") == 0)
  139. type = PG_TYPE_BOOL;
  140. else if (strcmp(PQgetvalue(res, row, 1), "geometry") == 0)
  141. type = PG_TYPE_POSTGIS_GEOM;
  142. else if (strcmp(PQgetvalue(res, row, 1), "topogeometry") == 0)
  143. type = PG_TYPE_POSTGIS_TOPOGEOM;
  144. else
  145. type = PG_TYPE_UNKNOWN;
  146. G_debug(3, "db_driver_open_database(): pgtype = %d, name = %s -> type = %d", pgtype,
  147. PQgetvalue(res, row, 1), type);
  148. pg_types[row][1] = type;
  149. }
  150. /* print notice messages only on verbose level */
  151. PQsetNoticeProcessor(pg_conn, notice_processor, NULL);
  152. PQclear(res);
  153. return DB_OK;
  154. }
  155. int db__driver_close_database()
  156. {
  157. PQfinish(pg_conn);
  158. return DB_OK;
  159. }
  160. /*!
  161. \brief Create new empty PostgreSQL database.
  162. \param handle dbHandle
  163. \return DB_OK on success
  164. \return DB_FAILED on failure
  165. */
  166. int db__driver_create_database(dbHandle *handle)
  167. {
  168. return create_delete_db(handle, TRUE);
  169. }
  170. /*!
  171. \brief Drop existing PostgreSQL database.
  172. \param handle dbHandle
  173. \return DB_OK on success
  174. \return DB_FAILED on failure
  175. */
  176. int db__driver_delete_database(dbHandle *handle)
  177. {
  178. return create_delete_db(handle, FALSE);
  179. }
  180. /* create or drop database */
  181. int create_delete_db(dbHandle *handle, int create)
  182. {
  183. dbString stmt;
  184. const char *template_db, *name, *user, *password;
  185. PGCONN pgconn;
  186. PGresult *res;
  187. db_init_string(&stmt);
  188. template_db = "template1";
  189. name = db_get_handle_dbname(handle); /* database to create */
  190. if (parse_conn(template_db, &pgconn) == DB_FAILED) {
  191. db_d_report_error();
  192. return DB_FAILED;
  193. }
  194. G_debug(3,
  195. "db_driver_create_database(): host = %s, port = %s, options = %s, tty = %s, "
  196. "dbname = %s, user = %s, password = %s, "
  197. "schema = %s", pgconn.host, pgconn.port, pgconn.options,
  198. pgconn.tty, pgconn.dbname, pgconn.user, pgconn.password,
  199. pgconn.schema);
  200. db_get_login("pg", template_db, &user, &password);
  201. pg_conn = PQsetdbLogin(pgconn.host, pgconn.port, pgconn.options, pgconn.tty,
  202. pgconn.dbname, user, password);
  203. if (PQstatus(pg_conn) == CONNECTION_BAD) {
  204. db_d_append_error(_("Connection failed."));
  205. db_d_append_error("\n");
  206. db_d_append_error(PQerrorMessage(pg_conn));
  207. db_d_report_error();
  208. PQfinish(pg_conn);
  209. return DB_FAILED;
  210. }
  211. /* create new database */
  212. if (create)
  213. db_set_string(&stmt, "CREATE DATABASE ");
  214. else
  215. db_set_string(&stmt, "DROP DATABASE ");
  216. db_append_string(&stmt, name);
  217. res = PQexec(pg_conn,
  218. db_get_string(&stmt));
  219. if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) {
  220. if (create)
  221. db_d_append_error(_("Unable to create database <%s>"), name);
  222. else
  223. db_d_append_error(_("Unable to drop database <%s>"), name);
  224. db_d_append_error("\n");
  225. db_d_append_error(PQerrorMessage(pg_conn));
  226. db_d_report_error();
  227. PQclear(res);
  228. PQfinish(pg_conn);
  229. return DB_FAILED;
  230. }
  231. PQclear(res);
  232. PQfinish(pg_conn);
  233. return DB_OK;
  234. }