Skip to content

Commit

Permalink
Improve performance of relationship discovery when adding OGR dataset…
Browse files Browse the repository at this point in the history
… with many layers (fixes #53525)
  • Loading branch information
rouault authored and nyalldawson committed Jul 19, 2023
1 parent c121ce3 commit 567fb82
Showing 1 changed file with 49 additions and 5 deletions.
54 changes: 49 additions & 5 deletions src/app/layers/qgsapplayerhandling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,10 @@ void QgsAppLayerHandling::addSortedLayersToLegend( QList<QgsMapLayer *> &layers

void QgsAppLayerHandling::postProcessAddedLayers( const QList<QgsMapLayer *> &layers )
{
std::map<QString, int> mapPathToReferenceCount;
std::map<QString, QList< QgsWeakRelation >> mapPathToRelations;

QgsProviderMetadata *ogrProviderMetadata = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "ogr" ) );
for ( QgsMapLayer *layer : layers )
{
switch ( layer->type() )
Expand All @@ -227,15 +231,55 @@ void QgsAppLayerHandling::postProcessAddedLayers( const QList<QgsMapLayer *> &la
// try to automatically load related tables for OGR layers
if ( vl->providerType() == QLatin1String( "ogr" ) )
{
const QVariantMap uriParts = ogrProviderMetadata->decodeUri( layer->source() );
const QString layerName = uriParts.value( QStringLiteral( "layerName" ) ).toString();
if ( layerName.isEmpty() )
continue;

// If this dataset is read more than once, collect and store all its
// relationships
const QString path = uriParts.value( QStringLiteral( "path" ) ).toString();
if ( ++mapPathToReferenceCount[path] == 2 )
{
std::unique_ptr< QgsAbstractDatabaseProviderConnection > conn { QgsMapLayerUtils::databaseConnection( vl ) };
if ( conn && ( conn->capabilities() & QgsAbstractDatabaseProviderConnection::Capability::RetrieveRelationships ) )
{
const QList< QgsWeakRelation > relations = conn->relationships( QString(), QString() );
mapPathToRelations[path] = relations;
}
}

// If this is a OGR dataset referenced by several layers, do not
// open a new connection on it but reuse the results of the first pass
auto iterMapPathToRelations = mapPathToRelations.find( path );
if ( iterMapPathToRelations != mapPathToRelations.end() )
{
if ( !iterMapPathToRelations->second.isEmpty() )
{
QList< QgsWeakRelation > layerRelations;
for ( const QgsWeakRelation &rel : std::as_const( iterMapPathToRelations->second ) )
{
const QVariantMap leftParts = ogrProviderMetadata->decodeUri( rel.referencedLayerSource() );
const QString leftTableName = leftParts.value( QStringLiteral( "layerName" ) ).toString();
if ( leftTableName == layerName )
{
layerRelations << rel;
}
}
if ( !layerRelations.isEmpty() )
{
vl->setWeakRelations( layerRelations );
resolveVectorLayerDependencies( vl, QgsMapLayer::StyleCategory::Relations, QgsVectorLayerRef::MatchType::Source, DependencyFlag::LoadAllRelationships | DependencyFlag::SilentLoad );
resolveVectorLayerWeakRelations( vl, QgsVectorLayerRef::MatchType::Source, true );
}
}
continue;
}

// first need to create weak relations!!
std::unique_ptr< QgsAbstractDatabaseProviderConnection > conn { QgsMapLayerUtils::databaseConnection( vl ) };
if ( conn && ( conn->capabilities() & QgsAbstractDatabaseProviderConnection::Capability::RetrieveRelationships ) )
{
const QVariantMap uriParts = QgsProviderRegistry::instance()->decodeUri( layer->providerType(), layer->source() );
const QString layerName = uriParts.value( QStringLiteral( "layerName" ) ).toString();
if ( layerName.isEmpty() )
continue;

const QList< QgsWeakRelation > relations = conn->relationships( QString(), layerName );
if ( !relations.isEmpty() )
{
Expand Down

0 comments on commit 567fb82

Please sign in to comment.