main.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /***************************************************************
  2. *
  3. * MODULE: v.out.postgis
  4. *
  5. * AUTHOR(S): Martin Landa <landa.martin gmail.com>
  6. *
  7. * PURPOSE: Converts GRASS vector map layer to PostGIS
  8. *
  9. * COPYRIGHT: (C) 2012-2013 by Martin Landa, and the GRASS Development Team
  10. *
  11. * This program is free software under the GNU General
  12. * Public License (>=v2). Read the file COPYING that
  13. * comes with GRASS for details.
  14. *
  15. **************************************************************/
  16. #include <stdlib.h>
  17. #include <grass/gis.h>
  18. #include <grass/glocale.h>
  19. #include <libpq-fe.h>
  20. #include "local_proto.h"
  21. static void link_handler(void *);
  22. static void output_handler(void *);
  23. int main(int argc, char *argv[])
  24. {
  25. struct GModule *module;
  26. struct params params;
  27. struct flags flags;
  28. int ret, field, otype;
  29. char *schema, *olayer, *pg_file;
  30. char *fid_column, *geom_column;
  31. struct Map_info In, Out;
  32. G_gisinit(argv[0]);
  33. module = G_define_module();
  34. G_add_keyword(_("vector"));
  35. G_add_keyword(_("export"));
  36. G_add_keyword(_("PostGIS"));
  37. G_add_keyword(_("simple features"));
  38. G_add_keyword(_("topology"));
  39. G_add_keyword(_("3D"));
  40. module->description =
  41. _("Exports a vector map layer to PostGIS feature table.");
  42. module->overwrite = TRUE;
  43. define_options(&params, &flags);
  44. if (G_parser(argc, argv))
  45. exit(EXIT_FAILURE);
  46. /* parse parameters */
  47. otype = Vect_option_to_types(params.type);
  48. /* if olayer not given, use input as the name */
  49. schema = NULL;
  50. if (!params.olayer->answer) {
  51. char name[GNAME_MAX], mapset[GMAPSET_MAX];
  52. /* check for fully qualified name */
  53. if (G_name_is_fully_qualified(params.input->answer,
  54. name, mapset))
  55. olayer = G_store(name);
  56. else
  57. olayer = G_store(params.input->answer);
  58. G_debug(1, "olayer=%s", olayer);
  59. }
  60. else {
  61. /* check for schema */
  62. char **tokens;
  63. tokens = G_tokenize(params.olayer->answer, ".");
  64. if (G_number_of_tokens(tokens) == 2) {
  65. schema = G_store(tokens[0]);
  66. olayer = G_store(tokens[1]);
  67. }
  68. else {
  69. olayer = G_store(params.olayer->answer);
  70. }
  71. G_free_tokens(tokens);
  72. }
  73. /* if schema not defined, use 'public' */
  74. if (!schema)
  75. schema = "public";
  76. G_debug(1, "Database schema: %s", schema);
  77. /* open input for reading */
  78. ret = Vect_open_old2(&In, params.input->answer, "", params.layer->answer);
  79. if (ret == -1)
  80. G_fatal_error(_("Unable to open vector map <%s>"),
  81. params.input->answer);
  82. if (Vect_maptype(&In) != GV_FORMAT_NATIVE)
  83. G_fatal_error(_("Vector map <%s> is not in native format. Export cancelled."),
  84. Vect_get_full_name(&In));
  85. Vect_set_error_handler_io(&In, NULL);
  86. if (params.olink->answer)
  87. G_add_error_handler(link_handler, params.olink->answer);
  88. if (ret < 2)
  89. G_warning(_("Unable to open vector map <%s> on topological level"),
  90. params.input->answer);
  91. /* default columns */
  92. fid_column = GV_PG_FID_COLUMN;
  93. geom_column = GV_PG_GEOMETRY_COLUMN;
  94. /* create output for writing */
  95. pg_file = create_pgfile(params.dsn->answer, schema, params.olink->answer,
  96. params.opts->answers, flags.topo->answer ? TRUE : FALSE,
  97. &fid_column, &geom_column);
  98. G_debug(1, "fid_column: %s", fid_column);
  99. G_debug(1, "geom_column: %s", geom_column);
  100. if (!flags.table->answer) {
  101. /* check fid column */
  102. check_columns(&In, params.layer->answer, fid_column, geom_column);
  103. }
  104. /* don't use temporary maps, writes vector features immediately to
  105. the output PostGIS layer */
  106. putenv("GRASS_VECTOR_EXTERNAL_IMMEDIATE=1");
  107. if (-1 == Vect_open_new(&Out, olayer,
  108. !flags.force2d->answer ? Vect_is_3d(&In) : WITHOUT_Z))
  109. G_fatal_error(_("Unable to create PostGIS layer <%s>"),
  110. olayer);
  111. G_add_error_handler(output_handler, &Out);
  112. /* copy attributes (must be done before checking output type
  113. otherwise attributes are not copied) */
  114. field = Vect_get_field_number(&In, params.layer->answer);
  115. if (!flags.table->answer)
  116. Vect_copy_map_dblinks(&In, &Out, TRUE);
  117. /* check output type */
  118. if (otype < 1 && Vect_level(&In) > 1) {
  119. /* type 'auto' -> try to guess output feature type on level 2 */
  120. if (Vect_get_num_areas(&In) > 0)
  121. otype = GV_AREA;
  122. else if (Vect_get_num_primitives(&In, GV_LINE) > 0)
  123. otype = GV_LINE;
  124. else if (Vect_get_num_primitives(&In, GV_POINT) > 0)
  125. otype = GV_POINT;
  126. }
  127. if (otype > 0) {
  128. if (otype & (GV_FACE | GV_KERNEL))
  129. G_fatal_error(_("Feature type '%s' not supported"),
  130. params.type->answer);
  131. /* set up output feature type if possible */
  132. if (Vect_write_line(&Out, otype, NULL, NULL) < 0)
  133. G_fatal_error(_("Feature type %d is not supported"), otype);
  134. Vect_set_constraint_type(&In, otype);
  135. }
  136. /* copy vector features & create PostGIS table */
  137. if (Vect_copy_map_lines_field(&In, field, &Out) != 0)
  138. G_fatal_error(_("Copying features failed"));
  139. /* close input map */
  140. Vect_close(&In);
  141. /* build topology for output map */
  142. Vect_build_partial(&Out, GV_BUILD_NONE);
  143. if (Vect_build(&Out) != 1)
  144. G_fatal_error(_("Building %s topology failed"),
  145. flags.topo->answer ? "PostGIS" : "pseudo");
  146. if (Vect_get_num_lines(&Out) < 1)
  147. G_fatal_error(_("No features exported. PostGIS layer <%s> not created."),
  148. Vect_get_name(&Out));
  149. if (!flags.topo->answer)
  150. G_done_msg(n_("%d feature (%s type) written to <%s>.",
  151. "%d features (%s type) written to <%s>.",
  152. Vect_sfa_get_num_features(&Out)),
  153. Vect_sfa_get_num_features(&Out), Vect_get_finfo_geometry_type(&Out),
  154. Vect_get_name(&Out));
  155. else
  156. G_done_msg(n_("%d primitive written to <%s>.",
  157. "%d primitives written to <%s>.",
  158. Vect_get_num_lines(&Out)),
  159. Vect_get_num_lines(&Out),
  160. Vect_get_name(&Out));
  161. /* close output map */
  162. Vect_close(&Out);
  163. /* remove PG file */
  164. G_remove("", pg_file);
  165. exit(EXIT_SUCCESS);
  166. }
  167. void link_handler(void *p)
  168. {
  169. const char *link = (const char *) p;
  170. G_debug(1, "link_handler: %s", link);
  171. if (G_find_vector2(link, G_mapset()))
  172. Vect_delete(link);
  173. }
  174. void output_handler(void *p)
  175. {
  176. char stmt[DB_SQL_MAX];
  177. struct Map_info *Map;
  178. struct Format_info_pg *pg_info;
  179. PGresult *result;
  180. Map = (struct Map_info *) p;
  181. pg_info = &Map->fInfo.pg;
  182. G_debug(1, "output_handler(): schema = %s; olayer = %s", pg_info->schema_name, pg_info->table_name);
  183. sprintf(stmt, "SELECT DropGeometryTable('%s', '%s')", pg_info->schema_name, pg_info->table_name);
  184. result = PQexec(pg_info->conn, stmt);
  185. /*
  186. be quiet - table may do not exists
  187. if (!result || PQresultStatus(result) != PGRES_TUPLES_OK) {
  188. G_warning(_("Unable to drop table <%s.%s>"), pg_info->schema_name, pg_info->table_name);
  189. }
  190. */
  191. PQclear(result);
  192. if (pg_info->toposchema_name) {
  193. sprintf(stmt, "SELECT topology.DropTopology('%s')", pg_info->toposchema_name);
  194. result = PQexec(pg_info->conn, stmt);
  195. if (!result || PQresultStatus(result) != PGRES_TUPLES_OK) {
  196. G_warning(_("Unable to drop topology schema <%s>"), pg_info->toposchema_name);
  197. }
  198. PQclear(result);
  199. }
  200. }