Skip to content

Commit

Permalink
[ogr] When querying sublayers, if an explicit geometry type is
Browse files Browse the repository at this point in the history
part of the uri being queried then we should only return
the sublayer with this same geometry type
  • Loading branch information
nyalldawson committed Jul 26, 2021
1 parent c5f7619 commit 54634d9
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 1 deletion.
29 changes: 28 additions & 1 deletion src/core/providers/ogr/qgsogrprovidermetadata.cpp
Expand Up @@ -1162,6 +1162,17 @@ QList<QgsProviderSublayerDetails> QgsOgrProviderMetadata::querySublayers( const
if ( originalUriLayerIdWasSpecified )
layerId = uriLayerId;

QgsWkbTypes::Type originalGeometryTypeFilter = QgsWkbTypes::Unknown;
bool originalUriGeometryTypeWasSpecified = false;
const QString originalGeometryTypeString = uriParts.value( QStringLiteral( "geometryType" ) ).toString();
if ( !originalGeometryTypeString.isEmpty() )
{
originalGeometryTypeFilter = QgsOgrUtils::ogrGeometryTypeToQgsWkbType(
QgsOgrProviderUtils::ogrWkbGeometryTypeFromName( originalGeometryTypeString )
);
originalUriGeometryTypeWasSpecified = true;
}

QString errCause;

QVariantMap firstLayerUriParts;
Expand Down Expand Up @@ -1226,6 +1237,13 @@ QList<QgsProviderSublayerDetails> QgsOgrProviderMetadata::querySublayers( const
for ( int i = 0; i < res.count(); ++i )
{
QVariantMap parts = decodeUri( res.at( i ).uri() );
if ( originalUriGeometryTypeWasSpecified && res.at( i ).wkbType() == QgsWkbTypes::Unknown )
{
res[ i ].setWkbType( originalGeometryTypeFilter );
parts.insert( QStringLiteral( "geometryType" ), originalGeometryTypeString );
res[i].setUri( encodeUri( parts ) );
}

if ( !parts.value( QStringLiteral( "layerName" ) ).toString().isEmpty() ||
!parts.value( QStringLiteral( "layerId" ) ).toString().isEmpty() )
continue;
Expand Down Expand Up @@ -1260,13 +1278,22 @@ QList<QgsProviderSublayerDetails> QgsOgrProviderMetadata::querySublayers( const

if ( originalUriLayerIdWasSpecified )
{
// remove non-matching, unwanted layers
// remove non-matching, unwanted layers by layer id
res.erase( std::remove_if( res.begin(), res.end(), [ = ]( const QgsProviderSublayerDetails & sublayer )
{
return sublayer.layerNumber() != uriLayerId;
} ), res.end() );
}

if ( originalUriGeometryTypeWasSpecified )
{
// remove non-matching, unwanted layers by geometry type
res.erase( std::remove_if( res.begin(), res.end(), [ = ]( const QgsProviderSublayerDetails & sublayer )
{
return sublayer.wkbType() != originalGeometryTypeFilter;
} ), res.end() );
}

return res;
}

Expand Down
101 changes: 101 additions & 0 deletions tests/src/python/test_provider_ogr.py
Expand Up @@ -1856,6 +1856,107 @@ def test_provider_sublayer_details(self):
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Polygon)

# mixed types source, but with a URI which specifies a particular type. Only this type should be returned
res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=Point"),
Qgis.SublayerQueryFlag.ResolveGeometryType)
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "mixed_types")
self.assertEqual(res[0].description(), "")
self.assertEqual(res[0].uri(), "{}/mixed_types.TAB|geometrytype=Point".format(TEST_DATA_DIR))
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].featureCount(), 4)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Point)
self.assertEqual(res[0].geometryColumnName(), '')
self.assertEqual(res[0].driverName(), 'MapInfo File')
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Point)

res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=LineString"),
Qgis.SublayerQueryFlag.ResolveGeometryType)
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "mixed_types")
self.assertEqual(res[0].description(), "")
self.assertEqual(res[0].uri(), "{}/mixed_types.TAB|geometrytype=LineString".format(TEST_DATA_DIR))
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].featureCount(), 4)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.LineString)
self.assertEqual(res[0].geometryColumnName(), '')
self.assertEqual(res[0].driverName(), 'MapInfo File')
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.LineString)

res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=Polygon"),
Qgis.SublayerQueryFlag.ResolveGeometryType)
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "mixed_types")
self.assertEqual(res[0].description(), "")
self.assertEqual(res[0].uri(), "{}/mixed_types.TAB|geometrytype=Polygon".format(TEST_DATA_DIR))
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].featureCount(), 3)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Polygon)
self.assertEqual(res[0].geometryColumnName(), '')
self.assertEqual(res[0].driverName(), 'MapInfo File')
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Polygon)

# same as above, but without ResolveGeometryType flag
res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=Point"))
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "mixed_types")
self.assertEqual(res[0].description(), "")
self.assertEqual(res[0].uri(), "{}/mixed_types.TAB|geometrytype=Point".format(TEST_DATA_DIR))
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Point)
self.assertEqual(res[0].geometryColumnName(), '')
self.assertEqual(res[0].driverName(), 'MapInfo File')
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Point)

res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=LineString"))
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "mixed_types")
self.assertEqual(res[0].description(), "")
self.assertEqual(res[0].uri(), "{}/mixed_types.TAB|geometrytype=LineString".format(TEST_DATA_DIR))
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.LineString)
self.assertEqual(res[0].geometryColumnName(), '')
self.assertEqual(res[0].driverName(), 'MapInfo File')
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.LineString)

res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB|geometrytype=Polygon"))
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "mixed_types")
self.assertEqual(res[0].description(), "")
self.assertEqual(res[0].uri(), "{}/mixed_types.TAB|geometrytype=Polygon".format(TEST_DATA_DIR))
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Polygon)
self.assertEqual(res[0].geometryColumnName(), '')
self.assertEqual(res[0].driverName(), 'MapInfo File')
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Polygon)

# spatialite
res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "provider/spatialite.db"))
self.assertCountEqual([{'name': r.name(),
Expand Down

0 comments on commit 54634d9

Please sign in to comment.