open_pg.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /*!
  2. \file lib/vector/Vlib/open_pg.c
  3. \brief Vector library - Open PostGIS layer as vector map layer
  4. Higher level functions for reading/writing/manipulating vectors.
  5. (C) 2011-2012 by the GRASS Development Team
  6. This program is free software under the GNU General Public License
  7. (>=v2). Read the file COPYING that comes with GRASS for details.
  8. \author Martin Landa <landa.martin gmail.com>
  9. */
  10. #include <string.h>
  11. #include <stdlib.h>
  12. #include <grass/vector.h>
  13. #include <grass/dbmi.h>
  14. #include <grass/glocale.h>
  15. #ifdef HAVE_POSTGRES
  16. #include "pg_local_proto.h"
  17. static char *get_key_column(struct Format_info_pg *pg_info)
  18. {
  19. char *key_column;
  20. char stmt[DB_SQL_MAX];
  21. PGresult *res;
  22. sprintf(stmt,
  23. "SELECT kcu.column_name "
  24. "FROM INFORMATION_SCHEMA.TABLES t "
  25. "LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc "
  26. "ON tc.table_catalog = t.table_catalog "
  27. "AND tc.table_schema = t.table_schema "
  28. "AND tc.table_name = t.table_name "
  29. "AND tc.constraint_type = 'PRIMARY KEY' "
  30. "LEFT JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu "
  31. "ON kcu.table_catalog = tc.table_catalog "
  32. "AND kcu.table_schema = tc.table_schema "
  33. "AND kcu.table_name = tc.table_name "
  34. "AND kcu.constraint_name = tc.constraint_name "
  35. "WHERE t.table_name = '%s'", pg_info->table_name);
  36. res = PQexec(pg_info->conn, stmt);
  37. if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
  38. PQntuples(res) != 1) {
  39. G_warning(_("No key column detected."));
  40. if (res)
  41. PQclear(res);
  42. return NULL;
  43. }
  44. key_column = G_store(PQgetvalue(res, 0, 0));
  45. PQclear(res);
  46. return key_column;
  47. }
  48. static SF_FeatureType ftype_from_string(const char *type)
  49. {
  50. SF_FeatureType sf_type;
  51. if (G_strcasecmp(type, "POINT") == 0)
  52. return SF_POINT;
  53. else if (G_strcasecmp(type, "LINESTRING") == 0)
  54. return SF_LINESTRING;
  55. else if (G_strcasecmp(type, "POLYGON") == 0)
  56. return SF_POLYGON;
  57. else if (G_strcasecmp(type, "MULTIPOINT") == 0)
  58. return SF_MULTIPOINT;
  59. else if (G_strcasecmp(type, "MULTILINESTRING") == 0)
  60. return SF_MULTILINESTRING;
  61. else if (G_strcasecmp(type, "MULTIPOLYGON") == 0)
  62. return SF_MULTIPOLYGON;
  63. else if (G_strcasecmp(type, "GEOMETRYCOLLECTION") == 0)
  64. return SF_GEOMETRYCOLLECTION;
  65. return SF_UNKNOWN;
  66. G_debug(3, "ftype_from_string(): type='%s' -> %d", type, sf_type);
  67. return sf_type;
  68. }
  69. #endif
  70. /*!
  71. \brief Open existing PostGIS feature table (level 1 - without topology)
  72. \todo Check database instead of geometry_columns
  73. \param[in,out] Map pointer to Map_info structure
  74. \param update TRUE for write mode, otherwise read-only
  75. \return 0 success
  76. \return -1 error
  77. */
  78. int V1_open_old_pg(struct Map_info *Map, int update)
  79. {
  80. #ifdef HAVE_POSTGRES
  81. int found, ntables, i;
  82. dbString stmt;
  83. PGresult *res;
  84. struct Format_info_pg *pg_info;
  85. db_init_string(&stmt);
  86. pg_info = &(Map->fInfo.pg);
  87. if (!pg_info->conninfo) {
  88. G_warning(_("Connection string not defined"));
  89. return -1;
  90. }
  91. if (!pg_info->table_name) {
  92. G_warning(_("PostGIS feature table not defined"));
  93. return -1;
  94. }
  95. G_debug(1, "V1_open_old_pg(): conninfo='%s' table='%s'", pg_info->conninfo,
  96. pg_info->table_name);
  97. /* connect database */
  98. pg_info->conn = PQconnectdb(pg_info->conninfo);
  99. G_debug(2, " PQconnectdb(): %s", pg_info->conninfo);
  100. if (PQstatus(pg_info->conn) == CONNECTION_BAD)
  101. G_fatal_error("%s\n%s", _("Connection ton PostgreSQL database failed."),
  102. PQerrorMessage(pg_info->conn));
  103. /* get DB name */
  104. pg_info->db_name = G_store(PQdb(pg_info->conn));
  105. if (!pg_info->db_name) {
  106. G_warning(_("Unable to get database name"));
  107. return -1;
  108. }
  109. /* get fid and geometry column */
  110. db_set_string(&stmt, "SELECT f_table_name, f_geometry_column,"
  111. "coord_dimension,srid,type "
  112. "FROM geometry_columns");
  113. G_debug(2, "SQL: %s", db_get_string(&stmt));
  114. res = PQexec(pg_info->conn, db_get_string(&stmt));
  115. if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
  116. G_fatal_error("%s\n%s", _("No feature tables found in database."),
  117. PQresultErrorMessage(res));
  118. ntables = PQntuples(res);
  119. G_debug(3, "\tnrows = %d", ntables);
  120. found = FALSE;
  121. for (i = 0; i < ntables; i++) {
  122. if (strcmp(PQgetvalue(res, i, 0), pg_info->table_name) == 0) {
  123. /* geometry column */
  124. pg_info->geom_column = G_store(PQgetvalue(res, i, 1));
  125. G_debug(3, "\t-> table = %s column = %s", pg_info->table_name,
  126. pg_info->geom_column);
  127. /* fid column */
  128. pg_info->fid_column = get_key_column(pg_info);
  129. /* coordinates dimension */
  130. pg_info->coor_dim = atoi(PQgetvalue(res, i, 2));
  131. /* SRS ID */
  132. pg_info->srid = atoi(PQgetvalue(res, i, 3));
  133. /* feature type */
  134. pg_info->feature_type = ftype_from_string(PQgetvalue(res, i, 4));
  135. found = TRUE;
  136. break;
  137. }
  138. }
  139. /* no feature in cache */
  140. pg_info->cache.fid = -1;
  141. PQclear(res);
  142. db_free_string(&stmt);
  143. if (!found) {
  144. G_warning(_("Feature table <%s> not found in 'geometry_columns'"));
  145. return -1;
  146. }
  147. return 0;
  148. #else
  149. G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
  150. return -1;
  151. #endif
  152. }
  153. /*!
  154. \brief Open existing PostGIS layer (level 2 - feature index)
  155. \param[in,out] Map pointer to Map_info structure
  156. \return 0 success
  157. \return -1 error
  158. */
  159. int V2_open_old_pg(struct Map_info *Map)
  160. {
  161. #ifdef HAVE_POSTGRES
  162. G_debug(3, "V2_open_old_pg(): name = %s mapset = %s", Map->name,
  163. Map->mapset);
  164. if (Vect_open_fidx(Map, &(Map->fInfo.pg.offset)) != 0) {
  165. G_warning(_("Unable to open feature index file for vector map <%s>"),
  166. Vect_get_full_name(Map));
  167. G_zero(&(Map->fInfo.pg.offset), sizeof(struct Format_info_offset));
  168. }
  169. return 0;
  170. #else
  171. G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
  172. return -1;
  173. #endif
  174. }
  175. /*!
  176. \brief Prepare PostGIS database for creating new feature table
  177. (level 1)
  178. \todo To implement
  179. \param[out] Map pointer to Map_info structure
  180. \param name name of PostGIS feature table to create
  181. \param with_z WITH_Z for 3D vector data otherwise WITHOUT_Z
  182. \return 0 success
  183. \return -1 error
  184. */
  185. int V1_open_new_pg(struct Map_info *Map, const char *name, int with_z)
  186. {
  187. G_debug(1, "V1_open_new_pg(): name = %s with_z = %d", name, with_z);
  188. #ifdef HAVE_POSTGRES
  189. return 0;
  190. #else
  191. G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
  192. return -1;
  193. #endif
  194. }