PostGIS 3.7.0dev-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 <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 */
27typedef struct struct_point
28{
29 double x, y, z, m;
31
32typedef struct struct_ring
33{
34 Point *list; /* list of points */
36 int n; /* number of points in list */
37 unsigned int linked; /* number of "next" rings */
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
49char *escape_copy_string(char *str);
50char *escape_insert_string(char *str);
51
52int GeneratePointGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry, int force_multi);
53int GenerateLineStringGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry);
54int PIP(Point P, Point *V, int n);
55int FindPolygons(SHPObject *obj, Ring ***Out);
56void ReleasePolygons(Ring **polys, int npolys);
57int GeneratePolygonGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry);
58
59
60/* Return allocated string containing UTF8 string converted from encoding fromcode */
61static int
62utf8(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
120char *
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
175char *
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
228int
229GeneratePointGeometry(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 {
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
319int
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)
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
416int
417PIP(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
438int
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
591void
592ReleasePolygons(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
621int
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)
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 */
747void
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 */
758void
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 */
845int
847{
848 SHPObject *obj = NULL;
849 int ret = SHPLOADEROK;
850 char name[MAXFIELDNAMELEN];
851 DBFFieldType type = FTInvalid;
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 {
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 */
1279int
1280ShpLoaderGetSQLHeader(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();
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 */
1492int
1494{
1495 //char *copystr;
1496 stringbuffer_t *sb;
1497 char *ret;
1498 sb = stringbuffer_create();
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 */
1539int
1541{
1542 return state->num_entities;
1543}
1544
1545
1546/* Return an allocated string representation of a specified record item */
1547int
1548ShpLoaderGenerateSQLRowStatement(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();
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
1730done_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 */
1878int
1879ShpLoaderGetSQLFooter(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();
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
1955void
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
const char SHPAPI_CALL1 * DBFReadStringAttribute(DBFHandle psDBF, int iRecord, int iField){ return STATIC_CAST(const char *, DBFReadAttribute(psDBF, iRecord, iField, 'C')
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
DBFFieldType SHPAPI_CALL DBFGetFieldInfo(DBFHandle psDBF, int iField, char *pszFieldName, int *pnWidth, int *pnDecimals)
Definition dbfopen.c:1274
LWCOLLECTION * lwcollection_construct(uint8_t type, int32_t srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
char * lwgeom_to_hexwkb_buffer(const LWGEOM *geom, uint8_t variant)
Definition lwout_wkb.c:845
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition lwgeom.c:372
#define LW_FALSE
Definition liblwgeom.h:94
#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
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:708
#define MULTIPOINTTYPE
Definition liblwgeom.h:105
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: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 * lwline_as_lwgeom(const LWLINE *obj)
Definition lwgeom.c:367
#define WKB_EXTENDED
Definition liblwgeom.h:2212
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:93
#define FLAGS_SET_M(flags, value)
Definition liblwgeom.h:173
LWPOLY * lwpoly_construct_empty(int32_t srid, char hasz, char hasm)
Definition lwpoly.c:161
#define SRID_UNKNOWN
Unknown SRID value.
Definition liblwgeom.h:215
#define FLAGS_SET_Z(flags, value)
Definition liblwgeom.h:172
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition lwgeom.c:357
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
Definition lwgeom.c:337
#define str(s)
#define LWDEBUGF(level, msg,...)
Definition lwgeom_log.h:106
void * malloc(YYSIZE_T)
void free(void *)
#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
#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
SHPObject SHPAPI_CALL1 * SHPReadObject(SHPHandle hSHP, int iShape);int SHPAPI_CALL SHPWriteObject(SHPHandle hSHP, int iShape, SHPObject *psObject
Definition shpopen.c:1842
#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.
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:217
void colmap_init(colmap *map)
Definition shpcommon.c:163
char * codepage2encoding(const char *cpg)
Definition shpcommon.c:302
void colmap_clean(colmap *map)
Definition shpcommon.c:171
const char * colmap_pg_by_dbf(colmap *map, const char *dbfname)
Definition shpcommon.c:203
#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.
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
SHPLOADERCONFIG * config
unsigned int linked
struct struct_ring * next
double * padfX
Definition shapefil.h:390
double * padfY
Definition shapefil.h:391
double * padfZ
Definition shapefil.h:392
int * panPartStart
Definition shapefil.h:386
double * padfM
Definition shapefil.h:393