[ogr] When querying sublayers, if an explicit geometry type is

part of the uri being queried then we should only return
the sublayer with this same geometry type
This commit is contained in:
Nyall Dawson 2021-07-26 16:53:09 +10:00
parent c5f76191ae
commit 54634d9bec
2 changed files with 129 additions and 1 deletions

View File

@ -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;
@ -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;
@ -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;
}

View File

@ -1856,6 +1856,107 @@ class PyQgsOGRProvider(unittest.TestCase):
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(),