PostGIS  3.7.0dev-r@@SVN_REVISION@@
shp2pgsql-core.c
Go to the documentation of this file.
1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  * http://postgis.net
5  *
6  * Copyright (C) 2008 OpenGeo.org
7  * Copyright (C) 2009 Mark Cave-Ayland <mark.cave-ayland@siriusit.co.uk>
8  *
9  * This is free software; you can redistribute and/or modify it under
10  * the terms of the GNU General Public Licence. See the COPYING file.
11  *
12  * Maintainer: Paul Ramsey <pramsey@cleverelephant.ca>
13  *
14  **********************************************************************/
15 
16 #include "../postgis_config.h"
17 
18 #include <math.h> /* for isnan */
19 
20 #include "shp2pgsql-core.h"
21 #include "../liblwgeom/liblwgeom.h"
22 #include "../liblwgeom/lwgeom_log.h" /* for LWDEBUG macros */
23 
24 
25 
26 /* Internal ring/point structures */
27 typedef struct struct_point
28 {
29  double x, y, z, m;
31 
32 typedef struct struct_ring
33 {
34  Point *list; /* list of points */
35  struct struct_ring *next;
36  int n; /* number of points in list */
37  unsigned int linked; /* number of "next" rings */
38 } Ring;
39 
40 
41 /*
42  * Internal functions
43  */
44 
45 #define UTF8_GOOD_RESULT 0
46 #define UTF8_BAD_RESULT 1
47 #define UTF8_NO_RESULT 2
48 
49 char *escape_copy_string(char *str);
50 char *escape_insert_string(char *str);
51 
52 int GeneratePointGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry, int force_multi);
53 int GenerateLineStringGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry);
54 int PIP(Point P, Point *V, int n);
55 int FindPolygons(SHPObject *obj, Ring ***Out);
56 void ReleasePolygons(Ring **polys, int npolys);
57 int GeneratePolygonGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry);
58 
59 
60 /* Return allocated string containing UTF8 string converted from encoding fromcode */
61 static int
62 utf8(const char *fromcode, char *inputbuf, char **outputbuf)
63 {
64  iconv_t cd;
65  char *outputptr;
66  size_t outbytesleft;
67  size_t inbytesleft;
68 
69  inbytesleft = strlen(inputbuf);
70 
71  cd = iconv_open("UTF-8", fromcode);
72  if ( cd == ((iconv_t)(-1)) )
73  return UTF8_NO_RESULT;
74 
75  outbytesleft = inbytesleft * 3 + 1; /* UTF8 string can be 3 times larger */
76  /* then local string */
77  *outputbuf = (char *)malloc(outbytesleft);
78  if (!*outputbuf)
79  return UTF8_NO_RESULT;
80 
81  memset(*outputbuf, 0, outbytesleft);
82  outputptr = *outputbuf;
83 
84  /* Does this string convert cleanly? */
85  if ( iconv(cd, &inputbuf, &inbytesleft, &outputptr, &outbytesleft) == (size_t)-1 )
86  {
87 #ifdef HAVE_ICONVCTL
88  int on = 1;
89  /* No. Try to convert it while transliterating. */
90  iconvctl(cd, ICONV_SET_TRANSLITERATE, &on);
91  if ( iconv(cd, &inputbuf, &inbytesleft, &outputptr, &outbytesleft) == -1 )
92  {
93  /* No. Try to convert it while discarding errors. */
94  iconvctl(cd, ICONV_SET_DISCARD_ILSEQ, &on);
95  if ( iconv(cd, &inputbuf, &inbytesleft, &outputptr, &outbytesleft) == -1 )
96  {
97  /* Still no. Throw away the buffer and return. */
98  free(*outputbuf);
99  iconv_close(cd);
100  return UTF8_NO_RESULT;
101  }
102  }
103  iconv_close(cd);
104  return UTF8_BAD_RESULT;
105 #else
106  free(*outputbuf);
107  iconv_close(cd);
108  return UTF8_NO_RESULT;
109 #endif
110  }
111  /* Return a good result, converted string is in buffer. */
112  iconv_close(cd);
113  return UTF8_GOOD_RESULT;
114 }
115 
120 char *
122 {
123  /*
124  * Escape the following characters by adding a preceding backslash
125  * tab, backslash, cr, lf
126  *
127  * 1. find # of escaped characters
128  * 2. make new string
129  *
130  */
131 
132  char *result;
133  char *ptr, *optr;
134  int toescape = 0;
135  size_t size;
136 
137  ptr = str;
138 
139  /* Count how many characters we need to escape so we know the size of the string we need to return */
140  while (*ptr)
141  {
142  if (*ptr == '\t' || *ptr == '\\' || *ptr == '\n' || *ptr == '\r')
143  toescape++;
144 
145  ptr++;
146  }
147 
148  /* If we don't have to escape anything, simply return the input pointer */
149  if (toescape == 0)
150  return str;
151 
152  size = ptr - str + toescape + 1;
153  result = calloc(1, size);
154  optr = result;
155  ptr = str;
156 
157  while (*ptr)
158  {
159  if ( *ptr == '\t' || *ptr == '\\' || *ptr == '\n' || *ptr == '\r' )
160  *optr++ = '\\';
161 
162  *optr++ = *ptr++;
163  }
164 
165  *optr = '\0';
166 
167  return result;
168 }
169 
170 
175 char *
177 {
178  /*
179  * Escape single quotes by adding a preceding single quote
180  *
181  * 1. find # of characters
182  * 2. make new string
183  */
184 
185  char *result;
186  char *ptr, *optr;
187  int toescape = 0;
188  size_t size;
189 
190  ptr = str;
191 
192  /* Count how many characters we need to escape so we know the size of the string we need to return */
193  while (*ptr)
194  {
195  if (*ptr == '\'')
196  toescape++;
197 
198  ptr++;
199  }
200 
201  /* If we don't have to escape anything, simply return the input pointer */
202  if (toescape == 0)
203  return str;
204 
205  size = ptr - str + toescape + 1;
206  result = calloc(1, size);
207  optr = result;
208  ptr = str;
209 
210  while (*ptr)
211  {
212  if (*ptr == '\'')
213  *optr++='\'';
214 
215  *optr++ = *ptr++;
216  }
217 
218  *optr='\0';
219 
220  return result;
221 }
222 
223 
228 int
229 GeneratePointGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry, int force_multi)
230 {
231  LWGEOM **lwmultipoints;
232  LWGEOM *lwgeom = NULL;
233 
234  POINT4D point4d;
235 
236  int dims = 0;
237  int u;
238 
239  char *mem;
240  size_t mem_length;
241 
242  FLAGS_SET_Z(dims, state->has_z);
243  FLAGS_SET_M(dims, state->has_m);
244 
245  /* POINT EMPTY encoded as POINT(NaN NaN) */
246  if (obj->nVertices == 1 && isnan(obj->padfX[0]) && isnan(obj->padfY[0]))
247  {
248  lwgeom = lwpoint_as_lwgeom(lwpoint_construct_empty(state->from_srid, state->has_z, state->has_m));
249  }
250  /* Not empty */
251  else
252  {
253  /* Allocate memory for our array of LWPOINTs and our dynptarrays */
254  lwmultipoints = malloc(sizeof(LWPOINT *) * obj->nVertices);
255 
256  /* We need an array of pointers to each of our sub-geometries */
257  for (u = 0; u < obj->nVertices; u++)
258  {
259  /* Create a ptarray containing a single point */
260  POINTARRAY *pa = ptarray_construct_empty(state->has_z, state->has_m, 1);
261 
262  /* Generate the point */
263  point4d.x = obj->padfX[u];
264  point4d.y = obj->padfY[u];
265 
266  if (state->has_z)
267  point4d.z = obj->padfZ[u];
268  if (state->has_m)
269  point4d.m = obj->padfM[u];
270 
271  /* Add in the point! */
272  ptarray_append_point(pa, &point4d, LW_TRUE);
273 
274  /* Generate the LWPOINT */
275  lwmultipoints[u] = lwpoint_as_lwgeom(lwpoint_construct(state->from_srid, NULL, pa));
276  }
277 
278  /* If we have more than 1 vertex then we are working on a MULTIPOINT and so generate a MULTIPOINT
279  rather than a POINT */
280  if ((obj->nVertices > 1) || force_multi)
281  {
282  lwgeom = lwcollection_as_lwgeom(lwcollection_construct(MULTIPOINTTYPE, state->from_srid, NULL, obj->nVertices, lwmultipoints));
283  }
284  else
285  {
286  lwgeom = lwmultipoints[0];
287  lwfree(lwmultipoints);
288  }
289  }
290 
291  if (state->config->use_wkt)
292  {
293  mem = lwgeom_to_wkt(lwgeom, WKT_EXTENDED, WKT_PRECISION, &mem_length);
294  }
295  else
296  {
297  mem = lwgeom_to_hexwkb_buffer(lwgeom, WKB_EXTENDED);
298  }
299 
300  if ( !mem )
301  {
302  snprintf(state->message, SHPLOADERMSGLEN, "unable to write geometry");
303  return SHPLOADERERR;
304  }
305 
306  /* Free all of the allocated items */
307  lwgeom_free(lwgeom);
308 
309  /* Return the string - everything ok */
310  *geometry = mem;
311 
312  return SHPLOADEROK;
313 }
314 
315 
319 int
321 {
322 
323  LWGEOM **lwmultilinestrings;
324  LWGEOM *lwgeom = NULL;
325  POINT4D point4d;
326  int dims = 0;
327  int u, v, start_vertex, end_vertex;
328  char *mem;
329  size_t mem_length;
330 
331 
332  FLAGS_SET_Z(dims, state->has_z);
333  FLAGS_SET_M(dims, state->has_m);
334 
335  if (state->config->simple_geometries == 1 && obj->nParts > 1)
336  {
337  snprintf(state->message, SHPLOADERMSGLEN, _("We have a Multilinestring with %d parts, can't use -S switch!"), obj->nParts);
338 
339  return SHPLOADERERR;
340  }
341 
342  /* Allocate memory for our array of LWLINEs and our dynptarrays */
343  lwmultilinestrings = malloc(sizeof(LWPOINT *) * obj->nParts);
344 
345  /* We need an array of pointers to each of our sub-geometries */
346  for (u = 0; u < obj->nParts; u++)
347  {
348  /* Create a ptarray containing the line points */
349  POINTARRAY *pa = ptarray_construct_empty(state->has_z, state->has_m, obj->nParts);
350 
351  /* Set the start/end vertices depending upon whether this is
352  a MULTILINESTRING or not */
353  if ( u == obj->nParts-1 )
354  end_vertex = obj->nVertices;
355  else
356  end_vertex = obj->panPartStart[u + 1];
357 
358  start_vertex = obj->panPartStart[u];
359 
360  for (v = start_vertex; v < end_vertex; v++)
361  {
362  /* Generate the point */
363  point4d.x = obj->padfX[v];
364  point4d.y = obj->padfY[v];
365 
366  if (state->has_z)
367  point4d.z = obj->padfZ[v];
368  if (state->has_m)
369  point4d.m = obj->padfM[v];
370 
371  ptarray_append_point(pa, &point4d, LW_FALSE);
372  }
373 
374  /* Generate the LWLINE */
375  lwmultilinestrings[u] = lwline_as_lwgeom(lwline_construct(state->from_srid, NULL, pa));
376  }
377 
378  /* If using MULTILINESTRINGs then generate the serialized collection, otherwise just a single LINESTRING */
379  if (state->config->simple_geometries == 0)
380  {
381  lwgeom = lwcollection_as_lwgeom(lwcollection_construct(MULTILINETYPE, state->from_srid, NULL, obj->nParts, lwmultilinestrings));
382  }
383  else
384  {
385  lwgeom = lwmultilinestrings[0];
386  lwfree(lwmultilinestrings);
387  }
388 
389  if (!state->config->use_wkt)
390  mem = lwgeom_to_hexwkb_buffer(lwgeom, WKB_EXTENDED);
391  else
392  mem = lwgeom_to_wkt(lwgeom, WKT_EXTENDED, WKT_PRECISION, &mem_length);
393 
394  if ( !mem )
395  {
396  snprintf(state->message, SHPLOADERMSGLEN, "unable to write geometry");
397  return SHPLOADERERR;
398  }
399 
400  /* Free all of the allocated items */
401  lwgeom_free(lwgeom);
402 
403  /* Return the string - everything ok */
404  *geometry = mem;
405 
406  return SHPLOADEROK;
407 }
408 
409 
416 int
417 PIP(Point P, Point *V, int n)
418 {
419  int cn = 0; /* the crossing number counter */
420  int i;
421 
422  /* loop through all edges of the polygon */
423  for (i = 0; i < n-1; i++) /* edge from V[i] to V[i+1] */
424  {
425  if (((V[i].y <= P.y) && (V[i + 1].y > P.y)) /* an upward crossing */
426  || ((V[i].y > P.y) && (V[i + 1].y <= P.y))) /* a downward crossing */
427  {
428  double vt = (float)(P.y - V[i].y) / (V[i + 1].y - V[i].y);
429  if (P.x < V[i].x + vt * (V[i + 1].x - V[i].x)) /* P.x < intersect */
430  ++cn; /* a valid crossing of y=P.y right of P.x */
431  }
432  }
433 
434  return (cn&1); /* 0 if even (out), and 1 if odd (in) */
435 }
436 
437 
438 int
440 {
441  Ring **Outer; /* Pointers to Outer rings */
442  int out_index=0; /* Count of Outer rings */
443  Ring **Inner; /* Pointers to Inner rings */
444  int in_index=0; /* Count of Inner rings */
445  int pi; /* part index */
446 
447 #if POSTGIS_DEBUG_LEVEL > 0
448  static int call = -1;
449  call++;
450 #endif
451 
452  LWDEBUGF(4, "FindPolygons[%d]: allocated space for %d rings\n", call, obj->nParts);
453 
454  /* Allocate initial memory */
455  Outer = (Ring **)malloc(sizeof(Ring *) * obj->nParts);
456  Inner = (Ring **)malloc(sizeof(Ring *) * obj->nParts);
457 
458  /* Iterate over rings dividing in Outers and Inners */
459  for (pi=0; pi < obj->nParts; pi++)
460  {
461  int vi; /* vertex index */
462  int vs; /* start index */
463  int ve; /* end index */
464  int nv; /* number of vertex */
465  double area = 0.0;
466  Ring *ring;
467 
468  /* Set start and end vertices */
469  if (pi == obj->nParts - 1)
470  ve = obj->nVertices;
471  else
472  ve = obj->panPartStart[pi + 1];
473 
474  vs = obj->panPartStart[pi];
475 
476  /* Compute number of vertices */
477  nv = ve - vs;
478 
479  /* Allocate memory for a ring */
480  ring = (Ring *)malloc(sizeof(Ring));
481  ring->list = (Point *)malloc(sizeof(Point) * nv);
482  ring->n = nv;
483  ring->next = NULL;
484  ring->linked = 0;
485 
486  /* Iterate over ring vertices */
487  for (vi = vs; vi < ve; vi++)
488  {
489  int vn = vi+1; /* next vertex for area */
490  if (vn == ve)
491  vn = vs;
492 
493  ring->list[vi - vs].x = obj->padfX[vi];
494  ring->list[vi - vs].y = obj->padfY[vi];
495  ring->list[vi - vs].z = obj->padfZ[vi];
496  ring->list[vi - vs].m = obj->padfM[vi];
497 
498  area += (obj->padfX[vi] * obj->padfY[vn]) -
499  (obj->padfY[vi] * obj->padfX[vn]);
500  }
501 
502  /* Close the ring with first vertex */
503  /*ring->list[vi].x = obj->padfX[vs]; */
504  /*ring->list[vi].y = obj->padfY[vs]; */
505  /*ring->list[vi].z = obj->padfZ[vs]; */
506  /*ring->list[vi].m = obj->padfM[vs]; */
507 
508  /* Clockwise (or single-part). It's an Outer Ring ! */
509  if (area < 0.0 || obj->nParts == 1)
510  {
511  Outer[out_index] = ring;
512  out_index++;
513  }
514  else
515  {
516  /* Counterclockwise. It's an Inner Ring ! */
517  Inner[in_index] = ring;
518  in_index++;
519  }
520  }
521 
522  LWDEBUGF(4, "FindPolygons[%d]: found %d Outer, %d Inners\n", call, out_index, in_index);
523 
524  /* Put the inner rings into the list of the outer rings */
525  /* of which they are within */
526  for (pi = 0; pi < in_index; pi++)
527  {
528  Point pt, pt2;
529  int i;
530  Ring *inner = Inner[pi], *outer = NULL;
531 
532  pt.x = inner->list[0].x;
533  pt.y = inner->list[0].y;
534  pt.z = 0.0;
535  pt.m = 0.0;
536 
537  pt2.x = inner->list[1].x;
538  pt2.y = inner->list[1].y;
539  pt2.z = 0.0;
540  pt2.m = 0.0;
541 
542  /*
543  * If we assume that the case of the "big polygon w/o hole
544  * containing little polygon w/ hold" is ordered so that the
545  * big polygon comes first, then checking the list in reverse
546  * will assign the little polygon's hole to the little polygon
547  * w/o a lot of extra fancy containment logic here
548  */
549  for (i = out_index - 1; i >= 0; i--)
550  {
551  int in;
552 
553  in = PIP(pt, Outer[i]->list, Outer[i]->n);
554  if ( in || PIP(pt2, Outer[i]->list, Outer[i]->n) )
555  {
556  outer = Outer[i];
557  break;
558  }
559  }
560 
561  if (outer)
562  {
563  outer->linked++;
564  while (outer->next)
565  outer = outer->next;
566 
567  outer->next = inner;
568  }
569  else
570  {
571  /* The ring wasn't within any outer rings, */
572  /* assume it is a new outer ring. */
573  LWDEBUGF(4, "FindPolygons[%d]: hole %d is orphan\n", call, pi);
574 
575  Outer[out_index] = inner;
576  out_index++;
577  }
578  }
579 
580  *Out = Outer;
581  /*
582  * Only free the containing Inner array, not the ring elements, because
583  * the rings are now owned by the linked lists in the Outer array elements.
584  */
585  free(Inner);
586 
587  return out_index;
588 }
589 
590 
591 void
592 ReleasePolygons(Ring **polys, int npolys)
593 {
594  int pi;
595 
596  /* Release all memory */
597  for (pi = 0; pi < npolys; pi++)
598  {
599  Ring *Poly, *temp;
600  Poly = polys[pi];
601  while (Poly != NULL)
602  {
603  temp = Poly;
604  Poly = Poly->next;
605  free(temp->list);
606  free(temp);
607  }
608  }
609 
610  free(polys);
611 }
612 
613 
621 int
622 GeneratePolygonGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry)
623 {
624  Ring **Outer;
625  int polygon_total, ring_total;
626  int pi, vi; /* part index and vertex index */
627 
628  LWGEOM **lwpolygons;
629  LWGEOM *lwgeom;
630 
631  POINT4D point4d;
632 
633  int dims = 0;
634 
635  char *mem;
636  size_t mem_length;
637 
638  FLAGS_SET_Z(dims, state->has_z);
639  FLAGS_SET_M(dims, state->has_m);
640 
641  polygon_total = FindPolygons(obj, &Outer);
642 
643  if (state->config->simple_geometries == 1 && polygon_total != 1) /* We write Non-MULTI geometries, but have several parts: */
644  {
645  snprintf(state->message, SHPLOADERMSGLEN, _("We have a Multipolygon with %d parts, can't use -S switch!"), polygon_total);
646 
647  return SHPLOADERERR;
648  }
649 
650  /* Allocate memory for our array of LWPOLYs */
651  lwpolygons = malloc(sizeof(LWPOLY *) * polygon_total);
652 
653  /* Cycle through each individual polygon */
654  for (pi = 0; pi < polygon_total; pi++)
655  {
656  LWPOLY *lwpoly = lwpoly_construct_empty(state->from_srid, state->has_z, state->has_m);
657 
658  Ring *polyring;
659  int ring_index = 0;
660 
661  /* Firstly count through the total number of rings in this polygon */
662  ring_total = 0;
663  polyring = Outer[pi];
664  while (polyring)
665  {
666  ring_total = ring_total + 1;
667  polyring = polyring->next;
668  }
669 
670  /* Cycle through each ring within the polygon, starting with the outer */
671  polyring = Outer[pi];
672 
673  while (polyring)
674  {
675  /* Create a POINTARRAY containing the points making up the ring */
676  POINTARRAY *pa = ptarray_construct_empty(state->has_z, state->has_m, polyring->n);
677 
678  for (vi = 0; vi < polyring->n; vi++)
679  {
680  /* Build up a point array of all the points in this ring */
681  point4d.x = polyring->list[vi].x;
682  point4d.y = polyring->list[vi].y;
683 
684  if (state->has_z)
685  point4d.z = polyring->list[vi].z;
686  if (state->has_m)
687  point4d.m = polyring->list[vi].m;
688 
689  ptarray_append_point(pa, &point4d, LW_TRUE);
690  }
691 
692  /* Copy the POINTARRAY pointer so we can use the LWPOLY constructor */
693  lwpoly_add_ring(lwpoly, pa);
694 
695  polyring = polyring->next;
696  ring_index = ring_index + 1;
697  }
698 
699  /* Generate the LWGEOM */
700  lwpolygons[pi] = lwpoly_as_lwgeom(lwpoly);
701  }
702 
703  /* If using MULTIPOLYGONS then generate the serialized collection, otherwise just a single POLYGON */
704  if (state->config->simple_geometries == 0)
705  {
706  lwgeom = lwcollection_as_lwgeom(lwcollection_construct(MULTIPOLYGONTYPE, state->from_srid, NULL, polygon_total, lwpolygons));
707  }
708  else
709  {
710  lwgeom = lwpolygons[0];
711  lwfree(lwpolygons);
712  }
713 
714  if (!state->config->use_wkt)
715  mem = lwgeom_to_hexwkb_buffer(lwgeom, WKB_EXTENDED);
716  else
717  mem = lwgeom_to_wkt(lwgeom, WKT_EXTENDED, WKT_PRECISION, &mem_length);
718 
719  if ( !mem )
720  {
721  /* Free the linked list of rings */
722  ReleasePolygons(Outer, polygon_total);
723 
724  snprintf(state->message, SHPLOADERMSGLEN, "unable to write geometry");
725  return SHPLOADERERR;
726  }
727 
728  /* Free all of the allocated items */
729  lwgeom_free(lwgeom);
730 
731  /* Free the linked list of rings */
732  ReleasePolygons(Outer, polygon_total);
733 
734  /* Return the string - everything ok */
735  *geometry = mem;
736 
737  return SHPLOADEROK;
738 }
739 
740 
741 /*
742  * External functions (defined in shp2pgsql-core.h)
743  */
744 
745 
746 /* Convert the string to lower case */
747 void
748 strtolower(char *s)
749 {
750  size_t j;
751 
752  for (j = 0; j < strlen(s); j++)
753  s[j] = tolower(s[j]);
754 }
755 
756 
757 /* Default configuration settings */
758 void
760 {
761  config->opt = 'c';
762  config->table = NULL;
763  config->schema = NULL;
764  config->geo_col = NULL;
765  config->shp_file = NULL;
766  config->dump_format = 0;
767  config->simple_geometries = 0;
768  config->geography = 0;
769  config->quoteidentifiers = 0;
770  config->forceint4 = 0;
771  config->createindex = 0;
772  config->analyze = 1;
773  config->readshape = 1;
775  config->encoding = strdup(ENCODING_DEFAULT);
777  config->sr_id = SRID_UNKNOWN;
778  config->shp_sr_id = SRID_UNKNOWN;
779  config->use_wkt = 0;
780  config->tablespace = NULL;
781  config->idxtablespace = NULL;
782  config->usetransaction = 1;
783  config->column_map_filename = NULL;
784 }
785 
786 /* Create a new shapefile state object */
789 {
790  SHPLOADERSTATE *state;
791 
792  /* Create a new state object and assign the config to it */
793  state = malloc(sizeof(SHPLOADERSTATE));
794  state->config = config;
795 
796  /* Set any state defaults */
797  state->hSHPHandle = NULL;
798  state->hDBFHandle = NULL;
799  state->has_z = 0;
800  state->has_m = 0;
801  state->types = NULL;
802  state->widths = NULL;
803  state->precisions = NULL;
804  state->col_names = NULL;
805  state->field_names = NULL;
806  state->num_fields = 0;
807  state->pgfieldtypes = NULL;
808 
809  state->from_srid = config->shp_sr_id;
810  state->to_srid = config->sr_id;
811 
812  /* If only one has a valid SRID, use it for both. */
813  if (state->to_srid == SRID_UNKNOWN)
814  {
815  if (config->geography)
816  {
817  state->to_srid = 4326;
818  }
819  else
820  {
821  state->to_srid = state->from_srid;
822  }
823  }
824 
825  if (state->from_srid == SRID_UNKNOWN)
826  {
827  state->from_srid = state->to_srid;
828  }
829 
830  /* If the geo col name is not set, use one of the defaults. */
831  state->geo_col = config->geo_col;
832 
833  if (!state->geo_col)
834  {
836  }
837 
838  colmap_init(&state->column_map);
839 
840  return state;
841 }
842 
843 
844 /* Open the shapefile and extract the relevant field information */
845 int
847 {
848  SHPObject *obj = NULL;
849  int ret = SHPLOADEROK;
850  char name[MAXFIELDNAMELEN];
852  char *utf8str;
853 
854  /* If we are reading the entire shapefile, open it */
855  if (state->config->readshape == 1)
856  {
857  state->hSHPHandle = SHPOpen(state->config->shp_file, "rb");
858 
859  if (state->hSHPHandle == NULL)
860  {
861  snprintf(state->message, SHPLOADERMSGLEN, _("%s: shape (.shp) or index files (.shx) can not be opened, will just import attribute data."), state->config->shp_file);
862  state->config->readshape = 0;
863 
864  ret = SHPLOADERWARN;
865  }
866  }
867 
868  /* Open the DBF (attributes) file */
869  state->hDBFHandle = DBFOpen(state->config->shp_file, "rb");
870  if ((state->hSHPHandle == NULL && state->config->readshape == 1) || state->hDBFHandle == NULL)
871  {
872  snprintf(state->message, SHPLOADERMSGLEN, _("%s: dbf file (.dbf) can not be opened."), state->config->shp_file);
873 
874  return SHPLOADERERR;
875  }
876 
877 
878  /* Open the column map if one was specified */
879  if (state->config->column_map_filename)
880  {
881  ret = colmap_read(state->config->column_map_filename,
882  &state->column_map, state->message, SHPLOADERMSGLEN);
883  if (!ret) return SHPLOADERERR;
884  }
885 
886  /* User hasn't altered the default encoding preference... */
887  if ( strcmp(state->config->encoding, ENCODING_DEFAULT) == 0 )
888  {
889  /* But the file has a code page entry... */
890  if ( state->hDBFHandle->pszCodePage )
891  {
892  /* And we figured out what iconv encoding it maps to, so use it! */
893  char *newencoding = NULL;
894  if ( (newencoding = codepage2encoding(state->hDBFHandle->pszCodePage)) )
895  {
896  lwfree(state->config->encoding);
897  state->config->encoding = newencoding;
898  }
899  }
900  }
901 
902  /* If reading the whole shapefile (not just attributes)... */
903  if (state->config->readshape == 1)
904  {
905  SHPGetInfo(state->hSHPHandle, &state->num_entities, &state->shpfiletype, NULL, NULL);
906 
907  /* If null_policy is set to abort, check for NULLs */
908  if (state->config->null_policy == POLICY_NULL_ABORT)
909  {
910  /* If we abort on null items, scan the entire file for NULLs */
911  for (int j = 0; j < state->num_entities; j++)
912  {
913  obj = SHPReadObject(state->hSHPHandle, j);
914 
915  if (!obj)
916  {
917  snprintf(state->message, SHPLOADERMSGLEN, _("Error reading shape object %d"), j);
918  return SHPLOADERERR;
919  }
920 
921  if (obj->nVertices == 0)
922  {
923  snprintf(state->message, SHPLOADERMSGLEN, _("Empty geometries found, aborted.)"));
924  return SHPLOADERERR;
925  }
926 
927  SHPDestroyObject(obj);
928  }
929  }
930 
931  /* Check the shapefile type */
932  int geomtype = 0;
933  switch (state->shpfiletype)
934  {
935  case SHPT_POINT:
936  /* Point */
937  state->pgtype = "POINT";
938  geomtype = POINTTYPE;
939  state->pgdims = 2;
940  break;
941 
942  case SHPT_ARC:
943  /* PolyLine */
944  state->pgtype = "MULTILINESTRING";
945  geomtype = MULTILINETYPE ;
946  state->pgdims = 2;
947  break;
948 
949  case SHPT_POLYGON:
950  /* Polygon */
951  state->pgtype = "MULTIPOLYGON";
952  geomtype = MULTIPOLYGONTYPE;
953  state->pgdims = 2;
954  break;
955 
956  case SHPT_MULTIPOINT:
957  /* MultiPoint */
958  state->pgtype = "MULTIPOINT";
959  geomtype = MULTIPOINTTYPE;
960  state->pgdims = 2;
961  break;
962 
963  case SHPT_POINTM:
964  /* PointM */
965  geomtype = POINTTYPE;
966  state->has_m = 1;
967  state->pgtype = "POINTM";
968  state->pgdims = 3;
969  break;
970 
971  case SHPT_ARCM:
972  /* PolyLineM */
973  geomtype = MULTILINETYPE;
974  state->has_m = 1;
975  state->pgtype = "MULTILINESTRINGM";
976  state->pgdims = 3;
977  break;
978 
979  case SHPT_POLYGONM:
980  /* PolygonM */
981  geomtype = MULTIPOLYGONTYPE;
982  state->has_m = 1;
983  state->pgtype = "MULTIPOLYGONM";
984  state->pgdims = 3;
985  break;
986 
987  case SHPT_MULTIPOINTM:
988  /* MultiPointM */
989  geomtype = MULTIPOINTTYPE;
990  state->has_m = 1;
991  state->pgtype = "MULTIPOINTM";
992  state->pgdims = 3;
993  break;
994 
995  case SHPT_POINTZ:
996  /* PointZ */
997  geomtype = POINTTYPE;
998  state->has_m = 1;
999  state->has_z = 1;
1000  state->pgtype = "POINT";
1001  state->pgdims = 4;
1002  break;
1003 
1004  case SHPT_ARCZ:
1005  /* PolyLineZ */
1006  state->pgtype = "MULTILINESTRING";
1007  geomtype = MULTILINETYPE;
1008  state->has_z = 1;
1009  state->has_m = 1;
1010  state->pgdims = 4;
1011  break;
1012 
1013  case SHPT_POLYGONZ:
1014  /* MultiPolygonZ */
1015  state->pgtype = "MULTIPOLYGON";
1016  geomtype = MULTIPOLYGONTYPE;
1017  state->has_z = 1;
1018  state->has_m = 1;
1019  state->pgdims = 4;
1020  break;
1021 
1022  case SHPT_MULTIPOINTZ:
1023  /* MultiPointZ */
1024  state->pgtype = "MULTIPOINT";
1025  geomtype = MULTIPOINTTYPE;
1026  state->has_z = 1;
1027  state->has_m = 1;
1028  state->pgdims = 4;
1029  break;
1030 
1031  default:
1032  state->pgtype = "GEOMETRY";
1033  geomtype = COLLECTIONTYPE;
1034  state->has_z = 1;
1035  state->has_m = 1;
1036  state->pgdims = 4;
1037 
1038  snprintf(state->message, SHPLOADERMSGLEN, _("Unknown geometry type: %d\n"), state->shpfiletype);
1039  return SHPLOADERERR;
1040 
1041  break;
1042  }
1043 
1044  /* Force Z/M-handling if configured to do so */
1045  switch(state->config->force_output)
1046  {
1047  case FORCE_OUTPUT_2D:
1048  state->has_z = 0;
1049  state->has_m = 0;
1050  state->pgdims = 2;
1051  break;
1052 
1053  case FORCE_OUTPUT_3DZ:
1054  state->has_z = 1;
1055  state->has_m = 0;
1056  state->pgdims = 3;
1057  break;
1058 
1059  case FORCE_OUTPUT_3DM:
1060  state->has_z = 0;
1061  state->has_m = 1;
1062  state->pgdims = 3;
1063  break;
1064 
1065  case FORCE_OUTPUT_4D:
1066  state->has_z = 1;
1067  state->has_m = 1;
1068  state->pgdims = 4;
1069  break;
1070  default:
1071  /* Simply use the auto-detected values above */
1072  break;
1073  }
1074 
1075  /* If in simple geometry mode, alter names for CREATE TABLE by skipping MULTI */
1076  if (state->config->simple_geometries)
1077  {
1078  if ((geomtype == MULTIPOLYGONTYPE) || (geomtype == MULTILINETYPE) || (geomtype == MULTIPOINTTYPE))
1079  {
1080  /* Chop off the "MULTI" from the string. */
1081  state->pgtype += 5;
1082  }
1083  }
1084 
1085  }
1086  else
1087  {
1088  /* Otherwise just count the number of records in the DBF */
1089  state->num_entities = DBFGetRecordCount(state->hDBFHandle);
1090  }
1091 
1092 
1093  /* Get the field information from the DBF */
1094  state->num_fields = DBFGetFieldCount(state->hDBFHandle);
1095 
1096  state->num_records = DBFGetRecordCount(state->hDBFHandle);
1097 
1098  /* Allocate storage for field information */
1099  state->field_names = malloc(state->num_fields * sizeof(char*));
1100  state->types = (DBFFieldType *)malloc(state->num_fields * sizeof(int));
1101  state->widths = malloc(state->num_fields * sizeof(int));
1102  state->precisions = malloc(state->num_fields * sizeof(int));
1103  state->pgfieldtypes = malloc(state->num_fields * sizeof(char *));
1104  state->col_names = malloc((state->num_fields + 2) * sizeof(char) * MAXFIELDNAMELEN);
1105 
1106  strcpy(state->col_names, "" );
1107  /* Generate a string of comma separated column names of the form "col1, col2 ... colN" for the SQL
1108  insertion string */
1109 
1110  for (int j = 0; j < state->num_fields; j++)
1111  {
1112  int field_precision = 0, field_width = 0;
1113  type = DBFGetFieldInfo(state->hDBFHandle, j, name, &field_width, &field_precision);
1114 
1115  state->types[j] = type;
1116  state->widths[j] = field_width;
1117  state->precisions[j] = field_precision;
1118 /* fprintf(stderr, "XXX %s width:%d prec:%d\n", name, field_width, field_precision); */
1119 
1120  if (state->config->encoding)
1121  {
1122  char *encoding_msg = _("Try \"LATIN1\" (Western European), or one of the values described at http://www.gnu.org/software/libiconv/.");
1123 
1124  int rv = utf8(state->config->encoding, name, &utf8str);
1125 
1126  if (rv != UTF8_GOOD_RESULT)
1127  {
1128  if ( rv == UTF8_BAD_RESULT )
1129  snprintf(state->message, SHPLOADERMSGLEN, _("Unable to convert field name \"%s\" to UTF-8 (iconv reports \"%s\"). Current encoding is \"%s\". %s"), utf8str, strerror(errno), state->config->encoding, encoding_msg);
1130  else if ( rv == UTF8_NO_RESULT )
1131  snprintf(state->message, SHPLOADERMSGLEN, _("Unable to convert field name to UTF-8 (iconv reports \"%s\"). Current encoding is \"%s\". %s"), strerror(errno), state->config->encoding, encoding_msg);
1132  else
1133  snprintf(state->message, SHPLOADERMSGLEN, _("Unexpected return value from utf8()"));
1134 
1135  if ( rv == UTF8_BAD_RESULT )
1136  free(utf8str);
1137 
1138  return SHPLOADERERR;
1139  }
1140 
1141  strncpy(name, utf8str, MAXFIELDNAMELEN);
1142  name[MAXFIELDNAMELEN-1] = '\0';
1143  free(utf8str);
1144  }
1145 
1146  /* If a column map file has been passed in, use this to create the postgresql field name from
1147  the dbf column name */
1148  {
1149  const char *mapped = colmap_pg_by_dbf(&state->column_map, name);
1150  if (mapped)
1151  {
1152  strncpy(name, mapped, MAXFIELDNAMELEN);
1153  name[MAXFIELDNAMELEN-1] = '\0';
1154  }
1155  }
1156 
1157  /*
1158  * Make field names lowercase unless asked to
1159  * keep identifiers case.
1160  */
1161  if (!state->config->quoteidentifiers)
1162  strtolower(name);
1163 
1164  /*
1165  * Escape names starting with the
1166  * escape char (_), those named 'gid'
1167  * or after pgsql reserved attribute names
1168  */
1169  if (name[0] == '_' ||
1170  ! strcmp(name, "gid") ||
1171  ! strcmp(name, "tableoid") ||
1172  ! strcmp(name, "cmin") ||
1173  ! strcmp(name, "cmax") ||
1174  ! strcmp(name, "xmin") ||
1175  ! strcmp(name, "xmax") ||
1176  ! strcmp(name, "primary") ||
1177  ! strcmp(name, "oid") ||
1178  ! strcmp(name, "ctid"))
1179  {
1180  char tmp[MAXFIELDNAMELEN] = "__";
1181  memcpy(tmp+2, name, MAXFIELDNAMELEN-2);
1182  tmp[MAXFIELDNAMELEN-1] = '\0';
1183  strncpy(name, tmp, MAXFIELDNAMELEN);
1184  }
1185 
1186  /* Avoid duplicating field names */
1187  for (int z = 0; z < j; z++)
1188  {
1189  if (strcmp(state->field_names[z], name) == 0)
1190  {
1191  strncat(name, "__", MAXFIELDNAMELEN - 1);
1192  snprintf(name + strlen(name),
1193  MAXFIELDNAMELEN - 1 - strlen(name),
1194  "%i",
1195  j);
1196  break;
1197  }
1198  }
1199 
1200  state->field_names[j] = strdup(name);
1201 
1202  /* Now generate the PostgreSQL type name string and width based upon the shapefile type */
1203  switch (state->types[j])
1204  {
1205  case FTString:
1206  state->pgfieldtypes[j] = strdup("varchar");
1207  break;
1208 
1209  case FTDate:
1210  state->pgfieldtypes[j] = strdup("date");
1211  break;
1212 
1213  case FTInteger:
1214  /* Determine exact type based upon field width */
1215  if (state->config->forceint4 || (state->widths[j] >=5 && state->widths[j] < 10))
1216  {
1217  state->pgfieldtypes[j] = strdup("int4");
1218  }
1219  else if (state->widths[j] >=10 && state->widths[j] < 19)
1220  {
1221  state->pgfieldtypes[j] = strdup("int8");
1222  }
1223  else if (state->widths[j] < 5)
1224  {
1225  state->pgfieldtypes[j] = strdup("int2");
1226  }
1227  else
1228  {
1229  state->pgfieldtypes[j] = strdup("numeric");
1230  }
1231  break;
1232 
1233  case FTDouble:
1234  /* Determine exact type based upon field width */
1235  fprintf(stderr, "Field %s is an FTDouble with width %d and precision %d\n",
1236  state->field_names[j], state->widths[j], state->precisions[j]);
1237  if (state->widths[j] > 18)
1238  {
1239  state->pgfieldtypes[j] = strdup("numeric");
1240  }
1241  else
1242  {
1243  state->pgfieldtypes[j] = strdup("float8");
1244  }
1245  break;
1246 
1247  case FTLogical:
1248  state->pgfieldtypes[j] = strdup("boolean");
1249  break;
1250 
1251  default:
1252  snprintf(state->message, SHPLOADERMSGLEN, _("Invalid type %x in DBF file"), state->types[j]);
1253  return SHPLOADERERR;
1254  }
1255 
1256  strcat(state->col_names, "\"");
1257  strcat(state->col_names, name);
1258 
1259  if (state->config->readshape == 1 || j < (state->num_fields - 1))
1260  {
1261  /* Don't include last comma if its the last field and no geometry field will follow */
1262  strcat(state->col_names, "\",");
1263  }
1264  else
1265  {
1266  strcat(state->col_names, "\"");
1267  }
1268  }
1269 
1270  /* Append the geometry column if required */
1271  if (state->config->readshape == 1)
1272  strcat(state->col_names, state->geo_col);
1273 
1274  /* Return status */
1275  return ret;
1276 }
1277 
1278 /* Return a pointer to an allocated string containing the header for the specified loader state */
1279 int
1280 ShpLoaderGetSQLHeader(SHPLOADERSTATE *state, char **strheader)
1281 {
1282  stringbuffer_t *sb;
1283  char *ret;
1284  int j;
1285 
1286  /* Create the stringbuffer containing the header; we use this API as it's easier
1287  for handling string resizing during append */
1288  sb = stringbuffer_create();
1289  stringbuffer_clear(sb);
1290 
1291  /* Set the client encoding if required */
1292  if (state->config->encoding)
1293  {
1294  stringbuffer_aprintf(sb, "SET CLIENT_ENCODING TO UTF8;\n");
1295  }
1296 
1297  /* Use SQL-standard string escaping rather than PostgreSQL standard */
1298  stringbuffer_aprintf(sb, "SET STANDARD_CONFORMING_STRINGS TO ON;\n");
1299 
1300  /* Drop table if requested */
1301  if (state->config->opt == 'd')
1302  {
1314  if (state->config->schema)
1315  {
1316  if (state->config->readshape == 1 && (! state->config->geography) )
1317  {
1318  stringbuffer_aprintf(sb, "SELECT DropGeometryColumn('%s','%s','%s');\n",
1319  state->config->schema, state->config->table, state->geo_col);
1320  }
1321 
1322  stringbuffer_aprintf(sb, "DROP TABLE IF EXISTS \"%s\".\"%s\";\n", state->config->schema,
1323  state->config->table);
1324  }
1325  else
1326  {
1327  if (state->config->readshape == 1 && (! state->config->geography) )
1328  {
1329  stringbuffer_aprintf(sb, "SELECT DropGeometryColumn('','%s','%s');\n",
1330  state->config->table, state->geo_col);
1331  }
1332 
1333  stringbuffer_aprintf(sb, "DROP TABLE IF EXISTS \"%s\";\n", state->config->table);
1334  }
1335  }
1336 
1337  /* Start of transaction if we are using one */
1338  if (state->config->usetransaction)
1339  {
1340  stringbuffer_aprintf(sb, "BEGIN;\n");
1341  }
1342 
1343  /* If not in 'append' mode create the spatial table */
1344  if (state->config->opt != 'a')
1345  {
1346  /*
1347  * Create a table for inserting the shapes into with appropriate
1348  * columns and types
1349  */
1350  if (state->config->schema)
1351  {
1352  stringbuffer_aprintf(sb, "CREATE TABLE \"%s\".\"%s\" (gid serial",
1353  state->config->schema, state->config->table);
1354  }
1355  else
1356  {
1357  stringbuffer_aprintf(sb, "CREATE TABLE \"%s\" (gid serial", state->config->table);
1358  }
1359 
1360  /* Generate the field types based upon the shapefile information */
1361  for (j = 0; j < state->num_fields; j++)
1362  {
1363  stringbuffer_aprintf(sb, ",\n\"%s\" ", state->field_names[j]);
1364 
1365  /* First output the raw field type string */
1366  stringbuffer_aprintf(sb, "%s", state->pgfieldtypes[j]);
1367 
1368  /* Some types do have typmods */
1369  /* Apply width typmod for varchar if there is positive width **/
1370  if (!strcmp("varchar", state->pgfieldtypes[j]) && state->widths[j] > 0)
1371  stringbuffer_aprintf(sb, "(%d)", state->widths[j]);
1372 
1373  if (!strcmp("numeric", state->pgfieldtypes[j]))
1374  {
1375  /* Doubles we just allow PostgreSQL to auto-detect the size */
1376  if (state->types[j] != FTDouble)
1377  stringbuffer_aprintf(sb, "(%d,0)", state->widths[j]);
1378  }
1379  }
1380 
1381  /* Add the geography column directly to the table definition, we don't
1382  need to do an AddGeometryColumn() call. */
1383  if (state->config->readshape == 1 && state->config->geography)
1384  {
1385  char *dimschar;
1386 
1387  if (state->pgdims == 4)
1388  dimschar = "ZM";
1389  else
1390  dimschar = "";
1391 
1392  if (state->to_srid == SRID_UNKNOWN ){
1393  state->to_srid = 4326;
1394  }
1395 
1396  stringbuffer_aprintf(sb, ",\n\"%s\" geography(%s%s,%d)", state->geo_col, state->pgtype, dimschar, state->to_srid);
1397  }
1398  stringbuffer_aprintf(sb, ")");
1399 
1400  /* Tablespace is optional. */
1401  if (state->config->tablespace != NULL)
1402  {
1403  stringbuffer_aprintf(sb, " TABLESPACE \"%s\"", state->config->tablespace);
1404  }
1405  stringbuffer_aprintf(sb, ";\n");
1406 
1407  /* Create the primary key. This is done separately because the index for the PK needs
1408  * to be in the correct tablespace. */
1409 
1410  /* TODO: Currently PostgreSQL does not allow specifying an index to use for a PK (so you get
1411  * a default one called table_pkey) and it does not provide a way to create a PK index
1412  * in a specific tablespace. So as a hacky solution we create the PK, then move the
1413  * index to the correct tablespace. Eventually this should be:
1414  * CREATE INDEX table_pkey on table(gid) TABLESPACE tblspc;
1415  * ALTER TABLE table ADD PRIMARY KEY (gid) USING INDEX table_pkey;
1416  * A patch has apparently been submitted to PostgreSQL to enable this syntax, see this thread:
1417  * http://archives.postgresql.org/pgsql-hackers/2011-01/msg01405.php */
1418  stringbuffer_aprintf(sb, "ALTER TABLE ");
1419 
1420  /* Schema is optional, include if present. */
1421  if (state->config->schema)
1422  {
1423  stringbuffer_aprintf(sb, "\"%s\".",state->config->schema);
1424  }
1425  stringbuffer_aprintf(sb, "\"%s\" ADD PRIMARY KEY (gid);\n", state->config->table);
1426 
1427  /* Tablespace is optional for the index. */
1428  if (state->config->idxtablespace != NULL)
1429  {
1430  stringbuffer_aprintf(sb, "ALTER INDEX ");
1431  if (state->config->schema)
1432  {
1433  stringbuffer_aprintf(sb, "\"%s\".",state->config->schema);
1434  }
1435 
1436  /* WARNING: We're assuming the default "table_pkey" name for the primary
1437  * key index. PostgreSQL may use "table_pkey1" or similar in the
1438  * case of a name conflict, so you may need to edit the produced
1439  * SQL in this rare case. */
1440  stringbuffer_aprintf(sb, "\"%s_pkey\" SET TABLESPACE \"%s\";\n",
1441  state->config->table, state->config->idxtablespace);
1442  }
1443 
1444  /* Create the geometry column with an addgeometry call */
1445  if (state->config->readshape == 1 && (!state->config->geography))
1446  {
1447  /* If they didn't specify a target SRID, see if they specified a source SRID. */
1448  int32_t srid = state->to_srid;
1449  if (state->config->schema)
1450  {
1451  stringbuffer_aprintf(sb, "SELECT AddGeometryColumn('%s','%s','%s','%d',",
1452  state->config->schema, state->config->table, state->geo_col, srid);
1453  }
1454  else
1455  {
1456  stringbuffer_aprintf(sb, "SELECT AddGeometryColumn('','%s','%s','%d',",
1457  state->config->table, state->geo_col, srid);
1458  }
1459 
1460  stringbuffer_aprintf(sb, "'%s',%d);\n", state->pgtype, state->pgdims);
1461  }
1462  }
1463 
1467  if (state->config->dump_format && state->to_srid != state->from_srid){
1469  stringbuffer_aprintf(sb, "CREATE TEMP TABLE \"pgis_tmp_%s\" AS SELECT * FROM ", state->config->table);
1470  /* Schema is optional, include if present. */
1471  if (state->config->schema)
1472  {
1473  stringbuffer_aprintf(sb, "\"%s\".",state->config->schema);
1474  }
1475  stringbuffer_aprintf(sb, "\"%s\" WHERE false;\n", state->config->table);
1477  stringbuffer_aprintf(sb, "ALTER TABLE \"pgis_tmp_%s\" ALTER COLUMN \"%s\" TYPE geometry USING ( (\"%s\"::geometry) ); \n", state->config->table, state->geo_col, state->geo_col);
1478  }
1479 
1480  /* Copy the string buffer into a new string, destroying the string buffer */
1481  ret = (char *)malloc(strlen((char *)stringbuffer_getstring(sb)) + 1);
1482  strcpy(ret, (char *)stringbuffer_getstring(sb));
1484 
1485  *strheader = ret;
1486 
1487  return SHPLOADEROK;
1488 }
1489 
1490 
1491 /* Return an allocated string containing the copy statement for this state */
1492 int
1494 {
1495  //char *copystr;
1496  stringbuffer_t *sb;
1497  char *ret;
1498  sb = stringbuffer_create();
1499  stringbuffer_clear(sb);
1500 
1501 
1502  /* Allocate the string for the COPY statement */
1503  if (state->config->dump_format)
1504  {
1505  stringbuffer_aprintf(sb, "COPY ");
1506 
1507  if (state->to_srid != state->from_srid){
1509  stringbuffer_aprintf(sb, " \"pgis_tmp_%s\" (%s) FROM stdin;\n", state->config->table, state->col_names);
1510  }
1511  else {
1512  if (state->config->schema)
1513  {
1514  stringbuffer_aprintf(sb, " \"%s\".", state->config->schema);
1515  }
1516 
1517  stringbuffer_aprintf(sb, "\"%s\" (%s) FROM stdin;\n", state->config->table, state->col_names);
1518  }
1519 
1520  /* Copy the string buffer into a new string, destroying the string buffer */
1521  ret = (char *)malloc(strlen((char *)stringbuffer_getstring(sb)) + 1);
1522  strcpy(ret, (char *)stringbuffer_getstring(sb));
1524 
1525  *strheader = ret;
1526  return SHPLOADEROK;
1527  }
1528  else
1529  {
1530  /* Flag an error as something has gone horribly wrong */
1531  snprintf(state->message, SHPLOADERMSGLEN, _("Internal error: attempt to generate a COPY statement for data that hasn't been requested in COPY format"));
1532 
1533  return SHPLOADERERR;
1534  }
1535 }
1536 
1537 
1538 /* Return a count of the number of entities in this shapefile */
1539 int
1541 {
1542  return state->num_entities;
1543 }
1544 
1545 
1546 /* Return an allocated string representation of a specified record item */
1547 int
1548 ShpLoaderGenerateSQLRowStatement(SHPLOADERSTATE *state, int item, char **strrecord)
1549 {
1550  SHPObject *obj = NULL;
1551  stringbuffer_t *sb;
1552  stringbuffer_t *sbwarn;
1553  char val[MAXVALUELEN];
1554  char *escval;
1555  char *geometry=NULL, *ret;
1556  char *utf8str;
1557  int res, i;
1558  int rv;
1559 
1560  /* Clear the stringbuffers */
1561  sbwarn = stringbuffer_create();
1562  stringbuffer_clear(sbwarn);
1563  sb = stringbuffer_create();
1564  stringbuffer_clear(sb);
1565 
1566  /* Skip deleted records */
1567  if (state->hDBFHandle && DBFIsRecordDeleted(state->hDBFHandle, item))
1568  {
1569  *strrecord = NULL;
1570  return SHPLOADERRECDELETED;
1571  }
1572 
1573  /* If we are reading the shapefile, open the specified record */
1574  if (state->config->readshape == 1)
1575  {
1576  obj = SHPReadObject(state->hSHPHandle, item);
1577  if (!obj)
1578  {
1579  snprintf(state->message, SHPLOADERMSGLEN, _("Error reading shape object %d"), item);
1580  return SHPLOADERERR;
1581  }
1582 
1583  /* If we are set to skip NULLs, return a NULL record status */
1584  if (state->config->null_policy == POLICY_NULL_SKIP && obj->nVertices == 0 )
1585  {
1586  SHPDestroyObject(obj);
1587 
1588  *strrecord = NULL;
1589  return SHPLOADERRECISNULL;
1590  }
1591  }
1592 
1593  /* If not in dump format, generate the INSERT string */
1594  if (!state->config->dump_format)
1595  {
1596  if (state->config->schema)
1597  {
1598  stringbuffer_aprintf(sb, "INSERT INTO \"%s\".\"%s\" (%s) VALUES (", state->config->schema,
1599  state->config->table, state->col_names);
1600  }
1601  else
1602  {
1603  stringbuffer_aprintf(sb, "INSERT INTO \"%s\" (%s) VALUES (", state->config->table,
1604  state->col_names);
1605  }
1606  }
1607 
1608 
1609  /* Read all of the attributes from the DBF file for this item */
1610  for (i = 0; i < DBFGetFieldCount(state->hDBFHandle); i++)
1611  {
1612  /* Special case for NULL attributes */
1613  if (DBFIsAttributeNULL(state->hDBFHandle, item, i))
1614  {
1615  if (state->config->dump_format)
1616  stringbuffer_aprintf(sb, "\\N");
1617  else
1618  stringbuffer_aprintf(sb, "NULL");
1619  }
1620  else
1621  {
1622  /* Attribute NOT NULL */
1623  switch (state->types[i])
1624  {
1625  case FTInteger:
1626  case FTDouble:
1627  rv = snprintf(val, MAXVALUELEN, "%s", DBFReadStringAttribute(state->hDBFHandle, item, i));
1628  if (rv >= MAXVALUELEN || rv == -1)
1629  {
1630  stringbuffer_aprintf(sbwarn, "Warning: field %d name truncated\n", i);
1631  val[MAXVALUELEN - 1] = '\0';
1632  }
1633 
1634  /* If the value is an empty string, change to 0 */
1635  if (val[0] == '\0')
1636  {
1637  val[0] = '0';
1638  val[1] = '\0';
1639  }
1640 
1641  /* If the value ends with just ".", remove the dot */
1642  if (val[strlen(val) - 1] == '.')
1643  val[strlen(val) - 1] = '\0';
1644  break;
1645 
1646  case FTString:
1647  case FTLogical:
1648  rv = snprintf(val, MAXVALUELEN, "%s", DBFReadStringAttribute(state->hDBFHandle, item, i));
1649  if (rv >= MAXVALUELEN || rv == -1)
1650  {
1651  stringbuffer_aprintf(sbwarn, "Warning: field %d name truncated\n", i);
1652  val[MAXVALUELEN - 1] = '\0';
1653  }
1654  break;
1655 
1656  case FTDate:
1657  rv = snprintf(val, MAXVALUELEN, "%s", DBFReadStringAttribute(state->hDBFHandle, item, i));
1658  if (rv >= MAXVALUELEN || rv == -1)
1659  {
1660  stringbuffer_aprintf(sbwarn, "Warning: field %d name truncated\n", i);
1661  val[MAXVALUELEN - 1] = '\0';
1662  }
1663  if (strlen(val) == 0)
1664  {
1665  if (state->config->dump_format)
1666  stringbuffer_aprintf(sb, "\\N");
1667  else
1668  stringbuffer_aprintf(sb, "NULL");
1669  goto done_cell;
1670  }
1671  break;
1672 
1673  default:
1674  snprintf(state->message, SHPLOADERMSGLEN, _("Error: field %d has invalid or unknown field type (%d)"), i, state->types[i]);
1675 
1676  /* clean up and return err */
1677  SHPDestroyObject(obj);
1678  stringbuffer_destroy(sbwarn);
1680  return SHPLOADERERR;
1681  }
1682 
1683  if (state->config->encoding)
1684  {
1685  char *encoding_msg = _("Try \"LATIN1\" (Western European), or one of the values described at http://www.postgresql.org/docs/current/static/multibyte.html.");
1686 
1687  rv = utf8(state->config->encoding, val, &utf8str);
1688 
1689  if (rv != UTF8_GOOD_RESULT)
1690  {
1691  if ( rv == UTF8_BAD_RESULT )
1692  snprintf(state->message, SHPLOADERMSGLEN, _("Unable to convert data value \"%s\" to UTF-8 (iconv reports \"%s\"). Current encoding is \"%s\". %s"), utf8str, strerror(errno), state->config->encoding, encoding_msg);
1693  else if ( rv == UTF8_NO_RESULT )
1694  snprintf(state->message, SHPLOADERMSGLEN, _("Unable to convert data value to UTF-8 (iconv reports \"%s\"). Current encoding is \"%s\". %s"), strerror(errno), state->config->encoding, encoding_msg);
1695  else
1696  snprintf(state->message, SHPLOADERMSGLEN, _("Unexpected return value from utf8()"));
1697 
1698  if ( rv == UTF8_BAD_RESULT )
1699  free(utf8str);
1700 
1701  /* clean up and return err */
1702  SHPDestroyObject(obj);
1703  stringbuffer_destroy(sbwarn);
1705  return SHPLOADERERR;
1706  }
1707  strncpy(val, utf8str, MAXVALUELEN);
1708  val[MAXVALUELEN-1] = '\0';
1709  free(utf8str);
1710 
1711  }
1712 
1713  /* Escape attribute correctly according to dump format */
1714  if (state->config->dump_format)
1715  {
1716  escval = escape_copy_string(val);
1717  stringbuffer_aprintf(sb, "%s", escval);
1718  }
1719  else
1720  {
1721  escval = escape_insert_string(val);
1722  stringbuffer_aprintf(sb, "'%s'", escval);
1723  }
1724 
1725  /* Free the escaped version if required */
1726  if (val != escval)
1727  free(escval);
1728  }
1729 
1730 done_cell:
1731 
1732  /* Only put in delimiter if not last field or a shape will follow */
1733  if (state->config->readshape == 1 || i < DBFGetFieldCount(state->hDBFHandle) - 1)
1734  {
1735  if (state->config->dump_format)
1736  stringbuffer_aprintf(sb, "\t");
1737  else
1738  stringbuffer_aprintf(sb, ",");
1739  }
1740 
1741  /* End of DBF attribute loop */
1742  }
1743 
1744 
1745  /* Add the shape attribute if we are reading it */
1746  if (state->config->readshape == 1)
1747  {
1748  /* Force the locale to C */
1749  char *oldlocale = setlocale(LC_NUMERIC, "C");
1750 
1751  /* Handle the case of a NULL shape */
1752  if (obj->nVertices == 0)
1753  {
1754  if (state->config->dump_format)
1755  stringbuffer_aprintf(sb, "\\N");
1756  else
1757  stringbuffer_aprintf(sb, "NULL");
1758  }
1759  else
1760  {
1761  /* Handle all other shape attributes */
1762  switch (obj->nSHPType)
1763  {
1764  case SHPT_POLYGON:
1765  case SHPT_POLYGONM:
1766  case SHPT_POLYGONZ:
1767  res = GeneratePolygonGeometry(state, obj, &geometry);
1768  break;
1769 
1770  case SHPT_POINT:
1771  case SHPT_POINTM:
1772  case SHPT_POINTZ:
1773  res = GeneratePointGeometry(state, obj, &geometry, 0);
1774  break;
1775 
1776  case SHPT_MULTIPOINT:
1777  case SHPT_MULTIPOINTM:
1778  case SHPT_MULTIPOINTZ:
1779  /* Force it to multi unless using -S */
1780  res = GeneratePointGeometry(state, obj, &geometry,
1781  state->config->simple_geometries ? 0 : 1);
1782  break;
1783 
1784  case SHPT_ARC:
1785  case SHPT_ARCM:
1786  case SHPT_ARCZ:
1787  res = GenerateLineStringGeometry(state, obj, &geometry);
1788  break;
1789 
1790  default:
1791  snprintf(state->message, SHPLOADERMSGLEN, _("Shape type is not supported, type id = %d"), obj->nSHPType);
1792  SHPDestroyObject(obj);
1793  stringbuffer_destroy(sbwarn);
1795 
1796  return SHPLOADERERR;
1797  }
1798  /* The default returns out of the function, so res will always have been set. */
1799  if (res != SHPLOADEROK)
1800  {
1801  /* Error message has already been set */
1802  SHPDestroyObject(obj);
1803  stringbuffer_destroy(sbwarn);
1805 
1806  return SHPLOADERERR;
1807  }
1808 
1809  /* Now generate the geometry string according to the current configuration */
1810  if (!state->config->dump_format)
1811  {
1812  if (state->to_srid != state->from_srid)
1813  {
1814  stringbuffer_aprintf(sb, "ST_Transform(");
1815  }
1816  stringbuffer_aprintf(sb, "'");
1817  }
1818 
1819  stringbuffer_aprintf(sb, "%s", geometry);
1820 
1821  if (!state->config->dump_format)
1822  {
1823  stringbuffer_aprintf(sb, "'");
1824 
1825  /* Close the ST_Transform if reprojecting. */
1826  if (state->to_srid != state->from_srid)
1827  {
1828  /* We need to add an explicit cast to geography/geometry to ensure that
1829  PostgreSQL doesn't get confused with the ST_Transform() raster
1830  function. */
1831  if (state->config->geography)
1832  stringbuffer_aprintf(sb, "::geometry, %d)::geography", state->to_srid);
1833  else
1834  stringbuffer_aprintf(sb, "::geometry, %d)", state->to_srid);
1835  }
1836  }
1837 
1838  lwfree(geometry);
1839  }
1840 
1841  /* Tidy up everything */
1842  SHPDestroyObject(obj);
1843 
1844  setlocale(LC_NUMERIC, oldlocale);
1845  }
1846 
1847  /* Close the line correctly for dump/insert format */
1848  if (!state->config->dump_format)
1849  stringbuffer_aprintf(sb, ");");
1850 
1851 
1852  /* Copy the string buffer into a new string, destroying the string buffer */
1853  ret = (char *)malloc(strlen((char *)stringbuffer_getstring(sb)) + 1);
1854  strcpy(ret, (char *)stringbuffer_getstring(sb));
1856 
1857  *strrecord = ret;
1858 
1859  /* If any warnings occurred, set the returned message string and warning status */
1860  if (strlen((char *)stringbuffer_getstring(sbwarn)) > 0)
1861  {
1862  snprintf(state->message, SHPLOADERMSGLEN, "%s", stringbuffer_getstring(sbwarn));
1863  stringbuffer_destroy(sbwarn);
1864 
1865  return SHPLOADERWARN;
1866  }
1867  else
1868  {
1869  /* Everything went okay */
1870  stringbuffer_destroy(sbwarn);
1871 
1872  return SHPLOADEROK;
1873  }
1874 }
1875 
1876 
1877 /* Return a pointer to an allocated string containing the header for the specified loader state */
1878 int
1879 ShpLoaderGetSQLFooter(SHPLOADERSTATE *state, char **strfooter)
1880 {
1881  stringbuffer_t *sb;
1882  char *ret;
1883 
1884  /* Create the stringbuffer containing the header; we use this API as it's easier
1885  for handling string resizing during append */
1886  sb = stringbuffer_create();
1887  stringbuffer_clear(sb);
1888 
1889  if ( state->config->dump_format && state->to_srid != state->from_srid){
1891  stringbuffer_aprintf(sb, "ALTER TABLE \"pgis_tmp_%s\" ALTER COLUMN \"%s\" TYPE ", state->config->table, state->geo_col);
1892  if (state->config->geography){
1893  stringbuffer_aprintf(sb, "geography USING (ST_Transform(\"%s\", %d)::geography );\n", state->geo_col, state->to_srid);
1894  }
1895  else {
1896  stringbuffer_aprintf(sb, "geometry USING (ST_Transform(\"%s\", %d)::geometry );\n", state->geo_col, state->to_srid);
1897  }
1898  stringbuffer_aprintf(sb, "INSERT INTO ");
1899  // /* Schema is optional, include if present. */
1900  if (state->config->schema)
1901  {
1902  stringbuffer_aprintf(sb, "\"%s\".", state->config->schema);
1903  }
1904  stringbuffer_aprintf(sb, "\"%s\" (%s) ", state->config->table, state->col_names);
1905  stringbuffer_aprintf(sb, "SELECT %s FROM \"pgis_tmp_%s\";\n", state->col_names, state->config->table);
1906  }
1907 
1908  /* Create gist index if specified and not in "prepare" mode */
1909  if (state->config->readshape && state->config->createindex)
1910  {
1911  stringbuffer_aprintf(sb, "CREATE INDEX ON ");
1912  /* Schema is optional, include if present. */
1913  if (state->config->schema)
1914  {
1915  stringbuffer_aprintf(sb, "\"%s\".",state->config->schema);
1916  }
1917  stringbuffer_aprintf(sb, "\"%s\" USING GIST (\"%s\")", state->config->table, state->geo_col);
1918  /* Tablespace is also optional. */
1919  if (state->config->idxtablespace != NULL)
1920  {
1921  stringbuffer_aprintf(sb, " TABLESPACE \"%s\"", state->config->idxtablespace);
1922  }
1923  stringbuffer_aprintf(sb, ";\n");
1924  }
1925 
1926  /* End the transaction if there is one. */
1927  if (state->config->usetransaction)
1928  {
1929  stringbuffer_aprintf(sb, "COMMIT;\n");
1930  }
1931 
1932 
1933  if(state->config->analyze)
1934  {
1935  /* Always ANALYZE the resulting table, for better stats */
1936  stringbuffer_aprintf(sb, "ANALYZE ");
1937  if (state->config->schema)
1938  {
1939  stringbuffer_aprintf(sb, "\"%s\".", state->config->schema);
1940  }
1941  stringbuffer_aprintf(sb, "\"%s\";\n", state->config->table);
1942  }
1943 
1944  /* Copy the string buffer into a new string, destroying the string buffer */
1945  ret = (char *)malloc(strlen((char *)stringbuffer_getstring(sb)) + 1);
1946  strcpy(ret, (char *)stringbuffer_getstring(sb));
1948 
1949  *strfooter = ret;
1950 
1951  return SHPLOADEROK;
1952 }
1953 
1954 
1955 void
1957 {
1958  /* Destroy a state object created with ShpLoaderOpenShape */
1959  int i;
1960  if (state != NULL)
1961  {
1962  if (state->hSHPHandle)
1963  SHPClose(state->hSHPHandle);
1964  if (state->hDBFHandle)
1965  DBFClose(state->hDBFHandle);
1966  if (state->field_names)
1967  {
1968  for (i = 0; i < state->num_fields; i++)
1969  free(state->field_names[i]);
1970 
1971  free(state->field_names);
1972  }
1973  if (state->pgfieldtypes)
1974  {
1975  for (i = 0; i < state->num_fields; i++)
1976  free(state->pgfieldtypes[i]);
1977 
1978  free(state->pgfieldtypes);
1979  }
1980  if (state->types)
1981  free(state->types);
1982  if (state->widths)
1983  free(state->widths);
1984  if (state->precisions)
1985  free(state->precisions);
1986  if (state->col_names)
1987  free(state->col_names);
1988 
1989  /* Free any column map fieldnames if specified */
1990  colmap_clean(&state->column_map);
1991 
1992  /* Free the state itself */
1993  free(state);
1994  }
1995 }
char * s
Definition: cu_in_wkt.c:23
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition: cu_print.c:267
int SHPAPI_CALL DBFGetFieldCount(DBFHandle psDBF)
Definition: dbfopen.c:1246
DBFHandle SHPAPI_CALL DBFOpen(const char *pszFilename, const char *pszAccess)
Definition: dbfopen.c:351
int SHPAPI_CALL DBFGetRecordCount(DBFHandle psDBF)
Definition: dbfopen.c:1259
void SHPAPI_CALL DBFClose(DBFHandle psDBF)
Definition: dbfopen.c:606
int SHPAPI_CALL DBFIsAttributeNULL(DBFHandle psDBF, int iRecord, int iField)
Definition: dbfopen.c:1226
int SHPAPI_CALL DBFIsRecordDeleted(DBFHandle psDBF, int iShape)
Definition: dbfopen.c:1750
const char SHPAPI_CALL1 * DBFReadStringAttribute(DBFHandle psDBF, int iRecord, int iField){ return STATIC_CAST(const char *, DBFReadAttribute(psDBF, iRecord, iField, 'C')
DBFFieldType SHPAPI_CALL DBFGetFieldInfo(DBFHandle psDBF, int iField, char *pszFieldName, int *pnWidth, int *pnDecimals)
Definition: dbfopen.c:1274
LWPOINT * lwpoint_construct_empty(int32_t srid, char hasz, char hasm)
Definition: lwpoint.c:151
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:367
#define LW_FALSE
Definition: liblwgeom.h:94
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
Definition: lwgeom.c:337
#define COLLECTIONTYPE
Definition: liblwgeom.h:108
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1246
#define MULTILINETYPE
Definition: liblwgeom.h:106
#define WKT_EXTENDED
Definition: liblwgeom.h:2221
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:357
#define MULTIPOINTTYPE
Definition: liblwgeom.h:105
char * lwgeom_to_hexwkb_buffer(const LWGEOM *geom, uint8_t variant)
Definition: lwout_wkb.c:845
int lwpoly_add_ring(LWPOLY *poly, POINTARRAY *pa)
Add a ring, allocating extra space if necessary.
Definition: lwpoly.c:247
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:102
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:42
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:107
void lwfree(void *mem)
Definition: lwutil.c:248
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:372
LWPOINT * lwpoint_construct(int32_t srid, GBOX *bbox, POINTARRAY *point)
Definition: lwpoint.c:129
#define WKB_EXTENDED
Definition: liblwgeom.h:2212
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
Definition: ptarray.c:59
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
Definition: lwout_wkt.c:708
int ptarray_append_point(POINTARRAY *pa, const POINT4D *pt, int allow_duplicates)
Append a point to the end of an existing POINTARRAY If allow_duplicate is LW_FALSE,...
Definition: ptarray.c:147
LWCOLLECTION * lwcollection_construct(uint8_t type, int32_t srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
Definition: lwcollection.c:42
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:93
#define FLAGS_SET_M(flags, value)
Definition: liblwgeom.h:173
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:215
#define FLAGS_SET_Z(flags, value)
Definition: liblwgeom.h:172
LWPOLY * lwpoly_construct_empty(int32_t srid, char hasz, char hasm)
Definition: lwpoly.c:161
#define str(s)
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:106
void * malloc(YYSIZE_T)
void free(void *)
type
Definition: ovdump.py:42
tuple res
Definition: window.py:79
#define SHPT_ARCZ
Definition: shapefil.h:354
DBFFieldType
Definition: shapefil.h:638
@ FTDouble
Definition: shapefil.h:641
@ FTString
Definition: shapefil.h:639
@ FTInvalid
Definition: shapefil.h:644
@ FTLogical
Definition: shapefil.h:642
@ FTDate
Definition: shapefil.h:643
@ FTInteger
Definition: shapefil.h:640
SHPObject SHPAPI_CALL1 * SHPReadObject(SHPHandle hSHP, int iShape);int SHPAPI_CALL SHPWriteObject(SHPHandle hSHP, int iShape, SHPObject *psObject
Definition: shpopen.c:1842
#define SHPT_ARCM
Definition: shapefil.h:358
#define SHPT_POLYGONM
Definition: shapefil.h:359
#define SHPT_ARC
Definition: shapefil.h:350
void SHPAPI_CALL SHPClose(SHPHandle hSHP)
Definition: shpopen.c:888
#define SHPT_POLYGON
Definition: shapefil.h:351
void SHPAPI_CALL SHPDestroyObject(SHPObject *psObject)
Definition: shpopen.c:2652
SHPHandle SHPAPI_CALL SHPOpen(const char *pszShapeFile, const char *pszAccess)
Definition: shpopen.c:291
#define SHPT_MULTIPOINT
Definition: shapefil.h:352
void SHPAPI_CALL SHPGetInfo(SHPHandle hSHP, int *pnEntities, int *pnShapeType, double *padfMinBound, double *padfMaxBound)
Definition: shpopen.c:956
#define SHPT_POINTZ
Definition: shapefil.h:353
#define SHPT_MULTIPOINTZ
Definition: shapefil.h:356
#define SHPT_MULTIPOINTM
Definition: shapefil.h:360
#define SHPT_POINTM
Definition: shapefil.h:357
#define SHPT_POINT
Definition: shapefil.h:349
#define SHPT_POLYGONZ
Definition: shapefil.h:355
static int utf8(const char *fromcode, char *inputbuf, char **outputbuf)
int GeneratePointGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry, int force_multi)
Generate an allocated geometry string for shapefile object obj using the state parameters if "force_m...
struct struct_ring Ring
int ShpLoaderGetRecordCount(SHPLOADERSTATE *state)
int PIP(Point P, Point *V, int n)
PIP(): crossing number test for a point in a polygon input: P = a point, V[] = vertex points of a pol...
char * escape_insert_string(char *str)
Escape input string suitable for INSERT.
#define UTF8_GOOD_RESULT
#define UTF8_BAD_RESULT
int GeneratePolygonGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry)
Generate an allocated geometry string for shapefile object obj using the state parameters.
int FindPolygons(SHPObject *obj, Ring ***Out)
void strtolower(char *s)
void ShpLoaderDestroy(SHPLOADERSTATE *state)
char * escape_copy_string(char *str)
Escape input string suitable for COPY.
int ShpLoaderGetSQLCopyStatement(SHPLOADERSTATE *state, char **strheader)
int ShpLoaderOpenShape(SHPLOADERSTATE *state)
void ReleasePolygons(Ring **polys, int npolys)
int ShpLoaderGenerateSQLRowStatement(SHPLOADERSTATE *state, int item, char **strrecord)
#define UTF8_NO_RESULT
void set_loader_config_defaults(SHPLOADERCONFIG *config)
int ShpLoaderGetSQLFooter(SHPLOADERSTATE *state, char **strfooter)
struct struct_point Point
SHPLOADERSTATE * ShpLoaderCreate(SHPLOADERCONFIG *config)
int GenerateLineStringGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry)
Generate an allocated geometry string for shapefile object obj using the state parameters.
int ShpLoaderGetSQLHeader(SHPLOADERSTATE *state, char **strheader)
#define FORCE_OUTPUT_4D
#define WKT_PRECISION
#define POLICY_NULL_ABORT
#define GEOGRAPHY_DEFAULT
#define FORCE_OUTPUT_2D
#define SHPLOADERRECISNULL
#define SHPLOADERWARN
#define FORCE_OUTPUT_3DM
#define POLICY_NULL_SKIP
#define POLICY_NULL_INSERT
#define ENCODING_DEFAULT
#define FORCE_OUTPUT_DISABLE
#define SHPLOADERMSGLEN
#define GEOMETRY_DEFAULT
#define SHPLOADERRECDELETED
#define MAXVALUELEN
#define SHPLOADERERR
#define MAXFIELDNAMELEN
#define SHPLOADEROK
#define FORCE_OUTPUT_3DZ
int colmap_read(const char *filename, colmap *map, char *errbuf, size_t errbuflen)
Read the content of filename into a symbol map.
Definition: shpcommon.c:217
void colmap_init(colmap *map)
Definition: shpcommon.c:163
const char * colmap_pg_by_dbf(colmap *map, const char *dbfname)
Definition: shpcommon.c:203
void colmap_clean(colmap *map)
Definition: shpcommon.c:171
char * codepage2encoding(const char *cpg)
Definition: shpcommon.c:302
#define _(String)
Definition: shpcommon.h:24
void stringbuffer_clear(stringbuffer_t *s)
Reset the stringbuffer_t.
Definition: stringbuffer.c:100
int stringbuffer_aprintf(stringbuffer_t *s, const char *fmt,...)
Appends a formatted string to the current string buffer, using the format and argument list provided.
Definition: stringbuffer.c:254
stringbuffer_t * stringbuffer_create(void)
Allocate a new stringbuffer_t.
Definition: stringbuffer.c:33
void stringbuffer_destroy(stringbuffer_t *s)
Free the stringbuffer_t and all memory managed within it.
Definition: stringbuffer.c:85
const char * stringbuffer_getstring(stringbuffer_t *s)
Returns a reference to the internal string being managed by the stringbuffer.
Definition: stringbuffer.c:125
char * pszCodePage
Definition: shapefil.h:625
double m
Definition: liblwgeom.h:414
double x
Definition: liblwgeom.h:414
double z
Definition: liblwgeom.h:414
double y
Definition: liblwgeom.h:414
char message[SHPLOADERMSGLEN]
DBFFieldType * types
SHPHandle hSHPHandle
DBFHandle hDBFHandle
SHPLOADERCONFIG * config
Point * list
unsigned int linked
struct struct_ring * next
double * padfX
Definition: shapefil.h:390
int nVertices
Definition: shapefil.h:389
double * padfY
Definition: shapefil.h:391
int nSHPType
Definition: shapefil.h:381
double * padfZ
Definition: shapefil.h:392
int * panPartStart
Definition: shapefil.h:386
double * padfM
Definition: shapefil.h:393