Skip to content
Permalink
Browse files
[ogr] Add support for retrieving system tables when querying sublayers
Fairly rudimentary for now, requires GDAL API update for more format
support
  • Loading branch information
nyalldawson committed Aug 26, 2021
1 parent 44d3ac8 commit 10287f02a66d546a526fd31cc4a1eccbbc9b31ac
@@ -599,9 +599,14 @@ QStringList subLayerDetailsToStringList( const QList< QgsProviderSublayerDetails
QStringList QgsOgrProvider::subLayers() const
{
const bool withFeatureCount = ( mReadFlags & QgsDataProvider::SkipFeatureCount ) == 0;
return subLayerDetailsToStringList( _subLayers( withFeatureCount
? ( Qgis::SublayerQueryFlag::CountFeatures | Qgis::SublayerQueryFlag::ResolveGeometryType )
: Qgis::SublayerQueryFlag::ResolveGeometryType ) );

Qgis::SublayerQueryFlags flags = withFeatureCount
? ( Qgis::SublayerQueryFlag::CountFeatures | Qgis::SublayerQueryFlag::ResolveGeometryType )
: Qgis::SublayerQueryFlag::ResolveGeometryType;
if ( mIsSubLayer )
flags |= Qgis::SublayerQueryFlag::IncludeSystemTables;

return subLayerDetailsToStringList( _subLayers( flags ) );
}

QgsLayerMetadata QgsOgrProvider::layerMetadata() const
@@ -625,7 +630,7 @@ QList<QgsProviderSublayerDetails> QgsOgrProvider::_subLayers( Qgis::SublayerQuer
const size_t totalLayerCount = layerCount();
if ( mOgrLayer && ( mIsSubLayer || totalLayerCount == 1 ) )
{
mSubLayerList << QgsOgrProviderUtils::querySubLayerList( mLayerIndex, mOgrLayer, mGDALDriverName, flags, mIsSubLayer, dataSourceUri(), totalLayerCount == 1 );
mSubLayerList << QgsOgrProviderUtils::querySubLayerList( mLayerIndex, mOgrLayer, mGDALDriverName, flags, dataSourceUri(), totalLayerCount == 1 );
}
else
{
@@ -648,13 +653,14 @@ QList<QgsProviderSublayerDetails> QgsOgrProvider::_subLayers( Qgis::SublayerQuer
if ( !layer )
continue;

mSubLayerList << QgsOgrProviderUtils::querySubLayerList( i, layer.get(), mGDALDriverName, flags, mIsSubLayer, dataSourceUri(), totalLayerCount == 1 );
mSubLayerList << QgsOgrProviderUtils::querySubLayerList( i, layer.get(), mGDALDriverName, flags, dataSourceUri(), totalLayerCount == 1 );
if ( firstLayer == nullptr )
{
firstLayer = std::move( layer );
}
}
}

return mSubLayerList;
}

@@ -1198,7 +1198,7 @@ QList<QgsProviderSublayerDetails> QgsOgrProviderMetadata::querySublayers( const
QList<QgsProviderSublayerDetails> res;
if ( layerCount == 1 )
{
res << QgsOgrProviderUtils::querySubLayerList( 0, firstLayer.get(), driverName, flags, false, uri, true, feedback );
res << QgsOgrProviderUtils::querySubLayerList( 0, firstLayer.get(), driverName, flags, uri, true, feedback );
}
else
{
@@ -1239,7 +1239,7 @@ QList<QgsProviderSublayerDetails> QgsOgrProviderMetadata::querySublayers( const
if ( !originalUriLayerName.isEmpty() && layerName != originalUriLayerName )
continue;

res << QgsOgrProviderUtils::querySubLayerList( i, sublayer, driverName, flags, false, uri, false, feedback );
res << QgsOgrProviderUtils::querySubLayerList( i, sublayer, driverName, flags, uri, false, feedback );
}
}

@@ -2313,26 +2313,27 @@ bool QgsOgrProviderUtils::canDriverShareSameDatasetAmongLayers( const QString &d
!( updateMode && dsName.endsWith( QLatin1String( ".shp.zip" ), Qt::CaseInsensitive ) );
}

QList< QgsProviderSublayerDetails > QgsOgrProviderUtils::querySubLayerList( int i, QgsOgrLayer *layer, const QString &driverName, Qgis::SublayerQueryFlags flags, bool isSubLayer, const QString &baseUri, bool hasSingleLayerOnly, QgsFeedback *feedback )
QList< QgsProviderSublayerDetails > QgsOgrProviderUtils::querySubLayerList( int i, QgsOgrLayer *layer, const QString &driverName, Qgis::SublayerQueryFlags flags, const QString &baseUri, bool hasSingleLayerOnly, QgsFeedback *feedback )
{
const QString layerName = QString::fromUtf8( layer->name() );

if ( !isSubLayer && ( layerName == QLatin1String( "layer_styles" ) ||
layerName == QLatin1String( "qgis_projects" ) ) )
QStringList privateLayerNames { QStringLiteral( "layer_styles" ),
QStringLiteral( "qgis_projects" )};
if ( driverName == QLatin1String( "SQLite" ) )
{
// Ignore layer_styles (coming from QGIS styling support) and
// qgis_projects (coming from http://plugins.qgis.org/plugins/QgisGeopackage/)
return {};
privateLayerNames.append( QgsSqliteUtils::systemTables() );
}

QStringList skippedLayerNames;
if ( driverName == QLatin1String( "SQLite" ) )
Qgis::SublayerFlags layerFlags;
if ( ( driverName == QLatin1String( "SQLite" ) && layerName.contains( QRegularExpression( QStringLiteral( "idx_.*_geom(etry)?($|_.*)" ), QRegularExpression::PatternOption::CaseInsensitiveOption ) ) )
|| privateLayerNames.contains( layerName ) )
{
skippedLayerNames = QgsSqliteUtils::systemTables();
layerFlags |= Qgis::SublayerFlag::SystemTable;
}
if ( ( driverName == QLatin1String( "SQLite" ) && layerName.contains( QRegularExpression( QStringLiteral( "idx_.*_geom(etry)?($|_.*)" ), QRegularExpression::PatternOption::CaseInsensitiveOption ) ) )
|| skippedLayerNames.contains( layerName ) )

if ( !( flags & Qgis::SublayerQueryFlag::IncludeSystemTables ) && ( layerFlags & Qgis::SublayerFlag::SystemTable ) )
{
// layer is a system table, and we are not scanning for them
return {};
}

@@ -2389,6 +2390,7 @@ QList< QgsProviderSublayerDetails > QgsOgrProviderUtils::querySubLayerList( int
details.setDescription( longDescription );
details.setProviderKey( QStringLiteral( "ogr" ) );
details.setDriverName( driverName );
details.setFlags( layerFlags );

const QString uri = QgsOgrProviderMetadata().encodeUri( parts );
details.setUri( uri );
@@ -2479,6 +2481,7 @@ QList< QgsProviderSublayerDetails > QgsOgrProviderUtils::querySubLayerList( int
details.setDescription( longDescription );
details.setProviderKey( QStringLiteral( "ogr" ) );
details.setDriverName( driverName );
details.setFlags( layerFlags );

// if we had to iterate through the table to find geometry types, make sure to include these
// in the uri for the sublayers (otherwise we'll be forced to re-do this iteration whenever
@@ -260,7 +260,7 @@ class CORE_EXPORT QgsOgrProviderUtils
bool updateMode,
const QString &dsName );

static QList<QgsProviderSublayerDetails> querySubLayerList( int i, QgsOgrLayer *layer, const QString &driverName, Qgis::SublayerQueryFlags flags, bool isSubLayer,
static QList<QgsProviderSublayerDetails> querySubLayerList( int i, QgsOgrLayer *layer, const QString &driverName, Qgis::SublayerQueryFlags flags,
const QString &baseUri, bool hasSingleLayerOnly, QgsFeedback *feedback = nullptr );

/**
@@ -2045,6 +2045,49 @@ def test_provider_sublayer_details(self):
'driverName': 'SQLite',
'geomColName': ''}])

# sqlite
res = metadata.querySublayers(
os.path.join(TEST_DATA_DIR, "valuerelation_widget_wrapper_test.spatialite.sqlite"))
self.assertCountEqual([{'name': r.name(),
'systemTable': bool(r.flags() & Qgis.SublayerFlag.SystemTable)} for r in res],
[{'name': 'authors', 'systemTable': False},
{'name': 'json', 'systemTable': False}])

# retrieve system tables
res = metadata.querySublayers(
os.path.join(TEST_DATA_DIR, "valuerelation_widget_wrapper_test.spatialite.sqlite"),
Qgis.SublayerQueryFlag.IncludeSystemTables)
self.assertCountEqual([{'name': r.name(),
'systemTable': bool(r.flags() & Qgis.SublayerFlag.SystemTable)} for r in res],
[{'name': 'ElementaryGeometries', 'systemTable': True},
{'name': 'SpatialIndex', 'systemTable': True},
{'name': 'authors', 'systemTable': False},
{'name': 'geom_cols_ref_sys', 'systemTable': True},
{'name': 'geometry_columns', 'systemTable': True},
{'name': 'geometry_columns_auth', 'systemTable': True},
{'name': 'geometry_columns_field_infos', 'systemTable': True},
{'name': 'geometry_columns_statistics', 'systemTable': True},
{'name': 'geometry_columns_time', 'systemTable': True},
{'name': 'json', 'systemTable': False},
{'name': 'spatial_ref_sys', 'systemTable': True},
{'name': 'spatial_ref_sys_all', 'systemTable': True},
{'name': 'spatial_ref_sys_aux', 'systemTable': True},
{'name': 'spatialite_history', 'systemTable': True},
{'name': 'sql_statements_log', 'systemTable': True},
{'name': 'sqlite_sequence', 'systemTable': True},
{'name': 'vector_layers', 'systemTable': True},
{'name': 'vector_layers_auth', 'systemTable': True},
{'name': 'vector_layers_field_infos', 'systemTable': True},
{'name': 'vector_layers_statistics', 'systemTable': True},
{'name': 'views_geometry_columns', 'systemTable': True},
{'name': 'views_geometry_columns_auth', 'systemTable': True},
{'name': 'views_geometry_columns_field_infos', 'systemTable': True},
{'name': 'views_geometry_columns_statistics', 'systemTable': True},
{'name': 'virts_geometry_columns', 'systemTable': True},
{'name': 'virts_geometry_columns_auth', 'systemTable': True},
{'name': 'virts_geometry_columns_field_infos', 'systemTable': True},
{'name': 'virts_geometry_columns_statistics', 'systemTable': True}])

@unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 4, 0), "GDAL 3.4 required")
def test_provider_sublayer_details_hierarchy(self):
"""

0 comments on commit 10287f0

Please sign in to comment.