Skip to content

Commit 016b03b

Browse files
committed
postgres: convert 4d geometries to 2d (fixes #9748)
1 parent 8089a4e commit 016b03b

6 files changed

+75
-45
lines changed

src/providers/postgres/qgspostgresconn.cpp

+13-7
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ bool QgsPostgresConn::getTableInfo( bool searchGeometryColumnsOnly, bool searchP
338338

339339
for ( int i = 0; i < ( hasTopology() ? 3 : 2 ); i++ )
340340
{
341-
QString sql, tableName, schemaName, columnName, typeName, sridName, gtableName;
341+
QString sql, tableName, schemaName, columnName, typeName, sridName, gtableName, dimName;
342342
QgsPostgresGeometryColumnType columnType = sctGeometry;
343343

344344
if ( i == 0 )
@@ -348,6 +348,7 @@ bool QgsPostgresConn::getTableInfo( bool searchGeometryColumnsOnly, bool searchP
348348
columnName = "l.f_geometry_column";
349349
typeName = "upper(l.type)";
350350
sridName = "l.srid";
351+
dimName = "l.coord_dimension";
351352
gtableName = "geometry_columns";
352353
columnType = sctGeometry;
353354
}
@@ -358,6 +359,7 @@ bool QgsPostgresConn::getTableInfo( bool searchGeometryColumnsOnly, bool searchP
358359
columnName = "l.f_geography_column";
359360
typeName = "upper(l.type)";
360361
sridName = "l.srid";
362+
dimName = "2";
361363
gtableName = "geography_columns";
362364
columnType = sctGeography;
363365
}
@@ -373,21 +375,22 @@ bool QgsPostgresConn::getTableInfo( bool searchGeometryColumnsOnly, bool searchP
373375
"WHEN l.feature_type = 4 THEN 'GEOMETRYCOLLECTION' "
374376
"END AS type";
375377
sridName = "(SELECT srid FROM topology.topology t WHERE l.topology_id=t.id)";
378+
dimName = "2";
376379
gtableName = "topology.layer";
377380
columnType = sctTopoGeometry;
378381
}
379382

380383
// The following query returns only tables that exist and the user has SELECT privilege on.
381384
// Can't use regclass here because table must exist, else error occurs.
382-
sql = QString( "SELECT %1,%2,%3,%4,%5,c.relkind"
383-
" FROM %6 l,pg_class c,pg_namespace n"
385+
sql = QString( "SELECT %1,%2,%3,%4,%5,%6,c.relkind"
386+
" FROM %7 l,pg_class c,pg_namespace n"
384387
" WHERE c.relname=%1"
385388
" AND %2=n.nspname"
386389
" AND n.oid=c.relnamespace"
387390
" AND has_schema_privilege(n.nspname,'usage')"
388391
" AND has_table_privilege('\"'||n.nspname||'\".\"'||c.relname||'\"','select')" // user has select privilege
389392
)
390-
.arg( tableName ).arg( schemaName ).arg( columnName ).arg( typeName ).arg( sridName ).arg( gtableName );
393+
.arg( tableName ).arg( schemaName ).arg( columnName ).arg( typeName ).arg( sridName ).arg( dimName ).arg( gtableName );
391394

392395
if ( searchPublicOnly )
393396
sql += " AND n.nspname='public'";
@@ -409,7 +412,8 @@ bool QgsPostgresConn::getTableInfo( bool searchGeometryColumnsOnly, bool searchP
409412
QString column = result.PQgetvalue( idx, 2 );
410413
QString type = result.PQgetvalue( idx, 3 );
411414
QString ssrid = result.PQgetvalue( idx, 4 );
412-
QString relkind = result.PQgetvalue( idx, 5 );
415+
int dim = result.PQgetvalue( idx, 5 ).toInt();
416+
QString relkind = result.PQgetvalue( idx, 6 );
413417
bool isView = relkind == "v" || relkind == "m";
414418

415419
int srid = ssrid.isEmpty() ? INT_MIN : ssrid.toInt();
@@ -419,12 +423,13 @@ bool QgsPostgresConn::getTableInfo( bool searchGeometryColumnsOnly, bool searchP
419423
srid = INT_MIN;
420424
}
421425

422-
QgsDebugMsg( QString( "%1 : %2.%3.%4: %5 %6 %7" )
426+
QgsDebugMsg( QString( "%1 : %2.%3.%4: %5 %6 %7 %8" )
423427
.arg( gtableName )
424428
.arg( schemaName ).arg( tableName ).arg( column )
425429
.arg( type )
426430
.arg( srid )
427-
.arg( relkind ) );
431+
.arg( relkind )
432+
.arg( dim ) );
428433

429434
layerProperty.schemaName = schemaName;
430435
layerProperty.tableName = tableName;
@@ -433,6 +438,7 @@ bool QgsPostgresConn::getTableInfo( bool searchGeometryColumnsOnly, bool searchP
433438
layerProperty.types = QList<QGis::WkbType>() << ( QgsPostgresConn::wkbTypeFromPostgis( type ) );
434439
layerProperty.srids = QList<int>() << srid;
435440
layerProperty.sql = "";
441+
layerProperty.force2d = dim == 4;
436442
addColumnInfo( layerProperty, schemaName, tableName, isView );
437443

438444
if ( isView && layerProperty.pkCols.empty() )

src/providers/postgres/qgspostgresconn.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ struct QgsPostgresLayerProperty
6464
QList<int> srids;
6565
unsigned int nSpCols;
6666
QString sql;
67+
bool force2d;
6768

6869

6970
// TODO: rename this !
@@ -113,15 +114,16 @@ struct QgsPostgresLayerProperty
113114
sridString += QString::number( srid );
114115
}
115116

116-
return QString( "%1.%2.%3 type=%4 srid=%5 pkCols=%6 sql=%7 nSpCols=%8" )
117+
return QString( "%1.%2.%3 type=%4 srid=%5 pkCols=%6 sql=%7 nSpCols=%8 force2d=%9" )
117118
.arg( schemaName )
118119
.arg( tableName )
119120
.arg( geometryColName )
120121
.arg( typeString )
121122
.arg( sridString )
122123
.arg( pkCols.join( "|" ) )
123124
.arg( sql )
124-
.arg( nSpCols );
125+
.arg( nSpCols )
126+
.arg( force2d ? "yes" : "no" );
125127
}
126128
#endif
127129
};

src/providers/postgres/qgspostgresfeatureiterator.cpp

+44-33
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,9 @@ bool QgsPostgresFeatureIterator::fetchFeature( QgsFeature& feature )
156156
bool QgsPostgresFeatureIterator::prepareSimplification( const QgsSimplifyMethod& simplifyMethod )
157157
{
158158
// setup simplification of geometries to fetch
159-
if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) && simplifyMethod.methodType() != QgsSimplifyMethod::NoSimplification && !simplifyMethod.forceLocalOptimization() )
159+
if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) &&
160+
simplifyMethod.methodType() != QgsSimplifyMethod::NoSimplification &&
161+
!simplifyMethod.forceLocalOptimization() )
160162
{
161163
QgsSimplifyMethod::MethodType methodType = simplifyMethod.methodType();
162164

@@ -279,43 +281,51 @@ bool QgsPostgresFeatureIterator::declareCursor( const QString& whereClause )
279281
{
280282
mFetchGeometry = !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) && !mSource->mGeometryColumn.isNull();
281283

284+
#if 0
282285
// TODO: check that all field indexes exist
283-
//if ( !hasAllFields )
284-
//{
285-
// rewind();
286-
// return false;
287-
//}
286+
if ( !hasAllFields )
287+
{
288+
rewind();
289+
return false;
290+
}
291+
#endif
288292

293+
QString query( "SELECT " ), delim( "" );
289294

290-
const QgsSimplifyMethod& simplifyMethod = mRequest.simplifyMethod();
295+
if ( mFetchGeometry )
296+
{
297+
QString geom = QgsPostgresConn::quotedIdentifier( mSource->mGeometryColumn );
291298

292-
QString query = "SELECT ", delim = "";
299+
if ( mSource->mSpatialColType == sctGeography )
300+
geom += "::geometry";
293301

294-
bool isPointLayer = QGis::flatType( QGis::singleType( mSource->mRequestedGeomType != QGis::WKBUnknown ? mSource->mRequestedGeomType : mSource->mDetectedGeomType ) ) == QGis::WKBPoint;
295-
if ( mFetchGeometry && !simplifyMethod.forceLocalOptimization() && simplifyMethod.methodType() != QgsSimplifyMethod::NoSimplification && !isPointLayer )
296-
{
297-
QString simplifyFunctionName = simplifyMethod.methodType() == QgsSimplifyMethod::OptimizeForRendering
298-
? ( mConn->majorVersion() < 2 ? "snaptogrid" : "st_snaptogrid" )
299-
: ( mConn->majorVersion() < 2 ? "simplifypreservetopology" : "st_simplifypreservetopology" );
300-
301-
double tolerance = simplifyMethod.tolerance() * 0.8; //-> Default factor for the maximum displacement distance for simplification, similar as GeoServer does
302-
303-
query += QString( "%1(%5(%2%3,%6),'%4')" )
304-
.arg( mConn->majorVersion() < 2 ? "asbinary" : "st_asbinary" )
305-
.arg( QgsPostgresConn::quotedIdentifier( mSource->mGeometryColumn ) )
306-
.arg( mSource->mSpatialColType == sctGeography ? "::geometry" : "" )
307-
.arg( QgsPostgresProvider::endianString() )
308-
.arg( simplifyFunctionName )
309-
.arg( tolerance );
310-
delim = ",";
311-
}
312-
else if ( mFetchGeometry )
313-
{
314-
query += QString( "%1(%2%3,'%4')" )
315-
.arg( mConn->majorVersion() < 2 ? "asbinary" : "st_asbinary" )
316-
.arg( QgsPostgresConn::quotedIdentifier( mSource->mGeometryColumn ) )
317-
.arg( mSource->mSpatialColType == sctGeography ? "::geometry" : "" )
318-
.arg( QgsPostgresProvider::endianString() );
302+
if ( mSource->mForce2d )
303+
{
304+
geom = QString( "%1(%2)" )
305+
.arg( mConn->majorVersion() < 2 ? "force2d" : "st_force2d" )
306+
.arg( geom );
307+
}
308+
309+
if ( !simplifyMethod.forceLocalOptimization() &&
310+
mRequest.simplifyMethod().methodType() != QgsSimplifyMethod::NoSimplification &&
311+
QGis::flatType( QGis::singleType( mSource->mRequestedGeomType != QGis::WKBUnknown
312+
? mSource->mRequestedGeomType
313+
: mSource->mDetectedGeomType ) ) != QGis::WKBPoint )
314+
{
315+
geom = QString( "%1(%2,%3)" )
316+
.arg( mRequest.simplifyMethod().methodType().methodType() == QgsSimplifyMethod::OptimizeForRendering
317+
? ( mConn->majorVersion() < 2 ? "snaptogrid" : "st_snaptogrid" )
318+
: ( mConn->majorVersion() < 2 ? "simplifypreservetopology" : "st_simplifypreservetopology" ) )
319+
.arg( geom )
320+
.arg( simplifyMethod.tolerance() * 0.8 ); //-> Default factor for the maximum displacement distance for simplification, similar as GeoServer does
321+
}
322+
323+
geom = QString( "%1(%2,'%3')" )
324+
.arg( mConn->majorVersion() < 2 ? "asbinary" : "st_asbinary" )
325+
.arg( geom )
326+
.arg( QgsPostgresProvider::endianString() );
327+
328+
query += delim + geom;
319329
delim = ",";
320330
}
321331

@@ -539,6 +549,7 @@ QgsPostgresFeatureSource::QgsPostgresFeatureSource( const QgsPostgresProvider* p
539549
, mSpatialColType( p->mSpatialColType )
540550
, mRequestedSrid( p->mRequestedSrid )
541551
, mDetectedSrid( p->mDetectedSrid )
552+
, mForce2d( p->mForce2d )
542553
, mRequestedGeomType( p->mRequestedGeomType )
543554
, mDetectedGeomType( p->mDetectedGeomType )
544555
, mPrimaryKeyType( p->mPrimaryKeyType )

src/providers/postgres/qgspostgresfeatureiterator.h

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class QgsPostgresFeatureSource : public QgsAbstractFeatureSource
4242
QgsPostgresGeometryColumnType mSpatialColType;
4343
QString mRequestedSrid;
4444
QString mDetectedSrid;
45+
bool mForce2d;
4546
QGis::WkbType mRequestedGeomType; //! geometry type requested in the uri
4647
QGis::WkbType mDetectedGeomType; //! geometry type detected in the database
4748
QgsPostgresPrimaryKeyType mPrimaryKeyType;

src/providers/postgres/qgspostgresprovider.cpp

+12-3
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ QgsPostgresProvider::QgsPostgresProvider( QString const & uri )
4646
, mPrimaryKeyType( pktUnknown )
4747
, mSpatialColType( sctNone )
4848
, mDetectedGeomType( QGis::WKBUnknown )
49+
, mForce2d( false )
4950
, mRequestedGeomType( QGis::WKBUnknown )
5051
, mShared( new QgsPostgresSharedData )
5152
, mUseEstimatedMetadata( false )
@@ -2558,12 +2559,12 @@ bool QgsPostgresProvider::getGeometryDetails()
25582559
}
25592560
}
25602561

2561-
QString detectedType = mRequestedGeomType == QGis::WKBUnknown ? "" : QgsPostgresConn::postgisWkbTypeName( mRequestedGeomType );
2562+
QString detectedType;
25622563
QString detectedSrid = mRequestedSrid;
2563-
if ( !schemaName.isEmpty() && ( detectedType.isEmpty() || detectedSrid.isEmpty() ) )
2564+
if ( !schemaName.isEmpty() )
25642565
{
25652566
// check geometry columns
2566-
sql = QString( "SELECT upper(type),srid FROM geometry_columns WHERE f_table_name=%1 AND f_geometry_column=%2 AND f_table_schema=%3" )
2567+
sql = QString( "SELECT upper(type),srid,coord_dimension FROM geometry_columns WHERE f_table_name=%1 AND f_geometry_column=%2 AND f_table_schema=%3" )
25672568
.arg( quotedValue( tableName ) )
25682569
.arg( quotedValue( geomCol ) )
25692570
.arg( quotedValue( schemaName ) );
@@ -2576,6 +2577,8 @@ bool QgsPostgresProvider::getGeometryDetails()
25762577
{
25772578
detectedType = result.PQgetvalue( 0, 0 );
25782579
detectedSrid = result.PQgetvalue( 0, 1 );
2580+
if ( result.PQgetvalue( 0, 2 ).toInt() == 4 )
2581+
mForce2d = true;
25792582
mSpatialColType = sctGeometry;
25802583
}
25812584
else
@@ -2667,6 +2670,10 @@ bool QgsPostgresProvider::getGeometryDetails()
26672670
}
26682671
}
26692672
}
2673+
else
2674+
{
2675+
detectedType = mRequestedGeomType == QGis::WKBUnknown ? "" : QgsPostgresConn::postgisWkbTypeName( mRequestedGeomType );
2676+
}
26702677

26712678
mDetectedGeomType = QgsPostgresConn::wkbTypeFromPostgis( detectedType );
26722679
mDetectedSrid = detectedSrid;
@@ -2729,6 +2736,7 @@ bool QgsPostgresProvider::getGeometryDetails()
27292736
// only what we requested is available
27302737
mDetectedGeomType = layerProperty.types[ 0 ];
27312738
mDetectedSrid = QString::number( layerProperty.srids[ 0 ] );
2739+
mForce2d = layerProperty.force2d;
27322740
}
27332741
}
27342742
else
@@ -2743,6 +2751,7 @@ bool QgsPostgresProvider::getGeometryDetails()
27432751
QgsDebugMsg( QString( "Requested SRID is %1" ).arg( mRequestedSrid ) );
27442752
QgsDebugMsg( QString( "Detected type is %1" ).arg( mDetectedGeomType ) );
27452753
QgsDebugMsg( QString( "Requested type is %1" ).arg( mRequestedGeomType ) );
2754+
QgsDebugMsg( QString( "Force to 2D %1" ).arg( mForce2d ? "Yes" : "No" ) );
27462755

27472756
mValid = ( mDetectedGeomType != QGis::WKBUnknown || mRequestedGeomType != QGis::WKBUnknown )
27482757
&& ( !mDetectedSrid.isEmpty() || !mRequestedSrid.isEmpty() );

src/providers/postgres/qgspostgresprovider.h

+1
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ class QgsPostgresProvider : public QgsVectorDataProvider
397397
QgsRectangle mLayerExtent; //! Rectangle that contains the extent (bounding box) of the layer
398398

399399
QGis::WkbType mDetectedGeomType; //! geometry type detected in the database
400+
bool mForce2d; //! geometry type needs to be forced to 2d (eg. ZM)
400401
QGis::WkbType mRequestedGeomType; //! geometry type requested in the uri
401402
QString mDetectedSrid; //! Spatial reference detected in the database
402403
QString mRequestedSrid; //! Spatial reference requested in the uri

0 commit comments

Comments
 (0)