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