66
nGeomType = wkbUnknown;
67
bGeometryInformationSet = FALSE;
66
69
bLaunderColumnNames = TRUE;
70
bPreservePrecision = TRUE;
67
71
bCopyActive = FALSE;
68
72
bUseCopy = USE_COPY_UNSET; // unknown
70
74
pszTableName = CPLStrdup( pszTableNameIn );
71
pszSchemaName = NULL; // set in ReadTableDefinition
72
pszSqlTableName = NULL; //set in ReadTableDefinition
76
pszGeomColumn = CPLStrdup(pszGeomColumnIn);
78
pszSchemaName = CPLStrdup( pszSchemaNameIn );
79
else if (strlen(osCurrentSchema))
80
pszSchemaName = CPLStrdup( osCurrentSchema );
73
84
pszSqlGeomParentTableName = NULL;
75
poFeatureDefn = ReadTableDefinition( osCurrentSchema,
79
bAdvertizeGeomColumn );
85
// check SRID if it's necessary
90
86
bHasWarnedIncompatibleGeom = FALSE;
87
bHasWarnedAlreadySetFID = FALSE;
89
/* Just in provision for people yelling about broken backward compatibility ... */
90
bRetrieveFID = CSLTestBoolean(CPLGetConfigOption("OGR_PG_RETRIEVE_FID", "TRUE"));
92
/* -------------------------------------------------------------------- */
93
/* Build the layer defn name. */
94
/* -------------------------------------------------------------------- */
95
if ( pszSchemaNameIn && osCurrentSchema != pszSchemaNameIn )
97
/* For backwards compatibility, don't report the geometry column name */
98
/* if it's wkb_geometry */
99
if (bAdvertizeGeomColumn && pszGeomColumnIn)
100
osDefnName.Printf( "%s.%s(%s)", pszSchemaNameIn, pszTableName, pszGeomColumnIn );
102
osDefnName.Printf("%s.%s", pszSchemaNameIn, pszTableName );
103
pszSqlTableName = CPLStrdup(CPLString().Printf("%s.%s",
104
OGRPGEscapeColumnName(pszSchemaNameIn).c_str(),
105
OGRPGEscapeColumnName(pszTableName).c_str() ));
109
//no prefix for current_schema in layer name, for backwards compatibility
110
/* For backwards compatibility, don't report the geometry column name */
111
/* if it's wkb_geometry */
112
if (bAdvertizeGeomColumn && pszGeomColumnIn)
113
osDefnName.Printf( "%s(%s)", pszTableName, pszGeomColumnIn );
115
osDefnName = pszTableName;
116
pszSqlTableName = CPLStrdup(OGRPGEscapeColumnName(pszTableName));
119
osPrimaryKey = CPLGetConfigOption( "PGSQL_OGR_FID", "ogc_fid" );
93
122
//************************************************************************/
107
136
/************************************************************************/
137
/* SetGeometryInformation() */
138
/************************************************************************/
140
void OGRPGTableLayer::SetGeometryInformation(const char* pszType,
143
PostgisType ePostgisType)
145
if (pszType == NULL || nCoordDimension == 0 || nSRID == UNDETERMINED_SRID ||
146
ePostgisType == GEOM_TYPE_UNKNOWN)
149
bGeometryInformationSet = TRUE;
151
nGeomType = OGRFromOGCGeomType(pszType);
153
this->nCoordDimension = nCoordDimension;
154
this->nSRSId = nSRID;
156
if( nCoordDimension == 3 && nGeomType != wkbUnknown )
157
nGeomType = (OGRwkbGeometryType) (nGeomType | wkb25DBit);
159
if( ePostgisType == GEOM_TYPE_GEOMETRY)
160
bHasPostGISGeometry = TRUE;
161
else if( ePostgisType == GEOM_TYPE_GEOGRAPHY)
162
bHasPostGISGeography = TRUE;
164
CPLDebug("PG","Layer '%s' geometry type: %s:%s, Dim=%d",
165
pszTableName, pszType, OGRGeometryTypeToName(nGeomType),
169
/************************************************************************/
171
/************************************************************************/
173
OGRwkbGeometryType OGRPGTableLayer::GetGeomType()
175
if (bGeometryInformationSet)
178
return GetLayerDefn()->GetGeomType();
181
/************************************************************************/
108
182
/* ReadTableDefinition() */
110
184
/* Build a schema from the named table. Done by querying the */
112
186
/************************************************************************/
114
OGRFeatureDefn *OGRPGTableLayer::ReadTableDefinition( CPLString& osCurrentSchema,
115
const char * pszTableIn,
116
const char * pszSchemaNameIn,
117
const char * pszGeomColumnIn,
118
int bAdvertizeGeomColumn)
188
OGRFeatureDefn *OGRPGTableLayer::ReadTableDefinition()
121
191
PGresult *hResult;
122
192
CPLString osCommand;
123
CPLString osPrimaryKey;
124
193
PGconn *hPGConn = poDS->GetPGConn();
126
195
poDS->FlushSoftTransaction();
128
/* -------------------------------------------- */
129
/* Detect table primary key */
130
/* -------------------------------------------- */
132
/* -------------------------------------------- */
133
/* Check config options */
134
/* -------------------------------------------- */
135
osPrimaryKey = CPLGetConfigOption( "PGSQL_OGR_FID", "ogc_fid" );
138
pszSchemaName = CPLStrdup( pszSchemaNameIn );
139
else if (strlen(osCurrentSchema))
140
pszSchemaName = CPLStrdup( osCurrentSchema );
142
197
CPLString osSchemaClause;
143
198
if( pszSchemaName )
144
199
osSchemaClause.Printf("AND n.nspname='%s'", pszSchemaName);
205
263
osCommand.Printf(
206
264
"DECLARE mycursor CURSOR for "
207
265
"SELECT DISTINCT a.attname, t.typname, a.attlen,"
208
" format_type(a.atttypid,a.atttypmod) "
266
" format_type(a.atttypid,a.atttypmod), a.attnum "
209
267
"FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n "
210
"WHERE c.relname = '%s' "
268
"WHERE c.relname = %s "
211
269
"AND a.attnum > 0 AND a.attrelid = c.oid "
212
270
"AND a.atttypid = t.oid "
213
271
"AND c.relnamespace=n.oid "
215
pszTableIn, osSchemaClause.c_str());
274
pszEscapedTableNameSingleQuote, osSchemaClause.c_str());
217
hResult = PQexec(hPGConn, osCommand.c_str() );
276
hResult = OGRPG_PQexec(hPGConn, osCommand.c_str() );
220
279
if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
222
281
OGRPGClearResult( hResult );
223
hResult = PQexec(hPGConn, "FETCH ALL in mycursor" );
282
hResult = OGRPG_PQexec(hPGConn, "FETCH ALL in mycursor" );
226
285
if( !hResult || PQresultStatus(hResult) != PGRES_TUPLES_OK )
237
296
OGRPGClearResult( hResult );
239
hResult = PQexec(hPGConn, "CLOSE mycursor");
298
hResult = OGRPG_PQexec(hPGConn, "CLOSE mycursor");
240
299
OGRPGClearResult( hResult );
242
hResult = PQexec(hPGConn, "COMMIT");
301
hResult = OGRPG_PQexec(hPGConn, "COMMIT");
243
302
OGRPGClearResult( hResult );
245
304
CPLError( CE_Failure, CPLE_AppDefined,
246
305
"No field definitions found for '%s', is it a table?",
251
310
/* -------------------------------------------------------------------- */
252
311
/* Parse the returned table information. */
253
312
/* -------------------------------------------------------------------- */
254
CPLString osDefnName;
255
if ( pszSchemaNameIn && osCurrentSchema != pszSchemaNameIn )
257
/* For backwards compatibility, don't report the geometry column name */
258
/* if it's wkb_geometry */
259
if (bAdvertizeGeomColumn && pszGeomColumnIn)
260
osDefnName.Printf( "%s.%s(%s)", pszSchemaNameIn, pszTableIn, pszGeomColumnIn );
262
osDefnName.Printf("%s.%s", pszSchemaNameIn, pszTableIn );
263
pszSqlTableName = CPLStrdup(CPLString().Printf("\"%s\".\"%s\"", pszSchemaNameIn, pszTableIn ));
267
//no prefix for current_schema in layer name, for backwards compatibility
268
/* For backwards compatibility, don't report the geometry column name */
269
/* if it's wkb_geometry */
270
if (bAdvertizeGeomColumn && pszGeomColumnIn)
271
osDefnName.Printf( "%s(%s)", pszTableIn, pszGeomColumnIn );
273
osDefnName = pszTableIn;
274
pszSqlTableName = CPLStrdup(CPLString().Printf("\"%s\"", pszTableIn ));
277
313
OGRFeatureDefn *poDefn = new OGRFeatureDefn( osDefnName );
280
316
poDefn->Reference();
281
poDefn->SetGeomType( wkbNone );
283
pszGeomColumn = CPLStrdup(pszGeomColumnIn);
285
318
for( iRecord = 0; iRecord < PQntuples(hResult); iRecord++ )
439
469
OGRPGClearResult( hResult );
441
hResult = PQexec(hPGConn, "CLOSE mycursor");
442
OGRPGClearResult( hResult );
444
hResult = PQexec(hPGConn, "COMMIT");
445
OGRPGClearResult( hResult );
471
hResult = OGRPG_PQexec(hPGConn, "CLOSE mycursor");
472
OGRPGClearResult( hResult );
474
hResult = OGRPG_PQexec(hPGConn, "COMMIT");
475
OGRPGClearResult( hResult );
477
/* If geometry type, SRID, etc... have always been set by SetGeometryInformation() */
478
/* no need to issue a new SQL query. Just record the geom type in the layer definition */
479
if (bGeometryInformationSet)
447
483
// get layer geometry type (for PostGIS dataset)
448
if ( bHasPostGISGeometry || bHasPostGISGeography )
484
else if ( bHasPostGISGeometry || bHasPostGISGeography )
450
486
/* Get the geometry type and dimensions from the table, or */
451
487
/* from its parents if it is a derived table, or from the parent of the parent, etc.. */
452
488
int bGoOn = TRUE;
455
492
osCommand.Printf(
456
493
"SELECT type, coord_dimension%s FROM %s WHERE f_table_name='%s'",
457
(nSRSId == -2) ? ", srid" : "",
494
(nSRSId == UNDETERMINED_SRID) ? ", srid" : "",
458
495
(bHasPostGISGeometry) ? "geometry_columns" : "geography_columns",
459
(pszSqlGeomParentTableName) ? pszSqlGeomParentTableName : pszTableIn);
496
(pszSqlGeomParentTableName) ? pszSqlGeomParentTableName : pszTableName);
460
497
if (pszGeomColumn)
462
499
osCommand += CPLString().Printf(" AND %s='%s'",
468
505
osCommand += CPLString().Printf(" AND f_table_schema='%s'", pszSchemaName);
471
hResult = PQexec(hPGConn,osCommand);
508
hResult = OGRPG_PQexec(hPGConn,osCommand);
473
510
if ( hResult && PQntuples(hResult) == 1 && !PQgetisnull(hResult,0,0) )
475
512
char * pszType = PQgetvalue(hResult,0,0);
476
OGRwkbGeometryType nGeomType = wkbUnknown;
478
514
nCoordDimension = MAX(2,MIN(3,atoi(PQgetvalue(hResult,0,1))));
516
if (nSRSId == UNDETERMINED_SRID)
481
517
nSRSId = atoi(PQgetvalue(hResult,0,2));
483
// check only standard OGC geometry types
484
if ( EQUAL(pszType, "POINT") )
485
nGeomType = wkbPoint;
486
else if ( EQUAL(pszType,"LINESTRING"))
487
nGeomType = wkbLineString;
488
else if ( EQUAL(pszType,"POLYGON"))
489
nGeomType = wkbPolygon;
490
else if ( EQUAL(pszType,"MULTIPOINT"))
491
nGeomType = wkbMultiPoint;
492
else if ( EQUAL(pszType,"MULTILINESTRING"))
493
nGeomType = wkbMultiLineString;
494
else if ( EQUAL(pszType,"MULTIPOLYGON"))
495
nGeomType = wkbMultiPolygon;
496
else if ( EQUAL(pszType,"GEOMETRYCOLLECTION"))
497
nGeomType = wkbGeometryCollection;
499
if( nCoordDimension == 3 && nGeomType != wkbUnknown )
500
nGeomType = (OGRwkbGeometryType) (nGeomType | wkb25DBit);
502
CPLDebug("PG","Layer '%s' geometry type: %s:%s, Dim=%d",
503
pszTableIn, pszType, OGRGeometryTypeToName(nGeomType),
506
poDefn->SetGeomType( nGeomType );
519
SetGeometryInformation(pszType, nCoordDimension, nSRSId,
520
(bHasPostGISGeometry) ? GEOM_TYPE_GEOMETRY : GEOM_TYPE_GEOGRAPHY);
526
CPLString osEscapedTableNameSingleQuote = OGRPGEscapeString(hPGConn,
527
(pszSqlGeomParentTableName) ? pszSqlGeomParentTableName : pszTableName, -1, "");
528
const char* pszEscapedTableNameSingleQuote = osEscapedTableNameSingleQuote.c_str();
512
530
/* Fetch the name of the parent table */
513
531
if (pszSchemaName)
515
533
osCommand.Printf("SELECT pg_class.relname FROM pg_class WHERE oid = "
516
534
"(SELECT pg_inherits.inhparent FROM pg_inherits WHERE inhrelid = "
517
"(SELECT c.oid FROM pg_class c, pg_namespace n WHERE c.relname = '%s' AND c.relnamespace=n.oid AND n.nspname = '%s'))",
518
(pszSqlGeomParentTableName) ? pszSqlGeomParentTableName : pszTableIn, pszSchemaName );
535
"(SELECT c.oid FROM pg_class c, pg_namespace n WHERE c.relname = %s AND c.relnamespace=n.oid AND n.nspname = '%s'))",
536
pszEscapedTableNameSingleQuote, pszSchemaName );
522
540
osCommand.Printf("SELECT pg_class.relname FROM pg_class WHERE oid = "
523
541
"(SELECT pg_inherits.inhparent FROM pg_inherits WHERE inhrelid = "
524
"(SELECT pg_class.oid FROM pg_class WHERE relname = '%s'))",
525
(pszSqlGeomParentTableName) ? pszSqlGeomParentTableName : pszTableIn );
542
"(SELECT pg_class.oid FROM pg_class WHERE relname = %s))",
543
pszEscapedTableNameSingleQuote );
528
546
OGRPGClearResult( hResult );
529
hResult = PQexec(hPGConn, osCommand.c_str() );
547
hResult = OGRPG_PQexec(hPGConn, osCommand.c_str() );
531
549
if ( hResult && PQntuples( hResult ) == 1 && !PQgetisnull( hResult,0,0 ) )
577
606
if( m_poFilterGeom != NULL && (bHasPostGISGeometry || bHasPostGISGeography) )
579
611
OGREnvelope sEnvelope;
581
613
m_poFilterGeom->getEnvelope( &sEnvelope );
582
osWHERE.Printf("WHERE \"%s\" && SetSRID('BOX3D(%.12f %.12f, %.12f %.12f)'::box3d,%d) ",
584
sEnvelope.MinX, sEnvelope.MinY,
585
sEnvelope.MaxX, sEnvelope.MaxY,
614
snprintf(szBox3D_1, sizeof(szBox3D_1), "%.12f %.12f", sEnvelope.MinX, sEnvelope.MinY);
615
while((pszComma = strchr(szBox3D_1, ',')) != NULL)
617
snprintf(szBox3D_2, sizeof(szBox3D_2), "%.12f %.12f", sEnvelope.MaxX, sEnvelope.MaxY);
618
while((pszComma = strchr(szBox3D_2, ',')) != NULL)
620
osWHERE.Printf("WHERE %s && %s('BOX3D(%s, %s)'::box3d,%d) ",
621
OGRPGEscapeColumnName(pszGeomColumn).c_str(),
622
(poDS->sPostGISVersion.nMajor >= 2) ? "ST_SetSRID" : "SetSRID",
623
szBox3D_1, szBox3D_2, nSRSId );
589
626
if( strlen(osQuery) > 0 )
696
735
if ( poDS->bUseBinaryCursor )
698
osFieldList += "AsEWKB(\"";
699
osFieldList += pszGeomColumn;
700
osFieldList += "\")";
737
osFieldList += OGRPGEscapeColumnName(pszGeomColumn);
739
else if (CSLTestBoolean(CPLGetConfigOption("PG_USE_BASE64", "NO")) &&
740
nCoordDimension != 4 /* we don't know how to decode 4-dim EWKB for now */)
742
if (poDS->sPostGISVersion.nMajor >= 2)
743
osFieldList += "encode(ST_AsEWKB(";
745
osFieldList += "encode(AsEWKB(";
746
osFieldList += OGRPGEscapeColumnName(pszGeomColumn);
747
osFieldList += "), 'base64') AS EWKBBase64";
749
else if ( !CSLTestBoolean(CPLGetConfigOption("PG_USE_TEXT", "NO")) &&
750
nCoordDimension != 4 && /* we don't know how to decode 4-dim EWKB for now */
751
/* perhaps works also for older version, but I didn't check */
752
(poDS->sPostGISVersion.nMajor > 1 ||
753
(poDS->sPostGISVersion.nMajor == 1 && poDS->sPostGISVersion.nMinor >= 1)) )
755
/* This will return EWKB in an hex encoded form */
756
osFieldList += OGRPGEscapeColumnName(pszGeomColumn);
702
758
else if ( poDS->sPostGISVersion.nMajor >= 1 )
704
osFieldList += "AsEWKT(\"";
705
osFieldList += pszGeomColumn;
706
osFieldList += "\")";
760
if (poDS->sPostGISVersion.nMajor >= 2)
761
osFieldList += "ST_AsEWKT(";
763
osFieldList += "AsEWKT(";
764
osFieldList += OGRPGEscapeColumnName(pszGeomColumn);
710
osFieldList += "AsText(\"";
711
osFieldList += pszGeomColumn;
712
osFieldList += "\")";
769
osFieldList += "AsText(";
770
osFieldList += OGRPGEscapeColumnName(pszGeomColumn);
715
774
else if ( bHasPostGISGeography )
717
776
if ( poDS->bUseBinaryCursor )
719
osFieldList += "ST_AsBinary(\"";
720
osFieldList += pszGeomColumn;
721
osFieldList += "\")";
778
osFieldList += "ST_AsBinary(";
779
osFieldList += OGRPGEscapeColumnName(pszGeomColumn);
782
else if (CSLTestBoolean(CPLGetConfigOption("PG_USE_BASE64", "NO")))
784
osFieldList += "encode(ST_AsBinary(";
785
osFieldList += OGRPGEscapeColumnName(pszGeomColumn);
786
osFieldList += "), 'base64') AS BinaryBase64";
788
else if ( !CSLTestBoolean(CPLGetConfigOption("PG_USE_TEXT", "NO")) )
790
osFieldList += OGRPGEscapeColumnName(pszGeomColumn);
725
osFieldList += "ST_AsText(\"";
726
osFieldList += pszGeomColumn;
727
osFieldList += "\")";
794
osFieldList += "ST_AsText(";
795
osFieldList += OGRPGEscapeColumnName(pszGeomColumn);
733
osFieldList += pszGeomColumn;
801
osFieldList += OGRPGEscapeColumnName(pszGeomColumn);
896
965
strcat( pszNeedToFree+nOff, "," );
898
967
nOff += strlen(pszNeedToFree+nOff);
899
sprintf( pszNeedToFree+nOff, "%.16g", padfItems[j] );
900
968
//Check for special values. They need to be quoted.
901
if( strcmp( pszNeedToFree+nOff, "nan" ) == 0 )
969
if( CPLIsNan(padfItems[j]) )
902
970
sprintf( pszNeedToFree+nOff, "NaN" );
903
else if( strcmp( pszNeedToFree+nOff, "inf" ) == 0 )
904
sprintf( pszNeedToFree+nOff, "Infinity" );
905
else if( strcmp( pszNeedToFree+nOff, "-inf" ) == 0 )
906
sprintf( pszNeedToFree+nOff, "-Infinity" );
971
else if( CPLIsInf(padfItems[j]) )
972
sprintf( pszNeedToFree+nOff, (padfItems[j] > 0) ? "Infinity" : "-Infinity" );
974
sprintf( pszNeedToFree+nOff, "%.16g", padfItems[j] );
976
char* pszComma = strchr(pszNeedToFree+nOff, ',');
908
980
strcat( pszNeedToFree+nOff, "}'" );
1066
1147
else if( bHasPostGISGeometry || bHasPostGISGeography )
1068
osCommand = osCommand + "\"" + pszGeomColumn + "\" = ";
1069
char *pszWKT = NULL;
1149
osCommand = osCommand + OGRPGEscapeColumnName(pszGeomColumn) + " = ";
1150
OGRGeometry *poGeom = NULL;
1071
1152
if( poFeature->GetGeometryRef() != NULL )
1073
OGRGeometry *poGeom = (OGRGeometry *) poFeature->GetGeometryRef();
1154
poGeom = (OGRGeometry *) poFeature->GetGeometryRef();
1075
1156
poGeom->closeRings();
1076
1157
poGeom->setCoordinateDimension( nCoordDimension );
1078
poGeom->exportToWkt( &pszWKT );
1081
if( pszWKT != NULL )
1161
if ( !CSLTestBoolean(CPLGetConfigOption("PG_USE_TEXT", "NO")) )
1083
if( bHasPostGISGeography )
1086
"ST_GeographyFromText('SRID=%d;%s'::TEXT) ", nSRSId, pszWKT );
1087
else if( poDS->sPostGISVersion.nMajor >= 1 )
1090
"GeomFromEWKT('SRID=%d;%s'::TEXT) ", nSRSId, pszWKT );
1163
if ( poGeom != NULL )
1165
char* pszHexEWKB = GeometryToHex( poGeom, nSRSId );
1166
if ( bHasPostGISGeography )
1167
osCommand += CPLString().Printf("'%s'::GEOGRAPHY", pszHexEWKB);
1169
osCommand += CPLString().Printf("'%s'::GEOMETRY", pszHexEWKB);
1170
OGRFree( pszHexEWKB );
1094
"GeometryFromText('%s'::TEXT,%d) ", pszWKT, nSRSId );
1173
osCommand += "NULL";
1098
osCommand += "NULL";
1177
char *pszWKT = NULL;
1180
poGeom->exportToWkt( &pszWKT );
1182
if( pszWKT != NULL )
1184
if( bHasPostGISGeography )
1187
"ST_GeographyFromText('SRID=%d;%s'::TEXT) ", nSRSId, pszWKT );
1188
else if( poDS->sPostGISVersion.nMajor >= 1 )
1191
"GeomFromEWKT('SRID=%d;%s'::TEXT) ", nSRSId, pszWKT );
1195
"GeometryFromText('%s'::TEXT,%d) ", pszWKT, nSRSId );
1199
osCommand += "NULL";
1100
1202
bNeedComma = TRUE;
1350
1480
osCommand += ", ";
1352
1482
osCommand = osCommand
1353
+ "\"" + poFeatureDefn->GetFieldDefn(i)->GetNameRef() + "\"";
1483
+ OGRPGEscapeColumnName(poFeatureDefn->GetFieldDefn(i)->GetNameRef());
1487
bEmptyInsert = TRUE;
1356
1489
osCommand += ") VALUES (";
1358
1491
/* Set the geometry */
1359
bNeedComma = poGeom != NULL;
1360
1493
if( (bHasPostGISGeometry || bHasPostGISGeography) && poGeom != NULL)
1362
char *pszWKT = NULL;
1364
1496
CheckGeomTypeCompatibility(poGeom);
1366
1498
poGeom->closeRings();
1367
1499
poGeom->setCoordinateDimension( nCoordDimension );
1369
poGeom->exportToWkt( &pszWKT );
1371
if( pszWKT != NULL )
1502
if ( !CSLTestBoolean(CPLGetConfigOption("PG_USE_TEXT", "NO")) )
1373
if( bHasPostGISGeography )
1376
"ST_GeographyFromText('SRID=%d;%s'::TEXT) ", nSRSId, pszWKT );
1377
else if( poDS->sPostGISVersion.nMajor >= 1 )
1380
"GeomFromEWKT('SRID=%d;%s'::TEXT) ", nSRSId, pszWKT );
1504
char *pszHexEWKB = GeometryToHex( poGeom, nSRSId );
1505
if ( bHasPostGISGeography )
1506
osCommand += CPLString().Printf("'%s'::GEOGRAPHY", pszHexEWKB);
1384
"GeometryFromText('%s'::TEXT,%d) ", pszWKT, nSRSId );
1508
osCommand += CPLString().Printf("'%s'::GEOMETRY", pszHexEWKB);
1509
OGRFree( pszHexEWKB );
1513
char *pszWKT = NULL;
1514
poGeom->exportToWkt( &pszWKT );
1516
if( pszWKT != NULL )
1518
if( bHasPostGISGeography )
1521
"ST_GeographyFromText('SRID=%d;%s'::TEXT) ", nSRSId, pszWKT );
1522
else if( poDS->sPostGISVersion.nMajor >= 1 )
1525
"GeomFromEWKT('SRID=%d;%s'::TEXT) ", nSRSId, pszWKT );
1529
"GeometryFromText('%s'::TEXT,%d) ", pszWKT, nSRSId );
1390
1538
else if( bHasWkb && !bWkbAsOid && poGeom != NULL )
1437
1590
osCommand += ")";
1593
osCommand.Printf( "INSERT INTO %s DEFAULT VALUES", pszSqlTableName );
1595
int bReturnRequested = FALSE;
1596
/* RETURNING is only available since Postgres 8.2 */
1597
/* We only get the FID, but we also could add the unset fields to get */
1598
/* the default values */
1599
if (bRetrieveFID && pszFIDColumn != NULL && poFeature->GetFID() == OGRNullFID &&
1600
(poDS->sPostgreSQLVersion.nMajor >= 9 ||
1601
(poDS->sPostgreSQLVersion.nMajor == 8 && poDS->sPostgreSQLVersion.nMinor >= 2)))
1603
bReturnRequested = TRUE;
1604
osCommand += " RETURNING ";
1605
osCommand += OGRPGEscapeColumnName(pszFIDColumn);
1439
1608
/* -------------------------------------------------------------------- */
1440
1609
/* Execute the insert. */
1441
1610
/* -------------------------------------------------------------------- */
1442
hResult = PQexec(hPGConn, osCommand);
1443
if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
1611
hResult = OGRPG_PQexec(hPGConn, osCommand);
1612
if (bReturnRequested && PQresultStatus(hResult) == PGRES_TUPLES_OK &&
1613
PQntuples(hResult) == 1 && PQnfields(hResult) == 1 )
1615
const char* pszFID = PQgetvalue(hResult, 0, 0 );
1616
long nFID = atol(pszFID);
1617
poFeature->SetFID(nFID);
1619
else if( bReturnRequested || PQresultStatus(hResult) != PGRES_COMMAND_OK )
1445
1621
CPLError( CE_Failure, CPLE_AppDefined,
1446
1622
"INSERT command for new feature failed.\n%s\nCommand: %s",
1447
1623
PQerrorMessage(hPGConn), osCommand.c_str() );
1625
if( !bHasWarnedAlreadySetFID && poFeature->GetFID() != OGRNullFID &&
1626
pszFIDColumn != NULL )
1628
bHasWarnedAlreadySetFID = TRUE;
1629
CPLError(CE_Warning, CPLE_AppDefined,
1630
"You've inserted feature with an already set FID and that's perhaps the reason for the failure. "
1631
"If so, this can happen if you reuse the same feature object for sequential insertions. "
1632
"Indeed, since GDAL 1.8.0, the FID of an inserted feature is got from the server, so it is not a good idea"
1633
"to reuse it afterwards... All in all, try unsetting the FID with SetFID(-1) before calling CreateFeature()");
1449
1636
OGRPGClearResult( hResult );
1451
1638
poDS->SoftRollback();
1573
1753
strcat( pszNeedToFree+nOff, "," );
1575
1755
nOff += strlen(pszNeedToFree+nOff);
1576
sprintf( pszNeedToFree+nOff, "%.16g", padfItems[j] );
1577
1756
//Check for special values. They need to be quoted.
1578
if( strcmp( pszNeedToFree+nOff, "nan" ) == 0 )
1579
sprintf( pszNeedToFree+nOff, "'NaN'" );
1580
else if( strcmp( pszNeedToFree+nOff, "inf" ) == 0 )
1581
sprintf( pszNeedToFree+nOff, "'Infinity'" );
1582
else if( strcmp( pszNeedToFree+nOff, "-inf" ) == 0 )
1583
sprintf( pszNeedToFree+nOff, "'-Infinity'" );
1757
if( CPLIsNan(padfItems[j]) )
1758
sprintf( pszNeedToFree+nOff, "NaN" );
1759
else if( CPLIsInf(padfItems[j]) )
1760
sprintf( pszNeedToFree+nOff, (padfItems[j] > 0) ? "Infinity" : "-Infinity" );
1762
sprintf( pszNeedToFree+nOff, "%.16g", padfItems[j] );
1764
char* pszComma = strchr(pszNeedToFree+nOff, ',');
1585
1768
strcat( pszNeedToFree+nOff, "}" );
1586
1769
pszStrValue = pszNeedToFree;
1740
1931
/************************************************************************/
1932
/* OGRPGTableLayerGetType() */
1742
1933
/************************************************************************/
1744
OGRErr OGRPGTableLayer::CreateField( OGRFieldDefn *poFieldIn, int bApproxOK )
1935
static CPLString OGRPGTableLayerGetType(OGRFieldDefn& oField,
1936
int bPreservePrecision,
1747
PGconn *hPGConn = poDS->GetPGConn();
1748
PGresult *hResult = NULL;
1749
CPLString osCommand;
1750
1939
char szFieldType[256];
1751
OGRFieldDefn oField( poFieldIn );
1753
/* -------------------------------------------------------------------- */
1754
/* Do we want to "launder" the column names into Postgres */
1755
/* friendly format? */
1756
/* -------------------------------------------------------------------- */
1757
if( bLaunderColumnNames )
1759
char *pszSafeName = poDS->LaunderName( oField.GetNameRef() );
1761
oField.SetName( pszSafeName );
1762
CPLFree( pszSafeName );
1764
if( EQUAL(oField.GetNameRef(),"oid") )
1766
CPLError( CE_Warning, CPLE_AppDefined,
1767
"Renaming field 'oid' to 'oid_' to avoid conflict with internal oid field." );
1768
oField.SetName( "oid_" );
1772
1941
/* -------------------------------------------------------------------- */
1773
1942
/* Work out the PostgreSQL type. */
1837
2006
"Can't create field %s with type %s on PostgreSQL layers.",
1838
2007
oField.GetNameRef(),
1839
2008
OGRFieldDefn::GetFieldTypeName(oField.GetType()) );
2009
strcpy( szFieldType, "");
2015
/************************************************************************/
2017
/************************************************************************/
2019
OGRErr OGRPGTableLayer::CreateField( OGRFieldDefn *poFieldIn, int bApproxOK )
2022
PGconn *hPGConn = poDS->GetPGConn();
2023
PGresult *hResult = NULL;
2024
CPLString osCommand;
2025
CPLString osFieldType;
2026
OGRFieldDefn oField( poFieldIn );
2030
/* -------------------------------------------------------------------- */
2031
/* Do we want to "launder" the column names into Postgres */
2032
/* friendly format? */
2033
/* -------------------------------------------------------------------- */
2034
if( bLaunderColumnNames )
2036
char *pszSafeName = poDS->LaunderName( oField.GetNameRef() );
2038
oField.SetName( pszSafeName );
2039
CPLFree( pszSafeName );
2041
if( EQUAL(oField.GetNameRef(),"oid") )
2043
CPLError( CE_Warning, CPLE_AppDefined,
2044
"Renaming field 'oid' to 'oid_' to avoid conflict with internal oid field." );
2045
oField.SetName( "oid_" );
2049
osFieldType = OGRPGTableLayerGetType(oField, bPreservePrecision, bApproxOK);
2050
if (osFieldType.size() == 0)
1841
2051
return OGRERR_FAILURE;
1844
2053
/* -------------------------------------------------------------------- */
1845
2054
/* Create the new field. */
1846
2055
/* -------------------------------------------------------------------- */
1847
2056
poDS->FlushSoftTransaction();
1848
hResult = PQexec(hPGConn, "BEGIN");
2057
hResult = OGRPG_PQexec(hPGConn, "BEGIN");
1849
2058
OGRPGClearResult( hResult );
1851
osCommand.Printf( "ALTER TABLE %s ADD COLUMN \"%s\" %s",
1852
pszSqlTableName, oField.GetNameRef(), szFieldType );
1853
hResult = PQexec(hPGConn, osCommand);
2060
osCommand.Printf( "ALTER TABLE %s ADD COLUMN %s %s",
2061
pszSqlTableName, OGRPGEscapeColumnName(oField.GetNameRef()).c_str(),
2062
osFieldType.c_str() );
2063
hResult = OGRPG_PQexec(hPGConn, osCommand);
1854
2064
if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
1856
2066
CPLError( CE_Failure, CPLE_AppDefined,
1879
2089
/************************************************************************/
2091
/************************************************************************/
2093
OGRErr OGRPGTableLayer::DeleteField( int iField )
2095
PGconn *hPGConn = poDS->GetPGConn();
2096
PGresult *hResult = NULL;
2097
CPLString osCommand;
2101
if( !bUpdateAccess )
2103
CPLError( CE_Failure, CPLE_NotSupported,
2104
"Can't delete fields on a read-only datasource.");
2105
return OGRERR_FAILURE;
2108
if (iField < 0 || iField >= poFeatureDefn->GetFieldCount())
2110
CPLError( CE_Failure, CPLE_NotSupported,
2111
"Invalid field index");
2112
return OGRERR_FAILURE;
2115
poDS->FlushSoftTransaction();
2117
hResult = OGRPG_PQexec(hPGConn, "BEGIN");
2118
OGRPGClearResult( hResult );
2120
osCommand.Printf( "ALTER TABLE %s DROP COLUMN %s",
2122
OGRPGEscapeColumnName(poFeatureDefn->GetFieldDefn(iField)->GetNameRef()).c_str() );
2123
hResult = OGRPG_PQexec(hPGConn, osCommand);
2124
if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
2126
CPLError( CE_Failure, CPLE_AppDefined,
2129
PQerrorMessage(hPGConn) );
2131
OGRPGClearResult( hResult );
2133
hResult = OGRPG_PQexec( hPGConn, "ROLLBACK" );
2134
OGRPGClearResult( hResult );
2136
return OGRERR_FAILURE;
2139
OGRPGClearResult( hResult );
2141
hResult = OGRPG_PQexec(hPGConn, "COMMIT");
2142
OGRPGClearResult( hResult );
2144
return poFeatureDefn->DeleteFieldDefn( iField );
2147
/************************************************************************/
2148
/* AlterFieldDefn() */
2149
/************************************************************************/
2151
OGRErr OGRPGTableLayer::AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn, int nFlags )
2153
PGconn *hPGConn = poDS->GetPGConn();
2154
PGresult *hResult = NULL;
2155
CPLString osCommand;
2159
if( !bUpdateAccess )
2161
CPLError( CE_Failure, CPLE_NotSupported,
2162
"Can't alter field definition on a read-only datasource.");
2163
return OGRERR_FAILURE;
2166
if (iField < 0 || iField >= poFeatureDefn->GetFieldCount())
2168
CPLError( CE_Failure, CPLE_NotSupported,
2169
"Invalid field index");
2170
return OGRERR_FAILURE;
2173
OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
2174
OGRFieldDefn oField( poNewFieldDefn );
2176
poDS->FlushSoftTransaction();
2178
hResult = OGRPG_PQexec(hPGConn, "BEGIN");
2179
OGRPGClearResult( hResult );
2181
if (!(nFlags & ALTER_TYPE_FLAG))
2182
oField.SetType(poFieldDefn->GetType());
2184
if (!(nFlags & ALTER_WIDTH_PRECISION_FLAG))
2186
oField.SetWidth(poFieldDefn->GetWidth());
2187
oField.SetPrecision(poFieldDefn->GetPrecision());
2190
if ((nFlags & ALTER_TYPE_FLAG) ||
2191
(nFlags & ALTER_WIDTH_PRECISION_FLAG))
2193
CPLString osFieldType = OGRPGTableLayerGetType(oField,
2196
if (osFieldType.size() == 0)
2198
hResult = OGRPG_PQexec( hPGConn, "ROLLBACK" );
2199
OGRPGClearResult( hResult );
2201
return OGRERR_FAILURE;
2204
osCommand.Printf( "ALTER TABLE %s ALTER COLUMN %s TYPE %s",
2206
OGRPGEscapeColumnName(poFieldDefn->GetNameRef()).c_str(),
2207
osFieldType.c_str() );
2208
hResult = OGRPG_PQexec(hPGConn, osCommand);
2209
if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
2211
CPLError( CE_Failure, CPLE_AppDefined,
2214
PQerrorMessage(hPGConn) );
2216
OGRPGClearResult( hResult );
2218
hResult = OGRPG_PQexec( hPGConn, "ROLLBACK" );
2219
OGRPGClearResult( hResult );
2221
return OGRERR_FAILURE;
2223
OGRPGClearResult( hResult );
2227
if( (nFlags & ALTER_NAME_FLAG) )
2229
if (bLaunderColumnNames)
2231
char *pszSafeName = poDS->LaunderName( oField.GetNameRef() );
2232
oField.SetName( pszSafeName );
2233
CPLFree( pszSafeName );
2236
if( EQUAL(oField.GetNameRef(),"oid") )
2238
CPLError( CE_Warning, CPLE_AppDefined,
2239
"Renaming field 'oid' to 'oid_' to avoid conflict with internal oid field." );
2240
oField.SetName( "oid_" );
2243
if ( strcmp(poFieldDefn->GetNameRef(), oField.GetNameRef()) != 0 )
2245
osCommand.Printf( "ALTER TABLE %s RENAME COLUMN %s TO %s",
2247
OGRPGEscapeColumnName(poFieldDefn->GetNameRef()).c_str(),
2248
OGRPGEscapeColumnName(oField.GetNameRef()).c_str() );
2249
hResult = OGRPG_PQexec(hPGConn, osCommand);
2250
if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
2252
CPLError( CE_Failure, CPLE_AppDefined,
2255
PQerrorMessage(hPGConn) );
2257
OGRPGClearResult( hResult );
2259
hResult = OGRPG_PQexec( hPGConn, "ROLLBACK" );
2260
OGRPGClearResult( hResult );
2262
return OGRERR_FAILURE;
2264
OGRPGClearResult( hResult );
2268
hResult = OGRPG_PQexec(hPGConn, "COMMIT");
2269
OGRPGClearResult( hResult );
2271
if (nFlags & ALTER_NAME_FLAG)
2272
poFieldDefn->SetName(oField.GetNameRef());
2273
if (nFlags & ALTER_TYPE_FLAG)
2274
poFieldDefn->SetType(oField.GetType());
2275
if (nFlags & ALTER_WIDTH_PRECISION_FLAG)
2277
poFieldDefn->SetWidth(oField.GetWidth());
2278
poFieldDefn->SetPrecision(oField.GetPrecision());
2285
/************************************************************************/
1880
2286
/* GetFeature() */
1881
2287
/************************************************************************/
1883
2289
OGRFeature *OGRPGTableLayer::GetFeature( long nFeatureId )
1886
2294
if( pszFIDColumn == NULL )
1887
2295
return OGRLayer::GetFeature( nFeatureId );
1906
2314
osCommand.Printf(
1907
2315
"DECLARE getfeaturecursor %s for "
1908
"SELECT %s FROM %s WHERE \"%s\" = %ld",
2316
"SELECT %s FROM %s WHERE %s = %ld",
1909
2317
( poDS->bUseBinaryCursor ) ? "BINARY CURSOR" : "CURSOR",
1910
osFieldList.c_str(), pszSqlTableName, pszFIDColumn,
2318
osFieldList.c_str(), pszSqlTableName, OGRPGEscapeColumnName(pszFIDColumn).c_str(),
1913
hResult = PQexec(hPGConn, osCommand.c_str() );
2321
hResult = OGRPG_PQexec(hPGConn, osCommand.c_str() );
1915
2323
if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
1917
2325
OGRPGClearResult( hResult );
1919
hResult = PQexec(hPGConn, "FETCH ALL in getfeaturecursor" );
2327
hResult = OGRPG_PQexec(hPGConn, "FETCH ALL in getfeaturecursor" );
1921
2329
if( hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK )
1995
2410
/* GetSpatialRef() */
1997
2412
/* We override this to try and fetch the table SRID from the */
1998
/* geometry_columns table if the srsid is -2 (meaning we */
1999
/* haven't yet even looked for it). */
2413
/* geometry_columns table if the srsid is UNDETERMINED_SRID */
2414
/* (meaning we haven't yet even looked for it). */
2000
2415
/************************************************************************/
2002
2417
OGRSpatialReference *OGRPGTableLayer::GetSpatialRef()
2420
if( nSRSId == UNDETERMINED_SRID )
2007
2422
PGconn *hPGConn = poDS->GetPGConn();
2008
2423
PGresult *hResult = NULL;
2009
2424
CPLString osCommand;
2426
nSRSId = poDS->GetUndefinedSRID();
2013
2428
poDS->SoftStartTransaction();
2015
if (bHasPostGISGeography)
2018
"SELECT srid FROM geography_columns "
2019
"WHERE f_table_name = '%s'",
2020
(pszSqlGeomParentTableName) ? pszSqlGeomParentTableName : pszTableName);
2024
osCommand += CPLString().Printf(" AND f_geography_column = '%s'", pszGeomColumn);
2030
"SELECT srid FROM geometry_columns "
2031
"WHERE f_table_name = '%s'",
2032
(pszSqlGeomParentTableName) ? pszSqlGeomParentTableName : pszTableName);
2036
osCommand += CPLString().Printf(" AND f_geometry_column = '%s'", pszGeomColumn);
2431
"SELECT srid FROM geometry_columns "
2432
"WHERE f_table_name = '%s'",
2437
osCommand += CPLString().Printf(" AND f_geometry_column = '%s'", pszGeomColumn);
2040
2440
if (pszSchemaName)
2071
2471
CPLString osCommand;
2475
const char* pszExtentFct;
2476
if (poDS->sPostGISVersion.nMajor >= 2)
2477
pszExtentFct = "ST_Extent";
2479
pszExtentFct = "Extent";
2073
2481
if ( TestCapability(OLCFastGetExtent) )
2075
osCommand.Printf( "SELECT Extent(\"%s\") FROM %s",
2076
pszGeomColumn, pszSqlTableName );
2483
osCommand.Printf( "SELECT %s(%s) FROM %s", pszExtentFct,
2484
OGRPGEscapeColumnName(pszGeomColumn).c_str(), pszSqlTableName );
2078
2486
else if ( bHasPostGISGeography )
2080
2488
/* Probably not very efficient, but more efficient than client-side implementation */
2081
osCommand.Printf( "SELECT Extent(ST_GeomFromWKB(ST_AsBinary(\"%s\"))) FROM %s",
2082
pszGeomColumn, pszSqlTableName );
2489
osCommand.Printf( "SELECT %s(ST_GeomFromWKB(ST_AsBinary(%s))) FROM %s",
2491
OGRPGEscapeColumnName(pszGeomColumn).c_str(), pszSqlTableName );
2085
2494
return RunGetExtentRequest(psExtent, bForce, osCommand);