Skip to content
Permalink
Browse files
Postgres: scan whole table when not using estimated metadata
Remove the LIMIT when not using estimated metadata.

Fixes #43186
  • Loading branch information
elpaso committed May 27, 2021
1 parent 0b511cc commit 2b404eaea8d19a5e9df1f2f7fcd5a8fc63d19325
@@ -1869,6 +1869,9 @@ void QgsPostgresConn::retrieveLayerTypes( QVector<QgsPostgresLayerProperty *> &l
QString table;
QString query;

// Limit table row scan if useEstimatedMetadata
const QString tableScanLimit { useEstimatedMetadata ? QStringLiteral( " LIMIT %1" ).arg( GEOM_TYPE_SELECT_LIMIT ) : QString() };

int i = 0;
for ( auto *layerPropertyPtr : layerProperties )
{
@@ -1924,12 +1927,12 @@ void QgsPostgresConn::retrieveLayerTypes( QVector<QgsPostgresLayerProperty *> &l
"FROM %3 "
"%2 IS NOT NULL "
"%4 " // SQL clause
"LIMIT %5" )
"%5" )
.arg( i - 1 )
.arg( quotedIdentifier( layerProperty.geometryColName ) )
.arg( table )
.arg( layerProperty.sql.isEmpty() ? QString() : QStringLiteral( " AND %1" ).arg( layerProperty.sql ) )
.arg( GEOM_TYPE_SELECT_LIMIT );
.arg( tableScanLimit );
}
}

@@ -1941,11 +1944,11 @@ void QgsPostgresConn::retrieveLayerTypes( QVector<QgsPostgresLayerProperty *> &l
// our estimation ignores that a where clause might restrict the feature type or srid
if ( useEstimatedMetadata )
{
table = QStringLiteral( "(SELECT %1 FROM %2 WHERE %3%1 IS NOT NULL LIMIT %4) AS t" )
table = QStringLiteral( "(SELECT %1 FROM %2 WHERE %3%1 IS NOT NULL %4) AS t" )
.arg( quotedIdentifier( layerProperty.geometryColName ),
table,
layerProperty.sql.isEmpty() ? QString() : QStringLiteral( " (%1) AND " ).arg( layerProperty.sql ) )
.arg( GEOM_TYPE_SELECT_LIMIT );
.arg( tableScanLimit );
}
else if ( !layerProperty.sql.isEmpty() )
{
@@ -1999,10 +2002,10 @@ void QgsPostgresConn::retrieveLayerTypes( QVector<QgsPostgresLayerProperty *> &l
if ( type == QgsWkbTypes::Unknown )
{
// Subselect to limit the "array_agg(DISTINCT", see previous comment.
sql += QStringLiteral( " FROM (SELECT %1 from %2 LIMIT %3) as _unused" )
sql += QStringLiteral( " FROM (SELECT %1 from %2 %3) as _unused" )
.arg( quotedIdentifier( layerProperty.geometryColName ) )
.arg( table )
.arg( GEOM_TYPE_SELECT_LIMIT );
.arg( tableScanLimit );
}
else
{
@@ -395,6 +395,60 @@ def test_zm(self):
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'])

def test_table_scan(self):
"""Test that with use estimated metadata disabled all geometry column
types can be identified, text for GH #43186 """

md = QgsProviderRegistry.instance().providerMetadata('postgres')
uri = QgsDataSourceUri(self.uri)
conn = md.createConnection(uri.uri(), {'estimatedMetadata': True})

sql = """
DROP TABLE IF EXISTS qgis_test.geometry_table_with_multiple_types;
CREATE TABLE qgis_test.geometry_table_with_multiple_types (
id SERIAL PRIMARY KEY,
geom geometry(Geometry,4326)
);
"""

conn.executeSql(sql)

for i in range(110):
sql = "INSERT INTO qgis_test.geometry_table_with_multiple_types (geom) VALUES (ST_GeomFromText('point(9 45)', 4326));"
conn.executeSql(sql)

for i in range(10):
sql = "INSERT INTO qgis_test.geometry_table_with_multiple_types (geom) VALUES (ST_GeomFromText('linestring(9 45, 10 46)', 4326));"
conn.executeSql(sql)

table = conn.table('qgis_test', 'geometry_table_with_multiple_types')

self.assertEqual(len(table.geometryColumnTypes()), 1)

uri = QgsDataSourceUri(self.uri)
uri.setUseEstimatedMetadata(False)
conn = md.createConnection(uri.uri(), {'estimatedMetadata': False})

table = conn.table('qgis_test', 'geometry_table_with_multiple_types')

self.assertEqual(len(table.geometryColumnTypes()), 2)

# Tesf for #43199

uri.setSchema('qgis_test')
uri.setTable('geometry_table_with_multiple_types')
uri.setGeometryColumn('geom')
uri.setWkbType(QgsWkbTypes.Point)
vl = QgsVectorLayer(uri.uri(), 'points', 'postgres')
self.assertTrue(vl.isValid())
self.assertEqual(vl.featureCount(), 110)

uri.setGeometryColumn('geom')
uri.setWkbType(QgsWkbTypes.LineString)
vl = QgsVectorLayer(uri.uri(), 'lines', 'postgres')
self.assertTrue(vl.isValid())
self.assertEqual(vl.featureCount(), 10)


if __name__ == '__main__':
unittest.main()

0 comments on commit 2b404ea

Please sign in to comment.