diff --git a/src/providers/postgres/qgspgsourceselect.cpp b/src/providers/postgres/qgspgsourceselect.cpp index c9f4a90a1d15..9d29bca724d9 100644 --- a/src/providers/postgres/qgspgsourceselect.cpp +++ b/src/providers/postgres/qgspgsourceselect.cpp @@ -61,10 +61,25 @@ QWidget *QgsPgSourceSelectDelegate::createEditor( QWidget *parent, const QStyleO QComboBox *cb = new QComboBox( parent ); static const QList types { QgsWkbTypes::Point, QgsWkbTypes::LineString, + QgsWkbTypes::LineStringZ, + QgsWkbTypes::LineStringM, + QgsWkbTypes::LineStringZM, QgsWkbTypes::Polygon, + QgsWkbTypes::PolygonZ, + QgsWkbTypes::PolygonM, + QgsWkbTypes::PolygonZM, QgsWkbTypes::MultiPoint, + QgsWkbTypes::MultiPointZ, + QgsWkbTypes::MultiPointM, + QgsWkbTypes::MultiPointZM, QgsWkbTypes::MultiLineString, + QgsWkbTypes::MultiLineStringZ, + QgsWkbTypes::MultiLineStringM, + QgsWkbTypes::MultiLineStringZM, QgsWkbTypes::MultiPolygon, + QgsWkbTypes::MultiPolygonZ, + QgsWkbTypes::MultiPolygonM, + QgsWkbTypes::MultiPolygonZM, QgsWkbTypes::NoGeometry }; for ( QgsWkbTypes::Type type : types ) { diff --git a/src/providers/postgres/qgspostgresconn.cpp b/src/providers/postgres/qgspostgresconn.cpp index c9dbcb911a36..1307fa423c5c 100644 --- a/src/providers/postgres/qgspostgresconn.cpp +++ b/src/providers/postgres/qgspostgresconn.cpp @@ -1900,7 +1900,7 @@ void QgsPostgresConn::retrieveLayerTypes( QVector &l // SRID is already known if ( srid != std::numeric_limits::min() ) { - sql += QStringLiteral( "SELECT %1, array_agg( '%2:RASTER'::text )" ) + sql += QStringLiteral( "SELECT %1, array_agg( '%2:RASTER:-1'::text )" ) .arg( i - 1 ) .arg( srid ); } @@ -1909,7 +1909,7 @@ void QgsPostgresConn::retrieveLayerTypes( QVector &l if ( useEstimatedMetadata ) { sql = QStringLiteral( "SELECT %1, " - "array_agg( srid || ':RASTER') " + "array_agg( srid || ':RASTER:-1') " "FROM raster_columns " "WHERE r_raster_column = %2 AND r_table_schema = %3 AND r_table_name = %4" ) .arg( i - 1 ) @@ -1920,7 +1920,7 @@ void QgsPostgresConn::retrieveLayerTypes( QVector &l else { sql = QStringLiteral( "SELECT %1, " - "array_agg( DISTINCT ST_SRID( %2 ) || ':RASTER' ) " + "array_agg( DISTINCT ST_SRID( %2 ) || ':RASTER:-1' ) " "FROM %3 " "%2 IS NOT NULL " "%4 " // SQL clause @@ -1983,13 +1983,13 @@ void QgsPostgresConn::retrieveLayerTypes( QVector &l // full table. However SQL does not allow that. // So we have to do a subselect on the table to add the LIMIT, // see comment in the following code. - sql += QStringLiteral( "UPPER(geometrytype(%1%2))" ) + sql += QStringLiteral( "UPPER(geometrytype(%1%2)) || ':' || ST_Zmflag(%1%2)" ) .arg( quotedIdentifier( layerProperty.geometryColName ), castToGeometry ? "::geometry" : "" ); } else { - sql += QStringLiteral( "%1::text" ) + sql += QStringLiteral( "%1::text || ':-1'" ) .arg( quotedValue( QgsPostgresConn::postgisWkbTypeName( type ) ) ); } @@ -2061,9 +2061,28 @@ void QgsPostgresConn::retrieveLayerTypes( QVector &l if ( sridAndTypeString == "NULL" ) continue; - QStringList sridAndType = sridAndTypeString.split( ':' ); - int srid = sridAndType[0].toInt(); + const QStringList sridAndType = sridAndTypeString.split( ':' ); + Q_ASSERT( sridAndType.size() == 3 ); + const int srid = sridAndType[0].toInt(); QString typeString = sridAndType[1]; + const int zmFlags = sridAndType[2].toInt(); + + switch ( zmFlags ) + { + case 1: + typeString.append( 'M' ); + break; + case 2: + typeString.append( 'Z' ); + break; + case 3: + typeString.append( QStringLiteral( "ZM" ) ); + break; + default: + case 0: + case -1: + break; + } auto type = QgsPostgresConn::wkbTypeFromPostgis( typeString ); auto flatType = QgsWkbTypes::flatType( type ); @@ -2332,10 +2351,34 @@ QgsWkbTypes::Type QgsPostgresConn::wkbTypeFromPostgis( const QString &type ) { return QgsWkbTypes::MultiPolygon; } + else if ( ( type == QLatin1String( "POLYHEDRALSURFACEZ" ) ) || ( type == QLatin1String( "TINZ" ) ) ) + { + return QgsWkbTypes::MultiPolygonZ; + } + else if ( ( type == QLatin1String( "POLYHEDRALSURFACEM" ) ) || ( type == QLatin1String( "TINM" ) ) ) + { + return QgsWkbTypes::MultiPolygonM; + } + else if ( ( type == QLatin1String( "POLYHEDRALSURFACEZM" ) ) || ( type == QLatin1String( "TINZM" ) ) ) + { + return QgsWkbTypes::MultiPolygonZM; + } else if ( type == QLatin1String( "TRIANGLE" ) ) { return QgsWkbTypes::Polygon; } + else if ( type == QLatin1String( "TRIANGLEZ" ) ) + { + return QgsWkbTypes::PolygonZ; + } + else if ( type == QLatin1String( "TRIANGLEM" ) ) + { + return QgsWkbTypes::PolygonM; + } + else if ( type == QLatin1String( "TRIANGLEZM" ) ) + { + return QgsWkbTypes::PolygonZM; + } return QgsWkbTypes::parseType( type ); } diff --git a/tests/src/python/test_qgsproviderconnection_postgres.py b/tests/src/python/test_qgsproviderconnection_postgres.py index a6c3d061c5b1..ed08eafe09f5 100644 --- a/tests/src/python/test_qgsproviderconnection_postgres.py +++ b/tests/src/python/test_qgsproviderconnection_postgres.py @@ -377,6 +377,24 @@ def test_exceptions(self): with self.assertRaises(QgsProviderConnectionException): conn.table('my_not_existent_schema', 'my_not_existent_table') + def test_zm(self): + """Test regression GH #43268""" + + md = QgsProviderRegistry.instance().providerMetadata('postgres') + conn = md.createConnection(self.uri, {}) + sql = """ + DROP TABLE IF EXISTS qgis_test.gh_43268_test_zm; + CREATE TABLE qgis_test.gh_43268_test_zm (geom geometry(GeometryZ)); + INSERT INTO qgis_test.gh_43268_test_zm (geom) VALUES + ('POINT(0 0 0)'), + ('LINESTRING(0 0 0, 0 0 0)'), + ('POLYGON((0 0 0, 0 0 0, 0 0 0, 0 0 0))'); + """ + conn.executeSql(sql) + + table_info = conn.table('qgis_test', 'gh_43268_test_zm') + self.assertEqual(sorted([QgsWkbTypes.displayString(col.wkbType) for col in table_info.geometryColumnTypes()]), ['LineStringZ', 'PointZ', 'PolygonZ']) + if __name__ == '__main__': unittest.main()