main.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  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, verbose;
  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(_("output"));
  37. G_add_keyword(_("PostGIS"));
  38. G_add_keyword(_("simple features"));
  39. G_add_keyword(_("topology"));
  40. G_add_keyword(_("3D"));
  41. module->description =
  42. _("Exports a vector map layer to PostGIS feature table.");
  43. module->overwrite = TRUE;
  44. define_options(&params, &flags);
  45. if (G_parser(argc, argv))
  46. exit(EXIT_FAILURE);
  47. /* parse parameters */
  48. otype = Vect_option_to_types(params.type);
  49. /* if olayer not given, use input as the name */
  50. schema = NULL;
  51. if (!params.olayer->answer) {
  52. char name[GNAME_MAX], mapset[GMAPSET_MAX];
  53. /* check for fully qualified name */
  54. if (G_name_is_fully_qualified(params.input->answer,
  55. name, mapset))
  56. olayer = G_store(name);
  57. else
  58. olayer = G_store(params.input->answer);
  59. G_debug(1, "olayer=%s", olayer);
  60. }
  61. else {
  62. /* check for schema */
  63. char **tokens;
  64. tokens = G_tokenize(params.olayer->answer, ".");
  65. if (G_number_of_tokens(tokens) == 2) {
  66. schema = G_store(tokens[0]);
  67. olayer = G_store(tokens[1]);
  68. }
  69. else {
  70. olayer = G_store(params.olayer->answer);
  71. }
  72. G_free_tokens(tokens);
  73. }
  74. /* if schema not defined, use 'public' */
  75. if (!schema)
  76. schema = "public";
  77. G_debug(1, "Database schema: %s", schema);
  78. /* open input for reading */
  79. ret = Vect_open_old2(&In, params.input->answer, "", params.layer->answer);
  80. if (ret == -1)
  81. G_fatal_error(_("Unable to open vector map <%s>"),
  82. params.input->answer);
  83. if (Vect_maptype(&In) != GV_FORMAT_NATIVE)
  84. G_fatal_error(_("Vector map <%s> is not in native format. Export cancelled."),
  85. Vect_get_full_name(&In));
  86. Vect_set_error_handler_io(&In, NULL);
  87. if (params.olink->answer)
  88. G_add_error_handler(link_handler, params.olink->answer);
  89. if (ret < 2)
  90. G_warning(_("Unable to open vector map <%s> on topological level"),
  91. params.input->answer);
  92. /* default columns */
  93. fid_column = GV_PG_FID_COLUMN;
  94. geom_column = GV_PG_GEOMETRY_COLUMN;
  95. /* create output for writing */
  96. pg_file = create_pgfile(params.dsn->answer, schema, params.olink->answer,
  97. params.opts->answers, flags.topo->answer ? TRUE : FALSE,
  98. &fid_column, &geom_column);
  99. G_debug(1, "fid_column: %s", fid_column);
  100. G_debug(1, "geom_column: %s", geom_column);
  101. if (!flags.table->answer) {
  102. /* check fid column */
  103. check_columns(&In, params.layer->answer, fid_column, geom_column);
  104. }
  105. /* don't use temporary maps, writes vector features immediately to
  106. the output PostGIS layer */
  107. putenv("GRASS_VECTOR_EXTERNAL_IMMEDIATE=1");
  108. if (-1 == Vect_open_new(&Out, olayer,
  109. !flags.force2d->answer ? Vect_is_3d(&In) : WITHOUT_Z))
  110. G_fatal_error(_("Unable to create PostGIS layer <%s>"),
  111. olayer);
  112. G_add_error_handler(output_handler, &Out);
  113. /* copy attributes (must be done before checking output type
  114. otherwise attributes are not copied) */
  115. field = Vect_get_field_number(&In, params.layer->answer);
  116. /* BUG: this works only if the input vector uses for its attributes
  117. * the same PG connection to be used for the output */
  118. if (!flags.table->answer)
  119. Vect_copy_map_dblinks(&In, &Out, TRUE);
  120. /* check output type */
  121. if (otype < 1 && Vect_level(&In) > 1) {
  122. /* type 'auto' -> try to guess output feature type on level 2 */
  123. if (Vect_get_num_areas(&In) > 0)
  124. otype = GV_AREA;
  125. else if (Vect_get_num_primitives(&In, GV_LINE) > 0)
  126. otype = GV_LINE;
  127. else if (Vect_get_num_primitives(&In, GV_POINT) > 0)
  128. otype = GV_POINT;
  129. }
  130. if (otype > 0) {
  131. if (otype & (GV_FACE | GV_KERNEL))
  132. G_fatal_error(_("Feature type '%s' not supported"),
  133. params.type->answer);
  134. /* set up output feature type if possible */
  135. if (Vect_write_line(&Out, otype, NULL, NULL) < 0)
  136. G_fatal_error(_("Feature type %d is not supported"), otype);
  137. Vect_set_constraint_type(&In, otype);
  138. }
  139. /* copy vector features & create PostGIS table */
  140. if (Vect_copy_map_lines_field(&In, field, &Out) != 0)
  141. G_fatal_error(_("Copying features failed"));
  142. /* close input map */
  143. Vect_close(&In);
  144. /* build topology for output map -> write output to DB */
  145. G_message(_("Writing output..."));
  146. verbose = G_verbose();
  147. if (!flags.topo->answer)
  148. G_set_verbose(0); /* do not print build info when writing simple features */
  149. Vect_build_partial(&Out, GV_BUILD_NONE);
  150. if (Vect_build(&Out) != 1)
  151. G_fatal_error(_("Building %s topology failed"),
  152. flags.topo->answer ? "PostGIS" : "pseudo");
  153. G_set_verbose(verbose);
  154. if (Vect_get_num_lines(&Out) < 1)
  155. G_fatal_error(_("No features exported. PostGIS layer <%s> not created."),
  156. Vect_get_name(&Out));
  157. if (!flags.topo->answer)
  158. G_done_msg(n_("%d feature (%s type) written to <%s>.",
  159. "%d features (%s type) written to <%s>.",
  160. Vect_sfa_get_num_features(&Out)),
  161. Vect_sfa_get_num_features(&Out), Vect_get_finfo_geometry_type(&Out),
  162. Vect_get_name(&Out));
  163. else
  164. G_done_msg(n_("%d primitive written to <%s>.",
  165. "%d primitives written to <%s>.",
  166. Vect_get_num_lines(&Out)),
  167. Vect_get_num_lines(&Out),
  168. Vect_get_name(&Out));
  169. /* close output map */
  170. Vect_close(&Out);
  171. /* remove PG file */
  172. G_remove("", pg_file);
  173. exit(EXIT_SUCCESS);
  174. }
  175. void link_handler(void *p)
  176. {
  177. const char *link = (const char *) p;
  178. G_debug(1, "link_handler: %s", link);
  179. if (G_find_vector2(link, G_mapset()))
  180. Vect_delete(link);
  181. }
  182. void output_handler(void *p)
  183. {
  184. char stmt[DB_SQL_MAX];
  185. struct Map_info *Map;
  186. struct Format_info_pg *pg_info;
  187. PGresult *result;
  188. Map = (struct Map_info *) p;
  189. pg_info = &Map->fInfo.pg;
  190. G_debug(1, "output_handler(): schema = %s; olayer = %s", pg_info->schema_name, pg_info->table_name);
  191. sprintf(stmt, "SELECT DropGeometryTable('%s', '%s')", pg_info->schema_name, pg_info->table_name);
  192. result = PQexec(pg_info->conn, stmt);
  193. /*
  194. be quiet - table may do not exists
  195. if (!result || PQresultStatus(result) != PGRES_TUPLES_OK) {
  196. G_warning(_("Unable to drop table <%s.%s>"), pg_info->schema_name, pg_info->table_name);
  197. }
  198. */
  199. PQclear(result);
  200. if (pg_info->toposchema_name) {
  201. sprintf(stmt, "SELECT topology.DropTopology('%s')", pg_info->toposchema_name);
  202. result = PQexec(pg_info->conn, stmt);
  203. if (!result || PQresultStatus(result) != PGRES_TUPLES_OK) {
  204. G_warning(_("Unable to drop topology schema <%s>"), pg_info->toposchema_name);
  205. }
  206. PQclear(result);
  207. }
  208. }