PostGIS  3.0.6dev-r@@SVN_REVISION@@
shp2pgsql-cli.c
Go to the documentation of this file.
1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  * http://www.postgis.org
5  * Copyright 2008 OpenGeo.org
6  * Copyright 2009 Mark Cave-Ayland <mark.cave-ayland@siriusit.co.uk>
7  *
8  * This is free software; you can redistribute and/or modify it under
9  * the terms of the GNU General Public Licence. See the COPYING file.
10  *
11  * Maintainer: Paul Ramsey <pramsey@opengeo.org>
12  *
13  **********************************************************************/
14 
15 #include "../postgis_config.h"
16 
17 #include "shp2pgsql-core.h"
18 #include "../liblwgeom/liblwgeom.h" /* for SRID_UNKNOWN */
19 
20 #define xstr(s) str(s)
21 #define str(s) #s
22 
23 static void
25 {
26  printf(_( "RELEASE: %s (%s)\n" ), POSTGIS_LIB_VERSION, xstr(POSTGIS_REVISION));
27  printf(_( "USAGE: shp2pgsql [<options>] <shapefile> [[<schema>.]<table>]\n"
28  "OPTIONS:\n" ));
29  printf(_( " -s [<from>:]<srid> Set the SRID field. Defaults to %d.\n"
30  " Optionally reprojects from given SRID.\n"),
31  SRID_UNKNOWN);
32  printf(_( " (-d|a|c|p) These are mutually exclusive options:\n"
33  " -d Drops the table, then recreates it and populates\n"
34  " it with current shape file data.\n"
35  " -a Appends shape file into current table, must be\n"
36  " exactly the same table schema.\n"
37  " -c Creates a new table and populates it, this is the\n"
38  " default if you do not specify any options.\n"
39  " -p Prepare mode, only creates the table.\n" ));
40  printf(_( " -g <geocolumn> Specify the name of the geometry/geography column\n"
41  " (mostly useful in append mode).\n" ));
42  printf(_( " -D Use postgresql dump format (defaults to SQL insert statements).\n" ));
43  printf(_( " -e Execute each statement individually, do not use a transaction.\n"
44  " Not compatible with -D.\n" ));
45  printf(_( " -G Use geography type (requires lon/lat data or -s to reproject).\n" ));
46  printf(_( " -k Keep postgresql identifiers case.\n" ));
47  printf(_( " -i Use int4 type for all integer dbf fields.\n" ));
48  printf(_( " -I Create a spatial index on the geocolumn.\n" ));
49  printf(_(" -m <filename> Specify a file containing a set of mappings of (long) column\n"
50  " names to 10 character DBF column names. The content of the file is one or\n"
51  " more lines of two names separated by white space and no trailing or\n"
52  " leading space. For example:\n"
53  " COLUMNNAME DBFFIELD1\n"
54  " AVERYLONGCOLUMNNAME DBFFIELD2\n" ));
55  printf(_( " -S Generate simple geometries instead of MULTI geometries.\n" ));
56  printf(_( " -t <dimensionality> Force geometry to be one of '2D', '3DZ', '3DM', or '4D'\n" ));
57 
58  printf(_( " -w Output WKT instead of WKB. Note that this can result in\n"
59  " coordinate drift.\n" ));
60  printf(_( " -W <encoding> Specify the character encoding of Shape's\n"
61  " attribute column. (default: \"UTF-8\")\n" ));
62  printf(_( " -N <policy> NULL geometries handling policy (insert*,skip,abort).\n" ));
63  printf(_( " -n Only import DBF file.\n" ));
64  printf(_( " -T <tablespace> Specify the tablespace for the new table.\n"
65  " Note that indexes will still use the default tablespace unless the\n"
66  " -X flag is also used.\n"));
67  printf(_( " -X <tablespace> Specify the tablespace for the table's indexes.\n"
68  " This applies to the primary key, and the spatial index if\n"
69  " the -I flag is used.\n" ));
70  printf(_( " -? Display this help screen.\n" ));
71  printf( "\n" );
72  printf(_( " An argument of `--' disables further option processing.\n" ));
73  printf(_( " (useful for unusual file names starting with '-')\n" ));
74 }
75 
76 
77 int
78 main (int argc, char **argv)
79 {
80  SHPLOADERCONFIG *config;
81  SHPLOADERSTATE *state;
82  char *header, *footer, *record;
83  int c;
84  int ret, i;
85 
86 #ifdef ENABLE_NLS
87  setlocale (LC_ALL, "");
88  bindtextdomain (PACKAGE, PGSQL_LOCALEDIR);
89  textdomain (PACKAGE);
90 #endif
91 
92  /* If no options are specified, display usage */
93  if (argc == 1)
94  {
95  usage();
96  exit(0);
97  }
98 
99  /* Parse command line options and set configuration */
100  config = malloc(sizeof(SHPLOADERCONFIG));
102 
103  /* Keep the flag list alphabetic so it's easy to see what's left. */
104  while ((c = pgis_getopt(argc, argv, "-acdeg:ikm:nps:t:wDGIN:ST:W:X:")) != EOF)
105  {
106  // can not do this inside the switch case
107  if ('-' == c)
108  break;
109 
110  switch (c)
111  {
112  case 'c':
113  case 'd':
114  case 'a':
115  case 'p':
116  config->opt = c;
117  break;
118 
119  case 'D':
120  config->dump_format = 1;
121  break;
122 
123  case 'G':
124  config->geography = 1;
125  break;
126 
127  case 'S':
128  config->simple_geometries = 1;
129  break;
130 
131  case 's':
132  if (pgis_optarg)
133  {
134  char *ptr = strchr(pgis_optarg, ':');
135  if (ptr)
136  {
137  *ptr++ = '\0';
138  sscanf(pgis_optarg, "%d", &config->shp_sr_id);
139  sscanf(ptr, "%d", &config->sr_id);
140  }
141  else
142  {
143  /* Only TO_SRID specified */
144  sscanf(pgis_optarg, "%d", &config->sr_id);
145  }
146  }
147  else
148  {
149  /* With -s, user must specify TO_SRID or FROM_SRID:TO_SRID */
150  fprintf(stderr, "The -s parameter must be specified in the form [FROM_SRID:]TO_SRID\n");
151  exit(1);
152  }
153  break;
154  case 'g':
155  config->geo_col = pgis_optarg;
156  break;
157  case 'm':
159  break;
160 
161  case 'k':
162  config->quoteidentifiers = 1;
163  break;
164 
165  case 'i':
166  config->forceint4 = 1;
167  break;
168 
169  case 'I':
170  config->createindex = 1;
171  break;
172 
173  case 'w':
174  config->use_wkt = 1;
175  break;
176 
177  case 'n':
178  config->readshape = 0;
179  break;
180 
181  case 'W':
182  config->encoding = strdup(pgis_optarg);
183  break;
184 
185  case 'N':
186  switch (pgis_optarg[0])
187  {
188  case 'a':
189  config->null_policy = POLICY_NULL_ABORT;
190  break;
191  case 'i':
193  break;
194  case 's':
195  config->null_policy = POLICY_NULL_SKIP;
196  break;
197  default:
198  fprintf(stderr, "Unsupported NULL geometry handling policy.\nValid policies: insert, skip, abort\n");
199  exit(1);
200  }
201  break;
202 
203  case 't':
204  if (strcasecmp(pgis_optarg, "2D") == 0)
205  {
206  config->force_output = FORCE_OUTPUT_2D;
207  }
208  else if (strcasecmp(pgis_optarg, "3DZ") == 0 )
209  {
210  config->force_output = FORCE_OUTPUT_3DZ;
211  }
212  else if (strcasecmp(pgis_optarg, "3DM") == 0 )
213  {
214  config->force_output = FORCE_OUTPUT_3DM;
215  }
216  else if (strcasecmp(pgis_optarg, "4D") == 0 )
217  {
218  config->force_output = FORCE_OUTPUT_4D;
219  }
220  else
221  {
222  fprintf(stderr, "Unsupported output type: %s\nValid output types are 2D, 3DZ, 3DM and 4D\n", pgis_optarg);
223  exit(1);
224  }
225  break;
226 
227  case 'T':
228  config->tablespace = pgis_optarg;
229  break;
230 
231  case 'X':
232  config->idxtablespace = pgis_optarg;
233  break;
234 
235  case 'e':
236  config->usetransaction = 0;
237  break;
238 
239  case '?':
240  usage();
241  exit(0);
242 
243  default:
244  usage();
245  exit(0);
246  }
247  }
248 
249  /* Once we have parsed the arguments, make sure certain combinations are valid */
250  if (config->dump_format && !config->usetransaction)
251  {
252  fprintf(stderr, "Invalid argument combination - cannot use both -D and -e\n");
253  exit(1);
254  }
255 
256  /* Determine the shapefile name from the next argument, if no shape file, exit. */
257  if (pgis_optind < argc)
258  {
259  config->shp_file = argv[pgis_optind];
260  pgis_optind++;
261  }
262  else
263  {
264  usage();
265  exit(0);
266  }
267 
268  /* Determine the table and schema names from the next argument */
269  if (pgis_optind < argc)
270  {
271  char *strptr = argv[pgis_optind];
272  char *chrptr = strchr(strptr, '.');
273 
274  /* OK, this is a schema-qualified table name... */
275  if (chrptr)
276  {
277  if ( chrptr == strptr )
278  {
279  /* ".something" ??? */
280  usage();
281  exit(0);
282  }
283  /* Null terminate at the '.' */
284  *chrptr = '\0';
285  /* Copy in the parts */
286  config->schema = strdup(strptr);
287  config->table = strdup(chrptr+1);
288  }
289  else
290  {
291  config->table = strdup(strptr);
292  }
293  }
294 
295  /* If the table parameter is not provided, use the shape file name as a proxy value.
296  Strip out the .shp and the leading path information first. */
297  if ( config->shp_file && config->table == NULL)
298  {
299  char *shp_file = strdup(config->shp_file);
300  char *ptr;
301 
302  /* Remove the extension, if present */
303  for ( ptr = shp_file + strlen(shp_file); ptr > shp_file; ptr-- )
304  {
305  if ( *ptr == '.' )
306  {
307  *ptr = '\0';
308  break;
309  }
310  }
311 
312  /* The remaining non-path section is the table name */
313  for ( ptr = shp_file + strlen(shp_file); ptr > shp_file; ptr-- )
314  {
315  if ( *ptr == '/' || *ptr == '\\' )
316  {
317  ptr++;
318  break;
319  }
320  }
321  config->table = strdup(ptr);
322  free(shp_file);
323  }
324 
325 
326  /* Transform table name to lower case if no quoting specified */
327  if (!config->quoteidentifiers)
328  {
329  if ( config->table )
330  strtolower(config->table);
331  if ( config->schema )
332  strtolower(config->schema);
333  }
334 
335  /* Create the shapefile state object */
336  state = ShpLoaderCreate(config);
337 
338  /* Open the shapefile */
339  ret = ShpLoaderOpenShape(state);
340  if (ret != SHPLOADEROK)
341  {
342  fprintf(stderr, "%s\n", state->message);
343 
344  if (ret == SHPLOADERERR)
345  exit(1);
346  }
347 
348  /* If reading the whole shapefile, display its type */
349  if (state->config->readshape)
350  {
351  fprintf(stderr, "Shapefile type: %s\n", SHPTypeName(state->shpfiletype));
352  fprintf(stderr, "Postgis type: %s[%d]\n", state->pgtype, state->pgdims);
353  }
354 
355  /* Print the header to stdout */
356  ret = ShpLoaderGetSQLHeader(state, &header);
357  if (ret != SHPLOADEROK)
358  {
359  fprintf(stderr, "%s\n", state->message);
360 
361  if (ret == SHPLOADERERR)
362  exit(1);
363  }
364 
365  printf("%s", header);
366  free(header);
367 
368  /* If we are not in "prepare" mode, go ahead and write out the data. */
369  if ( state->config->opt != 'p' )
370  {
371 
372  /* If in COPY mode, output the COPY statement */
373  if (state->config->dump_format)
374  {
375  ret = ShpLoaderGetSQLCopyStatement(state, &header);
376  if (ret != SHPLOADEROK)
377  {
378  fprintf(stderr, "%s\n", state->message);
379 
380  if (ret == SHPLOADERERR)
381  exit(1);
382  }
383 
384  printf("%s", header);
385  free(header);
386  }
387 
388  /* Main loop: iterate through all of the records and send them to stdout */
389  for (i = 0; i < ShpLoaderGetRecordCount(state); i++)
390  {
391  ret = ShpLoaderGenerateSQLRowStatement(state, i, &record);
392 
393  switch (ret)
394  {
395  case SHPLOADEROK:
396  /* Simply display the geometry */
397  printf("%s\n", record);
398  free(record);
399  break;
400 
401  case SHPLOADERERR:
402  /* Display the error message then stop */
403  fprintf(stderr, "%s\n", state->message);
404  exit(1);
405  break;
406 
407  case SHPLOADERWARN:
408  /* Display the warning, but continue */
409  fprintf(stderr, "%s\n", state->message);
410  printf("%s\n", record);
411  free(record);
412  break;
413 
414  case SHPLOADERRECDELETED:
415  /* Record is marked as deleted - ignore */
416  break;
417 
418  case SHPLOADERRECISNULL:
419  /* Record is NULL and should be ignored according to NULL policy */
420  break;
421  }
422  }
423 
424  /* If in COPY mode, terminate the COPY statement */
425  if (state->config->dump_format)
426  printf("\\.\n");
427 
428  }
429 
430  /* Print the footer to stdout */
431  ret = ShpLoaderGetSQLFooter(state, &footer);
432  if (ret != SHPLOADEROK)
433  {
434  fprintf(stderr, "%s\n", state->message);
435 
436  if (ret == SHPLOADERERR)
437  exit(1);
438  }
439 
440  printf("%s", footer);
441  free(footer);
442 
443 
444  /* Free the state object */
445  ShpLoaderDestroy(state);
446 
447  /* Free configuration variables */
448  if (config->schema)
449  free(config->schema);
450  if (config->table)
451  free(config->table);
452  if (config->encoding)
453  free(config->encoding);
454  free(config);
455 
456  return 0;
457 }
int pgis_optind
Definition: getopt.c:39
int pgis_getopt(int argc, char **argv, char *opts)
Definition: getopt.c:44
char * pgis_optarg
Definition: getopt.c:41
int main(int argc, char *argv[])
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:229
void * malloc(YYSIZE_T)
void free(void *)
const char SHPAPI_CALL1 * SHPTypeName(int nSHPType);const char SHPAPI_CALL1(*) SHPPartTypeName(int nPartType
Definition: shpopen.c:2092
static void usage()
Definition: shp2pgsql-cli.c:24
#define xstr(s)
Definition: shp2pgsql-cli.c:20
int ShpLoaderGetRecordCount(SHPLOADERSTATE *state)
void strtolower(char *s)
void ShpLoaderDestroy(SHPLOADERSTATE *state)
int ShpLoaderGetSQLCopyStatement(SHPLOADERSTATE *state, char **strheader)
int ShpLoaderOpenShape(SHPLOADERSTATE *state)
int ShpLoaderGenerateSQLRowStatement(SHPLOADERSTATE *state, int item, char **strrecord)
void set_loader_config_defaults(SHPLOADERCONFIG *config)
int ShpLoaderGetSQLFooter(SHPLOADERSTATE *state, char **strfooter)
SHPLOADERSTATE * ShpLoaderCreate(SHPLOADERCONFIG *config)
int ShpLoaderGetSQLHeader(SHPLOADERSTATE *state, char **strheader)
#define FORCE_OUTPUT_4D
#define POLICY_NULL_ABORT
#define FORCE_OUTPUT_2D
#define SHPLOADERRECISNULL
#define SHPLOADERWARN
#define FORCE_OUTPUT_3DM
#define POLICY_NULL_SKIP
#define POLICY_NULL_INSERT
#define SHPLOADERRECDELETED
#define SHPLOADERERR
#define SHPLOADEROK
#define FORCE_OUTPUT_3DZ
#define _(String)
Definition: shpcommon.h:24
#define POSTGIS_LIB_VERSION
Definition: sqldefines.h:13
char message[SHPLOADERMSGLEN]
SHPLOADERCONFIG * config