From fb3bd9d774144769e515f1e3068829fd85f352ce Mon Sep 17 00:00:00 2001 From: Sandro Santilli Date: Tue, 18 Nov 2003 14:39:26 +0000 Subject: [PATCH] Some more structuring. Initialization routine moved out of main loop. Preparing dumper for WKB parsing. git-svn-id: http://svn.osgeo.org/postgis/trunk@364 b70326c6-7e19-0410-871a-916f4a2858ee --- loader/pgsql2shp.c | 833 +++++++++++++++++++++++++++------------------ 1 file changed, 504 insertions(+), 329 deletions(-) diff --git a/loader/pgsql2shp.c b/loader/pgsql2shp.c index 765b21fd7..d5f13e2ad 100644 --- a/loader/pgsql2shp.c +++ b/loader/pgsql2shp.c @@ -10,6 +10,10 @@ * ********************************************************************** * $Log$ + * Revision 1.25 2003/11/18 14:39:26 strk + * Some more structuring. Initialization routine moved out of main loop. + * Preparing dumper for WKB parsing. + * * Revision 1.24 2003/11/16 00:27:46 strk * Huge code re-organization. More structured code, more errors handled, * cursor based iteration, less code lines. @@ -53,11 +57,19 @@ #define COLLECTIONTYPE 7 #define BBOXONLYTYPE 99 +/* + * Verbosity: + * set to 1 to see record fetching progress + * set to 2 to see also shapefile creation progress + */ +#define VERBOSE 1 + /* Global data */ PGconn *conn; -char *geo_col_name, *table; +int rowbuflen; +char *geo_col_name, *table, *shp_file; int type_ary[256]; -int geo_col_num; // attribute num for the requested or detected geometry +char *main_scan_query; DBFHandle dbf; SHPHandle shp; int geotype; @@ -65,9 +77,13 @@ int is3d; int (*shape_creator)(char *, int, SHPHandle, int); /* Prototypes */ +int getMaxFieldSize(PGconn *conn, char *table, char *fname); +int parse_commandline(int ARGC, char **ARGV); +void usage(int exitstatus); char *getTableOID(char *table); -int addRecord(PGresult *res, int row); +int addRecord(PGresult *res, int residx, int row); int initShapefile(char *shp_file, PGresult *res); +int initialize(void); int getGeometryOID(PGconn *conn); int getGeometryType(char *table, char *geo_col_name); int create_lines(char *str,int shape_id, SHPHandle shp,int dims); @@ -104,10 +120,10 @@ static void exit_nicely(PGconn *conn){ // -g Specify the geometry column to be exported. int main(int ARGC, char **ARGV){ - char *dbName, *query, *shp_file; - int c, errflg, curindex; + char *query=NULL; int row; PGresult *res; + char fetchquery[256]; dbf=NULL; shp=NULL; @@ -115,87 +131,26 @@ int main(int ARGC, char **ARGV){ shape_creator = NULL; table = NULL; geo_col_name = NULL; - dbName = NULL; shp_file = NULL; - geo_col_num = -1; + main_scan_query = NULL; + rowbuflen=1; is3d = 0; - errflg = 0; - /* Parse command line */ - while ((c = getopt(ARGC, ARGV, "f:h:du:p:P:g:")) != EOF){ - switch (c) { - case 'f': - shp_file = optarg; - break; - case 'h': - setenv("PGHOST", optarg, 1); - break; - case 'd': - is3d = 1; - break; - case 'u': - setenv("PGUSER", optarg, 1); - break; - case 'p': - setenv("PGPORT", optarg, 1); - break; - case 'P': - setenv("PGPASSWORD", optarg, 1); - break; - case 'g': - geo_col_name = optarg; - break; - case '?': - errflg=1; - } - } + if ( getenv("ROWBUFLEN") ) rowbuflen=atoi(getenv("ROWBUFLEN")); - curindex=0; - for ( ; optind < ARGC; optind++){ - if(curindex ==0){ - dbName = ARGV[optind]; - setenv("PGDATABASE", dbName, 1); - }else if(curindex == 1){ - table = ARGV[optind]; - } - curindex++; - } - if(curindex != 2){ - errflg = 1; - } + if ( ! parse_commandline(ARGC, ARGV) ) { + printf("\n**ERROR** invalid option or command parameters\n\n"); + usage(2); + exit_nicely(conn); + } - if (errflg==1) { - printf("\n**ERROR** invalid option or command parameters\n"); - printf("\n"); - printf("USAGE: pgsql2shp [] \n"); - printf("\n"); - printf("OPTIONS:\n"); - printf(" -d Set the dump file to 3 dimensions, if this option is not used\n"); - printf(" all dumping will be 2d only.\n"); - printf(" -f Use this option to specify the name of the file\n"); - printf(" to create.\n"); - printf(" -h Allows you to specify connection to a database on a\n"); - printf(" machine other than the localhost.\n"); - printf(" -p Allows you to specify a database port other than 5432.\n"); - printf(" -P Connect to the database with the specified password.\n"); - printf(" -u Connect to the database as the specified user.\n"); - printf(" -g Specify the geometry column to be exported.\n"); - printf("\n"); - exit (2); - } - if(shp_file == NULL){ - shp_file = malloc(strlen(table) + 1); - strcpy(shp_file,table); - } + /* Use table name as shapefile name */ + if(shp_file == NULL) shp_file = table; - /* make a connection to the specified database */ + /* Make a connection to the specified database, and exit on failure */ conn = PQconnectdb(""); - - /* check to see that the backend connection was successfully made */ - if (PQstatus(conn) == CONNECTION_BAD) - { - fprintf(stderr, "Connection to database '%s' failed.\n", dbName); + if (PQstatus(conn) == CONNECTION_BAD) { fprintf(stderr, "%s", PQerrorMessage(conn)); exit_nicely(conn); } @@ -206,74 +161,74 @@ int main(int ARGC, char **ARGV){ #endif /* DEBUG */ + /* Initialize shapefile and database infos */ + fprintf(stdout, "Initializing... "); fflush(stdout); + if ( ! initialize() ) exit_nicely(conn); + fprintf(stdout, "Done.\n"); -//------------------------------------------------------------ -//Get the table data in a cursor - - // begin the transaction + /* + * Begin the transaction + * (a cursor can only be defined inside a transaction block) + */ res=PQexec(conn, "BEGIN"); if ( ! res || PQresultStatus(res) != PGRES_COMMAND_OK ) { - fprintf(stderr, "%s\n", PQerrorMessage(conn)); + fprintf(stderr, "%s", PQerrorMessage(conn)); exit_nicely(conn); } PQclear(res); - // declare a cursor - query= (char *)malloc(strlen(table)+256); - sprintf(query, "DECLARE cur CURSOR FOR SELECT * FROM \"%s\"", table); - //printf("%s\n",query); + /* + * Declare a cursor for the main scan query + * as set by the initializer function. + */ + query = (char *)malloc(strlen(main_scan_query)+256); + sprintf(query, "DECLARE cur CURSOR FOR %s", main_scan_query); +//fprintf(stderr, "MAINSCAN: %s\n", main_scan_query); res = PQexec(conn, query); free(query); if ( ! res || PQresultStatus(res) != PGRES_COMMAND_OK ) { - fprintf(stderr, "%s\n", PQerrorMessage(conn)); + fprintf(stderr, "%s", PQerrorMessage(conn)); exit_nicely(conn); } PQclear(res); -//------------------------------------------------------------ -// Fetch each result in cursor, initialize stuff on first row -//------------------------------------------------------------ + /* Set the fetch query */ + sprintf(fetchquery, "FETCH %d FROM cur", rowbuflen); + fprintf(stdout, "Dumping... "); fflush(stdout); + /* + * Main scan + */ row=0; while(1) { - res = PQexec(conn, "FETCH FROM cur"); + int i; + + /* Fetch next record buffer from cursor */ +#if VERBOSE + fprintf(stdout, "X"); fflush(stdout); +#endif + res = PQexec(conn, fetchquery); if ( ! res || PQresultStatus(res) != PGRES_TUPLES_OK ) { - fprintf(stderr, "%s\n", PQerrorMessage(conn)); + fprintf(stderr, "%s", PQerrorMessage(conn)); exit_nicely(conn); } - // This is our first row.. let's initialize - if ( ! row ) { - - if ( ! PQntuples(res) ) { // No tuples ? Give up ! - fprintf(stderr, "No records in table\n"); - exit_nicely(conn); - } - - printf("Initializing shapefile %s... ", shp_file); - fflush(stdout); - if ( ! initShapefile(shp_file, res) ) - exit_nicely(conn); - printf("done.\n"); - printf("Adding records"); - fflush(stdout); - } - - /* No more rows, end of loop */ + /* No more rows, break the loop */ if ( ! PQntuples(res) ) { PQclear(res); break; } - /* Add record in all output files */ - if ( ! addRecord(res, row) ) exit_nicely(conn); - printf("."); fflush(stdout); - - row++; + for(i=0; i 0 ){ - char *temp_int = (char *)PQgetvalue(res2, 0, 0); - size = atoi(temp_int); - }else{ - size = 32; - } - - } - if(type == 20 || type == 21 || type == 22 || type == 23){ - if(DBFAddField(dbf, field_name,FTInteger,16,0) == -1)printf("error - Field could not be created.\n"); - type_ary[i]=1; - flds++; - }else if(type == 700 || type == 701){ - if(DBFAddField(dbf, field_name,FTDouble,32,10) == -1)printf("error - Field could not be created.\n"); - type_ary[i]=2; - flds++; - } - - // This is a geometry column - // - else if(type == geometry_oid) - { - type_ary[i]=9; //the geometry type field - - // a geometry attribute name as not been specified - if ( ! geo_col_name ) - { - geo_col_name = PQfname(res, i); - geo_col_num = i; - flds++; - } - else if (!strcasecmp(geo_col_name,field_name)) - { - geo_col_num = i; - flds++; - } - } - - else{ - if(DBFAddField(dbf, field_name,FTString,size,0) == -1)printf("error - Field could not be created.\n"); - type_ary[i]=3; - flds++; - } - } - - /* No geometry attribute has been found */ - if ( geo_col_num == -1 ) - { - /* If a geometry column was specified this is an error */ - if ( geo_col_name ) - { - fprintf(stderr, "%s: no such attribute in table %s\n", - geo_col_name, table); - return 0; - } - - /* Otherwise we'll just forget about .shp and .shx files */ - fprintf(stderr, "No geometry column found.\n"); - fprintf(stderr, "The DBF file will be created " - "but not the shx or shp files.\n"); - return 1; - } - - /* - * We now create the appropriate shape (shp) file. - */ - - geotype = getGeometryType(table, geo_col_name); - if ( geotype == -1 ) return 0; - - switch (geotype) - { - case MULTILINETYPE: - if ( is3d ) shp = SHPCreate(shp_file, SHPT_ARCZ); - else shp = SHPCreate(shp_file, SHPT_ARC); - shape_creator = create_multilines; - break; - - case LINETYPE: - if ( is3d ) shp = SHPCreate(shp_file, SHPT_ARCZ); - else shp = SHPCreate(shp_file, SHPT_ARC); - shape_creator = create_lines; - break; - - case POLYGONTYPE: - if ( is3d ) shp = SHPCreate(shp_file, SHPT_POLYGONZ); - else shp = SHPCreate(shp_file, SHPT_POLYGON); - shape_creator = create_polygons; - break; - - case MULTIPOLYGONTYPE: - if ( is3d ) shp = SHPCreate(shp_file, SHPT_POLYGONZ); - else shp = SHPCreate(shp_file, SHPT_POLYGON); - shape_creator = create_multipolygons; - break; - - case POINTTYPE: - if ( is3d ) shp = SHPCreate(shp_file, SHPT_POINTZ); - else shp = SHPCreate(shp_file, SHPT_POINT); - shape_creator = create_points; - break; - - case MULTIPOINTTYPE: - if ( is3d ) shp = SHPCreate(shp_file, SHPT_MULTIPOINTZ); - else shp = SHPCreate(shp_file, SHPT_MULTIPOINT); - shape_creator = create_multipoints; - break; - - - default: - shp = NULL; - shape_creator = NULL; - fprintf(stderr, "You've found a bug! (%s:%d)\n", - __FILE__, __LINE__); - return 0; - - } - - return 1; -} /* @@ -1352,7 +1112,7 @@ initShapefile(char *shp_file, PGresult *res) * Return 0 on failure. */ int -addRecord(PGresult *res, int row) +addRecord(PGresult *res, int residx, int row) { int j; int nFields = PQnfields(res); @@ -1364,8 +1124,11 @@ addRecord(PGresult *res, int row) /* Integer attribute */ if (type_ary[j] == 1) { - val = (char *)PQgetvalue(res, 0, j); + val = (char *)PQgetvalue(res, residx, j); int temp = atoi(val); +#if VERBOSE > 1 +fprintf(stdout, "i"); fflush(stdout); +#endif if (!DBFWriteIntegerAttribute(dbf, row, flds, temp)) { fprintf(stderr, "error(int) - Record could not be created\n"); @@ -1378,8 +1141,11 @@ addRecord(PGresult *res, int row) /* Double attribute */ if (type_ary[j] == 2) { - val = PQgetvalue(res, 0, j); + val = PQgetvalue(res, residx, j); double temp = atof(val); +#if VERBOSE > 1 +fprintf(stdout, "d"); fflush(stdout); +#endif if (!DBFWriteDoubleAttribute(dbf, row, flds, temp)) { fprintf(stderr, "error(double) - Record could " @@ -1393,7 +1159,10 @@ addRecord(PGresult *res, int row) /* Default (not geometry) attribute */ if (type_ary[j] != 9) { - val = PQgetvalue(res, 0, j); + val = PQgetvalue(res, residx, j); +#if VERBOSE > 1 +fprintf(stdout, "s"); fflush(stdout); +#endif if(!DBFWriteStringAttribute(dbf, row, flds, val)) { printf("error(string) - Record could not be " @@ -1406,17 +1175,12 @@ addRecord(PGresult *res, int row) /* If we arrived here it is a geometry attribute */ - /* not the requested one, skipping */ - if ( j != geo_col_num ) continue; - // (All your base belong to us. For great justice.) - val = PQgetvalue(res, 0, j); - if ( ! shape_creator ) - { - fprintf(stderr, "shape_creator is not set...\n"); - return 0; - } + val = PQgetvalue(res, residx, j); +#if VERBOSE > 1 + fprintf(stdout, "g"); fflush(stdout); +#endif if ( ! shape_creator(val, row, shp, is3d) ) { fprintf(stderr, "Error creating shape for record %d " @@ -1434,7 +1198,7 @@ addRecord(PGresult *res, int row) char * getTableOID(char *table) { - PGresult *res3; + PGresult *res3; char *query; char *ret; @@ -1443,7 +1207,7 @@ getTableOID(char *table) res3 = PQexec(conn, query); free(query); if ( ! res3 || PQresultStatus(res3) != PGRES_TUPLES_OK ) { - fprintf(stderr, "%s\n", PQerrorMessage(conn)); + fprintf(stderr, "%s", PQerrorMessage(conn)); exit_nicely(conn); } if(PQntuples(res3) == 1 ){ @@ -1476,7 +1240,7 @@ getGeometryType(char *table, char *geo_col_name) //printf("\n\n-->%s\n\n",query); res = PQexec(conn, query); if ( ! res || PQresultStatus(res) != PGRES_TUPLES_OK ) { - fprintf(stderr, "%s\n", PQerrorMessage(conn)); + fprintf(stderr, "%s", PQerrorMessage(conn)); return -1; } @@ -1504,3 +1268,414 @@ getGeometryType(char *table, char *geo_col_name) "or shp files.\n"); return 0; } + +void +usage(status) +{ + printf("USAGE: pgsql2shp []
\n"); + printf("\n"); + printf("OPTIONS:\n"); + printf(" -d Set the dump file to 3 dimensions, if this option is not used\n"); + printf(" all dumping will be 2d only.\n"); + printf(" -f Use this option to specify the name of the file\n"); + printf(" to create.\n"); + printf(" -h Allows you to specify connection to a database on a\n"); + printf(" machine other than the default.\n"); + printf(" -p Allows you to specify a database port other than the default.\n"); + printf(" -P Connect to the database with the specified password.\n"); + printf(" -u Connect to the database as the specified user.\n"); + printf(" -g Specify the geometry column to be exported.\n"); + printf("\n"); + exit (status); +} + +/* Parse command line parameters */ +int parse_commandline(int ARGC, char **ARGV) +{ + int c, curindex; + + /* Parse command line */ + while ((c = getopt(ARGC, ARGV, "f:h:du:p:P:g:")) != EOF){ + switch (c) { + case 'f': + shp_file = optarg; + break; + case 'h': + setenv("PGHOST", optarg, 1); + break; + case 'd': + is3d = 1; + break; + case 'u': + setenv("PGUSER", optarg, 1); + break; + case 'p': + setenv("PGPORT", optarg, 1); + break; + case 'P': + setenv("PGPASSWORD", optarg, 1); + break; + case 'g': + geo_col_name = optarg; + break; + case '?': + return 0; + } + } + + curindex=0; + for ( ; optind < ARGC; optind++){ + if(curindex ==0){ + setenv("PGDATABASE", ARGV[optind], 1); + }else if(curindex == 1){ + table = ARGV[optind]; + } + curindex++; + } + if(curindex != 2) return 0; + return 1; +} + +/* + * Initialize shapefile files, main scan query, + * type array. + */ +int +initialize() +{ + PGresult *res; + char *query; + int i; + char buf[256]; + int tmpint; + int geo_oid; // geometry oid + int geom_fld = -1; + char *mainscan_flds[256]; + int mainscan_nflds=0; + + /* Query user attributes name, type and size */ + query = (char *)malloc(sizeof(table)+256); + if ( ! query ) return 0; // out of virtual memory + sprintf(query, "SELECT a.attname, a.atttypid, a.attlen FROM " + "pg_attribute a, pg_class c WHERE " + "a.attrelid = c.oid and a.attnum > 0 AND " + "c.relname = '%s'", table); + + /* Exec query */ + //fprintf(stderr, "Attribute query:\n%s\n", query); + res = PQexec(conn, query); + free(query); + if ( ! res || PQresultStatus(res) != PGRES_TUPLES_OK ) { + fprintf(stderr, "%s", PQerrorMessage(conn)); + return 0; + } + if (! PQntuples(res)) { + fprintf(stderr, "Table %s does not exist\n", table); + PQclear(res); + return 0; + } + + /* Create the dbf file */ + dbf = DBFCreate(shp_file); + if ( ! dbf ) { + fprintf(stderr, "Could not create dbf file\n"); + return 0; + } + + /* Get geometry oid */ + geo_oid = getGeometryOID(conn); + if ( geo_oid == -1 ) + { + PQclear(res); + return 0; + } + + /* + * Scan the result setting fields to be returned in mainscan + * query, filling the type_ary, and creating .dbf and .shp files. + */ + for (i=0; i