]> granicus.if.org Git - postgis/commitdiff
Support for srid reprojection when using -D switch
authorRegina Obe <lr@pcorp.us>
Sun, 28 Jul 2019 21:14:48 +0000 (21:14 +0000)
committerRegina Obe <lr@pcorp.us>
Sun, 28 Jul 2019 21:14:48 +0000 (21:14 +0000)
References #4403
Tests forthcoming

git-svn-id: http://svn.osgeo.org/postgis/trunk@17621 b70326c6-7e19-0410-871a-916f4a2858ee

NEWS
doc/using_postgis_dataman.xml
loader/README.shp2pgsql
loader/shp2pgsql-cli.c
loader/shp2pgsql-core.c
loader/shp2pgsql-core.h

diff --git a/NEWS b/NEWS
index e5fa78e1814a044b535c635b0ac0ac683f5b937a..814a7b9754074e47e156a85e1034de7c2f27400a 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -16,6 +16,7 @@ Additional features enabled if you are running Proj6+ and PostgreSQL 12
   - #4454, Speed up _ST_OrderingEquals (Raúl Marín)
   - #4453, Speed up ST_IsEmpty (Raúl Marín)
   - #4271, postgis_extensions_upgrade() also updates after pg_upgrade (Raúl Marín)
+  - #4403, Support for shp2pgsql ability to reproject with copy mode (-D) (Regina Obe)
 
 PostGIS 3.0.0alpha3
 2019/07/01
index d84c4c42941dae4ab9addcabbc676fa2018ca3d8..8c2a95d10b9ba293808f8ee7d33bfaa4c2f31db6 100644 (file)
@@ -1672,7 +1672,6 @@ COMMIT;</programlisting>
           Optionally specifies that the input shapefile uses the given
           FROM_SRID, in which case the geometries will be reprojected to the
           target SRID.
-         FROM_SRID cannot be specified with -D.
         </para>
       </listitem>
     </varlistentry>
index 9e8b20d540fa425df4d3800c75260cb9549143ef..37ff700d344a103dff8c72a363e3327e713794ae 100644 (file)
@@ -53,9 +53,12 @@ OPTIONS
               the default "insert" SQL format. Use this for  very  large  data
               sets.
 
-       -s <SRID>
-              Creates  and  populates  the  geometry tables with the specified
-              SRID.
+       -s [<FROM_SRID>:]<SRID>
+              Creates and populates the geometry tables with the specified SRID.
+              Optionally specifies that the input shapefile uses the given
+              FROM_SRID, in which case the geometries will be reprojected 
+              to the target SRID.
+
 
        -g <geometry_column>
               Specify the name of the geometry column (mostly useful in append
@@ -113,8 +116,9 @@ EXAMPLES
 
 
 AUTHORS
-       Originally   written   by  Jeff  Lounsbury  <jeffloun@refractions.net>.
-       Improved and  maintained  by  Sandro  Santilli  <strk@kbt.io>.
+       Originally written by Jeff Lounsbury <jeffloun@refractions.net>.
+       Improved and maintained by 
+       Sandro Santilli <strk@kbt.io>, Regina Obe <lr@pcorp.us>.
        Includes small contributions and improvements by others.
 
        This  application  uses  functionality  from  shapelib  1.2.9  by Frank
index 6271b7659366c0baa1fd3223cd6ac30b008c968a..678e91a11e8507a3a72c806f181bcd7cc0988795 100644 (file)
@@ -24,7 +24,7 @@ usage()
        printf(_( "USAGE: shp2pgsql [<options>] <shapefile> [[<schema>.]<table>]\n"
                  "OPTIONS:\n" ));
        printf(_( "  -s [<from>:]<srid> Set the SRID field. Defaults to %d.\n"
-                 "      Optionally reprojects from given SRID (cannot be used with -D).\n"),
+                 "      Optionally reprojects from given SRID.\n"),
                  SRID_UNKNOWN);
        printf(_( " (-d|a|c|p) These are mutually exclusive options:\n"
                  "     -d  Drops the table, then recreates it and populates\n"
@@ -250,12 +250,6 @@ main (int argc, char **argv)
                exit(1);
        }
 
-       if (config->dump_format && config->shp_sr_id != SRID_UNKNOWN)
-       {
-               fprintf(stderr, "Invalid argument combination - cannot use -D with -s FROM_SRID:TO_SRID\n");
-               exit(1);
-       }
-
        /* Determine the shapefile name from the next argument, if no shape file, exit. */
        if (pgis_optind < argc)
        {
index b11f0eb24c8764c8d33a9443e39fbfda390c1d91..aa6970478d3db3060afac6d550c1ba8d0a2fa94e 100644 (file)
@@ -786,6 +786,7 @@ ShpLoaderCreate(SHPLOADERCONFIG *config)
        state->widths = NULL;
        state->precisions = NULL;
        state->col_names = NULL;
+       state->col_names_no_paren = NULL;
        state->field_names = NULL;
        state->num_fields = 0;
        state->pgfieldtypes = NULL;
@@ -1090,10 +1091,11 @@ ShpLoaderOpenShape(SHPLOADERSTATE *state)
        state->precisions = malloc(state->num_fields * sizeof(int));
        state->pgfieldtypes = malloc(state->num_fields * sizeof(char *));
        state->col_names = malloc((state->num_fields + 2) * sizeof(char) * MAXFIELDNAMELEN);
+       state->col_names_no_paren = malloc((state->num_fields + 2) * sizeof(char) * MAXFIELDNAMELEN);
 
-       /* Generate a string of comma separated column names of the form "(col1, col2 ... colN)" for the SQL
+       strcpy(state->col_names_no_paren, "" );
+       /* Generate a string of comma separated column names of the form "col1, col2 ... colN" for the SQL
           insertion string */
-       strcpy(state->col_names, "(" );
 
        for (j = 0; j < state->num_fields; j++)
        {
@@ -1243,23 +1245,27 @@ ShpLoaderOpenShape(SHPLOADERSTATE *state)
                        return SHPLOADERERR;
                }
 
-               strcat(state->col_names, "\"");
-               strcat(state->col_names, name);
+               strcat(state->col_names_no_paren, "\"");
+               strcat(state->col_names_no_paren, name);
 
                if (state->config->readshape == 1 || j < (state->num_fields - 1))
                {
                        /* Don't include last comma if its the last field and no geometry field will follow */
-                       strcat(state->col_names, "\",");
+                       strcat(state->col_names_no_paren, "\",");
                }
                else
                {
-                       strcat(state->col_names, "\"");
+                       strcat(state->col_names_no_paren, "\"");
                }
        }
 
        /* Append the geometry column if required */
        if (state->config->readshape == 1)
-               strcat(state->col_names, state->geo_col);
+               strcat(state->col_names_no_paren, state->geo_col);
+
+       /** Create with (col1,col2,..) ( **/
+       strcpy(state->col_names, "(" );
+       strcat(state->col_names, state->col_names_no_paren);
 
        strcat(state->col_names, ")");
 
@@ -1455,6 +1461,23 @@ ShpLoaderGetSQLHeader(SHPLOADERSTATE *state, char **strheader)
                }
        }
 
+                       
+       /**If we are in dump mode and a transform was asked for need to create a temp table to store original data
+        You may ask, why don't we go straight into the main table and then do an alter table alter column afterwards
+        Main reason is so we don't incur the penalty of WAL logging when we change the typmod in final run. **/
+       if (state->config->dump_format && state->to_srid != state->from_srid){
+               /** create a temp table with same structure as main except for no restriction on geometry type */
+               stringbuffer_aprintf(sb, "CREATE TEMP TABLE \"pgis_tmp_%s\" AS SELECT * FROM ", state->config->table);
+               /* Schema is optional, include if present. */
+               if (state->config->schema)
+               {
+                       stringbuffer_aprintf(sb, "\"%s\".",state->config->schema);
+               }
+               stringbuffer_aprintf(sb, "\"%s\" WHERE false;\n", state->config->table, state->geo_col);
+               /**out input data is going to be in different srid from target, so need to remove type constraint **/
+               stringbuffer_aprintf(sb, "ALTER TABLE \"pgis_tmp_%s\" ALTER COLUMN \"%s\" TYPE geometry USING ( (\"%s\"::geometry) ); \n", state->config->table,  state->geo_col, state->geo_col);
+       }
+
        /* Copy the string buffer into a new string, destroying the string buffer */
        ret = (char *)malloc(strlen((char *)stringbuffer_getstring(sb)) + 1);
        strcpy(ret, (char *)stringbuffer_getstring(sb));
@@ -1470,27 +1493,38 @@ ShpLoaderGetSQLHeader(SHPLOADERSTATE *state, char **strheader)
 int
 ShpLoaderGetSQLCopyStatement(SHPLOADERSTATE *state, char **strheader)
 {
-       char *copystr;
+       //char *copystr;
+       stringbuffer_t *sb;
+       char *ret;
+       sb = stringbuffer_create();
+       stringbuffer_clear(sb);
+
 
        /* Allocate the string for the COPY statement */
        if (state->config->dump_format)
        {
-               if (state->config->schema)
-               {
-                       copystr = malloc(strlen(state->config->schema) + strlen(state->config->table) +
-                                        strlen(state->col_names) + 40);
+               stringbuffer_aprintf(sb, "COPY ");
 
-                       sprintf(copystr, "COPY \"%s\".\"%s\" %s FROM stdin;\n",
-                               state->config->schema, state->config->table, state->col_names);
+               if (state->to_srid != state->from_srid){
+                       /** if we need to transform we copy into temp table instead of main table first */
+                       stringbuffer_aprintf(sb, " \"pgis_tmp_%s\" %s FROM stdin;\n", state->config->table, state->col_names);
                }
-               else
-               {
-                       copystr = malloc(strlen(state->config->table) + strlen(state->col_names) + 40);
+               else {
+                       if (state->config->schema)
+                       {
+                               stringbuffer_aprintf(sb, " \"%s\".\" ", state->config->schema);
+                       }
 
-                       sprintf(copystr, "COPY \"%s\" %s FROM stdin;\n", state->config->table, state->col_names);
+                       stringbuffer_aprintf(sb, " \"%s\" %s FROM stdin;\n", state->config->table, state->col_names);
                }
-
-               *strheader = copystr;
+               
+       
+               /* Copy the string buffer into a new string, destroying the string buffer */
+               ret = (char *)malloc(strlen((char *)stringbuffer_getstring(sb)) + 1);
+               strcpy(ret, (char *)stringbuffer_getstring(sb));
+               stringbuffer_destroy(sb);
+
+               *strheader = ret;
                return SHPLOADEROK;
        }
        else
@@ -1836,6 +1870,26 @@ ShpLoaderGetSQLFooter(SHPLOADERSTATE *state, char **strfooter)
        sb = stringbuffer_create();
        stringbuffer_clear(sb);
 
+       
+       if ( state->config->dump_format && state->to_srid != state->from_srid){
+               /** We need to copy from the temp table to the real table, transforming to to_srid **/
+               stringbuffer_aprintf(sb, "ALTER TABLE  \"pgis_tmp_%s\" ALTER COLUMN \"%s\" TYPE ",   state->config->table, state->geo_col );
+               if (state->config->geography){
+                       stringbuffer_aprintf(sb, "geography USING (ST_Transform(\"%s\", %d)::geography );\n", state->geo_col, state->to_srid);
+               }
+               else {
+                       stringbuffer_aprintf(sb, "geometry USING (ST_Transform(\"%s\", %d)::geometry );\n", state->geo_col, state->to_srid);
+               }
+               stringbuffer_aprintf(sb, "INSERT INTO ");
+               // /* Schema is optional, include if present. */
+               if (state->config->schema)
+               {
+                       stringbuffer_aprintf(sb, "\"%s\".", state->config->schema);
+               }
+               stringbuffer_aprintf(sb, "\"%s\" %s ", state->config->table, state->col_names);
+               stringbuffer_aprintf(sb, "SELECT %s FROM \"pgis_tmp_%s\";\n", state->col_names_no_paren, state->config->table );
+       }
+
        /* Create gist index if specified and not in "prepare" mode */
        if (state->config->readshape && state->config->createindex)
        {
@@ -1913,6 +1967,9 @@ ShpLoaderDestroy(SHPLOADERSTATE *state)
                if (state->col_names)
                        free(state->col_names);
 
+               if (state->col_names_no_paren)
+                       free(state->col_names_no_paren);
+
                /* Free any column map fieldnames if specified */
                colmap_clean(&state->column_map);
 
index 490e185223eb31288dc701c01579ead6a36375e7..5263324a419aa6f3e40376da13766362dc6392bd 100644 (file)
@@ -192,6 +192,9 @@ typedef struct shp_loader_state
        /* String containing colume name list in the form "(col1, col2, col3 ... , colN)" */
        char *col_names;
 
+       /* String containing colume name list in the form "col1, col2, col3 ... , colN" */
+       char *col_names_no_paren;
+
        /* String containing the PostGIS geometry type, e.g. POINT, POLYGON etc. */
        char *pgtype;