static CPLString OGRPGDumpEscapeStringList( char** papszItems, int bForInsertOrUpdate) { int bFirstItem = TRUE; CPLString osStr; if (bForInsertOrUpdate) osStr += "ARRAY["; else osStr += "{"; while(papszItems && *papszItems) { if (!bFirstItem) { osStr += ','; } char* pszStr = *papszItems; if (*pszStr != '\0') { if (bForInsertOrUpdate) osStr += OGRPGDumpEscapeString(pszStr); else { osStr += '"'; while(*pszStr) { if (*pszStr == '"' ) osStr += "\\"; osStr += *pszStr; pszStr++; } osStr += '"'; } } else osStr += "NULL"; bFirstItem = FALSE; papszItems++; } if (bForInsertOrUpdate) { osStr += "]"; if( papszItems == NULL ) osStr += "::varchar[]"; } else osStr += "}"; return osStr; }
void OGRPGDumpLayer::AppendFieldValue(CPLString& osCommand, OGRFeature* poFeature, int i) { int nOGRFieldType = poFeatureDefn->GetFieldDefn(i)->GetType(); // We need special formatting for integer list values. if( nOGRFieldType == OFTIntegerList ) { int nCount, nOff = 0, j; const int *panItems = poFeature->GetFieldAsIntegerList(i,&nCount); char *pszNeedToFree = NULL; pszNeedToFree = (char *) CPLMalloc(nCount * 13 + 10); strcpy( pszNeedToFree, "'{" ); for( j = 0; j < nCount; j++ ) { if( j != 0 ) strcat( pszNeedToFree+nOff, "," ); nOff += strlen(pszNeedToFree+nOff); sprintf( pszNeedToFree+nOff, "%d", panItems[j] ); } strcat( pszNeedToFree+nOff, "}'" ); osCommand += pszNeedToFree; CPLFree(pszNeedToFree); return; } // We need special formatting for real list values. else if( nOGRFieldType == OFTRealList ) { int nCount, nOff = 0, j; const double *padfItems =poFeature->GetFieldAsDoubleList(i,&nCount); char *pszNeedToFree = NULL; pszNeedToFree = (char *) CPLMalloc(nCount * 40 + 10); strcpy( pszNeedToFree, "'{" ); for( j = 0; j < nCount; j++ ) { if( j != 0 ) strcat( pszNeedToFree+nOff, "," ); nOff += strlen(pszNeedToFree+nOff); //Check for special values. They need to be quoted. if( CPLIsNan(padfItems[j]) ) sprintf( pszNeedToFree+nOff, "NaN" ); else if( CPLIsInf(padfItems[j]) ) sprintf( pszNeedToFree+nOff, (padfItems[j] > 0) ? "Infinity" : "-Infinity" ); else sprintf( pszNeedToFree+nOff, "%.16g", padfItems[j] ); } strcat( pszNeedToFree+nOff, "}'" ); osCommand += pszNeedToFree; CPLFree(pszNeedToFree); return; } // We need special formatting for string list values. else if( nOGRFieldType == OFTStringList ) { char **papszItems = poFeature->GetFieldAsStringList(i); osCommand += OGRPGDumpEscapeStringList(papszItems, TRUE); return; } // Binary formatting else if( nOGRFieldType == OFTBinary ) { osCommand += "'"; int nLen = 0; GByte* pabyData = poFeature->GetFieldAsBinary( i, &nLen ); char* pszBytea = GByteArrayToBYTEA( pabyData, nLen); osCommand += pszBytea; CPLFree(pszBytea); osCommand += "'"; return; } // Flag indicating NULL or not-a-date date value // e.g. 0000-00-00 - there is no year 0 OGRBoolean bIsDateNull = FALSE; const char *pszStrValue = poFeature->GetFieldAsString(i); // Check if date is NULL: 0000-00-00 if( nOGRFieldType == OFTDate ) { if( EQUALN( pszStrValue, "0000", 4 ) ) { pszStrValue = "NULL"; bIsDateNull = TRUE; } } else if ( nOGRFieldType == OFTReal ) { char* pszComma = strchr((char*)pszStrValue, ','); if (pszComma) *pszComma = '.'; //Check for special values. They need to be quoted. double dfVal = poFeature->GetFieldAsDouble(i); if( CPLIsNan(dfVal) ) pszStrValue = "'NaN'"; else if( CPLIsInf(dfVal) ) pszStrValue = (dfVal > 0) ? "'Infinity'" : "'-Infinity'"; } if( nOGRFieldType != OFTInteger && nOGRFieldType != OFTReal && !bIsDateNull ) { osCommand += OGRPGDumpEscapeString( pszStrValue, poFeatureDefn->GetFieldDefn(i)->GetWidth(), poFeatureDefn->GetFieldDefn(i)->GetNameRef() ); } else { osCommand += pszStrValue; } }
OGRErr OGRPGDumpLayer::CreateGeomField( OGRGeomFieldDefn *poGeomFieldIn, CPL_UNUSED int bApproxOK ) { OGRwkbGeometryType eType = poGeomFieldIn->GetType(); if( eType == wkbNone ) { CPLError(CE_Failure, CPLE_AppDefined, "Cannot create geometry field of type wkbNone"); return OGRERR_FAILURE; } CPLString osCommand; OGRPGDumpGeomFieldDefn *poGeomField = new OGRPGDumpGeomFieldDefn( poGeomFieldIn ); /* -------------------------------------------------------------------- */ /* Do we want to "launder" the column names into Postgres */ /* friendly format? */ /* -------------------------------------------------------------------- */ if( bLaunderColumnNames ) { char *pszSafeName = poDS->LaunderName( poGeomField->GetNameRef() ); poGeomField->SetName( pszSafeName ); CPLFree( pszSafeName ); } OGRSpatialReference* poSRS = poGeomField->GetSpatialRef(); int nSRSId = nUnknownSRSId; if( nForcedSRSId != -2 ) nSRSId = nForcedSRSId; else if( poSRS != NULL ) { const char* pszAuthorityName = poSRS->GetAuthorityName(NULL); if( pszAuthorityName != NULL && EQUAL( pszAuthorityName, "EPSG" ) ) { /* Assume the EPSG Id is the SRS ID. Might be a wrong guess ! */ nSRSId = atoi( poSRS->GetAuthorityCode(NULL) ); } else { const char* pszGeogCSName = poSRS->GetAttrValue("GEOGCS"); if (pszGeogCSName != NULL && EQUAL(pszGeogCSName, "GCS_WGS_1984")) nSRSId = 4326; } } int nDimension = 3; if( wkbFlatten(eType) == eType ) nDimension = 2; poGeomField->nSRSId = nSRSId; poGeomField->nCoordDimension = nDimension; /* -------------------------------------------------------------------- */ /* Create the new field. */ /* -------------------------------------------------------------------- */ if (bCreateTable) { const char *pszGeometryType = OGRToOGCGeomType(poGeomField->GetType()); osCommand.Printf( "SELECT AddGeometryColumn(%s,%s,%s,%d,'%s',%d)", OGRPGDumpEscapeString(pszSchemaName).c_str(), OGRPGDumpEscapeString(poFeatureDefn->GetName()).c_str(), OGRPGDumpEscapeString(poGeomField->GetNameRef()).c_str(), nSRSId, pszGeometryType, nDimension ); poDS->Log(osCommand); if( bCreateSpatialIndexFlag ) { osCommand.Printf("CREATE INDEX %s ON %s USING GIST (%s)", OGRPGDumpEscapeColumnName( CPLSPrintf("%s_%s_geom_idx", GetName(), poGeomField->GetNameRef())).c_str(), pszSqlTableName, OGRPGDumpEscapeColumnName(poGeomField->GetNameRef()).c_str()); poDS->Log(osCommand); } } poFeatureDefn->AddGeomFieldDefn( poGeomField, FALSE ); return OGRERR_NONE; }
OGRLayer * OGRPGDumpDataSource::ICreateLayer( const char * pszLayerName, OGRSpatialReference *poSRS, OGRwkbGeometryType eType, char ** papszOptions ) { CPLString osCommand; const char *pszGeomType = NULL; char *pszTableName = NULL; char *pszSchemaName = NULL; int nDimension = 3; int bHavePostGIS = TRUE; const char* pszFIDColumnNameIn = CSLFetchNameValue(papszOptions, "FID"); CPLString osFIDColumnName, osFIDColumnNameEscaped; if (pszFIDColumnNameIn == NULL) osFIDColumnName = "ogc_fid"; else { if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) ) { char* pszLaunderedFid = OGRPGCommonLaunderName(pszFIDColumnNameIn, "PGDump"); osFIDColumnName = pszLaunderedFid; CPLFree(pszLaunderedFid); } else { osFIDColumnName = pszFIDColumnNameIn; } } osFIDColumnNameEscaped = OGRPGDumpEscapeColumnName(osFIDColumnName); if (strncmp(pszLayerName, "pg", 2) == 0) { CPLError(CE_Warning, CPLE_AppDefined, "The layer name should not begin by 'pg' as it is a reserved prefix"); } //bHavePostGIS = CSLFetchBoolean(papszOptions,"POSTGIS", TRUE); int bCreateTable = CSLFetchBoolean(papszOptions,"CREATE_TABLE", TRUE); int bCreateSchema = CSLFetchBoolean(papszOptions,"CREATE_SCHEMA", TRUE); const char* pszDropTable = CSLFetchNameValueDef(papszOptions,"DROP_TABLE", "IF_EXISTS"); if( wkbFlatten(eType) == eType ) nDimension = 2; if( CSLFetchNameValue( papszOptions, "DIM") != NULL ) nDimension = atoi(CSLFetchNameValue( papszOptions, "DIM")); /* Should we turn layers with None geometry type as Unknown/GEOMETRY */ /* so they are still recorded in geometry_columns table ? (#4012) */ int bNoneAsUnknown = CSLTestBoolean(CSLFetchNameValueDef( papszOptions, "NONE_AS_UNKNOWN", "NO")); if (bNoneAsUnknown && eType == wkbNone) eType = wkbUnknown; else if (eType == wkbNone) bHavePostGIS = FALSE; int bExtractSchemaFromLayerName = CSLTestBoolean(CSLFetchNameValueDef( papszOptions, "EXTRACT_SCHEMA_FROM_LAYER_NAME", "YES")); /* Postgres Schema handling: Extract schema name from input layer name or passed with -lco SCHEMA. Set layer name to "schema.table" or to "table" if schema == current_schema() Usage without schema name is backwards compatible */ const char* pszDotPos = strstr(pszLayerName,"."); if ( pszDotPos != NULL && bExtractSchemaFromLayerName ) { int length = pszDotPos - pszLayerName; pszSchemaName = (char*)CPLMalloc(length+1); strncpy(pszSchemaName, pszLayerName, length); pszSchemaName[length] = '\0'; if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) ) pszTableName = OGRPGCommonLaunderName( pszDotPos + 1, "PGDump" ); //skip "." else pszTableName = CPLStrdup( pszDotPos + 1 ); //skip "." } else { pszSchemaName = NULL; if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) ) pszTableName = OGRPGCommonLaunderName( pszLayerName, "PGDump" ); //skip "." else pszTableName = CPLStrdup( pszLayerName ); //skip "." } LogCommit(); /* -------------------------------------------------------------------- */ /* Set the default schema for the layers. */ /* -------------------------------------------------------------------- */ if( CSLFetchNameValue( papszOptions, "SCHEMA" ) != NULL ) { CPLFree(pszSchemaName); pszSchemaName = CPLStrdup(CSLFetchNameValue( papszOptions, "SCHEMA" )); if (bCreateSchema) { osCommand.Printf("CREATE SCHEMA \"%s\"", pszSchemaName); Log(osCommand); } } if ( pszSchemaName == NULL) { pszSchemaName = CPLStrdup("public"); } /* -------------------------------------------------------------------- */ /* Do we already have this layer? */ /* -------------------------------------------------------------------- */ int iLayer; for( iLayer = 0; iLayer < nLayers; iLayer++ ) { if( EQUAL(pszLayerName,papoLayers[iLayer]->GetLayerDefn()->GetName()) ) { CPLError( CE_Failure, CPLE_AppDefined, "Layer %s already exists, CreateLayer failed.\n", pszLayerName ); CPLFree( pszTableName ); CPLFree( pszSchemaName ); return NULL; } } if (bCreateTable && (EQUAL(pszDropTable, "YES") || EQUAL(pszDropTable, "ON") || EQUAL(pszDropTable, "TRUE") || EQUAL(pszDropTable, "IF_EXISTS"))) { if (EQUAL(pszDropTable, "IF_EXISTS")) osCommand.Printf("DROP TABLE IF EXISTS \"%s\".\"%s\" CASCADE", pszSchemaName, pszTableName ); else osCommand.Printf("DROP TABLE \"%s\".\"%s\" CASCADE", pszSchemaName, pszTableName ); Log(osCommand); } /* -------------------------------------------------------------------- */ /* Handle the GEOM_TYPE option. */ /* -------------------------------------------------------------------- */ pszGeomType = CSLFetchNameValue( papszOptions, "GEOM_TYPE" ); if( pszGeomType == NULL ) { pszGeomType = "geometry"; } if( !EQUAL(pszGeomType,"geometry") && !EQUAL(pszGeomType, "geography")) { CPLError( CE_Failure, CPLE_AppDefined, "GEOM_TYPE in PostGIS enabled databases must be 'geometry' or 'geography'.\n" "Creation of layer %s with GEOM_TYPE %s has failed.", pszLayerName, pszGeomType ); CPLFree( pszTableName ); CPLFree( pszSchemaName ); return NULL; } /* -------------------------------------------------------------------- */ /* Try to get the SRS Id of this spatial reference system, */ /* adding tot the srs table if needed. */ /* -------------------------------------------------------------------- */ int nUnknownSRSId = -1; const char* pszPostgisVersion = CSLFetchNameValue( papszOptions, "POSTGIS_VERSION" ); int bPostGIS2 = FALSE; if( pszPostgisVersion != NULL && atoi(pszPostgisVersion) >= 2 ) { bPostGIS2 = TRUE; nUnknownSRSId = 0; } int nSRSId = nUnknownSRSId; int nForcedSRSId = -2; if( CSLFetchNameValue( papszOptions, "SRID") != NULL ) { nSRSId = atoi(CSLFetchNameValue( papszOptions, "SRID")); nForcedSRSId = nSRSId; } else { if (poSRS) { const char* pszAuthorityName = poSRS->GetAuthorityName(NULL); if( pszAuthorityName != NULL && EQUAL( pszAuthorityName, "EPSG" ) ) { /* Assume the EPSG Id is the SRS ID. Might be a wrong guess ! */ nSRSId = atoi( poSRS->GetAuthorityCode(NULL) ); } else { const char* pszGeogCSName = poSRS->GetAttrValue("GEOGCS"); if (pszGeogCSName != NULL && EQUAL(pszGeogCSName, "GCS_WGS_1984")) nSRSId = 4326; } } } CPLString osEscapedTableNameSingleQuote = OGRPGDumpEscapeString(pszTableName); const char* pszEscapedTableNameSingleQuote = osEscapedTableNameSingleQuote.c_str(); const char *pszGeometryType = OGRToOGCGeomType(eType); const char *pszGFldName = NULL; if( bHavePostGIS && !EQUAL(pszGeomType, "geography")) { if( CSLFetchNameValue( papszOptions, "GEOMETRY_NAME") != NULL ) pszGFldName = CSLFetchNameValue( papszOptions, "GEOMETRY_NAME"); else pszGFldName = "wkb_geometry"; if( pszPostgisVersion == NULL || atoi(pszPostgisVersion) < 2 ) { /* Sometimes there is an old cruft entry in the geometry_columns * table if things were not properly cleaned up before. We make * an effort to clean out such cruft. * Note: PostGIS 2.0 defines geometry_columns as a view (no clean up is needed) */ osCommand.Printf( "DELETE FROM geometry_columns WHERE f_table_name = %s AND f_table_schema = '%s'", pszEscapedTableNameSingleQuote, pszSchemaName ); if (bCreateTable) Log(osCommand); } } LogStartTransaction(); /* -------------------------------------------------------------------- */ /* Create a basic table with the FID. Also include the */ /* geometry if this is not a PostGIS enabled table. */ /* -------------------------------------------------------------------- */ int bFID64 = CSLFetchBoolean(papszOptions, "FID64", FALSE); const char* pszSerialType = bFID64 ? "BIGSERIAL": "SERIAL"; CPLString osCreateTable; int bTemporary = CSLFetchBoolean( papszOptions, "TEMPORARY", FALSE ); if (bTemporary) { CPLFree(pszSchemaName); pszSchemaName = CPLStrdup("pg_temp_1"); osCreateTable.Printf("CREATE TEMPORARY TABLE \"%s\"", pszTableName); } else osCreateTable.Printf("CREATE TABLE%s \"%s\".\"%s\"", CSLFetchBoolean( papszOptions, "UNLOGGED", FALSE ) ? " UNLOGGED": "", pszSchemaName, pszTableName); if( !bHavePostGIS ) { if (eType == wkbNone) osCommand.Printf( "%s ( " " %s %s, " " CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )", osCreateTable.c_str(), osFIDColumnNameEscaped.c_str(), pszSerialType, pszTableName, osFIDColumnNameEscaped.c_str() ); else osCommand.Printf( "%s ( " " %s %s, " " WKB_GEOMETRY %s, " " CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )", osCreateTable.c_str(), osFIDColumnNameEscaped.c_str(), pszSerialType, pszGeomType, pszTableName, osFIDColumnNameEscaped.c_str() ); } else if ( EQUAL(pszGeomType, "geography") ) { if( CSLFetchNameValue( papszOptions, "GEOMETRY_NAME") != NULL ) pszGFldName = CSLFetchNameValue( papszOptions, "GEOMETRY_NAME"); else pszGFldName = "the_geog"; if (nSRSId) osCommand.Printf( "%s ( %s %s, \"%s\" geography(%s%s,%d), CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )", osCreateTable.c_str(), osFIDColumnNameEscaped.c_str(), pszSerialType, pszGFldName, pszGeometryType, nDimension == 2 ? "" : "Z", nSRSId, pszTableName, osFIDColumnNameEscaped.c_str() ); else osCommand.Printf( "%s ( %s %s, \"%s\" geography(%s%s), CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )", osCreateTable.c_str(), osFIDColumnNameEscaped.c_str(), pszSerialType, pszGFldName, pszGeometryType, nDimension == 2 ? "" : "Z", pszTableName, osFIDColumnNameEscaped.c_str() ); } else { osCommand.Printf( "%s ( %s %s, CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )", osCreateTable.c_str(), osFIDColumnNameEscaped.c_str(), pszSerialType, pszTableName, osFIDColumnNameEscaped.c_str() ); } if (bCreateTable) Log(osCommand); /* -------------------------------------------------------------------- */ /* Eventually we should be adding this table to a table of */ /* "geometric layers", capturing the WKT projection, and */ /* perhaps some other housekeeping. */ /* -------------------------------------------------------------------- */ if( bCreateTable && bHavePostGIS && !EQUAL(pszGeomType, "geography")) { osCommand.Printf( "SELECT AddGeometryColumn('%s',%s,'%s',%d,'%s',%d)", pszSchemaName, pszEscapedTableNameSingleQuote, pszGFldName, nSRSId, pszGeometryType, nDimension ); Log(osCommand); } const char *pszSI = CSLFetchNameValue( papszOptions, "SPATIAL_INDEX" ); int bCreateSpatialIndex = ( pszSI == NULL || CSLTestBoolean(pszSI) ); if( bCreateTable && bHavePostGIS && bCreateSpatialIndex ) { /* -------------------------------------------------------------------- */ /* Create the spatial index. */ /* */ /* We're doing this before we add geometry and record to the table */ /* so this may not be exactly the best way to do it. */ /* -------------------------------------------------------------------- */ osCommand.Printf("CREATE INDEX \"%s_%s_geom_idx\" " "ON \"%s\".\"%s\" " "USING GIST (\"%s\")", pszTableName, pszGFldName, pszSchemaName, pszTableName, pszGFldName); Log(osCommand); } /* -------------------------------------------------------------------- */ /* Create the layer object. */ /* -------------------------------------------------------------------- */ OGRPGDumpLayer *poLayer; int bWriteAsHex = !CSLFetchBoolean(papszOptions,"WRITE_EWKT_GEOM",FALSE); poLayer = new OGRPGDumpLayer( this, pszSchemaName, pszTableName, osFIDColumnName, bWriteAsHex, bCreateTable ); poLayer->SetLaunderFlag( CSLFetchBoolean(papszOptions,"LAUNDER",TRUE) ); poLayer->SetPrecisionFlag( CSLFetchBoolean(papszOptions,"PRECISION",TRUE)); const char* pszOverrideColumnTypes = CSLFetchNameValue( papszOptions, "COLUMN_TYPES" ); poLayer->SetOverrideColumnTypes(pszOverrideColumnTypes); poLayer->SetUnknownSRSId(nUnknownSRSId); poLayer->SetForcedSRSId(nForcedSRSId); poLayer->SetCreateSpatialIndexFlag(bCreateSpatialIndex); poLayer->SetPostGIS2(bPostGIS2); if( bHavePostGIS ) { OGRGeomFieldDefn oTmp( pszGFldName, eType ); OGRPGDumpGeomFieldDefn *poGeomField = new OGRPGDumpGeomFieldDefn(&oTmp); poGeomField->nSRSId = nSRSId; poGeomField->nCoordDimension = nDimension; poLayer->GetLayerDefn()->AddGeomFieldDefn(poGeomField, FALSE); } /* -------------------------------------------------------------------- */ /* Add layer to data source layer list. */ /* -------------------------------------------------------------------- */ papoLayers = (OGRPGDumpLayer **) CPLRealloc( papoLayers, sizeof(OGRPGDumpLayer *) * (nLayers+1) ); papoLayers[nLayers++] = poLayer; CPLFree( pszTableName ); CPLFree( pszSchemaName ); return poLayer; }