geo_coder 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +12 -0
- data/Gemfile.lock +32 -0
- data/History.txt +6 -0
- data/Makefile +13 -0
- data/Manifest.txt +18 -0
- data/README.rdoc +197 -0
- data/Rakefile +53 -0
- data/TODO.txt +8 -0
- data/VERSION +1 -0
- data/bin/build_indexes +8 -0
- data/bin/rebuild_cluster +22 -0
- data/bin/rebuild_metaphones +23 -0
- data/bin/tiger_import +59 -0
- data/demos/demo/app/ext/geocodewrap.rb +84 -0
- data/demos/demo/app/views/index.builder +13 -0
- data/demos/demo/app/views/index.erb +71 -0
- data/demos/demo/config.ru +12 -0
- data/demos/demo/config/bootstraps.rb +130 -0
- data/demos/demo/config/geoenvironment.rb +25 -0
- data/demos/demo/geocoder_helper.rb +12 -0
- data/demos/demo/geocom_geocode.rb +10 -0
- data/demos/demo/main.rb +3 -0
- data/demos/demo/rakefile.rb +17 -0
- data/demos/demo/tmp/restart.txt +0 -0
- data/demos/simpledemo/views/index.builder +13 -0
- data/demos/simpledemo/views/index.erb +69 -0
- data/demos/simpledemo/ws.rb +83 -0
- data/doc/Makefile +7 -0
- data/doc/html4css1.css +279 -0
- data/doc/lookup.rst +193 -0
- data/doc/parsing.rst +125 -0
- data/doc/voidspace.css +147 -0
- data/geo_coder.gemspec +172 -0
- data/lib/geocoder/us.rb +21 -0
- data/lib/geocoder/us/address.rb +290 -0
- data/lib/geocoder/us/constants.rb +670 -0
- data/lib/geocoder/us/database.rb +745 -0
- data/lib/geocoder/us/import.rb +181 -0
- data/lib/geocoder/us/import/tiger.rb +13 -0
- data/lib/geocoder/us/numbers.rb +58 -0
- data/navteq/README +4 -0
- data/navteq/convert.sql +37 -0
- data/navteq/navteq_import +39 -0
- data/navteq/prepare.sql +92 -0
- data/sql/cluster.sql +16 -0
- data/sql/convert.sql +80 -0
- data/sql/create.sql +37 -0
- data/sql/index.sql +12 -0
- data/sql/place.csv +104944 -0
- data/sql/place.sql +104948 -0
- data/sql/setup.sql +78 -0
- data/src/Makefile +13 -0
- data/src/README +14 -0
- data/src/liblwgeom/Makefile +75 -0
- data/src/liblwgeom/box2d.c +54 -0
- data/src/liblwgeom/lex.yy.c +4799 -0
- data/src/liblwgeom/liblwgeom.h +1405 -0
- data/src/liblwgeom/lwalgorithm.c +946 -0
- data/src/liblwgeom/lwalgorithm.h +52 -0
- data/src/liblwgeom/lwcircstring.c +759 -0
- data/src/liblwgeom/lwcollection.c +541 -0
- data/src/liblwgeom/lwcompound.c +118 -0
- data/src/liblwgeom/lwcurvepoly.c +86 -0
- data/src/liblwgeom/lwgeom.c +886 -0
- data/src/liblwgeom/lwgeom_api.c +2201 -0
- data/src/liblwgeom/lwgparse.c +1219 -0
- data/src/liblwgeom/lwgunparse.c +1054 -0
- data/src/liblwgeom/lwline.c +525 -0
- data/src/liblwgeom/lwmcurve.c +125 -0
- data/src/liblwgeom/lwmline.c +137 -0
- data/src/liblwgeom/lwmpoint.c +138 -0
- data/src/liblwgeom/lwmpoly.c +141 -0
- data/src/liblwgeom/lwmsurface.c +129 -0
- data/src/liblwgeom/lwpoint.c +439 -0
- data/src/liblwgeom/lwpoly.c +579 -0
- data/src/liblwgeom/lwsegmentize.c +1047 -0
- data/src/liblwgeom/lwutil.c +369 -0
- data/src/liblwgeom/measures.c +861 -0
- data/src/liblwgeom/postgis_config.h +93 -0
- data/src/liblwgeom/ptarray.c +847 -0
- data/src/liblwgeom/vsprintf.c +179 -0
- data/src/liblwgeom/wktparse.h +126 -0
- data/src/liblwgeom/wktparse.lex +74 -0
- data/src/liblwgeom/wktparse.tab.c +2353 -0
- data/src/liblwgeom/wktparse.tab.h +145 -0
- data/src/liblwgeom/wktparse.y +385 -0
- data/src/libsqlite3_geocoder/Makefile +22 -0
- data/src/libsqlite3_geocoder/Makefile.nix +15 -0
- data/src/libsqlite3_geocoder/Makefile.redhat +15 -0
- data/src/libsqlite3_geocoder/extension.c +121 -0
- data/src/libsqlite3_geocoder/extension.h +13 -0
- data/src/libsqlite3_geocoder/levenshtein.c +42 -0
- data/src/libsqlite3_geocoder/metaphon.c +278 -0
- data/src/libsqlite3_geocoder/util.c +37 -0
- data/src/libsqlite3_geocoder/wkb_compress.c +54 -0
- data/src/metaphone/Makefile +7 -0
- data/src/metaphone/README +49 -0
- data/src/metaphone/extension.c +37 -0
- data/src/metaphone/metaphon.c +251 -0
- data/src/shp2sqlite/Makefile +37 -0
- data/src/shp2sqlite/Makefile.nix +36 -0
- data/src/shp2sqlite/Makefile.redhat +35 -0
- data/src/shp2sqlite/dbfopen.c +1595 -0
- data/src/shp2sqlite/getopt.c +695 -0
- data/src/shp2sqlite/getopt.h +127 -0
- data/src/shp2sqlite/shapefil.h +500 -0
- data/src/shp2sqlite/shp2sqlite.c +1974 -0
- data/src/shp2sqlite/shpopen.c +1894 -0
- data/tests/address.rb +236 -0
- data/tests/benchmark.rb +20 -0
- data/tests/constants.rb +57 -0
- data/tests/data/address-sample.csv +52 -0
- data/tests/data/db-test.csv +57 -0
- data/tests/data/locations.csv +4 -0
- data/tests/database.rb +137 -0
- data/tests/generate.rb +34 -0
- data/tests/numbers.rb +46 -0
- data/tests/run.rb +11 -0
- metadata +237 -0
|
@@ -0,0 +1,1974 @@
|
|
|
1
|
+
/**********************************************************************
|
|
2
|
+
* $Id: shp2pgsql.c 3623 2009-02-03 07:20:16Z pramsey $
|
|
3
|
+
*
|
|
4
|
+
* PostGIS - Spatial Types for PostgreSQL
|
|
5
|
+
* http://postgis.refractions.net
|
|
6
|
+
* Copyright 2001-2003 Refractions Research Inc.
|
|
7
|
+
*
|
|
8
|
+
* This is free software; you can redistribute and/or modify it under
|
|
9
|
+
* the terms of the GNU General Public Licence. See the COPYING file.
|
|
10
|
+
*
|
|
11
|
+
**********************************************************************
|
|
12
|
+
* Using shapelib 1.2.8, this program reads in shape files and
|
|
13
|
+
* processes it's contents into a Insert statements which can be
|
|
14
|
+
* easily piped into a database frontend.
|
|
15
|
+
* Specifically designed to insert type 'geometry' (a custom
|
|
16
|
+
* written PostgreSQL type) for the shape files and PostgreSQL
|
|
17
|
+
* standard types for all attributes of the entity.
|
|
18
|
+
*
|
|
19
|
+
* Original Author: Jeff Lounsbury, jeffloun@refractions.net
|
|
20
|
+
*
|
|
21
|
+
* Maintainer: Sandro Santilli, strk@refractions.net
|
|
22
|
+
*
|
|
23
|
+
**********************************************************************/
|
|
24
|
+
|
|
25
|
+
#include "../liblwgeom/postgis_config.h"
|
|
26
|
+
#include "shapefil.h"
|
|
27
|
+
#include <stdio.h>
|
|
28
|
+
#include <string.h>
|
|
29
|
+
#include <stdlib.h>
|
|
30
|
+
#include <ctype.h>
|
|
31
|
+
#include <sys/types.h>
|
|
32
|
+
#include <sys/stat.h>
|
|
33
|
+
#include <unistd.h>
|
|
34
|
+
#include <errno.h>
|
|
35
|
+
#include "getopt.h"
|
|
36
|
+
#ifdef HAVE_ICONV
|
|
37
|
+
#include <iconv.h>
|
|
38
|
+
#endif
|
|
39
|
+
|
|
40
|
+
#include "../liblwgeom/liblwgeom.h"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
#define POINTTYPE 1
|
|
44
|
+
#define LINETYPE 2
|
|
45
|
+
#define POLYGONTYPE 3
|
|
46
|
+
#define MULTIPOINTTYPE 4
|
|
47
|
+
#define MULTILINETYPE 5
|
|
48
|
+
#define MULTIPOLYGONTYPE 6
|
|
49
|
+
#define COLLECTIONTYPE 7
|
|
50
|
+
|
|
51
|
+
#define WKBZOFFSET 0x80000000
|
|
52
|
+
#define WKBMOFFSET 0x40000000
|
|
53
|
+
|
|
54
|
+
typedef struct {double x, y, z, m;} Point;
|
|
55
|
+
|
|
56
|
+
typedef struct Ring {
|
|
57
|
+
Point *list; /* list of points */
|
|
58
|
+
struct Ring *next;
|
|
59
|
+
int n; /* number of points in list */
|
|
60
|
+
unsigned int linked; /* number of "next" rings */
|
|
61
|
+
} Ring;
|
|
62
|
+
|
|
63
|
+
/* Values for null_policy global */
|
|
64
|
+
enum {
|
|
65
|
+
insert_null,
|
|
66
|
+
skip_null,
|
|
67
|
+
abort_on_null
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/* globals */
|
|
71
|
+
int dump_format = 0; /* 0=insert statements, 1 = dump */
|
|
72
|
+
int sqlite_format = 1; /* 0=PostGIS GEOMETRY, 1=SQLite BLOB */
|
|
73
|
+
int simple_geometries = 0; /* 0 = MULTILINESTRING/MULTIPOLYGON, 1 = LINESTRING/POLYGON */
|
|
74
|
+
int quoteidentifiers = 0;
|
|
75
|
+
int forceint4 = 0;
|
|
76
|
+
int createindex = 0;
|
|
77
|
+
int readshape = 1;
|
|
78
|
+
char opt = ' ';
|
|
79
|
+
char *col_names = NULL;
|
|
80
|
+
char *pgtype;
|
|
81
|
+
int istypeM = 0;
|
|
82
|
+
int pgdims;
|
|
83
|
+
unsigned int wkbtype;
|
|
84
|
+
char *shp_file = NULL;
|
|
85
|
+
int hwgeom = 0; /* old (hwgeom) mode */
|
|
86
|
+
#ifdef HAVE_ICONV
|
|
87
|
+
char *encoding=NULL;
|
|
88
|
+
#endif
|
|
89
|
+
int null_policy = insert_null;
|
|
90
|
+
|
|
91
|
+
DBFFieldType *types; /* Fields type, width and precision */
|
|
92
|
+
SHPHandle hSHPHandle;
|
|
93
|
+
DBFHandle hDBFHandle;
|
|
94
|
+
int shpfiletype;
|
|
95
|
+
SHPObject *obj=NULL;
|
|
96
|
+
int *widths;
|
|
97
|
+
int *precisions;
|
|
98
|
+
char *table=NULL,*schema=NULL,*geom=NULL;
|
|
99
|
+
int num_fields,num_records,num_entities;
|
|
100
|
+
char **field_names;
|
|
101
|
+
int sr_id = 0;
|
|
102
|
+
|
|
103
|
+
/* Prototypes */
|
|
104
|
+
int Insert_attributes(DBFHandle hDBFHandle, int row);
|
|
105
|
+
char *make_good_string(char *str);
|
|
106
|
+
char *protect_quotes_string(char *str);
|
|
107
|
+
int PIP( Point P, Point* V, int n );
|
|
108
|
+
void *safe_malloc(size_t size);
|
|
109
|
+
void CreateTable(void);
|
|
110
|
+
void CreateIndex(void);
|
|
111
|
+
void usage(char *me, int exitcode, FILE* out);
|
|
112
|
+
void InsertPoint(void);
|
|
113
|
+
void InsertMultiPoint(void);
|
|
114
|
+
void InsertPolygon(void);
|
|
115
|
+
void InsertLineString(void);
|
|
116
|
+
void OutputGeometry(char *geometry);
|
|
117
|
+
int ParseCmdline(int ARGC, char **ARGV);
|
|
118
|
+
void SetPgType(void);
|
|
119
|
+
char *dump_ring(Ring *ring);
|
|
120
|
+
#ifdef HAVE_ICONV
|
|
121
|
+
char *utf8(const char *fromcode, char *inputbuf);
|
|
122
|
+
#endif
|
|
123
|
+
int FindPolygons(SHPObject *obj, Ring ***Out);
|
|
124
|
+
void ReleasePolygons(Ring **polys, int npolys);
|
|
125
|
+
void DropTable(char *schema, char *table, char *geom);
|
|
126
|
+
void GetFieldsSpec(void);
|
|
127
|
+
void LoadData(void);
|
|
128
|
+
void OpenShape(void);
|
|
129
|
+
void LowerCase(char *s);
|
|
130
|
+
void Cleanup(void);
|
|
131
|
+
|
|
132
|
+
/*
|
|
133
|
+
static char rcsid[] =
|
|
134
|
+
"$Id: shp2pgsql.c 3623 2009-02-03 07:20:16Z pramsey $";
|
|
135
|
+
*/
|
|
136
|
+
|
|
137
|
+
/* liblwgeom allocator callback - install the defaults (malloc/free/stdout/stderr) */
|
|
138
|
+
void lwgeom_init_allocators()
|
|
139
|
+
{
|
|
140
|
+
lwgeom_install_default_allocators();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
void *safe_malloc(size_t size)
|
|
145
|
+
{
|
|
146
|
+
void *ret = malloc(size);
|
|
147
|
+
if ( ! ret ) {
|
|
148
|
+
fprintf(stderr, "Out of virtual memory\n");
|
|
149
|
+
exit(1);
|
|
150
|
+
}
|
|
151
|
+
return ret;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
#define malloc(x) safe_malloc(x)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
char *
|
|
158
|
+
make_good_string(char *str)
|
|
159
|
+
{
|
|
160
|
+
/*
|
|
161
|
+
* find all the tabs and make them \<tab>s
|
|
162
|
+
*
|
|
163
|
+
* 1. find # of tabs
|
|
164
|
+
* 2. make new string
|
|
165
|
+
*
|
|
166
|
+
* we dont escape already escaped tabs
|
|
167
|
+
*/
|
|
168
|
+
|
|
169
|
+
char *result;
|
|
170
|
+
char *ptr, *optr;
|
|
171
|
+
int toescape = 0;
|
|
172
|
+
size_t size;
|
|
173
|
+
#ifdef HAVE_ICONV
|
|
174
|
+
char *utf8str=NULL;
|
|
175
|
+
|
|
176
|
+
if ( encoding )
|
|
177
|
+
{
|
|
178
|
+
utf8str=utf8(encoding, str);
|
|
179
|
+
if ( ! utf8str ) exit(1);
|
|
180
|
+
str = utf8str;
|
|
181
|
+
}
|
|
182
|
+
#endif
|
|
183
|
+
|
|
184
|
+
ptr = str;
|
|
185
|
+
|
|
186
|
+
while (*ptr) {
|
|
187
|
+
if ( *ptr == '\t' || *ptr == '\\' ) toescape++;
|
|
188
|
+
ptr++;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (toescape == 0) return str;
|
|
192
|
+
|
|
193
|
+
size = ptr-str+toescape+1;
|
|
194
|
+
|
|
195
|
+
result = calloc(1, size);
|
|
196
|
+
|
|
197
|
+
optr=result;
|
|
198
|
+
ptr=str;
|
|
199
|
+
while (*ptr) {
|
|
200
|
+
if ( *ptr == '\t' || *ptr == '\\' ) *optr++='\\';
|
|
201
|
+
*optr++=*ptr++;
|
|
202
|
+
}
|
|
203
|
+
*optr='\0';
|
|
204
|
+
|
|
205
|
+
#ifdef HAVE_ICONV
|
|
206
|
+
if ( encoding ) free(str);
|
|
207
|
+
#endif
|
|
208
|
+
|
|
209
|
+
return result;
|
|
210
|
+
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
char *
|
|
214
|
+
protect_quotes_string(char *str)
|
|
215
|
+
{
|
|
216
|
+
/*
|
|
217
|
+
* find all quotes and make them \quotes
|
|
218
|
+
* find all '\' and make them '\\'
|
|
219
|
+
*
|
|
220
|
+
* 1. find # of characters
|
|
221
|
+
* 2. make new string
|
|
222
|
+
*/
|
|
223
|
+
|
|
224
|
+
char *result;
|
|
225
|
+
char *ptr, *optr;
|
|
226
|
+
int toescape = 0;
|
|
227
|
+
size_t size;
|
|
228
|
+
#ifdef HAVE_ICONV
|
|
229
|
+
char *utf8str=NULL;
|
|
230
|
+
|
|
231
|
+
if ( encoding )
|
|
232
|
+
{
|
|
233
|
+
utf8str=utf8(encoding, str);
|
|
234
|
+
if ( ! utf8str ) exit(1);
|
|
235
|
+
str = utf8str;
|
|
236
|
+
}
|
|
237
|
+
#endif
|
|
238
|
+
|
|
239
|
+
ptr = str;
|
|
240
|
+
|
|
241
|
+
while (*ptr) {
|
|
242
|
+
if ( *ptr == '\'' || *ptr == '\\' ) toescape++;
|
|
243
|
+
ptr++;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (toescape == 0) return str;
|
|
247
|
+
|
|
248
|
+
size = ptr-str+toescape+1;
|
|
249
|
+
|
|
250
|
+
result = calloc(1, size);
|
|
251
|
+
|
|
252
|
+
optr=result;
|
|
253
|
+
ptr=str;
|
|
254
|
+
while (*ptr) {
|
|
255
|
+
/* SQLite doesn't support backslash escaping in strings */
|
|
256
|
+
if ( *ptr == '\\' && !sqlite_format ) *optr++='\\';
|
|
257
|
+
if ( *ptr == '\'') *optr++='\'';
|
|
258
|
+
*optr++=*ptr++;
|
|
259
|
+
}
|
|
260
|
+
*optr='\0';
|
|
261
|
+
|
|
262
|
+
#ifdef HAVE_ICONV
|
|
263
|
+
if ( encoding ) free(str);
|
|
264
|
+
#endif
|
|
265
|
+
|
|
266
|
+
return result;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
/*
|
|
271
|
+
* PIP(): crossing number test for a point in a polygon
|
|
272
|
+
* input: P = a point,
|
|
273
|
+
* V[] = vertex points of a polygon V[n+1] with V[n]=V[0]
|
|
274
|
+
* returns: 0 = outside, 1 = inside
|
|
275
|
+
*/
|
|
276
|
+
int
|
|
277
|
+
PIP( Point P, Point* V, int n )
|
|
278
|
+
{
|
|
279
|
+
int cn = 0; /* the crossing number counter */
|
|
280
|
+
int i;
|
|
281
|
+
|
|
282
|
+
/* loop through all edges of the polygon */
|
|
283
|
+
for (i=0; i<n-1; i++) { /* edge from V[i] to V[i+1] */
|
|
284
|
+
if (((V[i].y <= P.y) && (V[i+1].y > P.y)) /* an upward crossing */
|
|
285
|
+
|| ((V[i].y > P.y) && (V[i+1].y <= P.y))) { /* a downward crossing */
|
|
286
|
+
double vt = (float)(P.y - V[i].y) / (V[i+1].y - V[i].y);
|
|
287
|
+
if (P.x < V[i].x + vt * (V[i+1].x - V[i].x)) /* P.x < intersect */
|
|
288
|
+
++cn; /* a valid crossing of y=P.y right of P.x */
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return (cn&1); /* 0 if even (out), and 1 if odd (in) */
|
|
292
|
+
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
/*Insert the attributes from the correct row of dbf file */
|
|
297
|
+
|
|
298
|
+
int
|
|
299
|
+
Insert_attributes(DBFHandle hDBFHandle, int row)
|
|
300
|
+
{
|
|
301
|
+
int i,num_fields;
|
|
302
|
+
char val[1024];
|
|
303
|
+
char *escval;
|
|
304
|
+
|
|
305
|
+
num_fields = DBFGetFieldCount( hDBFHandle );
|
|
306
|
+
for( i = 0; i < num_fields; i++ )
|
|
307
|
+
{
|
|
308
|
+
if(DBFIsAttributeNULL( hDBFHandle, row, i))
|
|
309
|
+
{
|
|
310
|
+
|
|
311
|
+
if(dump_format)
|
|
312
|
+
{
|
|
313
|
+
printf("\\N");
|
|
314
|
+
//printf("\t");
|
|
315
|
+
}
|
|
316
|
+
else
|
|
317
|
+
{
|
|
318
|
+
printf("NULL");
|
|
319
|
+
//printf(",");
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
else /* Attribute NOT NULL */
|
|
324
|
+
{
|
|
325
|
+
switch (types[i])
|
|
326
|
+
{
|
|
327
|
+
case FTInteger:
|
|
328
|
+
case FTDouble:
|
|
329
|
+
if ( -1 == snprintf(val, 1024, "%s",
|
|
330
|
+
DBFReadStringAttribute(hDBFHandle, row, i)) )
|
|
331
|
+
{
|
|
332
|
+
fprintf(stderr, "Warning: field %d name truncated\n", i);
|
|
333
|
+
val[1023] = '\0';
|
|
334
|
+
}
|
|
335
|
+
/* pg_atoi() does not do this */
|
|
336
|
+
if ( val[0] == '\0' ) { val[0] = '0'; val[1] = '\0'; }
|
|
337
|
+
if ( val[strlen(val)-1] == '.' ) val[strlen(val)-1] = '\0';
|
|
338
|
+
break;
|
|
339
|
+
|
|
340
|
+
case FTString:
|
|
341
|
+
case FTLogical:
|
|
342
|
+
case FTDate:
|
|
343
|
+
if ( -1 == snprintf(val, 1024, "%s",
|
|
344
|
+
DBFReadStringAttribute(hDBFHandle, row, i)) )
|
|
345
|
+
{
|
|
346
|
+
fprintf(stderr, "Warning: field %d name truncated\n", i);
|
|
347
|
+
val[1023] = '\0';
|
|
348
|
+
}
|
|
349
|
+
break;
|
|
350
|
+
|
|
351
|
+
default:
|
|
352
|
+
fprintf(stderr,
|
|
353
|
+
"Error: field %d has invalid or unknown field type (%d)\n",
|
|
354
|
+
i, types[i]);
|
|
355
|
+
exit(1);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (dump_format) {
|
|
359
|
+
escval = make_good_string(val);
|
|
360
|
+
printf("%s", escval);
|
|
361
|
+
//printf("\t");
|
|
362
|
+
} else {
|
|
363
|
+
escval = protect_quotes_string(val);
|
|
364
|
+
if (sqlite_format)
|
|
365
|
+
printf("'%s'", escval);
|
|
366
|
+
else
|
|
367
|
+
printf("E'%s'", escval);
|
|
368
|
+
//printf(",");
|
|
369
|
+
}
|
|
370
|
+
if ( val != escval ) free(escval);
|
|
371
|
+
}
|
|
372
|
+
//only put in delimeter if not last field or a shape will follow
|
|
373
|
+
if(readshape == 1 || i < (num_fields - 1))
|
|
374
|
+
{
|
|
375
|
+
if (dump_format){
|
|
376
|
+
printf("\t");
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
printf(",");
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
return 1;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
/*
|
|
390
|
+
* main()
|
|
391
|
+
* see description at the top of this file
|
|
392
|
+
*/
|
|
393
|
+
int
|
|
394
|
+
main (int ARGC, char **ARGV)
|
|
395
|
+
{
|
|
396
|
+
|
|
397
|
+
/*
|
|
398
|
+
* Parse command line
|
|
399
|
+
*/
|
|
400
|
+
if ( ! ParseCmdline(ARGC, ARGV) ) usage(ARGV[0], 2, stderr);
|
|
401
|
+
|
|
402
|
+
/*
|
|
403
|
+
* Open shapefile and initialize globals
|
|
404
|
+
*/
|
|
405
|
+
OpenShape();
|
|
406
|
+
|
|
407
|
+
if (readshape == 1){
|
|
408
|
+
/*
|
|
409
|
+
* Compute output geometry type
|
|
410
|
+
*/
|
|
411
|
+
|
|
412
|
+
SetPgType();
|
|
413
|
+
|
|
414
|
+
/*
|
|
415
|
+
fprintf(stderr, "Shapefile type: %s\n", SHPTypeName(shpfiletype));
|
|
416
|
+
fprintf(stderr, "Postgis type: %s[%d]\n", pgtype, pgdims);
|
|
417
|
+
*/
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
#ifdef HAVE_ICONV
|
|
421
|
+
if ( encoding )
|
|
422
|
+
{
|
|
423
|
+
printf("SET CLIENT_ENCODING TO UTF8;\n");
|
|
424
|
+
}
|
|
425
|
+
#endif /* defined HAVE_ICONV */
|
|
426
|
+
|
|
427
|
+
/*
|
|
428
|
+
* Drop table if requested
|
|
429
|
+
*/
|
|
430
|
+
if(opt == 'd') DropTable(schema, table, geom);
|
|
431
|
+
|
|
432
|
+
/*
|
|
433
|
+
* Get col names and types for table creation
|
|
434
|
+
* and data load.
|
|
435
|
+
*/
|
|
436
|
+
GetFieldsSpec();
|
|
437
|
+
|
|
438
|
+
printf("BEGIN;\n");
|
|
439
|
+
|
|
440
|
+
/*
|
|
441
|
+
* If not in 'append' mode create the spatial table
|
|
442
|
+
*/
|
|
443
|
+
if(opt != 'a') CreateTable();
|
|
444
|
+
|
|
445
|
+
/*
|
|
446
|
+
* Generate INSERT or COPY lines
|
|
447
|
+
*/
|
|
448
|
+
if(opt != 'p') LoadData();
|
|
449
|
+
|
|
450
|
+
/*
|
|
451
|
+
* Create GiST index if requested
|
|
452
|
+
*/
|
|
453
|
+
if(createindex) CreateIndex();
|
|
454
|
+
|
|
455
|
+
printf("END;\n"); /* End the last transaction */
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
return 0;
|
|
459
|
+
}/*end main() */
|
|
460
|
+
|
|
461
|
+
void
|
|
462
|
+
LowerCase(char *s)
|
|
463
|
+
{
|
|
464
|
+
int j;
|
|
465
|
+
for (j=0; j<strlen(s); j++) s[j] = tolower(s[j]);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
void
|
|
469
|
+
Cleanup(void)
|
|
470
|
+
{
|
|
471
|
+
if ( col_names ) free(col_names);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
void
|
|
475
|
+
OpenShape(void)
|
|
476
|
+
{
|
|
477
|
+
int j;
|
|
478
|
+
SHPObject *obj=NULL;
|
|
479
|
+
|
|
480
|
+
if (readshape == 1)
|
|
481
|
+
{
|
|
482
|
+
hSHPHandle = SHPOpen( shp_file, "rb" );
|
|
483
|
+
if (hSHPHandle == NULL)
|
|
484
|
+
{
|
|
485
|
+
fprintf(stderr, "%s: shape (.shp) or index files (.shx) can not be opened, will just import attribute data.\n", shp_file);
|
|
486
|
+
readshape = 0;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
hDBFHandle = DBFOpen( shp_file, "rb" );
|
|
491
|
+
if ((hSHPHandle == NULL && readshape == 1) || hDBFHandle == NULL){
|
|
492
|
+
fprintf(stderr, "%s: dbf file (.dbf) can not be opened.\n",shp_file);
|
|
493
|
+
exit(-1);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
if (readshape == 1)
|
|
497
|
+
{
|
|
498
|
+
SHPGetInfo(hSHPHandle, &num_entities, &shpfiletype, NULL, NULL);
|
|
499
|
+
|
|
500
|
+
if ( null_policy == abort_on_null )
|
|
501
|
+
{
|
|
502
|
+
for (j=0; j<num_entities; j++)
|
|
503
|
+
{
|
|
504
|
+
obj = SHPReadObject(hSHPHandle,j);
|
|
505
|
+
if ( ! obj )
|
|
506
|
+
{
|
|
507
|
+
fprintf(stderr, "Error reading shape object %d\n", j);
|
|
508
|
+
exit(1);
|
|
509
|
+
}
|
|
510
|
+
if ( obj->nVertices == 0 )
|
|
511
|
+
{
|
|
512
|
+
fprintf(stderr, "Empty geometries found, aborted.\n");
|
|
513
|
+
exit(1);
|
|
514
|
+
}
|
|
515
|
+
SHPDestroyObject(obj);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
else {
|
|
520
|
+
num_entities = DBFGetRecordCount(hDBFHandle);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
void
|
|
526
|
+
CreateTable(void)
|
|
527
|
+
{
|
|
528
|
+
int j;
|
|
529
|
+
int field_precision, field_width;
|
|
530
|
+
DBFFieldType type = -1;
|
|
531
|
+
const char *pk_type;
|
|
532
|
+
|
|
533
|
+
/*
|
|
534
|
+
* Create a table for inserting the shapes into with appropriate
|
|
535
|
+
* columns and types
|
|
536
|
+
*/
|
|
537
|
+
if (sqlite_format)
|
|
538
|
+
pk_type = "integer";
|
|
539
|
+
else
|
|
540
|
+
pk_type = "serial";
|
|
541
|
+
|
|
542
|
+
if ( schema )
|
|
543
|
+
{
|
|
544
|
+
printf("CREATE TABLE \"%s\".\"%s\" (gid %s PRIMARY KEY",
|
|
545
|
+
schema, table, pk_type);
|
|
546
|
+
}
|
|
547
|
+
else
|
|
548
|
+
{
|
|
549
|
+
printf("CREATE TABLE \"%s\" (gid %s PRIMARY KEY",
|
|
550
|
+
table, pk_type);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
for(j=0;j<num_fields;j++)
|
|
554
|
+
{
|
|
555
|
+
type = types[j];
|
|
556
|
+
field_width = widths[j];
|
|
557
|
+
field_precision = precisions[j];
|
|
558
|
+
|
|
559
|
+
printf(",\n\"%s\" ", field_names[j]);
|
|
560
|
+
|
|
561
|
+
if(type == FTString)
|
|
562
|
+
{
|
|
563
|
+
/* use DBF attribute size as maximum width */
|
|
564
|
+
printf ("varchar(%d)", field_width);
|
|
565
|
+
}
|
|
566
|
+
else if (type == FTDate)
|
|
567
|
+
{
|
|
568
|
+
printf ("date");
|
|
569
|
+
}
|
|
570
|
+
else if (type == FTInteger)
|
|
571
|
+
{
|
|
572
|
+
if ( forceint4 )
|
|
573
|
+
{
|
|
574
|
+
printf ("int4");
|
|
575
|
+
}
|
|
576
|
+
else if ( field_width < 5 )
|
|
577
|
+
{
|
|
578
|
+
printf ("int2");
|
|
579
|
+
}
|
|
580
|
+
else if ( field_width < 10 )
|
|
581
|
+
{
|
|
582
|
+
printf ("int4");
|
|
583
|
+
}
|
|
584
|
+
else if ( field_width < 19 )
|
|
585
|
+
{
|
|
586
|
+
printf ("int8");
|
|
587
|
+
}
|
|
588
|
+
else
|
|
589
|
+
{
|
|
590
|
+
printf("numeric(%d,0)",
|
|
591
|
+
field_width);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
else if(type == FTDouble)
|
|
595
|
+
{
|
|
596
|
+
if( field_width > 18 )
|
|
597
|
+
{
|
|
598
|
+
printf ("numeric");
|
|
599
|
+
}
|
|
600
|
+
else
|
|
601
|
+
{
|
|
602
|
+
printf ("float8");
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
else if(type == FTLogical)
|
|
606
|
+
{
|
|
607
|
+
printf ("boolean");
|
|
608
|
+
}
|
|
609
|
+
else
|
|
610
|
+
{
|
|
611
|
+
printf ("Invalid type in DBF file");
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
printf (");\n");
|
|
615
|
+
|
|
616
|
+
/* Create the geometry column with an addgeometry call */
|
|
617
|
+
if (sqlite_format) {
|
|
618
|
+
/* SQLite doesn't have a GEOMETRY type */
|
|
619
|
+
printf("ALTER TABLE %s ADD COLUMN %s blob;", table, geom);
|
|
620
|
+
} else {
|
|
621
|
+
if ( schema && readshape == 1 )
|
|
622
|
+
{
|
|
623
|
+
printf("SELECT AddGeometryColumn('%s','%s','%s','%d',",
|
|
624
|
+
schema, table, geom, sr_id);
|
|
625
|
+
}
|
|
626
|
+
else if (readshape == 1)
|
|
627
|
+
{
|
|
628
|
+
printf("SELECT AddGeometryColumn('','%s','%s','%d',",
|
|
629
|
+
table, geom, sr_id);
|
|
630
|
+
}
|
|
631
|
+
if (pgtype)
|
|
632
|
+
{ //pgtype will only be set if we are loading geometries
|
|
633
|
+
printf("'%s',%d);\n", pgtype, pgdims);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
void
|
|
639
|
+
CreateIndex(void)
|
|
640
|
+
{
|
|
641
|
+
/*
|
|
642
|
+
* Create gist index
|
|
643
|
+
*/
|
|
644
|
+
if ( schema )
|
|
645
|
+
{
|
|
646
|
+
printf("CREATE INDEX \"%s_%s_gist\" ON \"%s\".\"%s\" using gist (\"%s\" gist_geometry_ops);\n", table, geom, schema, table, geom);
|
|
647
|
+
}
|
|
648
|
+
else
|
|
649
|
+
{
|
|
650
|
+
printf("CREATE INDEX \"%s_%s_gist\" ON \"%s\" using gist (\"%s\" gist_geometry_ops);\n", table, geom, table, geom);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
void
|
|
655
|
+
LoadData(void)
|
|
656
|
+
{
|
|
657
|
+
int j, trans=0;
|
|
658
|
+
|
|
659
|
+
if (dump_format){
|
|
660
|
+
if ( schema )
|
|
661
|
+
{
|
|
662
|
+
printf("COPY \"%s\".\"%s\" %s FROM stdin;\n",
|
|
663
|
+
schema, table, col_names);
|
|
664
|
+
}
|
|
665
|
+
else
|
|
666
|
+
{
|
|
667
|
+
printf("COPY \"%s\" %s FROM stdin;\n",
|
|
668
|
+
table, col_names);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
|
|
673
|
+
/**************************************************************
|
|
674
|
+
*
|
|
675
|
+
* MAIN SHAPE OBJECTS SCAN
|
|
676
|
+
*
|
|
677
|
+
**************************************************************/
|
|
678
|
+
for (j=0; j<num_entities; j++)
|
|
679
|
+
{
|
|
680
|
+
/*wrap a transaction block around each 250 inserts... */
|
|
681
|
+
if ( ! dump_format )
|
|
682
|
+
{
|
|
683
|
+
if (trans == 250) {
|
|
684
|
+
trans=0;
|
|
685
|
+
printf("END;\n");
|
|
686
|
+
printf("BEGIN;\n");
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
trans++;
|
|
690
|
+
/* transaction stuff done */
|
|
691
|
+
|
|
692
|
+
/* skip the record if it has been deleted */
|
|
693
|
+
if(readshape != 1 && DBFReadDeleted(hDBFHandle, j)) {
|
|
694
|
+
continue;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/* open the next object */
|
|
698
|
+
if (readshape == 1)
|
|
699
|
+
{
|
|
700
|
+
obj = SHPReadObject(hSHPHandle,j);
|
|
701
|
+
if ( ! obj )
|
|
702
|
+
{
|
|
703
|
+
fprintf(stderr, "Error reading shape object %d\n", j);
|
|
704
|
+
exit(1);
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
if ( null_policy == skip_null && obj->nVertices == 0 )
|
|
708
|
+
{
|
|
709
|
+
SHPDestroyObject(obj);
|
|
710
|
+
continue;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
if (!dump_format)
|
|
715
|
+
{
|
|
716
|
+
if ( schema )
|
|
717
|
+
{
|
|
718
|
+
printf("INSERT INTO \"%s\".\"%s\" %s VALUES (",
|
|
719
|
+
schema, table, col_names);
|
|
720
|
+
}
|
|
721
|
+
else
|
|
722
|
+
{
|
|
723
|
+
printf("INSERT INTO \"%s\" %s VALUES (",
|
|
724
|
+
table, col_names);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
Insert_attributes(hDBFHandle,j);
|
|
728
|
+
|
|
729
|
+
if (readshape == 1)
|
|
730
|
+
{
|
|
731
|
+
/* ---------- NULL SHAPE ----------------- */
|
|
732
|
+
if (obj->nVertices == 0)
|
|
733
|
+
{
|
|
734
|
+
if (dump_format) printf("\\N\n");
|
|
735
|
+
else printf("NULL);\n");
|
|
736
|
+
SHPDestroyObject(obj);
|
|
737
|
+
continue;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
switch (obj->nSHPType)
|
|
741
|
+
{
|
|
742
|
+
case SHPT_POLYGON:
|
|
743
|
+
case SHPT_POLYGONM:
|
|
744
|
+
case SHPT_POLYGONZ:
|
|
745
|
+
InsertPolygon();
|
|
746
|
+
break;
|
|
747
|
+
|
|
748
|
+
case SHPT_POINT:
|
|
749
|
+
case SHPT_POINTM:
|
|
750
|
+
case SHPT_POINTZ:
|
|
751
|
+
case SHPT_MULTIPOINT:
|
|
752
|
+
case SHPT_MULTIPOINTM:
|
|
753
|
+
case SHPT_MULTIPOINTZ:
|
|
754
|
+
InsertPoint();
|
|
755
|
+
break;
|
|
756
|
+
|
|
757
|
+
case SHPT_ARC:
|
|
758
|
+
case SHPT_ARCM:
|
|
759
|
+
case SHPT_ARCZ:
|
|
760
|
+
InsertLineString();
|
|
761
|
+
break;
|
|
762
|
+
|
|
763
|
+
default:
|
|
764
|
+
printf ("\n\n**** Type is NOT SUPPORTED, type id = %d ****\n\n",
|
|
765
|
+
obj->nSHPType);
|
|
766
|
+
break;
|
|
767
|
+
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
SHPDestroyObject(obj);
|
|
771
|
+
}
|
|
772
|
+
else
|
|
773
|
+
if (dump_format){ /*close for dbf only dump format */
|
|
774
|
+
printf("\n");
|
|
775
|
+
}
|
|
776
|
+
else { /*close for dbf only sql insert format */
|
|
777
|
+
printf(");\n");
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
} /* END of MAIN SHAPE OBJECT LOOP */
|
|
781
|
+
|
|
782
|
+
|
|
783
|
+
|
|
784
|
+
if ((dump_format) ) {
|
|
785
|
+
printf("\\.\n");
|
|
786
|
+
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
void
|
|
791
|
+
usage(char *me, int exitcode, FILE* out)
|
|
792
|
+
{
|
|
793
|
+
/*
|
|
794
|
+
fprintf(out, "RCSID: %s RELEASE: %s\n", rcsid, POSTGIS_VERSION);
|
|
795
|
+
*/
|
|
796
|
+
fprintf(out, "USAGE: %s [<options>] <shapefile> [<schema>.]<table>\n", me);
|
|
797
|
+
fprintf(out, "OPTIONS:\n");
|
|
798
|
+
fprintf(out, " -s <srid> Set the SRID field. If not specified it defaults to -1.\n");
|
|
799
|
+
fprintf(out, " (-d|a|c|p) These are mutually exclusive options:\n");
|
|
800
|
+
fprintf(out, " -d Drops the table, then recreates it and populates\n");
|
|
801
|
+
fprintf(out, " it with current shape file data.\n");
|
|
802
|
+
fprintf(out, " -a Appends shape file into current table, must be\n");
|
|
803
|
+
fprintf(out, " exactly the same table schema.\n");
|
|
804
|
+
fprintf(out, " -c Creates a new table and populates it, this is the\n");
|
|
805
|
+
fprintf(out, " default if you do not specify any options.\n");
|
|
806
|
+
fprintf(out, " -p Prepare mode, only creates the table.\n");
|
|
807
|
+
fprintf(out, " -g <geometry_column> Specify the name of the geometry column\n");
|
|
808
|
+
fprintf(out, " (mostly useful in append mode).\n");
|
|
809
|
+
fprintf(out, " -i Use int4 type for all integer dbf fields.\n");
|
|
810
|
+
fprintf(out, " -S Generate simple geometries instead of MULTI geometries.\n");
|
|
811
|
+
fprintf(out, " -w Use wkt format (drops M - drifts coordinates).\n");
|
|
812
|
+
#ifdef HAVE_ICONV
|
|
813
|
+
fprintf(out, " -W <encoding> Specify the character encoding of Shape's\n");
|
|
814
|
+
fprintf(out, " attribute column. (default : \"ASCII\")\n");
|
|
815
|
+
#endif
|
|
816
|
+
fprintf(out, " -N <policy> Specify NULL geometries handling policy (insert,skip,abort)\n");
|
|
817
|
+
fprintf(out, " -n Only import DBF file.\n");
|
|
818
|
+
fprintf(out, " -? Display this help screen\n");
|
|
819
|
+
exit (exitcode);
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
void
|
|
823
|
+
InsertLineString()
|
|
824
|
+
{
|
|
825
|
+
LWCOLLECTION *lwcollection;
|
|
826
|
+
|
|
827
|
+
LWGEOM **lwmultilinestrings;
|
|
828
|
+
uchar *serialized_lwgeom;
|
|
829
|
+
LWGEOM_UNPARSER_RESULT lwg_unparser_result;
|
|
830
|
+
|
|
831
|
+
DYNPTARRAY **dpas;
|
|
832
|
+
POINT4D point4d;
|
|
833
|
+
|
|
834
|
+
int dims = 0, hasz = 0, hasm = 0;
|
|
835
|
+
int result;
|
|
836
|
+
int u, v, start_vertex, end_vertex;
|
|
837
|
+
|
|
838
|
+
/* Determine the correct dimensions: note that in hwgeom-compatible mode we cannot use
|
|
839
|
+
the M coordinate */
|
|
840
|
+
if (wkbtype & WKBZOFFSET) hasz = 1;
|
|
841
|
+
if (!hwgeom)
|
|
842
|
+
if (wkbtype & WKBMOFFSET) hasm = 1;
|
|
843
|
+
TYPE_SETZM(dims, hasz, hasm);
|
|
844
|
+
|
|
845
|
+
if (simple_geometries == 1 && obj->nParts > 1)
|
|
846
|
+
{
|
|
847
|
+
fprintf(stderr, "We have a Multilinestring with %d parts, can't use -S switch!\n", obj->nParts);
|
|
848
|
+
exit(1);
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
/* Allocate memory for our array of LWLINEs and our dynptarrays */
|
|
852
|
+
lwmultilinestrings = malloc(sizeof(LWPOINT *) * obj->nParts);
|
|
853
|
+
dpas = malloc(sizeof(DYNPTARRAY *) * obj->nParts);
|
|
854
|
+
|
|
855
|
+
/* We need an array of pointers to each of our sub-geometries */
|
|
856
|
+
for (u = 0; u < obj->nParts; u++)
|
|
857
|
+
{
|
|
858
|
+
/* Create a dynptarray containing the line points */
|
|
859
|
+
dpas[u] = dynptarray_create(obj->nParts, dims);
|
|
860
|
+
|
|
861
|
+
/* Set the start/end vertices depending upon whether this is
|
|
862
|
+
a MULTILINESTRING or not */
|
|
863
|
+
if ( u == obj->nParts-1 )
|
|
864
|
+
end_vertex = obj->nVertices;
|
|
865
|
+
else
|
|
866
|
+
end_vertex = obj->panPartStart[u + 1];
|
|
867
|
+
|
|
868
|
+
start_vertex = obj->panPartStart[u];
|
|
869
|
+
|
|
870
|
+
for (v = start_vertex; v < end_vertex; v++)
|
|
871
|
+
{
|
|
872
|
+
/* Generate the point */
|
|
873
|
+
point4d.x = obj->padfX[v];
|
|
874
|
+
point4d.y = obj->padfY[v];
|
|
875
|
+
|
|
876
|
+
if (wkbtype & WKBZOFFSET)
|
|
877
|
+
point4d.z = obj->padfZ[v];
|
|
878
|
+
if (wkbtype & WKBMOFFSET)
|
|
879
|
+
point4d.m = obj->padfM[v];
|
|
880
|
+
|
|
881
|
+
dynptarray_addPoint4d(dpas[u], &point4d, 0);
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
/* Generate the LWLINE */
|
|
885
|
+
lwmultilinestrings[u] = lwline_as_lwgeom(lwline_construct(sr_id, NULL, dpas[u]->pa));
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
/* If using MULTILINESTRINGs then generate the serialized collection, otherwise just a single LINESTRING */
|
|
889
|
+
if (simple_geometries == 0)
|
|
890
|
+
{
|
|
891
|
+
lwcollection = lwcollection_construct(MULTILINETYPE, sr_id, NULL, obj->nParts, lwmultilinestrings);
|
|
892
|
+
serialized_lwgeom = lwgeom_serialize(lwcollection_as_lwgeom(lwcollection));
|
|
893
|
+
}
|
|
894
|
+
else
|
|
895
|
+
{
|
|
896
|
+
serialized_lwgeom = lwgeom_serialize(lwmultilinestrings[0]);
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
if (!hwgeom)
|
|
900
|
+
result = serialized_lwgeom_to_hexwkb(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_ALL, -1);
|
|
901
|
+
else
|
|
902
|
+
result = serialized_lwgeom_to_ewkt(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_ALL);
|
|
903
|
+
|
|
904
|
+
if (result)
|
|
905
|
+
{
|
|
906
|
+
fprintf(stderr, "ERROR: %s\n", lwg_unparser_result.message);
|
|
907
|
+
exit(1);
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
OutputGeometry(lwg_unparser_result.wkoutput);
|
|
911
|
+
|
|
912
|
+
/* Free all of the allocated items */
|
|
913
|
+
lwfree(lwg_unparser_result.wkoutput);
|
|
914
|
+
lwfree(serialized_lwgeom);
|
|
915
|
+
|
|
916
|
+
for (u = 0; u < obj->nParts; u++)
|
|
917
|
+
{
|
|
918
|
+
lwline_free(lwgeom_as_lwline(lwmultilinestrings[u]));
|
|
919
|
+
lwfree(dpas[u]);
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
lwfree(dpas);
|
|
923
|
+
lwfree(lwmultilinestrings);
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
int
|
|
927
|
+
FindPolygons(SHPObject *obj, Ring ***Out)
|
|
928
|
+
{
|
|
929
|
+
Ring **Outer; /* Pointers to Outer rings */
|
|
930
|
+
int out_index=0; /* Count of Outer rings */
|
|
931
|
+
Ring **Inner; /* Pointers to Inner rings */
|
|
932
|
+
int in_index=0; /* Count of Inner rings */
|
|
933
|
+
int pi; /* part index */
|
|
934
|
+
|
|
935
|
+
#if POSTGIS_DEBUG_LEVEL > 0
|
|
936
|
+
static int call = -1;
|
|
937
|
+
call++;
|
|
938
|
+
#endif
|
|
939
|
+
|
|
940
|
+
LWDEBUGF(4, "FindPolygons[%d]: allocated space for %d rings\n", call, obj->nParts);
|
|
941
|
+
|
|
942
|
+
/* Allocate initial memory */
|
|
943
|
+
Outer = (Ring**)malloc(sizeof(Ring*)*obj->nParts);
|
|
944
|
+
Inner = (Ring**)malloc(sizeof(Ring*)*obj->nParts);
|
|
945
|
+
|
|
946
|
+
/* Iterate over rings dividing in Outers and Inners */
|
|
947
|
+
for (pi=0; pi<obj->nParts; pi++)
|
|
948
|
+
{
|
|
949
|
+
int vi; /* vertex index */
|
|
950
|
+
int vs; /* start index */
|
|
951
|
+
int ve; /* end index */
|
|
952
|
+
int nv; /* number of vertex */
|
|
953
|
+
double area = 0.0;
|
|
954
|
+
Ring *ring;
|
|
955
|
+
|
|
956
|
+
/* Set start and end vertexes */
|
|
957
|
+
if ( pi==obj->nParts-1 ) ve = obj->nVertices;
|
|
958
|
+
else ve = obj->panPartStart[pi+1];
|
|
959
|
+
vs = obj->panPartStart[pi];
|
|
960
|
+
|
|
961
|
+
/* Compute number of vertexes */
|
|
962
|
+
nv = ve-vs;
|
|
963
|
+
|
|
964
|
+
/* Allocate memory for a ring */
|
|
965
|
+
ring = (Ring*)malloc(sizeof(Ring));
|
|
966
|
+
ring->list = (Point*)malloc(sizeof(Point)*nv);
|
|
967
|
+
ring->n = nv;
|
|
968
|
+
ring->next = NULL;
|
|
969
|
+
ring->linked = 0;
|
|
970
|
+
|
|
971
|
+
/* Iterate over ring vertexes */
|
|
972
|
+
for ( vi=vs; vi<ve; vi++)
|
|
973
|
+
{
|
|
974
|
+
int vn = vi+1; /* next vertex for area */
|
|
975
|
+
if ( vn==ve ) vn = vs;
|
|
976
|
+
|
|
977
|
+
ring->list[vi-vs].x = obj->padfX[vi];
|
|
978
|
+
ring->list[vi-vs].y = obj->padfY[vi];
|
|
979
|
+
ring->list[vi-vs].z = obj->padfZ[vi];
|
|
980
|
+
ring->list[vi-vs].m = obj->padfM[vi];
|
|
981
|
+
|
|
982
|
+
area += (obj->padfX[vi] * obj->padfY[vn]) -
|
|
983
|
+
(obj->padfY[vi] * obj->padfX[vn]);
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
/* Close the ring with first vertex */
|
|
987
|
+
/*ring->list[vi].x = obj->padfX[vs]; */
|
|
988
|
+
/*ring->list[vi].y = obj->padfY[vs]; */
|
|
989
|
+
/*ring->list[vi].z = obj->padfZ[vs]; */
|
|
990
|
+
/*ring->list[vi].m = obj->padfM[vs]; */
|
|
991
|
+
|
|
992
|
+
/* Clockwise (or single-part). It's an Outer Ring ! */
|
|
993
|
+
if(area < 0.0 || obj->nParts ==1) {
|
|
994
|
+
Outer[out_index] = ring;
|
|
995
|
+
out_index++;
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
/* Counterclockwise. It's an Inner Ring ! */
|
|
999
|
+
else {
|
|
1000
|
+
Inner[in_index] = ring;
|
|
1001
|
+
in_index++;
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
LWDEBUGF(4, "FindPolygons[%d]: found %d Outer, %d Inners\n", call, out_index, in_index);
|
|
1006
|
+
|
|
1007
|
+
/* Put the inner rings into the list of the outer rings */
|
|
1008
|
+
/* of which they are within */
|
|
1009
|
+
for(pi=0; pi<in_index; pi++)
|
|
1010
|
+
{
|
|
1011
|
+
Point pt,pt2;
|
|
1012
|
+
int i;
|
|
1013
|
+
Ring *inner=Inner[pi], *outer=NULL;
|
|
1014
|
+
|
|
1015
|
+
pt.x = inner->list[0].x;
|
|
1016
|
+
pt.y = inner->list[0].y;
|
|
1017
|
+
|
|
1018
|
+
pt2.x = inner->list[1].x;
|
|
1019
|
+
pt2.y = inner->list[1].y;
|
|
1020
|
+
|
|
1021
|
+
for(i=0; i<out_index; i++)
|
|
1022
|
+
{
|
|
1023
|
+
int in;
|
|
1024
|
+
|
|
1025
|
+
in = PIP(pt, Outer[i]->list, Outer[i]->n);
|
|
1026
|
+
if( in || PIP(pt2, Outer[i]->list, Outer[i]->n) )
|
|
1027
|
+
{
|
|
1028
|
+
outer = Outer[i];
|
|
1029
|
+
break;
|
|
1030
|
+
}
|
|
1031
|
+
/*fprintf(stderr, "!PIP %s\nOUTE %s\n", dump_ring(inner), dump_ring(Outer[i])); */
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
if ( outer )
|
|
1035
|
+
{
|
|
1036
|
+
outer->linked++;
|
|
1037
|
+
while(outer->next) outer = outer->next;
|
|
1038
|
+
outer->next = inner;
|
|
1039
|
+
}
|
|
1040
|
+
else
|
|
1041
|
+
{
|
|
1042
|
+
/* The ring wasn't within any outer rings, */
|
|
1043
|
+
/* assume it is a new outer ring. */
|
|
1044
|
+
LWDEBUGF(4, "FindPolygons[%d]: hole %d is orphan\n", call, pi);
|
|
1045
|
+
|
|
1046
|
+
Outer[out_index] = inner;
|
|
1047
|
+
out_index++;
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
*Out = Outer;
|
|
1052
|
+
free(Inner);
|
|
1053
|
+
|
|
1054
|
+
return out_index;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
void
|
|
1058
|
+
ReleasePolygons(Ring **polys, int npolys)
|
|
1059
|
+
{
|
|
1060
|
+
int pi;
|
|
1061
|
+
/* Release all memory */
|
|
1062
|
+
for(pi=0; pi<npolys; pi++)
|
|
1063
|
+
{
|
|
1064
|
+
Ring *Poly, *temp;
|
|
1065
|
+
Poly = polys[pi];
|
|
1066
|
+
while(Poly != NULL){
|
|
1067
|
+
temp = Poly;
|
|
1068
|
+
Poly = Poly->next;
|
|
1069
|
+
free(temp->list);
|
|
1070
|
+
free(temp);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
free(polys);
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
/*This function basically deals with the polygon case. */
|
|
1077
|
+
/*it sorts the polys in order of outer,inner,inner, so that inners */
|
|
1078
|
+
/*always come after outers they are within */
|
|
1079
|
+
void
|
|
1080
|
+
InsertPolygon(void)
|
|
1081
|
+
{
|
|
1082
|
+
Ring **Outer;
|
|
1083
|
+
int polygon_total, ring_total;
|
|
1084
|
+
int pi, vi; // part index and vertex index
|
|
1085
|
+
int u;
|
|
1086
|
+
|
|
1087
|
+
LWCOLLECTION *lwcollection = NULL;
|
|
1088
|
+
|
|
1089
|
+
LWGEOM **lwpolygons;
|
|
1090
|
+
uchar *serialized_lwgeom;
|
|
1091
|
+
LWGEOM_UNPARSER_RESULT lwg_unparser_result;
|
|
1092
|
+
|
|
1093
|
+
LWPOLY *lwpoly;
|
|
1094
|
+
DYNPTARRAY *dpas;
|
|
1095
|
+
POINTARRAY ***pas;
|
|
1096
|
+
POINT4D point4d;
|
|
1097
|
+
|
|
1098
|
+
int dims = 0, hasz = 0, hasm = 0;
|
|
1099
|
+
int result;
|
|
1100
|
+
|
|
1101
|
+
/* Determine the correct dimensions: note that in hwgeom-compatible mode we cannot use
|
|
1102
|
+
the M coordinate */
|
|
1103
|
+
if (wkbtype & WKBZOFFSET) hasz = 1;
|
|
1104
|
+
if (!hwgeom)
|
|
1105
|
+
if (wkbtype & WKBMOFFSET) hasm = 1;
|
|
1106
|
+
TYPE_SETZM(dims, hasz, hasm);
|
|
1107
|
+
|
|
1108
|
+
polygon_total = FindPolygons(obj, &Outer);
|
|
1109
|
+
|
|
1110
|
+
if (simple_geometries == 1 && polygon_total != 1) /* We write Non-MULTI geometries, but have several parts: */
|
|
1111
|
+
{
|
|
1112
|
+
fprintf(stderr, "We have a Multipolygon with %d parts, can't use -S switch!\n", polygon_total);
|
|
1113
|
+
exit(1);
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
/* Allocate memory for our array of LWPOLYs */
|
|
1117
|
+
lwpolygons = malloc(sizeof(LWPOLY *) * polygon_total);
|
|
1118
|
+
|
|
1119
|
+
/* Allocate memory for our POINTARRAY pointers for each polygon */
|
|
1120
|
+
pas = malloc(sizeof(POINTARRAY **) * polygon_total);
|
|
1121
|
+
|
|
1122
|
+
/* Cycle through each individual polygon */
|
|
1123
|
+
for(pi = 0; pi < polygon_total; pi++)
|
|
1124
|
+
{
|
|
1125
|
+
Ring *polyring;
|
|
1126
|
+
int ring_index = 0;
|
|
1127
|
+
|
|
1128
|
+
/* Firstly count through the total number of rings in this polygon */
|
|
1129
|
+
ring_total = 0;
|
|
1130
|
+
polyring = Outer[pi];
|
|
1131
|
+
while (polyring)
|
|
1132
|
+
{
|
|
1133
|
+
ring_total++;
|
|
1134
|
+
polyring = polyring->next;
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
/* Reserve memory for the POINTARRAYs representing each ring */
|
|
1138
|
+
pas[pi] = malloc(sizeof(POINTARRAY *) * ring_total);
|
|
1139
|
+
|
|
1140
|
+
/* Cycle through each ring within the polygon, starting with the outer */
|
|
1141
|
+
polyring = Outer[pi];
|
|
1142
|
+
|
|
1143
|
+
while (polyring)
|
|
1144
|
+
{
|
|
1145
|
+
/* Create a DYNPTARRAY containing the points making up the ring */
|
|
1146
|
+
dpas = dynptarray_create(polyring->n, dims);
|
|
1147
|
+
|
|
1148
|
+
for(vi = 0; vi < polyring->n; vi++)
|
|
1149
|
+
{
|
|
1150
|
+
/* Build up a point array of all the points in this ring */
|
|
1151
|
+
point4d.x = polyring->list[vi].x;
|
|
1152
|
+
point4d.y = polyring->list[vi].y;
|
|
1153
|
+
|
|
1154
|
+
if (wkbtype & WKBZOFFSET)
|
|
1155
|
+
point4d.z = polyring->list[vi].z;
|
|
1156
|
+
if (wkbtype & WKBMOFFSET)
|
|
1157
|
+
point4d.m = polyring->list[vi].m;
|
|
1158
|
+
|
|
1159
|
+
dynptarray_addPoint4d(dpas, &point4d, 0);
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
/* Copy the POINTARRAY pointer from the DYNPTARRAY structure so we can
|
|
1163
|
+
use the LWPOLY constructor */
|
|
1164
|
+
pas[pi][ring_index] = dpas->pa;
|
|
1165
|
+
|
|
1166
|
+
/* Free the DYNPTARRAY structure (we don't need this part anymore as we
|
|
1167
|
+
have the reference to the internal POINTARRAY) */
|
|
1168
|
+
lwfree(dpas);
|
|
1169
|
+
|
|
1170
|
+
polyring = polyring->next;
|
|
1171
|
+
ring_index++;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
/* Generate the LWGEOM */
|
|
1175
|
+
lwpoly = lwpoly_construct(sr_id, NULL, ring_total, pas[pi]);
|
|
1176
|
+
lwpolygons[pi] = lwpoly_as_lwgeom(lwpoly);
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
ReleasePolygons(Outer, polygon_total);
|
|
1180
|
+
|
|
1181
|
+
/* If using MULTIPOLYGONS then generate the serialized collection, otherwise just a single POLYGON */
|
|
1182
|
+
if (simple_geometries == 0)
|
|
1183
|
+
{
|
|
1184
|
+
lwcollection = lwcollection_construct(MULTIPOLYGONTYPE, sr_id, NULL, polygon_total, lwpolygons);
|
|
1185
|
+
serialized_lwgeom = lwgeom_serialize(lwcollection_as_lwgeom(lwcollection));
|
|
1186
|
+
}
|
|
1187
|
+
else
|
|
1188
|
+
{
|
|
1189
|
+
serialized_lwgeom = lwgeom_serialize(lwpolygons[0]);
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
if (!hwgeom)
|
|
1193
|
+
result = serialized_lwgeom_to_hexwkb(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_ALL, -1);
|
|
1194
|
+
else
|
|
1195
|
+
result = serialized_lwgeom_to_ewkt(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_ALL);
|
|
1196
|
+
|
|
1197
|
+
if (result)
|
|
1198
|
+
{
|
|
1199
|
+
fprintf(stderr, "ERROR: %s\n", lwg_unparser_result.message);
|
|
1200
|
+
exit(1);
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
OutputGeometry(lwg_unparser_result.wkoutput);
|
|
1204
|
+
|
|
1205
|
+
/* Free all of the allocated items */
|
|
1206
|
+
lwfree(lwg_unparser_result.wkoutput);
|
|
1207
|
+
lwfree(serialized_lwgeom);
|
|
1208
|
+
|
|
1209
|
+
/* Cycle through each polygon, freeing everything we need... */
|
|
1210
|
+
for (u = 0; u < polygon_total; u++)
|
|
1211
|
+
lwpoly_free(lwgeom_as_lwpoly(lwpolygons[u]));
|
|
1212
|
+
|
|
1213
|
+
/* Free the pointer arrays */
|
|
1214
|
+
lwfree(pas);
|
|
1215
|
+
lwfree(lwpolygons);
|
|
1216
|
+
if (simple_geometries == 0)
|
|
1217
|
+
lwfree(lwcollection);
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
/*
|
|
1221
|
+
* Insert either a POINT or MULTIPOINT into the output stream
|
|
1222
|
+
*/
|
|
1223
|
+
void
|
|
1224
|
+
InsertPoint(void)
|
|
1225
|
+
{
|
|
1226
|
+
LWCOLLECTION *lwcollection;
|
|
1227
|
+
|
|
1228
|
+
LWGEOM **lwmultipoints;
|
|
1229
|
+
uchar *serialized_lwgeom;
|
|
1230
|
+
LWGEOM_UNPARSER_RESULT lwg_unparser_result;
|
|
1231
|
+
|
|
1232
|
+
DYNPTARRAY **dpas;
|
|
1233
|
+
POINT4D point4d;
|
|
1234
|
+
|
|
1235
|
+
int dims = 0, hasz = 0, hasm = 0;
|
|
1236
|
+
int result;
|
|
1237
|
+
int u;
|
|
1238
|
+
|
|
1239
|
+
/* Determine the correct dimensions: note that in hwgeom-compatible mode we cannot use
|
|
1240
|
+
the M coordinate */
|
|
1241
|
+
if (wkbtype & WKBZOFFSET) hasz = 1;
|
|
1242
|
+
if (!hwgeom)
|
|
1243
|
+
if (wkbtype & WKBMOFFSET) hasm = 1;
|
|
1244
|
+
TYPE_SETZM(dims, hasz, hasm);
|
|
1245
|
+
|
|
1246
|
+
/* Allocate memory for our array of LWPOINTs and our dynptarrays */
|
|
1247
|
+
lwmultipoints = malloc(sizeof(LWPOINT *) * obj->nVertices);
|
|
1248
|
+
dpas = malloc(sizeof(DYNPTARRAY *) * obj->nVertices);
|
|
1249
|
+
|
|
1250
|
+
/* We need an array of pointers to each of our sub-geometries */
|
|
1251
|
+
for (u = 0; u < obj->nVertices; u++)
|
|
1252
|
+
{
|
|
1253
|
+
/* Generate the point */
|
|
1254
|
+
point4d.x = obj->padfX[u];
|
|
1255
|
+
point4d.y = obj->padfY[u];
|
|
1256
|
+
|
|
1257
|
+
if (wkbtype & WKBZOFFSET)
|
|
1258
|
+
point4d.z = obj->padfZ[u];
|
|
1259
|
+
if (wkbtype & WKBMOFFSET)
|
|
1260
|
+
point4d.m = obj->padfM[u];
|
|
1261
|
+
|
|
1262
|
+
/* Create a dynptarray containing a single point */
|
|
1263
|
+
dpas[u] = dynptarray_create(1, dims);
|
|
1264
|
+
dynptarray_addPoint4d(dpas[u], &point4d, 0);
|
|
1265
|
+
|
|
1266
|
+
/* Generate the LWPOINT */
|
|
1267
|
+
lwmultipoints[u] = lwpoint_as_lwgeom(lwpoint_construct(sr_id, NULL, dpas[u]->pa));
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
/* If we have more than 1 vertex then we are working on a MULTIPOINT and so generate a MULTIPOINT
|
|
1271
|
+
rather than a POINT */
|
|
1272
|
+
if (obj->nVertices > 1)
|
|
1273
|
+
{
|
|
1274
|
+
lwcollection = lwcollection_construct(MULTIPOINTTYPE, sr_id, NULL, obj->nVertices, lwmultipoints);
|
|
1275
|
+
serialized_lwgeom = lwgeom_serialize(lwcollection_as_lwgeom(lwcollection));
|
|
1276
|
+
}
|
|
1277
|
+
else
|
|
1278
|
+
{
|
|
1279
|
+
serialized_lwgeom = lwgeom_serialize(lwmultipoints[0]);
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
if (!hwgeom)
|
|
1283
|
+
result = serialized_lwgeom_to_hexwkb(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_ALL, -1);
|
|
1284
|
+
else
|
|
1285
|
+
result = serialized_lwgeom_to_ewkt(&lwg_unparser_result, serialized_lwgeom, PARSER_CHECK_ALL);
|
|
1286
|
+
|
|
1287
|
+
if (result)
|
|
1288
|
+
{
|
|
1289
|
+
fprintf(stderr, "ERROR: %s\n", lwg_unparser_result.message);
|
|
1290
|
+
exit(1);
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
OutputGeometry(lwg_unparser_result.wkoutput);
|
|
1294
|
+
|
|
1295
|
+
/* Free all of the allocated items */
|
|
1296
|
+
lwfree(lwg_unparser_result.wkoutput);
|
|
1297
|
+
lwfree(serialized_lwgeom);
|
|
1298
|
+
|
|
1299
|
+
for (u = 0; u < obj->nVertices; u++)
|
|
1300
|
+
{
|
|
1301
|
+
lwpoint_free(lwgeom_as_lwpoint(lwmultipoints[u]));
|
|
1302
|
+
lwfree(dpas[u]);
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
lwfree(dpas);
|
|
1306
|
+
lwfree(lwmultipoints);
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
void
|
|
1310
|
+
OutputGeometry(char *geometry)
|
|
1311
|
+
{
|
|
1312
|
+
/* This function outputs the specified geometry string (WKB or WKT) formatted
|
|
1313
|
+
* according to whether we have specified dump format or hwgeom format */
|
|
1314
|
+
|
|
1315
|
+
if (hwgeom)
|
|
1316
|
+
{
|
|
1317
|
+
if (!dump_format)
|
|
1318
|
+
printf("GeomFromText('");
|
|
1319
|
+
else
|
|
1320
|
+
{
|
|
1321
|
+
/* Output SRID if relevant */
|
|
1322
|
+
if (sr_id != 0)
|
|
1323
|
+
printf("SRID=%d;", sr_id);
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
printf("%s", geometry);
|
|
1327
|
+
|
|
1328
|
+
if (!dump_format)
|
|
1329
|
+
{
|
|
1330
|
+
printf("'");
|
|
1331
|
+
|
|
1332
|
+
/* Output SRID if relevant */
|
|
1333
|
+
if (sr_id != 0)
|
|
1334
|
+
printf(", %d)", sr_id);
|
|
1335
|
+
|
|
1336
|
+
printf(");\n");
|
|
1337
|
+
}
|
|
1338
|
+
else
|
|
1339
|
+
printf("\n");
|
|
1340
|
+
}
|
|
1341
|
+
else
|
|
1342
|
+
{
|
|
1343
|
+
if (!dump_format) {
|
|
1344
|
+
if (sqlite_format)
|
|
1345
|
+
/* SQLite BLOBs are formatted as a string of hex
|
|
1346
|
+
* digits with an X before the leading quote. */
|
|
1347
|
+
printf("X'");
|
|
1348
|
+
else
|
|
1349
|
+
printf("'");
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
printf("%s", geometry);
|
|
1353
|
+
|
|
1354
|
+
if (!dump_format)
|
|
1355
|
+
printf("');\n");
|
|
1356
|
+
else
|
|
1357
|
+
printf("\n");
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
|
|
1362
|
+
int
|
|
1363
|
+
ParseCmdline(int ARGC, char **ARGV)
|
|
1364
|
+
{
|
|
1365
|
+
int c;
|
|
1366
|
+
int curindex=0;
|
|
1367
|
+
char *ptr;
|
|
1368
|
+
extern char *optarg;
|
|
1369
|
+
extern int optind;
|
|
1370
|
+
|
|
1371
|
+
if ( ARGC == 1 ) {
|
|
1372
|
+
usage(ARGV[0], 0, stdout);
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
while ((c = pgis_getopt(ARGC, ARGV, "kcdapDLs:Sg:iW:wIN:n")) != EOF){
|
|
1376
|
+
switch (c) {
|
|
1377
|
+
case 'c':
|
|
1378
|
+
if (opt == ' ')
|
|
1379
|
+
opt ='c';
|
|
1380
|
+
else
|
|
1381
|
+
return 0;
|
|
1382
|
+
break;
|
|
1383
|
+
case 'd':
|
|
1384
|
+
if (opt == ' ')
|
|
1385
|
+
opt ='d';
|
|
1386
|
+
else
|
|
1387
|
+
return 0;
|
|
1388
|
+
break;
|
|
1389
|
+
case 'a':
|
|
1390
|
+
if (opt == ' ')
|
|
1391
|
+
opt ='a';
|
|
1392
|
+
else
|
|
1393
|
+
return 0;
|
|
1394
|
+
break;
|
|
1395
|
+
case 'p':
|
|
1396
|
+
if (opt == ' ')
|
|
1397
|
+
opt ='p';
|
|
1398
|
+
else
|
|
1399
|
+
return 0;
|
|
1400
|
+
break;
|
|
1401
|
+
case 'D':
|
|
1402
|
+
dump_format =1;
|
|
1403
|
+
break;
|
|
1404
|
+
case 'L':
|
|
1405
|
+
sqlite_format=1;
|
|
1406
|
+
break;
|
|
1407
|
+
case 'S':
|
|
1408
|
+
simple_geometries =1;
|
|
1409
|
+
break;
|
|
1410
|
+
case 's':
|
|
1411
|
+
(void)sscanf(optarg, "%d", &sr_id);
|
|
1412
|
+
break;
|
|
1413
|
+
case 'g':
|
|
1414
|
+
geom = optarg;
|
|
1415
|
+
break;
|
|
1416
|
+
case 'k':
|
|
1417
|
+
quoteidentifiers = 1;
|
|
1418
|
+
break;
|
|
1419
|
+
case 'i':
|
|
1420
|
+
forceint4 = 1;
|
|
1421
|
+
break;
|
|
1422
|
+
case 'I':
|
|
1423
|
+
createindex = 1;
|
|
1424
|
+
break;
|
|
1425
|
+
case 'w':
|
|
1426
|
+
hwgeom = 1;
|
|
1427
|
+
break;
|
|
1428
|
+
case 'n':
|
|
1429
|
+
readshape = 0;
|
|
1430
|
+
break;
|
|
1431
|
+
case 'W':
|
|
1432
|
+
#ifdef HAVE_ICONV
|
|
1433
|
+
encoding = optarg;
|
|
1434
|
+
#else
|
|
1435
|
+
fprintf(stderr, "WARNING: the -W switch will have no effect. UTF8 disabled at compile time\n");
|
|
1436
|
+
#endif
|
|
1437
|
+
break;
|
|
1438
|
+
case 'N':
|
|
1439
|
+
switch (optarg[0])
|
|
1440
|
+
{
|
|
1441
|
+
case 'a':
|
|
1442
|
+
null_policy = abort_on_null;
|
|
1443
|
+
break;
|
|
1444
|
+
case 'i':
|
|
1445
|
+
null_policy = insert_null;
|
|
1446
|
+
break;
|
|
1447
|
+
case 's':
|
|
1448
|
+
null_policy = skip_null;
|
|
1449
|
+
break;
|
|
1450
|
+
default:
|
|
1451
|
+
fprintf(stderr, "Unsupported NULL geometry handling policy.\nValid policies: insert, skip, abort\n");
|
|
1452
|
+
exit(1);
|
|
1453
|
+
}
|
|
1454
|
+
break;
|
|
1455
|
+
case '?':
|
|
1456
|
+
usage(ARGV[0], 0, stdout);
|
|
1457
|
+
default:
|
|
1458
|
+
return 0;
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
if ( !sr_id ) sr_id = -1;
|
|
1463
|
+
|
|
1464
|
+
if ( !geom ) geom = "the_geom";
|
|
1465
|
+
|
|
1466
|
+
if ( opt==' ' ) opt = 'c';
|
|
1467
|
+
|
|
1468
|
+
for (; optind < ARGC; optind++){
|
|
1469
|
+
if(curindex ==0){
|
|
1470
|
+
shp_file = ARGV[optind];
|
|
1471
|
+
}else if(curindex == 1){
|
|
1472
|
+
table = ARGV[optind];
|
|
1473
|
+
if ( (ptr=strchr(table, '.')) )
|
|
1474
|
+
{
|
|
1475
|
+
*ptr = '\0';
|
|
1476
|
+
schema = table;
|
|
1477
|
+
table = ptr+1;
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
curindex++;
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
/*
|
|
1484
|
+
* Third argument (if present) is supported for compatibility
|
|
1485
|
+
* with old shp2pgsql versions taking also database name.
|
|
1486
|
+
*/
|
|
1487
|
+
if(curindex < 2 || curindex > 3){
|
|
1488
|
+
return 0;
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
/*
|
|
1492
|
+
* Transform table name to lower case unless asked
|
|
1493
|
+
* to keep original case (we'll quote it later on)
|
|
1494
|
+
*/
|
|
1495
|
+
if ( ! quoteidentifiers )
|
|
1496
|
+
{
|
|
1497
|
+
LowerCase(table);
|
|
1498
|
+
if ( schema ) LowerCase(schema);
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
return 1;
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
|
|
1505
|
+
void
|
|
1506
|
+
SetPgType(void)
|
|
1507
|
+
{
|
|
1508
|
+
switch(shpfiletype)
|
|
1509
|
+
{
|
|
1510
|
+
case SHPT_POINT: /* Point */
|
|
1511
|
+
pgtype = "POINT";
|
|
1512
|
+
wkbtype = POINTTYPE;
|
|
1513
|
+
pgdims = 2;
|
|
1514
|
+
break;
|
|
1515
|
+
case SHPT_ARC: /* PolyLine */
|
|
1516
|
+
pgtype = "MULTILINESTRING";
|
|
1517
|
+
wkbtype = MULTILINETYPE ;
|
|
1518
|
+
pgdims = 2;
|
|
1519
|
+
break;
|
|
1520
|
+
case SHPT_POLYGON: /* Polygon */
|
|
1521
|
+
pgtype = "MULTIPOLYGON";
|
|
1522
|
+
wkbtype = MULTIPOLYGONTYPE;
|
|
1523
|
+
pgdims = 2;
|
|
1524
|
+
break;
|
|
1525
|
+
case SHPT_MULTIPOINT: /* MultiPoint */
|
|
1526
|
+
pgtype = "MULTIPOINT";
|
|
1527
|
+
wkbtype = MULTIPOINTTYPE;
|
|
1528
|
+
pgdims = 2;
|
|
1529
|
+
break;
|
|
1530
|
+
case SHPT_POINTM: /* PointM */
|
|
1531
|
+
wkbtype = POINTTYPE | WKBMOFFSET;
|
|
1532
|
+
if ( ! hwgeom ) {
|
|
1533
|
+
pgtype = "POINTM";
|
|
1534
|
+
pgdims = 3;
|
|
1535
|
+
istypeM = 1;
|
|
1536
|
+
} else {
|
|
1537
|
+
pgtype = "POINT";
|
|
1538
|
+
pgdims = 2;
|
|
1539
|
+
}
|
|
1540
|
+
break;
|
|
1541
|
+
case SHPT_ARCM: /* PolyLineM */
|
|
1542
|
+
wkbtype = MULTILINETYPE | WKBMOFFSET;
|
|
1543
|
+
if ( ! hwgeom ) {
|
|
1544
|
+
pgtype = "MULTILINESTRINGM";
|
|
1545
|
+
pgdims = 3;
|
|
1546
|
+
istypeM = 1;
|
|
1547
|
+
} else {
|
|
1548
|
+
pgtype = "MULTILINESTRING";
|
|
1549
|
+
pgdims = 2;
|
|
1550
|
+
}
|
|
1551
|
+
break;
|
|
1552
|
+
case SHPT_POLYGONM: /* PolygonM */
|
|
1553
|
+
wkbtype = MULTIPOLYGONTYPE | WKBMOFFSET;
|
|
1554
|
+
if ( ! hwgeom ) {
|
|
1555
|
+
pgtype = "MULTIPOLYGONM";
|
|
1556
|
+
pgdims = 3;
|
|
1557
|
+
istypeM = 1;
|
|
1558
|
+
} else {
|
|
1559
|
+
pgtype = "MULTIPOLYGON";
|
|
1560
|
+
pgdims = 2;
|
|
1561
|
+
}
|
|
1562
|
+
break;
|
|
1563
|
+
case SHPT_MULTIPOINTM: /* MultiPointM */
|
|
1564
|
+
wkbtype = MULTIPOINTTYPE | WKBMOFFSET;
|
|
1565
|
+
if ( ! hwgeom ) {
|
|
1566
|
+
pgtype = "MULTIPOINTM";
|
|
1567
|
+
pgdims = 3;
|
|
1568
|
+
istypeM = 1;
|
|
1569
|
+
} else {
|
|
1570
|
+
pgtype = "MULTIPOINT";
|
|
1571
|
+
pgdims = 2;
|
|
1572
|
+
}
|
|
1573
|
+
break;
|
|
1574
|
+
case SHPT_POINTZ: /* PointZ */
|
|
1575
|
+
wkbtype = POINTTYPE | WKBMOFFSET | WKBZOFFSET;
|
|
1576
|
+
pgtype = "POINT";
|
|
1577
|
+
if ( ! hwgeom ) pgdims = 4;
|
|
1578
|
+
else pgdims = 3;
|
|
1579
|
+
break;
|
|
1580
|
+
case SHPT_ARCZ: /* PolyLineZ */
|
|
1581
|
+
pgtype = "MULTILINESTRING";
|
|
1582
|
+
wkbtype = MULTILINETYPE | WKBZOFFSET | WKBMOFFSET;
|
|
1583
|
+
if ( ! hwgeom ) pgdims = 4;
|
|
1584
|
+
else pgdims = 3;
|
|
1585
|
+
break;
|
|
1586
|
+
case SHPT_POLYGONZ: /* MultiPolygonZ */
|
|
1587
|
+
pgtype = "MULTIPOLYGON";
|
|
1588
|
+
wkbtype = MULTIPOLYGONTYPE | WKBZOFFSET | WKBMOFFSET;
|
|
1589
|
+
if ( ! hwgeom ) pgdims = 4;
|
|
1590
|
+
else pgdims = 3;
|
|
1591
|
+
break;
|
|
1592
|
+
case SHPT_MULTIPOINTZ: /* MultiPointZ */
|
|
1593
|
+
pgtype = "MULTIPOINT";
|
|
1594
|
+
wkbtype = MULTIPOINTTYPE | WKBZOFFSET | WKBMOFFSET;
|
|
1595
|
+
if ( ! hwgeom ) pgdims = 4;
|
|
1596
|
+
else pgdims = 3;
|
|
1597
|
+
break;
|
|
1598
|
+
default:
|
|
1599
|
+
pgtype = "GEOMETRY";
|
|
1600
|
+
wkbtype = COLLECTIONTYPE | WKBZOFFSET | WKBMOFFSET;
|
|
1601
|
+
pgdims = 4;
|
|
1602
|
+
fprintf(stderr, "Unknown geometry type: %d\n",
|
|
1603
|
+
shpfiletype);
|
|
1604
|
+
break;
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
if (simple_geometries)
|
|
1608
|
+
{
|
|
1609
|
+
// adjust geometry name for CREATE TABLE by skipping MULTI
|
|
1610
|
+
if ((wkbtype & 0x7) == MULTIPOLYGONTYPE) pgtype += 5;
|
|
1611
|
+
if ((wkbtype & 0x7) == MULTILINETYPE) pgtype += 5;
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
char *
|
|
1616
|
+
dump_ring(Ring *ring)
|
|
1617
|
+
{
|
|
1618
|
+
char *buf = malloc(256*ring->n);
|
|
1619
|
+
int i;
|
|
1620
|
+
|
|
1621
|
+
buf[0] = '\0';
|
|
1622
|
+
for (i=0; i<ring->n; i++)
|
|
1623
|
+
{
|
|
1624
|
+
if (i) strcat(buf, ",");
|
|
1625
|
+
sprintf(buf+strlen(buf), "%g %g",
|
|
1626
|
+
ring->list[i].x,
|
|
1627
|
+
ring->list[i].y);
|
|
1628
|
+
}
|
|
1629
|
+
return buf;
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
void
|
|
1633
|
+
DropTable(char *schema, char *table, char *geom)
|
|
1634
|
+
{
|
|
1635
|
+
/*---------------Drop the table--------------------------
|
|
1636
|
+
* TODO: if the table has more then one geometry column
|
|
1637
|
+
* the DROP TABLE call will leave spurious records in
|
|
1638
|
+
* geometry_columns.
|
|
1639
|
+
*
|
|
1640
|
+
* If the geometry column in the table being dropped
|
|
1641
|
+
* does not match 'the_geom' or the name specified with
|
|
1642
|
+
* -g an error is returned by DropGeometryColumn.
|
|
1643
|
+
*
|
|
1644
|
+
* The table to be dropped might not exist.
|
|
1645
|
+
*
|
|
1646
|
+
*/
|
|
1647
|
+
if ( schema )
|
|
1648
|
+
{
|
|
1649
|
+
if (readshape == 1){
|
|
1650
|
+
printf("SELECT DropGeometryColumn('%s','%s','%s');\n",
|
|
1651
|
+
schema, table, geom);
|
|
1652
|
+
}
|
|
1653
|
+
printf("DROP TABLE \"%s\".\"%s\";\n", schema, table);
|
|
1654
|
+
}
|
|
1655
|
+
else
|
|
1656
|
+
{
|
|
1657
|
+
if (readshape == 1){
|
|
1658
|
+
printf("SELECT DropGeometryColumn('','%s','%s');\n",
|
|
1659
|
+
table, geom);
|
|
1660
|
+
}
|
|
1661
|
+
printf("DROP TABLE \"%s\";\n", table);
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
void
|
|
1666
|
+
GetFieldsSpec(void)
|
|
1667
|
+
{
|
|
1668
|
+
/*
|
|
1669
|
+
* Shapefile (dbf) field name are at most 10chars + 1 NULL.
|
|
1670
|
+
* Postgresql field names are at most 63 bytes + 1 NULL.
|
|
1671
|
+
*/
|
|
1672
|
+
#define MAXFIELDNAMELEN 64
|
|
1673
|
+
int field_precision, field_width;
|
|
1674
|
+
int j, z;
|
|
1675
|
+
char name[MAXFIELDNAMELEN];
|
|
1676
|
+
char name2[MAXFIELDNAMELEN];
|
|
1677
|
+
DBFFieldType type = -1;
|
|
1678
|
+
#ifdef HAVE_ICONV
|
|
1679
|
+
char *utf8str;
|
|
1680
|
+
#endif
|
|
1681
|
+
|
|
1682
|
+
num_fields = DBFGetFieldCount( hDBFHandle );
|
|
1683
|
+
num_records = DBFGetRecordCount(hDBFHandle);
|
|
1684
|
+
field_names = malloc(num_fields*sizeof(char*));
|
|
1685
|
+
types = (DBFFieldType *)malloc(num_fields*sizeof(int));
|
|
1686
|
+
widths = malloc(num_fields*sizeof(int));
|
|
1687
|
+
precisions = malloc(num_fields*sizeof(int));
|
|
1688
|
+
if (readshape == 1)
|
|
1689
|
+
{
|
|
1690
|
+
col_names = malloc((num_fields+2) * sizeof(char) * MAXFIELDNAMELEN);
|
|
1691
|
+
}
|
|
1692
|
+
{ //for dbf only, we do not need to allocate slot for the_geom
|
|
1693
|
+
col_names = malloc((num_fields+1) * sizeof(char) * MAXFIELDNAMELEN);
|
|
1694
|
+
}
|
|
1695
|
+
strcpy(col_names, "(" );
|
|
1696
|
+
|
|
1697
|
+
/*fprintf(stderr, "Number of fields from DBF: %d\n", num_fields); */
|
|
1698
|
+
for(j=0;j<num_fields;j++)
|
|
1699
|
+
{
|
|
1700
|
+
type = DBFGetFieldInfo(hDBFHandle, j, name, &field_width, &field_precision);
|
|
1701
|
+
|
|
1702
|
+
/*fprintf(stderr, "Field %d (%s) width/decimals: %d/%d\n", j, name, field_width, field_precision); */
|
|
1703
|
+
types[j] = type;
|
|
1704
|
+
widths[j] = field_width;
|
|
1705
|
+
precisions[j] = field_precision;
|
|
1706
|
+
|
|
1707
|
+
#ifdef HAVE_ICONV
|
|
1708
|
+
if ( encoding )
|
|
1709
|
+
{
|
|
1710
|
+
utf8str = utf8(encoding, name);
|
|
1711
|
+
if ( ! utf8str ) exit(1);
|
|
1712
|
+
strcpy(name, utf8str);
|
|
1713
|
+
free(utf8str);
|
|
1714
|
+
}
|
|
1715
|
+
#endif
|
|
1716
|
+
|
|
1717
|
+
|
|
1718
|
+
/*
|
|
1719
|
+
* Make field names lowercase unless asked to
|
|
1720
|
+
* keep identifiers case.
|
|
1721
|
+
*/
|
|
1722
|
+
if ( ! quoteidentifiers ) LowerCase(name);
|
|
1723
|
+
|
|
1724
|
+
/*
|
|
1725
|
+
* Escape names starting with the
|
|
1726
|
+
* escape char (_), those named 'gid'
|
|
1727
|
+
* or after pgsql reserved attribute names
|
|
1728
|
+
*/
|
|
1729
|
+
if( name[0]=='_' ||
|
|
1730
|
+
! strcmp(name,"gid") ||
|
|
1731
|
+
! strcmp(name, "tableoid") ||
|
|
1732
|
+
! strcmp(name, "cmax") ||
|
|
1733
|
+
! strcmp(name, "xmax") ||
|
|
1734
|
+
! strcmp(name, "cmin") ||
|
|
1735
|
+
! strcmp(name, "primary") ||
|
|
1736
|
+
! strcmp(name, "oid") ||
|
|
1737
|
+
! strcmp(name, "ctid") )
|
|
1738
|
+
{
|
|
1739
|
+
strcpy(name2+2, name);
|
|
1740
|
+
name2[0] = '_';
|
|
1741
|
+
name2[1] = '_';
|
|
1742
|
+
strcpy(name, name2);
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
/* Avoid duplicating field names */
|
|
1746
|
+
for(z=0; z < j ; z++){
|
|
1747
|
+
if(strcmp(field_names[z],name)==0){
|
|
1748
|
+
strcat(name,"__");
|
|
1749
|
+
sprintf(name+strlen(name),"%i",j);
|
|
1750
|
+
break;
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
field_names[j] = malloc (strlen(name)+1);
|
|
1755
|
+
strcpy(field_names[j], name);
|
|
1756
|
+
|
|
1757
|
+
/*sprintf(col_names, "%s\"%s\",", col_names, name);*/
|
|
1758
|
+
strcat(col_names, "\"");
|
|
1759
|
+
strcat(col_names, name);
|
|
1760
|
+
if (readshape == 1 || j < (num_fields - 1)){
|
|
1761
|
+
//don't include last comma if its the last field and no geometry field will follow
|
|
1762
|
+
strcat(col_names, "\",");
|
|
1763
|
+
}
|
|
1764
|
+
else {
|
|
1765
|
+
strcat(col_names, "\"");
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
/*sprintf(col_names, "%s\"%s\")", col_names, geom);*/
|
|
1769
|
+
if (readshape == 1){
|
|
1770
|
+
strcat(col_names, geom);
|
|
1771
|
+
}
|
|
1772
|
+
strcat(col_names, ")");
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
#ifdef HAVE_ICONV
|
|
1776
|
+
|
|
1777
|
+
char *
|
|
1778
|
+
utf8 (const char *fromcode, char *inputbuf)
|
|
1779
|
+
{
|
|
1780
|
+
iconv_t cd;
|
|
1781
|
+
char *outputptr;
|
|
1782
|
+
char *outputbuf;
|
|
1783
|
+
size_t outbytesleft;
|
|
1784
|
+
size_t inbytesleft;
|
|
1785
|
+
|
|
1786
|
+
inbytesleft = strlen (inputbuf);
|
|
1787
|
+
|
|
1788
|
+
cd = iconv_open ("UTF-8", fromcode);
|
|
1789
|
+
if (cd == (iconv_t) - 1)
|
|
1790
|
+
{
|
|
1791
|
+
fprintf(stderr, "utf8: iconv_open: %s\n", strerror (errno));
|
|
1792
|
+
return NULL;
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
outbytesleft = inbytesleft*3+1; /* UTF8 string can be 3 times larger */
|
|
1796
|
+
/* then local string */
|
|
1797
|
+
outputbuf = (char *) malloc (outbytesleft);
|
|
1798
|
+
if (!outputbuf)
|
|
1799
|
+
{
|
|
1800
|
+
fprintf(stderr, "utf8: malloc: %s\n", strerror (errno));
|
|
1801
|
+
return NULL;
|
|
1802
|
+
}
|
|
1803
|
+
memset (outputbuf, 0, outbytesleft);
|
|
1804
|
+
outputptr = outputbuf;
|
|
1805
|
+
|
|
1806
|
+
if (-1==iconv(cd, &inputbuf, &inbytesleft, &outputptr, &outbytesleft))
|
|
1807
|
+
{
|
|
1808
|
+
fprintf(stderr, "utf8: %s", strerror (errno));
|
|
1809
|
+
return NULL;
|
|
1810
|
+
}
|
|
1811
|
+
|
|
1812
|
+
iconv_close (cd);
|
|
1813
|
+
|
|
1814
|
+
return outputbuf;
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
#endif /* defined HAVE_ICONV */
|
|
1818
|
+
|
|
1819
|
+
/**********************************************************************
|
|
1820
|
+
* $Log$
|
|
1821
|
+
* Revision 1.109 2008/04/09 14:12:17 robe
|
|
1822
|
+
* - Added support to load dbf-only files
|
|
1823
|
+
*
|
|
1824
|
+
* Revision 1.108 2006/06/16 14:12:17 strk
|
|
1825
|
+
* - BUGFIX in pgsql2shp successful return code.
|
|
1826
|
+
* - BUGFIX in shp2pgsql handling of MultiLine WKT.
|
|
1827
|
+
*
|
|
1828
|
+
* Revision 1.107 2006/04/18 09:16:26 strk
|
|
1829
|
+
* Substituted bzero() use with memset()
|
|
1830
|
+
*
|
|
1831
|
+
* Revision 1.106 2006/01/16 10:42:58 strk
|
|
1832
|
+
* Added support for Bool and Date DBF<=>PGIS mapping
|
|
1833
|
+
*
|
|
1834
|
+
* Revision 1.105 2006/01/09 16:40:16 strk
|
|
1835
|
+
* ISO C90 comments, signedness mismatch fixes
|
|
1836
|
+
*
|
|
1837
|
+
* Revision 1.104 2005/11/01 09:25:47 strk
|
|
1838
|
+
* Reworked NULL geometries handling code letting user specify policy (insert,skip,abort). Insert is the default.
|
|
1839
|
+
*
|
|
1840
|
+
* Revision 1.103 2005/10/24 15:54:22 strk
|
|
1841
|
+
* fixed wrong assumption about maximum size of integer attributes (width is maximum size of text representation)
|
|
1842
|
+
*
|
|
1843
|
+
* Revision 1.102 2005/10/24 11:30:59 strk
|
|
1844
|
+
*
|
|
1845
|
+
* Fixed a bug in string attributes handling truncating values of maximum
|
|
1846
|
+
* allowed length, curtesy of Lars Roessiger.
|
|
1847
|
+
* Reworked integer attributes handling to be stricter in dbf->sql mapping
|
|
1848
|
+
* and to allow for big int8 values in sql->dbf conversion
|
|
1849
|
+
*
|
|
1850
|
+
* Revision 1.101 2005/10/21 11:33:55 strk
|
|
1851
|
+
* Applied patch by Lars Roessiger handling numerical values with a trailing decima
|
|
1852
|
+
* l dot
|
|
1853
|
+
*
|
|
1854
|
+
* Revision 1.100 2005/10/13 13:40:20 strk
|
|
1855
|
+
* Fixed return code from shp2pgsql
|
|
1856
|
+
*
|
|
1857
|
+
* Revision 1.99 2005/10/03 18:08:55 strk
|
|
1858
|
+
* Stricter string attributes lenght handling. DBF header will be used
|
|
1859
|
+
* to set varchar maxlenght, (var)char typmod will be used to set DBF header
|
|
1860
|
+
* len.
|
|
1861
|
+
*
|
|
1862
|
+
* Revision 1.98 2005/10/03 07:45:58 strk
|
|
1863
|
+
* Issued a warning when -W is specified and no UTF8 support has been compiled in.
|
|
1864
|
+
*
|
|
1865
|
+
* Revision 1.97 2005/09/30 08:59:29 strk
|
|
1866
|
+
* Fixed release of stack memory occurring when shp2pgsql is compiled with USE_ICONV defined, an attribute value needs to be escaped and no -W is used
|
|
1867
|
+
*
|
|
1868
|
+
* Revision 1.96 2005/08/29 22:36:25 strk
|
|
1869
|
+
* Removed premature object destruction in InsertLineString{WKT,} causing segfault
|
|
1870
|
+
*
|
|
1871
|
+
* Revision 1.95 2005/08/29 11:48:33 strk
|
|
1872
|
+
* Fixed sprintf() calls to avoid overlapping memory,
|
|
1873
|
+
* reworked not-null objects existance check to reduce startup costs.
|
|
1874
|
+
*
|
|
1875
|
+
* Revision 1.94 2005/07/27 02:47:14 strk
|
|
1876
|
+
* Support for multibyte field names in loader
|
|
1877
|
+
*
|
|
1878
|
+
* Revision 1.93 2005/07/27 02:35:50 strk
|
|
1879
|
+
* Minor cleanups in loader
|
|
1880
|
+
*
|
|
1881
|
+
* Revision 1.92 2005/07/27 02:07:01 strk
|
|
1882
|
+
* Fixed handling of POINT types as WKT (-w) in loader
|
|
1883
|
+
*
|
|
1884
|
+
* Revision 1.91 2005/07/04 09:47:03 strk
|
|
1885
|
+
* Added conservative iconv detection code
|
|
1886
|
+
*
|
|
1887
|
+
* Revision 1.90 2005/06/16 17:55:58 strk
|
|
1888
|
+
* Added -I switch for GiST index creation in loader
|
|
1889
|
+
*
|
|
1890
|
+
* Revision 1.89 2005/04/21 09:08:34 strk
|
|
1891
|
+
* Applied patch from Ron Mayer fixing a segfault in string escaper funx
|
|
1892
|
+
*
|
|
1893
|
+
* Revision 1.88 2005/04/14 12:58:59 strk
|
|
1894
|
+
* Applied patch by Gino Lucrezi fixing bug in string escaping code.
|
|
1895
|
+
*
|
|
1896
|
+
* Revision 1.87 2005/04/06 14:16:43 strk
|
|
1897
|
+
* Removed manual update of gid field.
|
|
1898
|
+
*
|
|
1899
|
+
* Revision 1.86 2005/04/06 14:02:08 mschaber
|
|
1900
|
+
* added -p option (prepare mode) that spits out the table schema without
|
|
1901
|
+
* inserting any data.
|
|
1902
|
+
*
|
|
1903
|
+
* Revision 1.85 2005/04/06 10:46:10 strk
|
|
1904
|
+
* Bugfix in -w (hwgeom) handling of ZM shapefiles.
|
|
1905
|
+
* Big reorganizzation of code to easy maintainance.
|
|
1906
|
+
*
|
|
1907
|
+
* Revision 1.84 2005/04/04 20:51:26 strk
|
|
1908
|
+
* Added -w flag to output old (WKT/HWGEOM) sql.
|
|
1909
|
+
*
|
|
1910
|
+
* Revision 1.83 2005/03/15 12:24:40 strk
|
|
1911
|
+
* hole-in-ring detector made more readable
|
|
1912
|
+
*
|
|
1913
|
+
* Revision 1.82 2005/03/14 22:02:31 strk
|
|
1914
|
+
* Fixed holes handling.
|
|
1915
|
+
*
|
|
1916
|
+
* Revision 1.81 2005/03/08 11:06:33 strk
|
|
1917
|
+
* modernized old-style parameter declarations
|
|
1918
|
+
*
|
|
1919
|
+
* Revision 1.80 2005/03/04 14:48:22 strk
|
|
1920
|
+
* Applied patch from Jonne Savolainen fixing multilines handling
|
|
1921
|
+
*
|
|
1922
|
+
* Revision 1.79 2005/01/31 22:15:22 strk
|
|
1923
|
+
* Added maintainer notice, to reduce Jeff-strk mail bounces
|
|
1924
|
+
*
|
|
1925
|
+
* Revision 1.78 2005/01/17 09:21:13 strk
|
|
1926
|
+
* Added one more bytes for terminating NULL in utf8 encoder
|
|
1927
|
+
*
|
|
1928
|
+
* Revision 1.77 2005/01/16 16:50:01 strk
|
|
1929
|
+
* String escaping algorithm made simpler and more robust.
|
|
1930
|
+
* Removed escaped strings leaking.
|
|
1931
|
+
* Fixed UTF8 encoder to allocate enough space for 3bytes chars strings.
|
|
1932
|
+
*
|
|
1933
|
+
* Revision 1.76 2005/01/12 17:03:20 strk
|
|
1934
|
+
* Added optional UTF8 output support as suggested by IIDA Tetsushi
|
|
1935
|
+
*
|
|
1936
|
+
* Revision 1.75 2004/11/15 10:51:35 strk
|
|
1937
|
+
* Fixed a bug in PIP invocation, added some debugging lines.
|
|
1938
|
+
*
|
|
1939
|
+
* Revision 1.74 2004/10/17 13:25:44 strk
|
|
1940
|
+
* removed USE_WKB partially-used define
|
|
1941
|
+
*
|
|
1942
|
+
* Revision 1.73 2004/10/17 13:24:44 strk
|
|
1943
|
+
* HEXWKB polygon
|
|
1944
|
+
*
|
|
1945
|
+
* Revision 1.72 2004/10/17 12:59:12 strk
|
|
1946
|
+
* HEXWKB multiline output
|
|
1947
|
+
*
|
|
1948
|
+
* Revision 1.71 2004/10/17 12:26:02 strk
|
|
1949
|
+
* Point and MultiPoint loaded using HEXWKB.
|
|
1950
|
+
*
|
|
1951
|
+
* Revision 1.70 2004/10/15 22:01:35 strk
|
|
1952
|
+
* Initial WKB functionalities
|
|
1953
|
+
*
|
|
1954
|
+
* Revision 1.69 2004/10/07 21:52:28 strk
|
|
1955
|
+
* Lots of rewriting/cleanup. TypeM/TypeZ supports.
|
|
1956
|
+
*
|
|
1957
|
+
* Revision 1.68 2004/10/07 06:54:24 strk
|
|
1958
|
+
* cleanups
|
|
1959
|
+
*
|
|
1960
|
+
* Revision 1.67 2004/10/06 10:11:16 strk
|
|
1961
|
+
* Other separator fixes
|
|
1962
|
+
*
|
|
1963
|
+
* Revision 1.66 2004/10/06 09:40:27 strk
|
|
1964
|
+
* Handled 0-DBF-attributes corner case.
|
|
1965
|
+
*
|
|
1966
|
+
* Revision 1.65 2004/09/20 17:13:31 strk
|
|
1967
|
+
* changed comments to better show shape type handling
|
|
1968
|
+
*
|
|
1969
|
+
* Revision 1.64 2004/08/20 08:14:37 strk
|
|
1970
|
+
* Whole output wrapped in transaction blocks.
|
|
1971
|
+
* Drops are out of transaction, and multiple transactions are used
|
|
1972
|
+
* for INSERT mode.
|
|
1973
|
+
*
|
|
1974
|
+
**********************************************************************/
|