db.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  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, *host, *port;
  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, host = %s, port = %s "
  47. "schema = %s", pgconn.host, pgconn.port, pgconn.options,
  48. pgconn.tty, pgconn.dbname, pgconn.user, pgconn.password,
  49. pgconn.host, pgconn.port,
  50. pgconn.schema);
  51. db_get_login2("pg", name, &user, &password, &host, &port);
  52. pg_conn = PQsetdbLogin(host, port, pgconn.options, pgconn.tty,
  53. pgconn.dbname, user, password);
  54. if (PQstatus(pg_conn) == CONNECTION_BAD) {
  55. db_d_append_error("%s\n%s",
  56. _("Connection failed."),
  57. PQerrorMessage(pg_conn));
  58. db_d_report_error();
  59. PQfinish(pg_conn);
  60. return DB_FAILED;
  61. }
  62. /* set schema */
  63. schema = db_get_handle_dbschema(handle);
  64. /* Cannot use default schema because link to table can point to
  65. different database */
  66. /*
  67. if ( schema )
  68. schema = connection.schemaName;
  69. */
  70. if (pgconn.schema) {
  71. schema = pgconn.schema;
  72. }
  73. /* set path to the schema */
  74. if (schema && strlen(schema) > 0) {
  75. sprintf(buf, "set search_path to %s", schema);
  76. res = PQexec(pg_conn, buf);
  77. if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) {
  78. db_d_append_error("%s %s",
  79. _("Unable to set schema:"),
  80. schema);
  81. db_d_report_error();
  82. PQclear(res);
  83. return DB_FAILED;
  84. }
  85. }
  86. /* read internal codes */
  87. res = PQexec(pg_conn,
  88. "select oid, typname from pg_type where typname in ( "
  89. "'bit', 'int2', 'int4', 'int8', 'serial', 'oid', "
  90. "'float4', 'float8', 'numeric', "
  91. "'char', 'bpchar', 'varchar', 'text', "
  92. "'time', 'date', 'timestamp', "
  93. "'bool', 'geometry', 'topogeometry') order by oid");
  94. if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) {
  95. db_d_append_error(_("Unable to select data types"));
  96. db_d_report_error();
  97. PQclear(res);
  98. return DB_FAILED;
  99. }
  100. pg_ntypes = PQntuples(res);
  101. pg_types = G_realloc(pg_types, 2 * pg_ntypes * sizeof(int));
  102. for (row = 0; row < pg_ntypes; row++) {
  103. int pgtype, type;
  104. pgtype = atoi(PQgetvalue(res, row, 0));
  105. pg_types[row][0] = pgtype;
  106. G_debug(3, "row = %d value = %s", row, PQgetvalue(res, row, 1));
  107. if (strcmp(PQgetvalue(res, row, 1), "bit") == 0)
  108. type = PG_TYPE_BIT;
  109. else if (strcmp(PQgetvalue(res, row, 1), "int2") == 0)
  110. type = PG_TYPE_INT2;
  111. else if (strcmp(PQgetvalue(res, row, 1), "int4") == 0)
  112. type = PG_TYPE_INT4;
  113. else if (strcmp(PQgetvalue(res, row, 1), "int8") == 0)
  114. type = PG_TYPE_INT8;
  115. else if (strcmp(PQgetvalue(res, row, 1), "serial") == 0)
  116. type = PG_TYPE_SERIAL;
  117. else if (strcmp(PQgetvalue(res, row, 1), "oid") == 0)
  118. type = PG_TYPE_OID;
  119. else if (strcmp(PQgetvalue(res, row, 1), "float4") == 0)
  120. type = PG_TYPE_FLOAT4;
  121. else if (strcmp(PQgetvalue(res, row, 1), "float8") == 0)
  122. type = PG_TYPE_FLOAT8;
  123. else if (strcmp(PQgetvalue(res, row, 1), "numeric") == 0)
  124. type = PG_TYPE_NUMERIC;
  125. else if (strcmp(PQgetvalue(res, row, 1), "char") == 0)
  126. type = PG_TYPE_CHAR;
  127. else if (strcmp(PQgetvalue(res, row, 1), "bpchar") == 0)
  128. type = PG_TYPE_BPCHAR;
  129. else if (strcmp(PQgetvalue(res, row, 1), "varchar") == 0)
  130. type = PG_TYPE_VARCHAR;
  131. else if (strcmp(PQgetvalue(res, row, 1), "text") == 0)
  132. type = PG_TYPE_TEXT;
  133. else if (strcmp(PQgetvalue(res, row, 1), "date") == 0)
  134. type = PG_TYPE_DATE;
  135. else if (strcmp(PQgetvalue(res, row, 1), "time") == 0)
  136. type = PG_TYPE_TIME;
  137. else if (strcmp(PQgetvalue(res, row, 1), "timestamp") == 0)
  138. type = PG_TYPE_TIMESTAMP;
  139. else if (strcmp(PQgetvalue(res, row, 1), "bool") == 0)
  140. type = PG_TYPE_BOOL;
  141. else if (strcmp(PQgetvalue(res, row, 1), "geometry") == 0)
  142. type = PG_TYPE_POSTGIS_GEOM;
  143. else if (strcmp(PQgetvalue(res, row, 1), "topogeometry") == 0)
  144. type = PG_TYPE_POSTGIS_TOPOGEOM;
  145. else
  146. type = PG_TYPE_UNKNOWN;
  147. G_debug(3, "db_driver_open_database(): pgtype = %d, name = %s -> type = %d", pgtype,
  148. PQgetvalue(res, row, 1), type);
  149. pg_types[row][1] = type;
  150. }
  151. /* print notice messages only on verbose level */
  152. PQsetNoticeProcessor(pg_conn, notice_processor, NULL);
  153. PQclear(res);
  154. return DB_OK;
  155. }
  156. int db__driver_close_database()
  157. {
  158. PQfinish(pg_conn);
  159. return DB_OK;
  160. }
  161. /*!
  162. \brief Create new empty PostgreSQL database.
  163. \param handle dbHandle
  164. \return DB_OK on success
  165. \return DB_FAILED on failure
  166. */
  167. int db__driver_create_database(dbHandle *handle)
  168. {
  169. return create_delete_db(handle, TRUE);
  170. }
  171. /*!
  172. \brief Drop existing PostgreSQL database.
  173. \param handle dbHandle
  174. \return DB_OK on success
  175. \return DB_FAILED on failure
  176. */
  177. int db__driver_delete_database(dbHandle *handle)
  178. {
  179. return create_delete_db(handle, FALSE);
  180. }
  181. /* create or drop database */
  182. int create_delete_db(dbHandle *handle, int create)
  183. {
  184. dbString stmt;
  185. const char *template_db, *name, *user, *password, *host, *port;
  186. PGCONN pgconn;
  187. PGresult *res;
  188. db_init_string(&stmt);
  189. template_db = "template1";
  190. name = db_get_handle_dbname(handle); /* database to create */
  191. if (parse_conn(template_db, &pgconn) == DB_FAILED) {
  192. db_d_report_error();
  193. return DB_FAILED;
  194. }
  195. G_debug(3,
  196. "db_driver_create_database(): host = %s, port = %s, options = %s, tty = %s, "
  197. "dbname = %s, user = %s, password = %s, host = %s, port = %s"
  198. "schema = %s", pgconn.host, pgconn.port, pgconn.options,
  199. pgconn.tty, pgconn.dbname, pgconn.user, pgconn.password,
  200. pgconn.host, pgconn.port,
  201. pgconn.schema);
  202. db_get_login2("pg", template_db, &user, &password, &host, &port);
  203. pg_conn = PQsetdbLogin(host, port, pgconn.options, pgconn.tty,
  204. pgconn.dbname, user, password);
  205. if (PQstatus(pg_conn) == CONNECTION_BAD) {
  206. db_d_append_error(_("Connection failed."));
  207. db_d_append_error("\n");
  208. db_d_append_error(PQerrorMessage(pg_conn));
  209. db_d_report_error();
  210. PQfinish(pg_conn);
  211. return DB_FAILED;
  212. }
  213. /* create new database */
  214. if (create)
  215. db_set_string(&stmt, "CREATE DATABASE ");
  216. else
  217. db_set_string(&stmt, "DROP DATABASE ");
  218. db_append_string(&stmt, name);
  219. res = PQexec(pg_conn,
  220. db_get_string(&stmt));
  221. if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) {
  222. if (create)
  223. db_d_append_error(_("Unable to create database <%s>"), name);
  224. else
  225. db_d_append_error(_("Unable to drop database <%s>"), name);
  226. db_d_append_error("\n");
  227. db_d_append_error(PQerrorMessage(pg_conn));
  228. db_d_report_error();
  229. PQclear(res);
  230. PQfinish(pg_conn);
  231. return DB_FAILED;
  232. }
  233. PQclear(res);
  234. PQfinish(pg_conn);
  235. return DB_OK;
  236. }