1
/**********************************************************************
2
* $Id: pgsql2shp.c,v 1.74 2005/03/25 18:43:07 strk Exp $
4
* PostGIS - Spatial Types for PostgreSQL
5
* http://postgis.refractions.net
6
* Copyright 2001-2003 Refractions Research Inc.
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.
11
**********************************************************************
13
* PostGIS to Shapefile converter
15
* Original Author: Jeff Lounsbury, jeffloun@refractions.net
17
* Maintainer: Sandro Santilli, strk@refractions.net
19
**********************************************************************/
22
"$Id: pgsql2shp.c,v 1.74 2005/03/25 18:43:07 strk Exp $";
29
#include <sys/types.h>
36
#include <sys/param.h>
42
#define MULTIPOINTTYPE 4
43
#define MULTILINETYPE 5
44
#define MULTIPOLYGONTYPE 6
45
#define COLLECTIONTYPE 7
46
#define BBOXONLYTYPE 99
50
* set to 1 to see record fetching progress
51
* set to 2 to see also shapefile creation progress
55
/* Define this to use HEX encoding instead of bytea encoding */
58
typedef unsigned long int uint32;
59
typedef unsigned char byte;
64
char *geo_col_name, *table, *shp_file, *schema, *usrquery;
66
char *main_scan_query;
76
SHPObject * (*shape_creator)(byte *, int);
78
int pgis_major_version;
81
int getMaxFieldSize(PGconn *conn, char *schema, char *table, char *fname);
82
int parse_commandline(int ARGC, char **ARGV);
83
void usage(int exitstatus);
84
char *getTableOID(char *schema, char *table);
85
int addRecord(PGresult *res, int residx, int row);
86
int initShapefile(char *shp_file, PGresult *res);
88
int getGeometryOID(PGconn *conn);
89
int getGeometryType(char *schema, char *table, char *geo_col_name);
90
int getGeometryMaxDims(char *schema, char *table, char *geo_col_name);
91
char *shapetypename(int num);
92
int parse_points(char *str, int num_points, double *x,double *y,double *z);
93
int num_points(char *str);
94
int num_lines(char *str);
95
char *scan_to_same_level(char *str);
96
int points_per_sublist( char *str, int *npoints, long max_lists);
97
int reverse_points(int num_points, double *x, double *y, double *z, double *m);
98
int is_clockwise(int num_points,double *x,double *y,double *z);
99
int is_bigendian(void);
100
SHPObject * shape_creator_wrapper_WKB(byte *str, int idx);
101
int get_postgis_major_version(void);
102
static void parse_table(char *spec);
103
static int create_usrquerytable(void);
106
SHPObject * create_polygon2D_WKB(byte *wkb);
107
SHPObject * create_polygon3D_WKB(byte *wkb);
108
SHPObject * create_polygon4D_WKB(byte *wkb);
109
SHPObject * create_multipoint2D_WKB(byte *wkb);
110
SHPObject * create_multipoint3D_WKB(byte *wkb);
111
SHPObject * create_multipoint4D_WKB(byte *wkb);
112
SHPObject * create_point2D_WKB(byte *wkb);
113
SHPObject * create_point3D_WKB(byte *wkb);
114
SHPObject * create_point4D_WKB(byte *wkb);
115
SHPObject * create_multiline2D_WKB (byte *wkb);
116
SHPObject * create_multiline3D_WKB (byte *wkb);
117
SHPObject * create_multiline4D_WKB (byte *wkb);
118
SHPObject * create_line2D_WKB(byte *wkb);
119
SHPObject * create_line3D_WKB(byte *wkb);
120
SHPObject * create_line4D_WKB(byte *wkb);
121
SHPObject * create_multipolygon2D_WKB(byte *wkb);
122
SHPObject * create_multipolygon3D_WKB(byte *wkb);
123
SHPObject * create_multipolygon4D_WKB(byte *wkb);
124
byte getbyte(byte *c);
125
void skipbyte(byte **c);
126
byte popbyte(byte **c);
127
uint32 popint(byte **c);
128
uint32 getint(byte *c);
129
void skipint(byte **c);
130
double popdouble(byte **c);
131
void skipdouble(byte **c);
132
void dump_wkb(byte *wkb);
133
byte * HexDecode(byte *hex);
135
#define WKBZOFFSET 0x80000000
136
#define WKBMOFFSET 0x40000000
137
#define ZMFLAG(x) (((x)&((WKBZOFFSET)+(WKBMOFFSET)))>>30)
140
static void exit_nicely(PGconn *conn){
146
main(int ARGC, char **ARGV)
151
char fetchquery[256];
156
shape_creator = NULL;
162
main_scan_query = NULL;
173
if ( getenv("ROWBUFLEN") ) rowbuflen=atoi(getenv("ROWBUFLEN"));
179
if ( ! parse_commandline(ARGC, ARGV) ) {
180
printf("\n**ERROR** invalid option or command parameters\n\n");
184
/* Use table name as shapefile name */
185
if(shp_file == NULL) shp_file = table;
187
/* Make a connection to the specified database, and exit on failure */
188
conn = PQconnectdb("");
189
if (PQstatus(conn) == CONNECTION_BAD) {
190
printf( "%s", PQerrorMessage(conn));
194
/* Create temporary table for user query */
196
if ( ! create_usrquerytable() ) {
202
debug = fopen("/tmp/trace.out", "w");
203
PQtrace(conn, debug);
207
/* Initialize shapefile and database infos */
208
fprintf(stdout, "Initializing... "); fflush(stdout);
209
if ( ! initialize() ) exit_nicely(conn);
210
fprintf(stdout, "Done (postgis major version: %d).\n",
213
if ( pgis_major_version > 0 && dswitchprovided )
215
printf("WARNING: -d switch is useless when dumping from postgis-1.0.0+\n");
219
printf("Output shape: %s\n", shapetypename(outshptype));
223
* Begin the transaction
224
* (a cursor can only be defined inside a transaction block)
226
res=PQexec(conn, "BEGIN");
227
if ( ! res || PQresultStatus(res) != PGRES_COMMAND_OK ) {
228
printf( "%s", PQerrorMessage(conn));
234
* Declare a cursor for the main scan query
235
* as set by the initializer function.
237
query = (char *)malloc(strlen(main_scan_query)+256);
239
sprintf(query, "DECLARE cur BINARY CURSOR FOR %s",
242
sprintf(query, "DECLARE cur CURSOR FOR %s", main_scan_query);
245
printf( "MAINSCAN: %s\n", main_scan_query);
247
free(main_scan_query);
248
res = PQexec(conn, query);
250
if ( ! res || PQresultStatus(res) != PGRES_COMMAND_OK ) {
251
printf( "MainScanQuery: %s", PQerrorMessage(conn));
256
/* Set the fetch query */
257
sprintf(fetchquery, "FETCH %d FROM cur", rowbuflen);
259
fprintf(stdout, "Dumping: "); fflush(stdout);
268
/* Fetch next record buffer from cursor */
270
fprintf(stdout, "X"); fflush(stdout);
272
res = PQexec(conn, fetchquery);
273
if ( ! res || PQresultStatus(res) != PGRES_TUPLES_OK ) {
274
printf( "RecordFetch: %s",
275
PQerrorMessage(conn));
279
/* No more rows, break the loop */
280
if ( ! PQntuples(res) ) {
285
for(i=0; i<PQntuples(res); i++)
287
/* Add record in all output files */
288
if ( ! addRecord(res, i, row) ) exit_nicely(conn);
293
printf("End of result, clearing..."); fflush(stdout);
300
printf(" [%d rows].\n", row);
303
if (shp) SHPClose(shp);
317
shape_creator_wrapper_WKB(byte *str, int idx)
326
wkb_big_endian = ! popbyte(&ptr);
327
if ( wkb_big_endian != big_endian )
329
printf( "Wrong WKB endiannes, dunno how to flip\n");
337
if ( type&WKBZOFFSET ) ndims++;
338
if ( type&WKBMOFFSET )
351
return create_multiline2D_WKB(str);
352
else if ( ndims == 3 )
353
return create_multiline3D_WKB(str);
354
else if ( ndims == 4 )
355
return create_multiline4D_WKB(str);
359
return create_line2D_WKB(str);
360
else if ( ndims == 3 )
361
return create_line3D_WKB(str);
362
else if ( ndims == 4 )
363
return create_line4D_WKB(str);
367
return create_polygon2D_WKB(str);
368
else if ( ndims == 3 )
369
return create_polygon3D_WKB(str);
370
else if ( ndims == 4 )
371
return create_polygon4D_WKB(str);
373
case MULTIPOLYGONTYPE:
375
return create_multipolygon2D_WKB(str);
376
else if ( ndims == 3 )
377
return create_multipolygon3D_WKB(str);
378
else if ( ndims == 4 )
379
return create_multipolygon4D_WKB(str);
383
return create_point2D_WKB(str);
384
else if ( ndims == 3 )
385
return create_point3D_WKB(str);
386
else if ( ndims == 4 )
387
return create_point4D_WKB(str);
391
return create_multipoint2D_WKB(str);
392
else if ( ndims == 3 )
393
return create_multipoint3D_WKB(str);
394
else if ( ndims == 4 )
395
return create_multipoint4D_WKB(str);
398
printf( "Unknown WKB type (%8.8lx) - (%s:%d)\n",
399
type, __FILE__, __LINE__);
404
//reads points into x,y,z co-ord arrays
405
int parse_points(char *str, int num_points, double *x,double *y,double *z){
410
if ( (str == NULL) || (str[0] == 0) ){
411
return 0; //either null string or empty string
414
//look ahead for the "("
415
str = strchr(str,'(') ;
417
if ( (str == NULL) || (str[1] == 0) ){ // str[0] = '(';
418
return 0; //either didnt find "(" or its at the end of the string
420
str++; //move forward one char
422
while (keep_going == 1){
424
//attempt to get the point
425
//scanf is slow, so we use strtod()
427
x[num_found] = (double)strtod(str,&end_of_double);
428
if (end_of_double == str){
429
return 0; //error occured (nothing parsed)
432
y[num_found] = strtod(str,&end_of_double);
433
if (end_of_double == str){
434
return 0; //error occured (nothing parsed)
437
z[num_found] = strtod(str,&end_of_double); //will be zero if error occured
441
str=strpbrk(str,",)"); // look for a "," or ")"
442
if (str != NULL && str[0] == ','){
445
keep_going = (str != NULL) && (str[0] != ')');
454
//returns how many points are in the first list in str
456
// 1. scan ahead looking for "("
457
// 2. find "," until hit a ")"
458
// 3. return number of points found
460
// NOTE: doesnt actually parse the points, so if the
461
// str contains an invalid geometry, this could give
462
// back the wrong answer.
464
// "(1 2 3, 4 5 6),(7 8, 9 10, 11 12 13)" => 2 (2nd list is not included)
465
int num_points(char *str){
467
int points_found = 1; //no "," if only one point (and last point)
470
if ( (str == NULL) || (str[0] == 0) )
472
return 0; //either null string or empty string
475
//look ahead for the "("
477
str = strchr(str,'(') ;
479
if ( (str == NULL) || (str[1] == 0) ) // str[0] = '(';
481
return 0; //either didnt find "(" or its at the end of the string
487
str=strpbrk(str,",)"); // look for a "," or ")"
488
keep_going = (str != NULL);
489
if (keep_going) // found a , or )
499
str++; //move 1 char forward
503
return points_found; // technically it should return an error.
506
//number of sublist in a string.
508
// Find the number of lines in a Multiline
510
// The number of rings in a Polygon
512
// The number of polygons in a multipolygon
514
// ( (..),(..),(..) ) -> 3
515
// ( ( (..),(..) ), ( (..) )) -> 2
517
// scan through the list, for every "(", depth (nesting) increases by 1
518
// for every ")", depth (nesting) decreases by 1
519
// if find a "(" at depth 1, then there is a sub list
522
// "(((..),(..)),((..)))"
523
//depth 12333223332112333210
526
int num_lines(char *str){
527
int current_depth = 0;
531
while ( (str != NULL) && (str[0] != 0) )
533
str=strpbrk(str,"()"); //look for "(" or ")"
539
if (current_depth == 2)
545
if (current_depth == 0)
551
return numb_lists ; // probably should give an error
556
//simple scan-forward to find the next "(" at the same level
557
// ( (), (),(), ),(...
558
// + return this location
559
char *scan_to_same_level(char *str){
561
//scan forward in string looking for at "(" at the same level
562
// as the one its already pointing at
564
int current_depth = 0;
568
while ( (str != NULL) && (str[0] != 0) )
570
str=strpbrk(str,"()");
577
if (current_depth == 0)
581
first_one = 0; //ignore the first opening "("
592
return str ; // probably should give an error
600
// Find out how many points are in each sublist, put the result in the array npoints[]
601
// (for at most max_list sublists)
603
// ( (L1),(L2),(L3) ) --> npoints[0] = points in L1,
604
// npoints[1] = points in L2,
605
// npoints[2] = points in L3
607
// We find these by, again, scanning through str looking for "(" and ")"
608
// to determine the current depth. We dont actually parse the points.
610
int points_per_sublist( char *str, int *npoints, long max_lists){
611
//scan through, noting depth and ","s
613
int current_depth = 0;
614
int current_list =-1 ;
617
while ( (str != NULL) && (str[0] != 0) )
619
str=strpbrk(str,"(),"); //find "(" or ")" or ","
625
if (current_depth == 2)
628
if (current_list >=max_lists)
629
return 1; // too many sub lists found
630
npoints[current_list] = 1;
632
// might want to return an error if depth>2
637
if (current_depth == 0)
642
if (current_depth==2)
644
npoints[current_list] ++;
651
return 1 ; // probably should give an error
655
create_multiline3D_WKB (byte *wkb)
658
double *x=NULL, *y=NULL, *zm=NULL;
659
int *part_index=NULL, totpoints=0, nlines=0;
666
// extract zmflag from type
667
zmflag = ZMFLAG(popint(&wkb));
670
* Scan all lines in multiline
672
nlines=popint(&wkb); // num_wkbLineStrings
674
printf("Multiline with %d lines\n", nlines);
677
part_index = (int *)malloc(sizeof(int)*(nlines));
678
for (li=0; li<nlines; li++)
682
// skip byteOrder and wkbType
683
skipbyte(&wkb); skipint(&wkb);
685
npoints = popint(&wkb);
688
printf("Line %d has %d points\n", li, npoints);
691
x = realloc(x, sizeof(double)*(totpoints+npoints));
692
y = realloc(y, sizeof(double)*(totpoints+npoints));
693
zm = realloc(zm, sizeof(double)*(totpoints+npoints));
695
/* wkb now points at first point */
696
for (pn=0; pn<npoints; pn++)
698
x[totpoints+pn] = popdouble(&wkb);
699
y[totpoints+pn] = popdouble(&wkb);
700
zm[totpoints+pn] = popdouble(&wkb);
703
part_index[li] = totpoints;
704
totpoints += npoints;
708
obj = SHPCreateObject(outshptype, -1, nlines,
709
part_index, NULL, totpoints,
712
obj = SHPCreateObject(outshptype, -1, nlines,
713
part_index, NULL, totpoints,
717
free(part_index); free(x); free(y); free(zm);
723
create_multiline4D_WKB (byte *wkb)
726
double *x=NULL, *y=NULL, *z=NULL, *m=NULL;
727
int *part_index=NULL, totpoints=0, nlines=0;
734
// extract zmflag from type
735
zmflag = ZMFLAG(popint(&wkb));
738
* Scan all lines in multiline
740
nlines=popint(&wkb); // num_wkbLineStrings
742
printf("Multiline with %d lines\n", nlines);
745
part_index = (int *)malloc(sizeof(int)*(nlines));
746
for (li=0; li<nlines; li++)
750
// skip byteOrder and wkbType
751
skipbyte(&wkb); skipint(&wkb);
753
npoints = popint(&wkb);
756
printf("Line %d has %d points\n", li, npoints);
759
x = realloc(x, sizeof(double)*(totpoints+npoints));
760
y = realloc(y, sizeof(double)*(totpoints+npoints));
761
z = realloc(z, sizeof(double)*(totpoints+npoints));
762
m = realloc(m, sizeof(double)*(totpoints+npoints));
764
/* wkb now points at first point */
765
for (pn=0; pn<npoints; pn++)
767
x[totpoints+pn] = popdouble(&wkb);
768
y[totpoints+pn] = popdouble(&wkb);
769
z[totpoints+pn] = popdouble(&wkb);
770
m[totpoints+pn] = popdouble(&wkb);
773
part_index[li] = totpoints;
774
totpoints += npoints;
777
obj = SHPCreateObject(outshptype, -1, nlines,
778
part_index, NULL, totpoints,
781
free(part_index); free(x); free(y); free(z); free(m);
787
create_multiline2D_WKB (byte *wkb)
789
double *x=NULL, *y=NULL;
790
int *part_index=NULL, totpoints=0, nlines=0;
798
// extract zmflag from type
799
zmflag = ZMFLAG(popint(&wkb));
802
* Scan all lines in multiline
804
nlines=popint(&wkb); // num_wkbLineStrings
806
printf("Multiline with %d lines\n", nlines);
809
part_index = (int *)malloc(sizeof(int)*(nlines));
810
for (li=0; li<nlines; li++)
814
// skip byteOrder and wkbType
815
skipbyte(&wkb); skipint(&wkb);
817
npoints = popint(&wkb);
820
printf("Line %d has %d points\n", li, npoints);
823
x = realloc(x, sizeof(double)*(totpoints+npoints));
824
y = realloc(y, sizeof(double)*(totpoints+npoints));
826
/* wkb now points at first point */
827
for (pn=0; pn<npoints; pn++)
829
x[totpoints+pn] = popdouble(&wkb);
830
y[totpoints+pn] = popdouble(&wkb);
833
part_index[li] = totpoints;
834
totpoints += npoints;
838
obj = SHPCreateObject(outshptype, -1, nlines,
839
part_index, NULL, totpoints,
842
free(part_index); free(x); free(y);
848
create_line4D_WKB (byte *wkb)
850
double *x=NULL, *y=NULL, *z=NULL, *m=NULL;
851
uint32 npoints=0, pn;
858
// extract zmflag from type
859
zmflag = ZMFLAG(popint(&wkb));
861
npoints = popint(&wkb);
864
printf("Line has %lu points\n", npoints);
867
x = malloc(sizeof(double)*(npoints));
868
y = malloc(sizeof(double)*(npoints));
869
z = malloc(sizeof(double)*(npoints));
870
m = malloc(sizeof(double)*(npoints));
872
/* wkb now points at first point */
873
for (pn=0; pn<npoints; pn++)
875
x[pn] = popdouble(&wkb);
876
y[pn] = popdouble(&wkb);
877
z[pn] = popdouble(&wkb);
878
m[pn] = popdouble(&wkb);
881
obj = SHPCreateObject(outshptype, -1, 0, NULL, NULL,
882
npoints, x, y, z, m);
883
free(x); free(y); free(z); free(m);
889
create_line3D_WKB (byte *wkb)
891
double *x=NULL, *y=NULL, *zm=NULL;
892
uint32 npoints=0, pn;
899
// extract zmflag from type
900
zmflag = ZMFLAG(popint(&wkb));
902
npoints = popint(&wkb);
905
printf("Line has %lu points\n", npoints);
908
x = malloc(sizeof(double)*(npoints));
909
y = malloc(sizeof(double)*(npoints));
910
zm = malloc(sizeof(double)*(npoints));
912
/* wkb now points at first point */
913
for (pn=0; pn<npoints; pn++)
915
x[pn] = popdouble(&wkb);
916
y[pn] = popdouble(&wkb);
917
zm[pn] = popdouble(&wkb);
921
obj = SHPCreateObject(outshptype, -1, 0, NULL, NULL,
922
npoints, x, y, NULL, zm);
924
obj = SHPCreateObject(outshptype, -1, 0, NULL, NULL,
925
npoints, x, y, zm, NULL);
928
free(x); free(y); free(zm);
934
create_line2D_WKB (byte *wkb)
936
double *x=NULL, *y=NULL, *z=NULL;
937
uint32 npoints=0, pn;
944
// extract zmflag from type
945
zmflag = ZMFLAG(popint(&wkb));
947
npoints = popint(&wkb);
950
printf("Line has %lu points\n", npoints);
953
x = malloc(sizeof(double)*(npoints));
954
y = malloc(sizeof(double)*(npoints));
956
/* wkb now points at first point */
957
for (pn=0; pn<npoints; pn++)
959
x[pn] = popdouble(&wkb);
960
y[pn] = popdouble(&wkb);
963
obj = SHPCreateSimpleObject(outshptype, npoints, x, y, z);
970
create_point4D_WKB(byte *wkb)
979
// extract zmflag from type
980
zmflag = ZMFLAG(popint(&wkb));
987
obj = SHPCreateObject(outshptype, -1, 0, NULL, NULL,
994
create_point3D_WKB(byte *wkb)
1003
// extract zmflag from type
1004
zmflag = ZMFLAG(popint(&wkb));
1006
x = popdouble(&wkb);
1007
y = popdouble(&wkb);
1008
zm = popdouble(&wkb);
1010
if ( zmflag == 1 ) {
1011
obj = SHPCreateObject(outshptype, -1, 0, NULL, NULL,
1012
1, &x, &y, NULL, &zm);
1014
obj = SHPCreateObject(outshptype, -1, 0, NULL, NULL,
1015
1, &x, &y, &zm, NULL);
1022
create_point2D_WKB(byte *wkb)
1031
// extract zmflag from type
1032
zmflag = ZMFLAG(popint(&wkb));
1034
x = popdouble(&wkb);
1035
y = popdouble(&wkb);
1037
obj = SHPCreateSimpleObject(outshptype, 1, &x, &y, NULL);
1043
create_multipoint4D_WKB(byte *wkb)
1046
double *x=NULL, *y=NULL, *z=NULL, *m=NULL;
1054
// extract zmflag from type
1055
zmflag = ZMFLAG(popint(&wkb));
1057
npoints = popint(&wkb);
1059
x = (double *)malloc(sizeof(double)*npoints);
1060
y = (double *)malloc(sizeof(double)*npoints);
1061
z = (double *)malloc(sizeof(double)*npoints);
1062
m = (double *)malloc(sizeof(double)*npoints);
1064
for (pn=0; pn<npoints; pn++)
1066
skipbyte(&wkb); // byteOrder
1067
skipint(&wkb); // wkbType
1068
x[pn]=popdouble(&wkb);
1069
y[pn]=popdouble(&wkb);
1070
z[pn]=popdouble(&wkb);
1071
m[pn]=popdouble(&wkb);
1074
obj = SHPCreateObject(outshptype, -1, 0, NULL, NULL,
1075
npoints, x, y, z, m);
1077
free(x); free(y); free(z); free(m);
1083
create_multipoint3D_WKB(byte *wkb)
1086
double *x=NULL, *y=NULL, *zm=NULL;
1094
// extract zmflag from type
1095
zmflag = ZMFLAG(popint(&wkb));
1097
npoints = popint(&wkb);
1099
x = (double *)malloc(sizeof(double)*npoints);
1100
y = (double *)malloc(sizeof(double)*npoints);
1101
zm = (double *)malloc(sizeof(double)*npoints);
1103
for (pn=0; pn<npoints; pn++)
1105
skipbyte(&wkb); // byteOrder
1106
skipint(&wkb); // wkbType
1107
x[pn]=popdouble(&wkb);
1108
y[pn]=popdouble(&wkb);
1109
zm[pn]=popdouble(&wkb);
1112
if ( zmflag == 1 ) {
1113
obj = SHPCreateObject(outshptype, -1, 0, NULL, NULL,
1114
npoints, x, y, NULL, zm);
1116
obj = SHPCreateObject(outshptype, -1, 0, NULL, NULL,
1117
npoints, x, y, zm, NULL);
1120
free(x); free(y); free(zm);
1126
create_multipoint2D_WKB(byte *wkb)
1129
double *x=NULL, *y=NULL;
1137
// extract zmflag from type
1138
zmflag = ZMFLAG(popint(&wkb));
1140
npoints = popint(&wkb);
1142
x = (double *)malloc(sizeof(double)*npoints);
1143
y = (double *)malloc(sizeof(double)*npoints);
1145
for (pn=0; pn<npoints; pn++)
1147
skipbyte(&wkb); // byteOrder
1148
skipint(&wkb); // wkbType
1149
x[pn]=popdouble(&wkb);
1150
y[pn]=popdouble(&wkb);
1154
obj = SHPCreateSimpleObject(outshptype,npoints,x,y,NULL);
1161
create_polygon2D_WKB(byte *wkb)
1164
int ri, nrings, totpoints=0, *part_index=NULL;
1165
double *x=NULL, *y=NULL, *z=NULL;
1171
// extract zmflag from type
1172
zmflag = ZMFLAG(popint(&wkb));
1177
nrings = popint(&wkb);
1179
printf("Polygon with %d rings\n", nrings);
1181
part_index = (int *)malloc(sizeof(int)*nrings);
1182
for (ri=0; ri<nrings; ri++)
1185
int npoints = popint(&wkb);
1187
x = realloc(x, sizeof(double)*(totpoints+npoints));
1188
y = realloc(y, sizeof(double)*(totpoints+npoints));
1190
for (pn=0; pn<npoints; pn++)
1192
x[totpoints+pn] = popdouble(&wkb);
1193
y[totpoints+pn] = popdouble(&wkb);
1197
* First ring should be clockwise,
1198
* other rings should be counter-clockwise
1201
if ( ! is_clockwise(npoints, x+totpoints,
1202
y+totpoints, NULL) )
1205
printf("Forcing CW\n");
1207
reverse_points(npoints, x+totpoints,
1208
y+totpoints, NULL, NULL);
1211
if ( is_clockwise(npoints, x+totpoints,
1212
y+totpoints, NULL) )
1215
printf("Forcing CCW\n");
1217
reverse_points(npoints, x+totpoints,
1218
y+totpoints, NULL, NULL);
1222
part_index[ri] = totpoints;
1223
totpoints += npoints;
1226
obj = SHPCreateObject(outshptype, -1, nrings,
1227
part_index, NULL, totpoints,
1237
create_polygon4D_WKB(byte *wkb)
1240
int ri, nrings, totpoints=0, *part_index=NULL;
1241
double *x=NULL, *y=NULL, *z=NULL, *m=NULL;
1247
// extract zmflag from type
1248
zmflag = ZMFLAG(popint(&wkb));
1253
nrings = popint(&wkb);
1255
printf("Polygon with %d rings\n", nrings);
1257
part_index = (int *)malloc(sizeof(int)*nrings);
1258
for (ri=0; ri<nrings; ri++)
1261
int npoints = popint(&wkb);
1263
x = realloc(x, sizeof(double)*(totpoints+npoints));
1264
y = realloc(y, sizeof(double)*(totpoints+npoints));
1265
z = realloc(z, sizeof(double)*(totpoints+npoints));
1266
m = realloc(m, sizeof(double)*(totpoints+npoints));
1268
for (pn=0; pn<npoints; pn++)
1270
x[totpoints+pn] = popdouble(&wkb);
1271
y[totpoints+pn] = popdouble(&wkb);
1272
z[totpoints+pn] = popdouble(&wkb);
1273
m[totpoints+pn] = popdouble(&wkb);
1277
* First ring should be clockwise,
1278
* other rings should be counter-clockwise
1281
if ( ! is_clockwise(npoints, x+totpoints,
1282
y+totpoints, z+totpoints) ) {
1284
printf("Forcing CW\n");
1286
reverse_points(npoints, x+totpoints,
1287
y+totpoints, z+totpoints, m+totpoints);
1290
if ( is_clockwise(npoints, x+totpoints,
1291
y+totpoints, z+totpoints) ) {
1293
printf("Forcing CCW\n");
1295
reverse_points(npoints, x+totpoints,
1296
y+totpoints, z+totpoints, m+totpoints);
1300
part_index[ri] = totpoints;
1301
totpoints += npoints;
1304
obj = SHPCreateObject(outshptype, -1, nrings,
1305
part_index, NULL, totpoints,
1309
free(x); free(y); free(z); free(m);
1315
create_polygon3D_WKB(byte *wkb)
1318
int ri, nrings, totpoints=0, *part_index=NULL;
1319
double *x=NULL, *y=NULL, *zm=NULL, *z=NULL;
1325
// extract zmflag from type
1326
zmflag = ZMFLAG(popint(&wkb));
1331
nrings = popint(&wkb);
1333
printf("Polygon with %d rings\n", nrings);
1335
part_index = (int *)malloc(sizeof(int)*nrings);
1336
for (ri=0; ri<nrings; ri++)
1339
int npoints = popint(&wkb);
1341
x = realloc(x, sizeof(double)*(totpoints+npoints));
1342
y = realloc(y, sizeof(double)*(totpoints+npoints));
1343
zm = realloc(zm, sizeof(double)*(totpoints+npoints));
1345
for (pn=0; pn<npoints; pn++)
1347
x[totpoints+pn] = popdouble(&wkb);
1348
y[totpoints+pn] = popdouble(&wkb);
1349
zm[totpoints+pn] = popdouble(&wkb);
1353
* First ring should be clockwise,
1354
* other rings should be counter-clockwise
1357
// Set z to NULL if TYPEM
1358
if ( zmflag == 1 ) z = NULL;
1359
else z = zm+totpoints;
1362
if ( ! is_clockwise(npoints, x+totpoints,
1365
printf("Forcing CW\n");
1367
reverse_points(npoints, x+totpoints,
1368
y+totpoints, zm+totpoints, NULL);
1371
if ( is_clockwise(npoints, x+totpoints,
1374
printf("Forcing CCW\n");
1376
reverse_points(npoints, x+totpoints,
1377
y+totpoints, zm+totpoints, NULL);
1381
part_index[ri] = totpoints;
1382
totpoints += npoints;
1385
if ( zmflag == 1 ) {
1386
obj = SHPCreateObject(outshptype, -1, nrings,
1387
part_index, NULL, totpoints,
1390
obj = SHPCreateObject(outshptype, -1, nrings,
1391
part_index, NULL, totpoints,
1396
free(x); free(y); free(zm);
1402
create_multipolygon2D_WKB(byte *wkb)
1405
uint32 nrings, nparts=0;
1408
int *part_index=NULL;
1410
double *x=NULL, *y=NULL;
1416
// extract zmflag from type
1417
zmflag = ZMFLAG(popint(&wkb));
1420
* Scan all polygons in multipolygon
1422
npolys = popint(&wkb); // num_wkbPolygons
1424
printf("Multipolygon with %lu polygons\n", npolys);
1428
* Now wkb points to a WKBPolygon structure
1430
for (pi=0; pi<npolys; pi++)
1432
uint32 ri; // ring index
1434
// skip byteOrder and wkbType
1435
skipbyte(&wkb); skipint(&wkb);
1438
* Find total number of points and
1442
nrings = popint(&wkb);
1443
part_index = (int *)realloc(part_index,
1444
sizeof(int)*(nparts+nrings));
1447
printf("Polygon %lu has %lu rings\n", pi, nrings);
1450
// wkb now points at first ring
1451
for (ri=0; ri<nrings; ri++)
1453
uint32 pn; // point number
1456
npoints = popint(&wkb);
1459
printf("Ring %lu has %lu points\n", ri, npoints);
1462
x = realloc(x, sizeof(double)*(totpoints+npoints));
1463
y = realloc(y, sizeof(double)*(totpoints+npoints));
1465
/* wkb now points at first point */
1466
for (pn=0; pn<npoints; pn++)
1468
x[totpoints+pn] = popdouble(&wkb);
1469
y[totpoints+pn] = popdouble(&wkb);
1471
printf("Point%lu (%f,%f)\n", pn, x[totpoints+pn], y[totpoints+pn]);
1476
* First ring should be clockwise,
1477
* other rings should be counter-clockwise
1480
if (!is_clockwise(npoints, x+totpoints,
1484
printf("Forcing CW\n");
1486
reverse_points(npoints, x+totpoints,
1487
y+totpoints, NULL, NULL);
1490
if (is_clockwise(npoints, x+totpoints,
1494
printf("Forcing CCW\n");
1496
reverse_points(npoints, x+totpoints,
1497
y+totpoints, NULL, NULL);
1501
part_index[nparts+ri] = totpoints;
1502
totpoints += npoints;
1505
printf("End of rings\n");
1511
printf("End of polygons\n");
1514
obj = SHPCreateObject(outshptype, -1, nparts,
1515
part_index, NULL, totpoints,
1519
printf("Object created\n");
1529
create_multipolygon3D_WKB(byte *wkb)
1532
int nrings, nparts=0;
1535
int *part_index=NULL;
1537
double *x=NULL, *y=NULL, *z=NULL, *zm=NULL;
1543
// extract zmflag from type
1544
zmflag = ZMFLAG(popint(&wkb));
1547
* Scan all polygons in multipolygon
1549
npolys = popint(&wkb); // num_wkbPolygons
1551
printf("Multipolygon with %lu polygons\n", npolys);
1555
* Now wkb points to a WKBPolygon structure
1557
for (pi=0; pi<npolys; pi++)
1559
int ri; // ring index
1561
// skip byteOrder and wkbType
1562
skipbyte(&wkb); skipint(&wkb);
1565
* Find total number of points and
1569
nrings = popint(&wkb);
1570
part_index = (int *)realloc(part_index,
1571
sizeof(int)*(nparts+nrings));
1574
printf("Polygon %d has %d rings\n", pi, nrings);
1577
// wkb now points at first ring
1578
for (ri=0; ri<nrings; ri++)
1580
int pn; // point number
1583
npoints = popint(&wkb);
1586
printf("Ring %d has %d points\n", ri, npoints);
1589
x = realloc(x, sizeof(double)*(totpoints+npoints));
1590
y = realloc(y, sizeof(double)*(totpoints+npoints));
1591
zm = realloc(zm, sizeof(double)*(totpoints+npoints));
1593
/* wkb now points at first point */
1594
for (pn=0; pn<npoints; pn++)
1596
x[totpoints+pn] = popdouble(&wkb);
1597
y[totpoints+pn] = popdouble(&wkb);
1598
zm[totpoints+pn] = popdouble(&wkb);
1600
printf("Point%d (%f,%f)\n", pn, x[totpoints+pn], y[totpoints+pn]);
1605
* First ring should be clockwise,
1606
* other rings should be counter-clockwise
1609
// Set z to NULL if TYPEM
1610
if ( zmflag == 1 ) z = NULL;
1611
else z = zm+totpoints;
1614
if (!is_clockwise(npoints, x+totpoints,
1618
printf("Forcing CW\n");
1620
reverse_points(npoints, x+totpoints,
1621
y+totpoints, zm+totpoints, NULL);
1624
if (is_clockwise(npoints, x+totpoints,
1628
printf("Forcing CCW\n");
1630
reverse_points(npoints, x+totpoints,
1631
y+totpoints, zm+totpoints, NULL);
1635
part_index[nparts+ri] = totpoints;
1636
totpoints += npoints;
1639
printf("End of rings\n");
1645
printf("End of polygons\n");
1648
if ( zmflag == 1 ) {
1649
obj = SHPCreateObject(outshptype, -1, nparts,
1650
part_index, NULL, totpoints,
1653
obj = SHPCreateObject(outshptype, -1, nparts,
1654
part_index, NULL, totpoints,
1659
printf("Object created\n");
1663
free(x); free(y); free(zm);
1669
create_multipolygon4D_WKB(byte *wkb)
1672
int nrings, nparts=0;
1675
int *part_index=NULL;
1677
double *x=NULL, *y=NULL, *z=NULL, *m=NULL;
1683
// extract zmflag from type
1684
zmflag = ZMFLAG(popint(&wkb));
1687
* Scan all polygons in multipolygon
1689
npolys = popint(&wkb); // num_wkbPolygons
1691
printf("Multipolygon with %lu polygons\n", npolys);
1695
* Now wkb points to a WKBPolygon structure
1697
for (pi=0; pi<npolys; pi++)
1699
int ri; // ring index
1701
// skip byteOrder and wkbType
1702
skipbyte(&wkb); skipint(&wkb);
1705
* Find total number of points and
1709
nrings = popint(&wkb);
1710
part_index = (int *)realloc(part_index,
1711
sizeof(int)*(nparts+nrings));
1714
printf("Polygon %d has %d rings\n", pi, nrings);
1717
// wkb now points at first ring
1718
for (ri=0; ri<nrings; ri++)
1720
int pn; // point number
1723
npoints = popint(&wkb);
1726
printf("Ring %d has %d points\n", ri, npoints);
1729
x = realloc(x, sizeof(double)*(totpoints+npoints));
1730
y = realloc(y, sizeof(double)*(totpoints+npoints));
1731
z = realloc(z, sizeof(double)*(totpoints+npoints));
1732
m = realloc(m, sizeof(double)*(totpoints+npoints));
1734
/* wkb now points at first point */
1735
for (pn=0; pn<npoints; pn++)
1737
x[totpoints+pn] = popdouble(&wkb);
1738
y[totpoints+pn] = popdouble(&wkb);
1739
z[totpoints+pn] = popdouble(&wkb);
1740
m[totpoints+pn] = popdouble(&wkb);
1742
printf("Point%d (%f,%f)\n", pn, x[totpoints+pn], y[totpoints+pn]);
1747
* First ring should be clockwise,
1748
* other rings should be counter-clockwise
1751
if (!is_clockwise(npoints, x+totpoints,
1752
y+totpoints, z+totpoints))
1755
printf("Forcing CW\n");
1757
reverse_points(npoints, x+totpoints,
1758
y+totpoints, z+totpoints, m+totpoints);
1761
if (is_clockwise(npoints, x+totpoints,
1762
y+totpoints, z+totpoints))
1765
printf("Forcing CCW\n");
1767
reverse_points(npoints, x+totpoints,
1768
y+totpoints, z+totpoints, m+totpoints);
1772
part_index[nparts+ri] = totpoints;
1773
totpoints += npoints;
1776
printf("End of rings\n");
1782
printf("End of polygons\n");
1785
obj = SHPCreateObject(outshptype, -1, nparts,
1786
part_index, NULL, totpoints,
1790
printf("Object created\n");
1794
free(x); free(y); free(z); free(m);
1799
//Reverse the clockwise-ness of the point list...
1801
reverse_points(int num_points, double *x, double *y, double *z, double *m)
1807
for(i=0; i <num_points; i++){
1838
//return 1 if the points are in clockwise order
1839
int is_clockwise(int num_points, double *x, double *y, double *z)
1842
double x_change,y_change,area;
1843
double *x_new, *y_new; //the points, translated to the origin for safer accuracy
1845
x_new = (double *)malloc(sizeof(double) * num_points);
1846
y_new = (double *)malloc(sizeof(double) * num_points);
1851
for(i=0; i < num_points ; i++){
1852
x_new[i] = x[i] - x_change;
1853
y_new[i] = y[i] - y_change;
1856
for(i=0; i < num_points - 1; i++){
1857
area += (x[i] * y[i+1]) - (y[i] * x[i+1]); //calculate the area
1860
free(x_new); free(y_new);
1861
return 0; //counter-clockwise
1863
free(x_new); free(y_new);
1864
return 1; //clockwise
1869
* Returns OID integer on success
1870
* Returns -1 on error.
1873
getGeometryOID(PGconn *conn)
1879
res1=PQexec(conn, "select OID from pg_type where typname = 'geometry'");
1880
if ( ! res1 || PQresultStatus(res1) != PGRES_TUPLES_OK )
1882
printf( "OIDQuery: %s", PQerrorMessage(conn));
1886
if(PQntuples(res1) <= 0 )
1888
printf( "Geometry type unknown "
1889
"(have you enabled postgis?)\n");
1893
temp_int = (char *)PQgetvalue(res1, 0, 0);
1894
OID = atoi(temp_int);
1903
* Passed result is a 1 row result.
1904
* Return 1 on success.
1905
* Return 0 on failure.
1908
addRecord(PGresult *res, int residx, int row)
1911
int nFields = PQnfields(res);
1912
int flds = 0; /* number of dbf field */
1917
for (j=0; j<nFields; j++)
1921
/* Default (not geometry) attribute */
1922
if (type_ary[j] != 9)
1925
* Transform NULL numbers to '0'
1926
* This is because the shapelibe
1927
* won't easly take care of setting
1928
* nulls unless paying the acquisition
1929
* of a bug in long integer values
1931
if ( PQgetisnull(res, residx, j) &&
1932
( type_ary[j] == 1 || type_ary[j] == 2 ) )
1938
val = PQgetvalue(res, residx, j);
1941
fprintf(stdout, "s"); fflush(stdout);
1943
if(!DBFWriteAttributeDirectly(dbf, row, flds, val))
1945
printf("error(string) - Record could not be "
1953
/* If we arrived here it is a geometry attribute */
1955
// Handle NULL shapes
1956
if ( PQgetisnull(res, residx, j) ) {
1957
obj=SHPCreateSimpleObject(SHPT_NULL,0,NULL,NULL,NULL);
1958
if ( SHPWriteObject(shp,-1,obj) == -1)
1961
"Error writing null shape %d\n", row);
1962
SHPDestroyObject(obj);
1965
SHPDestroyObject(obj);
1971
v = PQgetvalue(res, residx, j);
1973
val = PQunescapeBytea(v, &junk);
1975
if ( pgis_major_version > 0 )
1977
val = PQunescapeBytea(v, &junk);
1986
#endif // VERBOSE > 2
1990
val = (char *)PQgetvalue(res, residx, j);
1994
fprintf(stdout, "g"); fflush(stdout);
1997
obj = shape_creator_wrapper_WKB(val, row);
2000
printf( "Error creating shape for record %d "
2001
"(geotype is %d)\n", row, geotype);
2004
if ( SHPWriteObject(shp,-1,obj) == -1)
2006
printf( "Error writing shape %d\n", row);
2007
SHPDestroyObject(obj);
2010
SHPDestroyObject(obj);
2012
if ( ! binary ) free(val);
2016
printf("Finished adding record %d\n", row);
2023
* Return allocate memory. Free after use.
2026
getTableOID(char *schema, char *table)
2033
size = strlen(table)+256;
2034
if ( schema ) size += strlen(schema)+1;
2036
query = (char *)malloc(size);
2040
sprintf(query, "SELECT oid FROM pg_class c, pg_namespace n WHERE c.relnamespace n.oid AND n.nspname = '%s' AND c.relname = '%s'", schema, table);
2042
sprintf(query, "SELECT oid FROM pg_class WHERE relname = '%s'", table);
2045
res3 = PQexec(conn, query);
2047
if ( ! res3 || PQresultStatus(res3) != PGRES_TUPLES_OK ) {
2048
printf( "TableOID: %s", PQerrorMessage(conn));
2051
if(PQntuples(res3) == 1 ){
2052
ret = strdup(PQgetvalue(res3, 0, 0));
2053
}else if(PQntuples(res3) == 0 ){
2054
printf( "Cannot find relation OID (does table exist?).\n");
2058
ret = strdup(PQgetvalue(res3, 0, 0));
2059
printf( "Warning: Multiple relations detected, the program will only dump the first relation.\n");
2066
* Return geometry type as defined at top file.
2067
* Return -1 on error.
2068
* Return 0 on unknown or unsupported geometry type.
2069
* Set outtype to 'm' or 'z' depending on input type.
2072
getGeometryType(char *schema, char *table, char *geo_col_name)
2076
char *geo_str; // the geometry type string
2083
/**************************************************
2084
* Get what kind of Geometry type is in the table
2085
**************************************************/
2089
sprintf(query, "SELECT DISTINCT geometrytype(\"%s\") "
2090
"FROM \"%s\".\"%s\" WHERE NOT geometrytype(\"%s\") "
2091
"IS NULL", geo_col_name, schema, table, geo_col_name);
2095
sprintf(query, "SELECT DISTINCT geometrytype(\"%s\") "
2096
"FROM \"%s\" WHERE NOT geometrytype(\"%s\") IS NULL",
2097
geo_col_name, table, geo_col_name);
2101
printf( "%s\n",query);
2103
res = PQexec(conn, query);
2104
if ( ! res || PQresultStatus(res) != PGRES_TUPLES_OK ) {
2105
printf( "GeometryType: %s", PQerrorMessage(conn));
2109
if (PQntuples(res) == 0)
2111
printf("ERROR: Cannot determine geometry type (empty table).\n");
2116
/* This will iterate max 2 times */
2117
for (i=0; i<PQntuples(res); i++)
2119
geo_str = PQgetvalue(res, i, 0);
2120
if ( ! strncmp(geo_str, "MULTI", 5) )
2130
if ( ! strncmp(geo_str, "LINESTRI", 8) )
2132
if ( basetype && basetype != LINETYPE )
2134
printf( "ERROR: uncompatible mixed geometry types in table\n");
2138
basetype = LINETYPE;
2139
multitype = MULTILINETYPE;
2141
else if ( ! strncmp(geo_str, "POLYGON", 7) )
2143
if ( basetype && basetype != POLYGONTYPE )
2145
printf( "ERROR: uncompatible mixed geometries in table\n");
2149
basetype = POLYGONTYPE;
2150
multitype = MULTIPOLYGONTYPE;
2152
else if ( ! strncmp(geo_str, "POINT", 5) )
2154
if ( basetype && basetype != POINTTYPE )
2156
printf( "ERROR: uncompatible mixed geometries in table\n");
2160
basetype = POINTTYPE;
2161
multitype = MULTIPOINTTYPE;
2165
printf( "type '%s' is not Supported at this time.\n",
2167
printf( "The DBF file will be created but not the shx "
2177
/**************************************************
2178
* Get Geometry dimensions (2d/3dm/3dz/4d)
2179
**************************************************/
2180
if ( pgis_major_version > 0 )
2181
if ( -1 == getGeometryMaxDims(schema, table, geo_col_name) )
2192
* Set global outtype variable to:
2194
* 'z' for 3dz or 4d input
2196
* Return -1 on error, 0 on success.
2197
* Call only on postgis >= 1.0.0
2200
getGeometryMaxDims(char *schema, char *table, char *geo_col_name)
2208
sprintf(query, "SELECT max(zmflag(\"%s\")) "
2209
"FROM \"%s\".\"%s\"",
2210
geo_col_name, schema, table);
2214
sprintf(query, "SELECT max(zmflag(\"%s\")) "
2216
geo_col_name, table);
2220
printf("%s\n",query);
2222
res = PQexec(conn, query);
2223
if ( ! res || PQresultStatus(res) != PGRES_TUPLES_OK ) {
2224
printf( "ZMflagQuery: %s", PQerrorMessage(conn));
2229
if (PQntuples(res) == 0)
2231
printf("ERROR: Cannot determine geometry dimensions (empty table).\n");
2236
maxzmflag = atoi(PQgetvalue(res, 0, 0));
2259
printf("RCSID: %s\n", rcsid);
2260
printf("USAGE: pgsql2shp [<options>] <database> [<schema>.]<table>\n");
2261
printf(" pgsql2shp [<options>] <database> <query>\n");
2263
printf("OPTIONS:\n");
2264
printf(" -f <filename> Use this option to specify the name of the file\n");
2265
printf(" to create.\n");
2266
printf(" -h <host> Allows you to specify connection to a database on a\n");
2267
printf(" machine other than the default.\n");
2268
printf(" -p <port> Allows you to specify a database port other than the default.\n");
2269
printf(" -P <password> Connect to the database with the specified password.\n");
2270
printf(" -u <user> Connect to the database as the specified user.\n");
2271
printf(" -g <geometry_column> Specify the geometry column to be exported.\n");
2272
printf(" -b Use a binary cursor.\n");
2273
printf(" -r Raw mode. Do not assume table has been created by \n");
2274
printf(" the loader. This would not unescape attribute names\n");
2275
printf(" and will not skip the 'gid' attribute.");
2280
/* Parse command line parameters */
2282
parse_commandline(int ARGC, char **ARGV)
2287
buf[1023] = '\0'; // just in case...
2289
/* Parse command line */
2290
while ((c = getopt(ARGC, ARGV, "bf:h:du:p:P:g:r")) != EOF){
2299
//setenv("PGHOST", optarg, 1);
2300
snprintf(buf, 255, "PGHOST=%s", optarg);
2301
putenv(strdup(buf));
2304
dswitchprovided = 1;
2312
//setenv("PGUSER", optarg, 1);
2313
snprintf(buf, 255, "PGUSER=%s", optarg);
2314
putenv(strdup(buf));
2317
//setenv("PGPORT", optarg, 1);
2318
snprintf(buf, 255, "PGPORT=%s", optarg);
2319
putenv(strdup(buf));
2322
//setenv("PGPASSWORD", optarg, 1);
2323
snprintf(buf, 255, "PGPASSWORD=%s", optarg);
2324
putenv(strdup(buf));
2327
geo_col_name = optarg;
2337
for (; optind<ARGC; optind++){
2338
if (curindex == 0) {
2339
//setenv("PGDATABASE", ARGV[optind], 1);
2340
snprintf(buf, 255, "PGDATABASE=%s", ARGV[optind]);
2341
putenv(strdup(buf));
2342
}else if(curindex == 1){
2343
parse_table(ARGV[optind]);
2348
if (curindex < 2) return 0;
2353
get_postgis_major_version(void)
2358
char query[] = "SELECT postgis_version()";
2359
res = PQexec(conn, query);
2361
if ( ! res || PQresultStatus(res) != PGRES_TUPLES_OK ) {
2362
printf( "Can't detect postgis version:\n");
2363
printf( "PostgisVersionQuery: %s",
2364
PQerrorMessage(conn));
2368
res = PQexec(conn, query);
2369
version = PQgetvalue(res, 0, 0);
2370
ver = atoi(version);
2376
* Initialize shapefile files, main scan query,
2387
int geo_oid; // geometry oid
2389
char *mainscan_flds[256];
2390
int mainscan_nflds=0;
2394
/* Detect postgis version */
2395
pgis_major_version = get_postgis_major_version();
2397
/* Detect host endiannes */
2398
big_endian = is_bigendian();
2400
/* Query user attributes name, type and size */
2402
size = strlen(table);
2403
if ( schema ) size += strlen(schema);
2406
query = (char *)malloc(size);
2407
if ( ! query ) return 0; // out of virtual memory
2411
sprintf(query, "SELECT a.attname, a.atttypid, a.attlen FROM "
2412
"pg_attribute a, pg_class c, pg_namespace n WHERE "
2413
"n.nspname = '%s' AND a.attrelid = c.oid AND "
2414
"n.oid = c.relnamespace AND "
2415
"a.atttypid != 0 AND "
2416
"a.attnum > 0 AND c.relname = '%s'", schema, table);
2420
sprintf(query, "SELECT a.attname, a.atttypid, a.attlen FROM "
2421
"pg_attribute a, pg_class c WHERE "
2422
"a.attrelid = c.oid and a.attnum > 0 AND "
2423
"a.atttypid != 0 AND "
2424
"c.relname = '%s'", table);
2430
printf( "Attribute query: %s\n", query);
2432
res = PQexec(conn, query);
2434
if ( ! res || PQresultStatus(res) != PGRES_TUPLES_OK ) {
2435
printf( "Querying for attributes: %s",
2436
PQerrorMessage(conn));
2439
if (! PQntuples(res)) {
2440
printf( "Table %s does not exist\n", table);
2445
/* Create the dbf file */
2446
dbf = DBFCreate(shp_file);
2448
printf( "Could not create dbf file\n");
2453
/* Get geometry oid */
2454
geo_oid = getGeometryOID(conn);
2455
if ( geo_oid == -1 )
2462
* Scan the result setting fields to be returned in mainscan
2463
* query, filling the type_ary, and creating .dbf and .shp files.
2465
for (i=0; i<PQntuples(res); i++)
2469
char *fname; // pgsql attribute name
2471
char field_name[32]; // dbf version of field name
2473
fname = PQgetvalue(res, i, 0);
2474
type = atoi(PQgetvalue(res, i, 1));
2475
size = atoi(PQgetvalue(res, i, 2));
2477
//printf( "A: %s, T: %d, S: %d\n", fname, type, size);
2479
* This is a geometry column
2483
/* We've already found our geometry column */
2484
if ( geom_fld != -1 ) continue;
2487
* A geometry attribute name has not been
2488
* provided: we'll use this one (the first).
2490
if ( ! geo_col_name )
2492
geom_fld = mainscan_nflds;
2493
type_ary[mainscan_nflds]=9;
2494
geo_col_name = fname;
2495
mainscan_flds[mainscan_nflds++] = fname;
2499
* This is exactly the geometry privided
2502
else if (!strcmp(geo_col_name,fname))
2504
geom_fld = mainscan_nflds;
2505
type_ary[mainscan_nflds]=9;
2506
mainscan_flds[mainscan_nflds++] = fname;
2514
* Everything else (non geometries) will be
2518
/* Skip gid (if not asked to do otherwise */
2519
if ( ! strcmp(fname, "gid") )
2522
if ( ! includegid ) continue;
2525
/* Unescape field name */
2527
if ( ! unescapedattrs )
2529
if (*ptr=='_') ptr+=2;
2532
* This needs special handling since both xmin and _xmin
2533
* becomes __xmin when escaped
2537
if(strlen(ptr) <32) strcpy(field_name, ptr);
2541
* TODO: you find an appropriate name if
2542
* running in RAW mode
2544
printf("dbf attribute name %s is too long, must be "
2545
"less than 32 characters.\n", ptr);
2550
/* make UPPERCASE */
2551
for(j=0; j < strlen(field_name); j++)
2552
field_name[j] = toupper(field_name[j]);
2555
* make sure the fields all have unique names,
2556
* 10-digit limit on dbf names...
2560
if(strncmp(field_name, PQgetvalue(res, j, 0),10) == 0)
2562
printf("\nWarning: Field '%s' has first 10 characters which "
2563
"duplicate a previous field name's.\n"
2564
"Renaming it to be: '",field_name);
2565
strncpy(field_name,field_name,9);
2567
sprintf(field_name,"%s%d",field_name,i);
2568
printf("%s'\n\n",field_name);
2573
* Find appropriate type of dbf attributes
2577
if(type == 20 || type == 21 || type == 23)
2579
if(DBFAddField(dbf, field_name,FTInteger,16,0) == -1)
2581
printf( "error - Field could not "
2585
type_ary[mainscan_nflds]=1;
2586
mainscan_flds[mainscan_nflds++] = fname;
2591
if(type == 700 || type == 701 || type == 1700 )
2593
if(DBFAddField(dbf, field_name,FTDouble,32,10) == -1)
2595
printf( "error - Field could not "
2599
type_ary[mainscan_nflds]=2;
2600
mainscan_flds[mainscan_nflds++] = fname;
2605
* date field, which we store as a string so we need
2606
* more width in the column
2614
* timestamp field, which we store as a string so we need
2615
* more width in the column
2617
else if(type == 1114)
2623
* For variable-sized fields we'll use max size in table
2628
size = getMaxFieldSize(conn, schema, table, fname);
2629
if ( size == -1 ) return 0;
2630
if ( ! size ) size = 32; // might 0 be a good size ?
2632
//printf( "FIELD_NAME: %s, SIZE: %d\n", field_name, size);
2634
/* generic type (use string representation) */
2635
if(DBFAddField(dbf, field_name,FTString,size,0) == -1)
2637
printf( "error - Field could not "
2641
type_ary[mainscan_nflds]=3;
2642
mainscan_flds[mainscan_nflds++] = fname;
2646
* If no geometry has been found
2647
* we have finished with initialization
2649
if ( geom_fld == -1 )
2653
printf( "%s: no such attribute in table %s\n",
2654
geo_col_name, table);
2657
printf( "No geometry column found.\n");
2658
printf( "The DBF file will be created "
2659
"but not the shx or shp files.\n");
2665
* We now create the appropriate shape (shp) file.
2666
* And set the shape creator function.
2668
geotype = getGeometryType(schema, table, geo_col_name);
2669
if ( geotype == -1 ) return 0;
2675
if (outtype == 'z') outshptype=SHPT_ARCZ;
2676
else if (outtype == 'm') outshptype=SHPT_ARCM;
2677
else outshptype=SHPT_ARC;
2681
case MULTIPOLYGONTYPE:
2682
if (outtype == 'z') outshptype=SHPT_POLYGONZ;
2683
else if (outtype == 'm') outshptype=SHPT_POLYGONM;
2684
else outshptype=SHPT_POLYGON;
2688
if (outtype == 'z') outshptype=SHPT_POINTZ;
2689
else if (outtype == 'm') outshptype=SHPT_POINTM;
2690
else outshptype=SHPT_POINT;
2693
case MULTIPOINTTYPE:
2694
if (outtype == 'z') outshptype=SHPT_MULTIPOINTZ;
2695
else if (outtype == 'm') outshptype=SHPT_MULTIPOINTM;
2696
else outshptype=SHPT_MULTIPOINT;
2701
shape_creator = NULL;
2702
printf( "You've found a bug! (%s:%d)\n",
2703
__FILE__, __LINE__);
2707
shp = SHPCreate(shp_file, outshptype);
2711
* Ok. Now we should have an array of allocate strings
2712
* representing the fields we'd like to be returned by
2716
tmpint = strlen(table)+2;
2717
for (i=0; i<mainscan_nflds; i++)
2718
tmpint += strlen(mainscan_flds[i])+32;
2719
main_scan_query = (char *)malloc(tmpint+256);
2721
sprintf(main_scan_query, "SELECT ");
2722
for (i=0; i<mainscan_nflds; i++)
2726
strcat(main_scan_query, buf);
2729
/* this is the geometry */
2730
if ( type_ary[i] == 9 )
2737
if ( pgis_major_version > 0 )
2739
sprintf(buf, "asEWKB(setSRID(\"%s\", -1), 'XDR')", mainscan_flds[i]);
2743
sprintf(buf, "asbinary(\"%s\", 'XDR')",
2747
if ( pgis_major_version > 0 )
2749
sprintf(buf, "asEWKB(setSRID(\"%s\", -1), 'XDR')", mainscan_flds[i]);
2753
sprintf(buf, "asbinary(\"%s\", 'XDR')::bytea", mainscan_flds[i]);
2758
else // little_endian
2762
if ( pgis_major_version > 0 )
2764
sprintf(buf, "asEWKB(setSRID(\"%s\", -1), 'NDR')", mainscan_flds[i]);
2768
sprintf(buf, "asbinary(\"%s\", 'NDR')",
2771
#else // ndef HEXWKB
2772
if ( pgis_major_version > 0 )
2774
sprintf(buf, "asEWKB(setSRID(\"%s\", -1), 'NDR')", mainscan_flds[i]);
2778
sprintf(buf, "asbinary(\"%s\", 'NDR')::bytea",
2781
#endif // def HEXWKB
2788
sprintf(buf, "\"%s\"::text", mainscan_flds[i]);
2790
sprintf(buf, "\"%s\"", mainscan_flds[i]);
2793
strcat(main_scan_query, buf);
2798
sprintf(buf, " FROM \"%s\".\"%s\"", schema, table);
2802
sprintf(buf, " FROM \"%s\"", table);
2805
strcat(main_scan_query, buf);
2807
// Order by 'gid' (if found)
2810
sprintf(buf, " ORDER BY \"gid\"");
2811
strcat(main_scan_query, buf);
2820
* Return the maximum octet_length from given table.
2821
* Return -1 on error.
2824
getMaxFieldSize(PGconn *conn, char *schema, char *table, char *fname)
2830
//( this is ugly: don't forget counting the length
2831
// when changing the fixed query strings )
2835
query = (char *)malloc(strlen(fname)+strlen(table)+
2838
"select max(octet_length(\"%s\")) from \"%s\".\"%s\"",
2839
fname, schema, table);
2843
query = (char *)malloc(strlen(fname)+strlen(table)+40);
2845
"select max(octet_length(\"%s\")) from \"%s\"",
2849
printf( "maxFieldLenQuery: %s\n", query);
2851
res = PQexec(conn, query);
2853
if ( ! res || PQresultStatus(res) != PGRES_TUPLES_OK ) {
2854
printf( "Querying for maximum field length: %s",
2855
PQerrorMessage(conn));
2859
if(PQntuples(res) <= 0 )
2864
size = atoi(PQgetvalue(res, 0, 0));
2870
* Input is a NULL-terminated string.
2871
* Output is a binary string.
2874
HexDecode(byte *hex)
2876
byte *ret, *retptr, *hexptr;
2880
len = strlen(hex)/2;
2881
ret = (byte *)malloc(len);
2883
printf( "Out of virtual memory\n");
2887
//printf("Decoding %d bytes", len); fflush(stdout);
2888
hexptr = hex; retptr = ret;
2890
// for postgis > 0.9.x skip SRID=#; if found
2891
if ( pgis_major_version > 0 )
2893
if ( hexptr[0] == 'S' )
2895
hexptr = strchr(hexptr, ';');
2903
* All these checks on WKB correctness
2904
* can be avoided, are only here because
2905
* I keep getting segfaults whereas
2906
* bytea unescaping works fine...
2909
//printf("%c", *hexptr);
2910
if ( *hexptr < 58 && *hexptr > 47 )
2911
byt = (((*hexptr)-48)<<4);
2912
else if ( *hexptr > 64 && *hexptr < 71 )
2913
byt = (((*hexptr)-55)<<4);
2915
printf( "Malformed WKB\n");
2920
//printf("%c", *hexptr);
2921
if ( *hexptr < 58 && *hexptr > 47 )
2922
byt |= ((*hexptr)-48);
2923
else if ( *hexptr > 64 && *hexptr < 71 )
2924
byt |= ((*hexptr)-55);
2926
printf("Malformed WKB\n");
2931
//printf("(%d)", byt);
2933
*retptr = (byte)byt;
2936
//printf(" Done.\n");
2946
if ( (((char *)(&test))[0]) == 1)
2948
return 0; //NDR (little_endian)
2952
return 1; //XDR (big_endian)
2956
/*********************************************************************
2958
* The following functions might go in a wkb lib
2960
* Right now they work on a binary representation, they
2961
* might work on an exadecimal representation of it as returned
2962
* by text cursors by postgis.
2964
*********************************************************************/
2972
printf("\n-----\n");
2973
byteOrder = popbyte(&wkb);
2974
if ( byteOrder == 0 ) printf("ByteOrder: XDR\n");
2975
else if ( byteOrder == 1 ) printf("ByteOrder: NDR\n");
2976
else printf("ByteOrder: unknown (%d)\n", byteOrder);
2978
type = popint(&wkb);
2979
if ( type&WKBZOFFSET ) printf ("Has Z!\n");
2980
if ( type&WKBMOFFSET ) printf ("Has M!\n");
2981
type &= ~WKBZOFFSET; // strip Z flag
2982
type &= ~WKBMOFFSET; // strip M flag
2983
printf ("Type: %x\n", type);
2989
void skipbyte(byte **c) {
2993
byte getbyte(byte *c) {
2997
byte popbyte(byte **c) {
3001
uint32 popint(byte **c) {
3008
uint32 getint(byte *c) {
3014
void skipint(byte **c) {
3018
double popdouble(byte **c) {
3025
void skipdouble(byte **c) {
3030
shapetypename(int num)
3035
return "Null Shape";
3042
case SHPT_MULTIPOINT:
3043
return "MultiPoint";
3050
case SHPT_MULTIPOINTZ:
3051
return "MultiPointZ";
3058
case SHPT_MULTIPOINTM:
3059
return "MultiPointM";
3060
case SHPT_MULTIPATCH:
3061
return "MultiPatch";
3068
* Either get a table (and optionally a schema)
3070
* A query starts with a "select" or "SELECT" string.
3073
parse_table(char *spec)
3078
if ( strstr(spec, "SELECT ") || strstr(spec, "select ") )
3081
table = "__pgsql2shp_tmp_table";
3086
if ( (ptr=strchr(table, '.')) )
3096
create_usrquerytable(void)
3101
query = malloc(sizeof(table)+sizeof(usrquery)+256);
3102
sprintf(query, "CREATE TEMP TABLE \"%s\" AS %s", table, usrquery);
3104
printf("Preparing table for user query... ");
3106
res = PQexec(conn, query);
3108
if ( ! res || PQresultStatus(res) != PGRES_COMMAND_OK ) {
3109
printf( "Failed: %s\n",
3110
PQerrorMessage(conn));
3118
/**********************************************************************
3119
* $Log: pgsql2shp.c,v $
3120
* Revision 1.74 2005/03/25 18:43:07 strk
3121
* Fixed PQunescapeBytearea argument (might give problems on 64bit archs)
3123
* Revision 1.73 2005/03/08 11:06:33 strk
3124
* modernized old-style parameter declarations
3126
* Revision 1.72 2005/03/04 14:54:03 strk
3127
* Fixed bug in multiline handling.
3129
* Revision 1.71 2005/01/31 22:15:22 strk
3130
* Added maintainer notice, to reduce Jeff-strk mail bounces
3132
* Revision 1.70 2004/12/22 10:29:09 strk
3133
* Drop useless SRID from geometry when downloading EWKB format.
3135
* Revision 1.69 2004/12/15 08:46:47 strk
3136
* Fixed memory leaks depending on input size.
3138
* Revision 1.68 2004/11/18 18:14:19 strk
3139
* Added a copy of the PQunescapeBytea function found in libpq of PG>=73
3141
* Revision 1.67 2004/10/17 12:16:47 strk
3142
* fixed prototype for user query table
3144
* Revision 1.66 2004/10/17 12:15:10 strk
3145
* Bug fixed in multipoint4D creation
3147
* Revision 1.65 2004/10/15 08:26:03 strk
3148
* Fixed handling of mixed dimensioned geometries in source table.
3150
* Revision 1.64 2004/10/14 09:59:51 strk
3151
* Added support for user query (replacing schema.table)
3153
* Revision 1.63 2004/10/11 14:34:40 strk
3154
* Added endiannes specification for postgis-1.0.0+
3156
* Revision 1.62 2004/10/07 21:51:05 strk
3157
* Fixed a bug in 4d handling
3159
* Revision 1.61 2004/10/07 17:15:28 strk
3160
* Fixed TYPEM handling.
3162
* Revision 1.60 2004/10/07 06:54:24 strk
3165
* Revision 1.59 2004/10/06 17:04:38 strk
3166
* ZM handling. Log trimmed.
3168
* Revision 1.58 2004/09/23 16:14:19 strk
3169
* Added -m / -z switches to control output type: XYM,XYMZ.
3171
* Revision 1.57 2004/09/20 17:11:44 strk
3172
* Added -d -d availability notice in help string.
3173
* Added user notice about output shape type.
3175
* Revision 1.56 2004/09/20 16:33:05 strk
3176
* Added 4d geometries support.
3177
* Changelog section moved at bottom file.
3179
* Revision 1.55 2004/09/20 14:14:43 strk
3180
* Fixed a bug in popbyte. Trapped WKB endiannes errors.
3182
* Revision 1.54 2004/09/20 13:49:27 strk
3183
* Postgis-1.x support (LWGEOM) added.
3184
* postgis version detected at runtime.
3185
* Endiannes unchecked ... TODO.
3187
**********************************************************************/