Skip to content

Commit

Permalink
Fix querying sublayers for zip items
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Jul 12, 2021
1 parent 593823c commit 5556848
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 4 deletions.
29 changes: 26 additions & 3 deletions src/core/providers/ogr/qgsogrprovidermetadata.cpp
Expand Up @@ -28,6 +28,7 @@ email : nyall dot dawson at gmail dot com
#include "qgsgeopackageproviderconnection.h"
#include "qgsogrdbconnection.h"
#include "qgsprovidersublayerdetails.h"
#include "qgszipitem.h"

#include <QFileInfo>
#include <QFile>
Expand Down Expand Up @@ -1029,11 +1030,25 @@ bool QgsOgrProviderMetadata::uriIsBlocklisted( const QString &uri ) const
return false;
}

QList<QgsProviderSublayerDetails> QgsOgrProviderMetadata::querySublayers( const QString &uri, Qgis::SublayerQueryFlags flags, QgsFeedback *feedback ) const
QList<QgsProviderSublayerDetails> QgsOgrProviderMetadata::querySublayers( const QString &u, Qgis::SublayerQueryFlags flags, QgsFeedback *feedback ) const
{
QString uri = u;
QStringList options { QStringLiteral( "@LIST_ALL_TABLES=YES" ) };

const QVariantMap uriParts = decodeUri( uri );
QVariantMap uriParts = decodeUri( uri );

// Try to open using VSIFileHandler
QString vsiPrefix = QgsZipItem::vsiPrefix( uri );
if ( !vsiPrefix.isEmpty() && uriParts.value( QStringLiteral( "vsiPrefix" ) ).toString().isEmpty() )
{
if ( !uri.startsWith( vsiPrefix ) )
{
// update zip etc to use vsi prefix if it wasn't explicitly specified
uri = vsiPrefix + uri;
uriParts = decodeUri( uri );
}
}

const QString originalUriLayerName = uriParts.value( QStringLiteral( "layerName" ) ).toString();
int layerId = 0;
bool originalUriLayerIdWasSpecified = false;
Expand All @@ -1042,7 +1057,15 @@ QList<QgsProviderSublayerDetails> QgsOgrProviderMetadata::querySublayers( const
layerId = uriLayerId;

QString errCause;
QgsOgrLayerUniquePtr firstLayer = QgsOgrProviderUtils::getLayer( uriParts.value( QStringLiteral( "path" ) ).toString(), false, options, layerId, errCause, true );

QVariantMap firstLayerUriParts;
if ( !uriParts.value( QStringLiteral( "vsiPrefix" ) ).toString().isEmpty() )
firstLayerUriParts.insert( QStringLiteral( "vsiPrefix" ), uriParts.value( QStringLiteral( "vsiPrefix" ) ) );
if ( !uriParts.value( QStringLiteral( "vsiSuffix" ) ).toString().isEmpty() )
firstLayerUriParts.insert( QStringLiteral( "vsiSuffix" ), uriParts.value( QStringLiteral( "vsiSuffix" ) ) );
firstLayerUriParts.insert( QStringLiteral( "path" ), uriParts.value( QStringLiteral( "path" ) ) );

QgsOgrLayerUniquePtr firstLayer = QgsOgrProviderUtils::getLayer( encodeUri( firstLayerUriParts ), false, options, layerId, errCause, true );
if ( !firstLayer )
return {};

Expand Down
17 changes: 16 additions & 1 deletion tests/src/python/test_provider_ogr.py
Expand Up @@ -1530,6 +1530,22 @@ def test_provider_sublayer_details(self):
self.assertEqual(res[0].wkbType(), QgsWkbTypes.LineString)
self.assertEqual(res[0].geometryColumnName(), '')

# zip file layer vector
res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'zip', 'points2.zip'))
self.assertEqual(len(res), 1)
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "points")
self.assertEqual(res[0].description(), '')
self.assertEqual(res[0].uri(), '/vsizip/' + TEST_DATA_DIR + "/zip/points2.zip|layername=points")
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Point)
self.assertEqual(res[0].geometryColumnName(), '')
options = QgsProviderSublayerDetails.LayerOptions(QgsCoordinateTransformContext())
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
self.assertEqual(vl.wkbType(), QgsWkbTypes.Point)

# geometry collection sublayers -- requires a scan to resolve geometry type
res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'multipatch.shp'))
self.assertEqual(len(res), 1)
Expand Down Expand Up @@ -1568,7 +1584,6 @@ def test_provider_sublayer_details(self):
self.assertEqual(res[0].geometryColumnName(), 'geometry')

# make sure result is valid to load layer from
options = QgsProviderSublayerDetails.LayerOptions(QgsCoordinateTransformContext())
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())

Expand Down

0 comments on commit 5556848

Please sign in to comment.