mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
[OGR provider] Fix reading of OSM datasets when opening several layers at the same time (fixes #19477)
This commit is contained in:
parent
9dd1406539
commit
fabdc04764
@ -58,7 +58,7 @@ QgsOgrFeatureIterator::QgsOgrFeatureIterator( QgsOgrFeatureSource *source, bool
|
||||
else
|
||||
{
|
||||
//QgsDebugMsg( "Feature iterator of " + mSource->mLayerName + ": acquiring connection");
|
||||
mConn = QgsOgrConnPool::instance()->acquireConnection( QgsOgrProviderUtils::connectionPoolId( mSource->mDataSource ), mRequest.timeout(), mRequest.requestMayBeNested() );
|
||||
mConn = QgsOgrConnPool::instance()->acquireConnection( QgsOgrProviderUtils::connectionPoolId( mSource->mDataSource, mSource->mShareSameDatasetAmongLayers ), mRequest.timeout(), mRequest.requestMayBeNested() );
|
||||
if ( !mConn || !mConn->ds )
|
||||
{
|
||||
return;
|
||||
@ -468,6 +468,7 @@ bool QgsOgrFeatureIterator::readFeature( gdal::ogr_feature_unique_ptr fet, QgsFe
|
||||
|
||||
QgsOgrFeatureSource::QgsOgrFeatureSource( const QgsOgrProvider *p )
|
||||
: mDataSource( p->dataSourceUri( true ) )
|
||||
, mShareSameDatasetAmongLayers( p->mShareSameDatasetAmongLayers )
|
||||
, mLayerName( p->layerName() )
|
||||
, mLayerIndex( p->layerIndex() )
|
||||
, mSubsetString( p->mSubsetString )
|
||||
@ -486,12 +487,12 @@ QgsOgrFeatureSource::QgsOgrFeatureSource( const QgsOgrProvider *p )
|
||||
}
|
||||
for ( int i = ( p->mFirstFieldIsFid ) ? 1 : 0; i < mFields.size(); i++ )
|
||||
mFieldsWithoutFid.append( mFields.at( i ) );
|
||||
QgsOgrConnPool::instance()->ref( QgsOgrProviderUtils::connectionPoolId( mDataSource ) );
|
||||
QgsOgrConnPool::instance()->ref( QgsOgrProviderUtils::connectionPoolId( mDataSource, mShareSameDatasetAmongLayers ) );
|
||||
}
|
||||
|
||||
QgsOgrFeatureSource::~QgsOgrFeatureSource()
|
||||
{
|
||||
QgsOgrConnPool::instance()->unref( QgsOgrProviderUtils::connectionPoolId( mDataSource ) );
|
||||
QgsOgrConnPool::instance()->unref( QgsOgrProviderUtils::connectionPoolId( mDataSource, mShareSameDatasetAmongLayers ) );
|
||||
}
|
||||
|
||||
QgsFeatureIterator QgsOgrFeatureSource::getFeatures( const QgsFeatureRequest &request )
|
||||
|
@ -38,6 +38,7 @@ class QgsOgrFeatureSource : public QgsAbstractFeatureSource
|
||||
|
||||
private:
|
||||
QString mDataSource;
|
||||
bool mShareSameDatasetAmongLayers;
|
||||
QString mLayerName;
|
||||
int mLayerIndex;
|
||||
QString mSubsetString;
|
||||
|
@ -538,15 +538,15 @@ QgsOgrProvider::QgsOgrProvider( QString const &uri, const ProviderOptions &optio
|
||||
|
||||
setNativeTypes( nativeTypes );
|
||||
|
||||
QgsOgrConnPool::instance()->ref( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ) ) );
|
||||
QgsOgrConnPool::instance()->ref( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ), mShareSameDatasetAmongLayers ) );
|
||||
}
|
||||
|
||||
QgsOgrProvider::~QgsOgrProvider()
|
||||
{
|
||||
QgsOgrConnPool::instance()->unref( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ) ) );
|
||||
QgsOgrConnPool::instance()->unref( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ), mShareSameDatasetAmongLayers ) );
|
||||
// We must also make sure to flush unusef cached connections so that
|
||||
// the file can be removed (#15137)
|
||||
QgsOgrConnPool::instance()->invalidateConnections( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ) ) );
|
||||
QgsOgrConnPool::instance()->invalidateConnections( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ), mShareSameDatasetAmongLayers ) );
|
||||
|
||||
// Do that as last step for final cleanup that might be prevented by
|
||||
// still opened datasets.
|
||||
@ -948,7 +948,7 @@ OGRwkbGeometryType QgsOgrProvider::getOgrGeomType( OGRLayerH ogrLayer )
|
||||
|
||||
void QgsOgrProvider::loadFields()
|
||||
{
|
||||
QgsOgrConnPool::instance()->invalidateConnections( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ) ) );
|
||||
QgsOgrConnPool::instance()->invalidateConnections( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ), mShareSameDatasetAmongLayers ) );
|
||||
//the attribute fields need to be read again when the encoding changes
|
||||
mAttributeFields.clear();
|
||||
mDefaultValues.clear();
|
||||
@ -1642,7 +1642,7 @@ bool QgsOgrProvider::addAttributes( const QList<QgsField> &attributes )
|
||||
{
|
||||
// adding attributes in mapinfo requires to be able to delete the .dat file
|
||||
// so drop any cached connections.
|
||||
QgsOgrConnPool::instance()->invalidateConnections( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ) ) );
|
||||
QgsOgrConnPool::instance()->invalidateConnections( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ), mShareSameDatasetAmongLayers ) );
|
||||
}
|
||||
|
||||
bool returnvalue = true;
|
||||
@ -1885,10 +1885,10 @@ bool QgsOgrProvider::_setSubsetString( const QString &theSQL, bool updateFeature
|
||||
if ( uri != dataSourceUri() )
|
||||
{
|
||||
if ( hasExistingRef )
|
||||
QgsOgrConnPool::instance()->unref( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ) ) );
|
||||
QgsOgrConnPool::instance()->unref( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ), mShareSameDatasetAmongLayers ) );
|
||||
setDataSourceUri( uri );
|
||||
if ( hasExistingRef )
|
||||
QgsOgrConnPool::instance()->ref( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ) ) );
|
||||
QgsOgrConnPool::instance()->ref( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ), mShareSameDatasetAmongLayers ) );
|
||||
}
|
||||
|
||||
mOgrLayer->ResetReading();
|
||||
@ -2061,7 +2061,7 @@ bool QgsOgrProvider::changeAttributeValues( const QgsChangedAttributesMap &attr_
|
||||
{
|
||||
pushError( tr( "OGR error syncing to disk: %1" ).arg( CPLGetLastErrorMsg() ) );
|
||||
}
|
||||
QgsOgrConnPool::instance()->invalidateConnections( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ) ) );
|
||||
QgsOgrConnPool::instance()->invalidateConnections( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ), mShareSameDatasetAmongLayers ) );
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2140,7 +2140,7 @@ bool QgsOgrProvider::changeGeometryValues( const QgsGeometryMap &geometry_map )
|
||||
if ( mTransaction )
|
||||
mTransaction->dirtyLastSavePoint();
|
||||
|
||||
QgsOgrConnPool::instance()->invalidateConnections( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ) ) );
|
||||
QgsOgrConnPool::instance()->invalidateConnections( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ), mShareSameDatasetAmongLayers ) );
|
||||
return syncToDisc();
|
||||
}
|
||||
|
||||
@ -3595,21 +3595,24 @@ QByteArray QgsOgrProvider::quotedIdentifier( const QByteArray &field ) const
|
||||
|
||||
void QgsOgrProvider::forceReload()
|
||||
{
|
||||
QgsOgrConnPool::instance()->invalidateConnections( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ) ) );
|
||||
QgsOgrConnPool::instance()->invalidateConnections( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ), mShareSameDatasetAmongLayers ) );
|
||||
}
|
||||
|
||||
QString QgsOgrProviderUtils::connectionPoolId( const QString &dataSourceURI )
|
||||
QString QgsOgrProviderUtils::connectionPoolId( const QString &dataSourceURI, bool shareSameDatasetAmongLayers )
|
||||
{
|
||||
// If the file part of the URI is really a file, then use it as the
|
||||
// connection pool id (for example, so that all layers of a .gpkg file can
|
||||
// use the same GDAL dataset object)
|
||||
// Otherwise use the datasourceURI
|
||||
// Not completely sure about this logic. But at least, for GeoPackage this
|
||||
// works fine with multi layer datasets.
|
||||
QString filePath = dataSourceURI.left( dataSourceURI.indexOf( QLatin1String( "|" ) ) );
|
||||
QFileInfo fi( filePath );
|
||||
if ( fi.isFile() )
|
||||
return filePath;
|
||||
if ( shareSameDatasetAmongLayers )
|
||||
{
|
||||
// If the file part of the URI is really a file, then use it as the
|
||||
// connection pool id (for example, so that all layers of a .gpkg file can
|
||||
// use the same GDAL dataset object)
|
||||
// Otherwise use the datasourceURI
|
||||
// Not completely sure about this logic. But at least, for GeoPackage this
|
||||
// works fine with multi layer datasets.
|
||||
QString filePath = dataSourceURI.left( dataSourceURI.indexOf( QLatin1String( "|" ) ) );
|
||||
QFileInfo fi( filePath );
|
||||
if ( fi.isFile() )
|
||||
return filePath;
|
||||
}
|
||||
return dataSourceURI;
|
||||
}
|
||||
|
||||
@ -3877,7 +3880,7 @@ QString QgsOgrProviderUtils::quotedValue( const QVariant &value )
|
||||
bool QgsOgrProvider::syncToDisc()
|
||||
{
|
||||
//for shapefiles, remove spatial index files and create a new index
|
||||
QgsOgrConnPool::instance()->unref( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ) ) );
|
||||
QgsOgrConnPool::instance()->unref( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ), mShareSameDatasetAmongLayers ) );
|
||||
bool shapeIndex = false;
|
||||
if ( mGDALDriverName == QLatin1String( "ESRI Shapefile" ) )
|
||||
{
|
||||
@ -3892,7 +3895,7 @@ bool QgsOgrProvider::syncToDisc()
|
||||
{
|
||||
shapeIndex = true;
|
||||
close();
|
||||
QgsOgrConnPool::instance()->invalidateConnections( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ) ) );
|
||||
QgsOgrConnPool::instance()->invalidateConnections( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ), mShareSameDatasetAmongLayers ) );
|
||||
QFile::remove( sbnIndexFile );
|
||||
open( OpenModeSameAsCurrent );
|
||||
if ( !mValid )
|
||||
@ -3916,7 +3919,7 @@ bool QgsOgrProvider::syncToDisc()
|
||||
}
|
||||
#endif
|
||||
|
||||
QgsOgrConnPool::instance()->ref( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ) ) );
|
||||
QgsOgrConnPool::instance()->ref( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ), mShareSameDatasetAmongLayers ) );
|
||||
if ( shapeIndex )
|
||||
{
|
||||
return createSpatialIndex();
|
||||
@ -3978,7 +3981,7 @@ void QgsOgrProvider::recalculateFeatureCount()
|
||||
mOgrLayer->SetSpatialFilter( filter );
|
||||
}
|
||||
|
||||
QgsOgrConnPool::instance()->invalidateConnections( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ) ) );
|
||||
QgsOgrConnPool::instance()->invalidateConnections( QgsOgrProviderUtils::connectionPoolId( dataSourceUri( true ), mShareSameDatasetAmongLayers ) );
|
||||
}
|
||||
|
||||
bool QgsOgrProvider::doesStrictFeatureTypeCheck() const
|
||||
@ -4010,13 +4013,13 @@ OGRwkbGeometryType QgsOgrProvider::ogrWkbSingleFlatten( OGRwkbGeometryType type
|
||||
OGRLayerH QgsOgrProviderUtils::setSubsetString( OGRLayerH layer, GDALDatasetH ds, QTextCodec *encoding, const QString &subsetString, bool addOriginalFid, bool *origFidAdded )
|
||||
{
|
||||
QByteArray layerName = OGR_FD_GetName( OGR_L_GetLayerDefn( layer ) );
|
||||
GDALDriverH mGDALDriver = GDALGetDatasetDriver( ds );
|
||||
QString mGDALDriverName = GDALGetDriverShortName( mGDALDriver );
|
||||
GDALDriverH driver = GDALGetDatasetDriver( ds );
|
||||
QString driverName = GDALGetDriverShortName( driver );
|
||||
bool origFidAddAttempted = false;
|
||||
if ( origFidAdded )
|
||||
*origFidAdded = false;
|
||||
|
||||
if ( mGDALDriverName == QLatin1String( "ODBC" ) ) //the odbc driver does not like schema names for subset
|
||||
if ( driverName == QLatin1String( "ODBC" ) ) //the odbc driver does not like schema names for subset
|
||||
{
|
||||
QString layerNameString = encoding->toUnicode( layerName );
|
||||
int dotIndex = layerNameString.indexOf( '.' );
|
||||
@ -4037,7 +4040,7 @@ OGRLayerH QgsOgrProviderUtils::setSubsetString( OGRLayerH layer, GDALDatasetH ds
|
||||
else
|
||||
{
|
||||
QByteArray sqlPart1 = "SELECT *";
|
||||
QByteArray sqlPart3 = " FROM " + quotedIdentifier( layerName, mGDALDriverName );
|
||||
QByteArray sqlPart3 = " FROM " + quotedIdentifier( layerName, driverName );
|
||||
if ( !subsetString.isEmpty() )
|
||||
sqlPart3 += " WHERE " + encoding->fromUnicode( subsetString );
|
||||
|
||||
@ -4179,6 +4182,7 @@ void QgsOgrProvider::open( OpenMode mode )
|
||||
if ( mOgrOrigLayer )
|
||||
{
|
||||
mGDALDriverName = mOgrOrigLayer->driverName();
|
||||
mShareSameDatasetAmongLayers = QgsOgrProviderUtils::canDriverShareSameDatasetAmongLayers( mGDALDriverName );
|
||||
|
||||
QgsDebugMsg( "OGR opened using Driver " + mGDALDriverName );
|
||||
|
||||
@ -4493,6 +4497,8 @@ QgsOgrLayerUniquePtr QgsOgrProviderUtils::getLayer( const QString &dsName,
|
||||
auto &datasetList = iter.value();
|
||||
Q_FOREACH ( QgsOgrProviderUtils::DatasetWithLayers *ds, datasetList )
|
||||
{
|
||||
if ( !ds->canBeShared )
|
||||
continue;
|
||||
Q_ASSERT( ds->refCount > 0 );
|
||||
|
||||
QString layerName;
|
||||
@ -4546,6 +4552,8 @@ QgsOgrLayerUniquePtr QgsOgrProviderUtils::getLayer( const QString &dsName,
|
||||
auto datasetList = iter.value();
|
||||
Q_FOREACH ( QgsOgrProviderUtils::DatasetWithLayers *ds, datasetList )
|
||||
{
|
||||
if ( !ds->canBeShared )
|
||||
continue;
|
||||
Q_ASSERT( ds->refCount > 0 );
|
||||
|
||||
QString layerName;
|
||||
@ -4590,6 +4598,10 @@ QgsOgrLayerUniquePtr QgsOgrProviderUtils::getLayer( const QString &dsName,
|
||||
new QgsOgrProviderUtils::DatasetWithLayers;
|
||||
ds->hDS = hDS;
|
||||
|
||||
GDALDriverH driver = GDALGetDatasetDriver( hDS );
|
||||
QString driverName = GDALGetDriverShortName( driver );
|
||||
ds->canBeShared = canDriverShareSameDatasetAmongLayers( driverName );
|
||||
|
||||
QgsOgrLayerUniquePtr layer = QgsOgrLayer::CreateForLayer(
|
||||
ident, layerName, ds, hLayer );
|
||||
ds->setLayers[layerName] = layer.get();
|
||||
@ -4616,6 +4628,8 @@ QgsOgrLayerUniquePtr QgsOgrProviderUtils::getLayer( const QString &dsName,
|
||||
auto &datasetList = iter.value();
|
||||
Q_FOREACH ( QgsOgrProviderUtils::DatasetWithLayers *ds, datasetList )
|
||||
{
|
||||
if ( !ds->canBeShared )
|
||||
continue;
|
||||
Q_ASSERT( ds->refCount > 0 );
|
||||
|
||||
auto iter2 = ds->setLayers.find( layerName );
|
||||
@ -4979,6 +4993,45 @@ bool QgsOgrProviderUtils::canUseOpenedDatasets( const QString &dsName )
|
||||
return getLastModified( dsName ) <= iter.value();
|
||||
}
|
||||
|
||||
QgsOgrProviderUtils::DatasetWithLayers *QgsOgrProviderUtils::createDatasetWithLayers(
|
||||
const QString &dsName,
|
||||
bool updateMode,
|
||||
const QStringList &options,
|
||||
const QString &layerName,
|
||||
const DatasetIdentification &ident,
|
||||
QgsOgrLayerUniquePtr &layer,
|
||||
QString &errCause )
|
||||
{
|
||||
GDALDatasetH hDS = OpenHelper( dsName, updateMode, options );
|
||||
if ( !hDS )
|
||||
{
|
||||
errCause = QObject::tr( "Cannot open %1." ).arg( dsName );
|
||||
return nullptr;
|
||||
}
|
||||
sMapDSNameToLastModifiedDate[dsName] = getLastModified( dsName );
|
||||
|
||||
OGRLayerH hLayer = GDALDatasetGetLayerByName(
|
||||
hDS, layerName.toUtf8().constData() );
|
||||
if ( !hLayer )
|
||||
{
|
||||
errCause = QObject::tr( "Cannot find layer %1." ).arg( layerName );
|
||||
QgsOgrProviderUtils::GDALCloseWrapper( hDS );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QgsOgrProviderUtils::DatasetWithLayers *ds =
|
||||
new QgsOgrProviderUtils::DatasetWithLayers;
|
||||
ds->hDS = hDS;
|
||||
|
||||
GDALDriverH driver = GDALGetDatasetDriver( hDS );
|
||||
QString driverName = GDALGetDriverShortName( driver );
|
||||
ds->canBeShared = canDriverShareSameDatasetAmongLayers( driverName );
|
||||
|
||||
layer = QgsOgrLayer::CreateForLayer(
|
||||
ident, layerName, ds, hLayer );
|
||||
ds->setLayers[layerName] = layer.get();
|
||||
return ds;
|
||||
}
|
||||
|
||||
QgsOgrLayerUniquePtr QgsOgrProviderUtils::getLayer( const QString &dsName,
|
||||
bool updateMode,
|
||||
@ -5018,6 +5071,8 @@ QgsOgrLayerUniquePtr QgsOgrProviderUtils::getLayer( const QString &dsName,
|
||||
auto &datasetList = iter.value();
|
||||
Q_FOREACH ( QgsOgrProviderUtils::DatasetWithLayers *ds, datasetList )
|
||||
{
|
||||
if ( !ds->canBeShared )
|
||||
continue;
|
||||
Q_ASSERT( ds->refCount > 0 );
|
||||
|
||||
auto iter2 = ds->setLayers.find( layerName );
|
||||
@ -5045,60 +5100,22 @@ QgsOgrLayerUniquePtr QgsOgrProviderUtils::getLayer( const QString &dsName,
|
||||
|
||||
// All existing DatasetWithLayers* already reference our layer of
|
||||
// interest, so instantiate a new DatasetWithLayers*
|
||||
GDALDatasetH hDS = OpenHelper( dsName, updateMode, options );
|
||||
if ( !hDS )
|
||||
{
|
||||
errCause = QObject::tr( "Cannot open %1." ).arg( dsName );
|
||||
return nullptr;
|
||||
}
|
||||
sMapDSNameToLastModifiedDate[dsName] = getLastModified( dsName );
|
||||
|
||||
OGRLayerH hLayer = GDALDatasetGetLayerByName(
|
||||
hDS, layerName.toUtf8().constData() );
|
||||
if ( !hLayer )
|
||||
{
|
||||
QgsOgrProviderUtils::GDALCloseWrapper( hDS );
|
||||
errCause = QObject::tr( "Cannot find layer %1." ).arg( layerName );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QgsOgrLayerUniquePtr layer;
|
||||
QgsOgrProviderUtils::DatasetWithLayers *ds =
|
||||
new QgsOgrProviderUtils::DatasetWithLayers;
|
||||
createDatasetWithLayers( dsName, updateMode, options, layerName, ident, layer, errCause );
|
||||
if ( !ds )
|
||||
return nullptr;
|
||||
|
||||
datasetList.push_back( ds );
|
||||
|
||||
ds->hDS = hDS;
|
||||
|
||||
QgsOgrLayerUniquePtr layer = QgsOgrLayer::CreateForLayer(
|
||||
ident, layerName, ds, hLayer );
|
||||
ds->setLayers[layerName] = layer.get();
|
||||
return layer;
|
||||
}
|
||||
|
||||
GDALDatasetH hDS = OpenHelper( dsName, updateMode, options );
|
||||
if ( !hDS )
|
||||
{
|
||||
errCause = QObject::tr( "Cannot open %1." ).arg( dsName );
|
||||
return nullptr;
|
||||
}
|
||||
sMapDSNameToLastModifiedDate[dsName] = getLastModified( dsName );
|
||||
|
||||
OGRLayerH hLayer = GDALDatasetGetLayerByName(
|
||||
hDS, layerName.toUtf8().constData() );
|
||||
if ( !hLayer )
|
||||
{
|
||||
errCause = QObject::tr( "Cannot find layer %1." ).arg( layerName );
|
||||
QgsOgrProviderUtils::GDALCloseWrapper( hDS );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QgsOgrLayerUniquePtr layer;
|
||||
QgsOgrProviderUtils::DatasetWithLayers *ds =
|
||||
new QgsOgrProviderUtils::DatasetWithLayers;
|
||||
ds->hDS = hDS;
|
||||
|
||||
QgsOgrLayerUniquePtr layer = QgsOgrLayer::CreateForLayer(
|
||||
ident, layerName, ds, hLayer );
|
||||
ds->setLayers[layerName] = layer.get();
|
||||
createDatasetWithLayers( dsName, updateMode, options, layerName, ident, layer, errCause );
|
||||
if ( !ds )
|
||||
return nullptr;
|
||||
|
||||
QList<DatasetWithLayers *> datasetList;
|
||||
datasetList.push_back( ds );
|
||||
@ -5192,6 +5209,11 @@ void QgsOgrProviderUtils::releaseDataset( QgsOgrDataset *&ds )
|
||||
ds = nullptr;
|
||||
}
|
||||
|
||||
bool QgsOgrProviderUtils::canDriverShareSameDatasetAmongLayers( const QString &driverName )
|
||||
{
|
||||
return driverName != QStringLiteral( "OSM" );
|
||||
}
|
||||
|
||||
|
||||
QgsOgrDatasetSharedPtr QgsOgrDataset::create( const QgsOgrProviderUtils::DatasetIdentification &ident,
|
||||
QgsOgrProviderUtils::DatasetWithLayers *ds )
|
||||
|
@ -274,6 +274,9 @@ class QgsOgrProvider : public QgsVectorDataProvider
|
||||
// Friendly name of the GDAL Driver that was actually used to open the layer
|
||||
QString mGDALDriverName;
|
||||
|
||||
//! Whether we can share the same dataset handle among different layers
|
||||
bool mShareSameDatasetAmongLayers = true;
|
||||
|
||||
bool mValid = false;
|
||||
|
||||
OGRwkbGeometryType mOGRGeomType = wkbUnknown;
|
||||
@ -323,7 +326,6 @@ class QgsOgrProvider : public QgsVectorDataProvider
|
||||
QgsOgrTransaction *mTransaction = nullptr;
|
||||
|
||||
void setTransaction( QgsTransaction *transaction ) override;
|
||||
|
||||
};
|
||||
|
||||
class QgsOgrDataset;
|
||||
@ -365,6 +367,7 @@ class QgsOgrProviderUtils
|
||||
GDALDatasetH hDS = nullptr;
|
||||
QMap<QString, QgsOgrLayer *> setLayers;
|
||||
int refCount = 0;
|
||||
bool canBeShared = true;
|
||||
|
||||
DatasetWithLayers(): mutex( QMutex::Recursive ) {}
|
||||
};
|
||||
@ -390,6 +393,14 @@ class QgsOgrProviderUtils
|
||||
DatasetWithLayers *ds,
|
||||
bool removeFromDatasetList );
|
||||
|
||||
static DatasetWithLayers *createDatasetWithLayers(
|
||||
const QString &dsName,
|
||||
bool updateMode,
|
||||
const QStringList &options,
|
||||
const QString &layerName,
|
||||
const DatasetIdentification &ident,
|
||||
QgsOgrLayerUniquePtr &layer,
|
||||
QString &errCause );
|
||||
public:
|
||||
|
||||
//! Inject credentials into the dsName (if any)
|
||||
@ -460,7 +471,7 @@ class QgsOgrProviderUtils
|
||||
static void invalidateCachedDatasets( const QString &dsName );
|
||||
|
||||
//! Returns the string to provide to QgsOgrConnPool::instance() methods
|
||||
static QString connectionPoolId( const QString &dataSourceURI );
|
||||
static QString connectionPoolId( const QString &dataSourceURI, bool datasetSharedAmongLayers );
|
||||
|
||||
//! Invalidate the cached last modified date of a dataset
|
||||
static void invalidateCachedLastModifiedDate( const QString &dsName );
|
||||
@ -471,6 +482,8 @@ class QgsOgrProviderUtils
|
||||
//! Converts a OGR WKB type to the corresponding QGIS wkb type
|
||||
static QgsWkbTypes::Type qgisTypeFromOgrType( OGRwkbGeometryType type );
|
||||
|
||||
//! Whether a driver can share the same dataset handle among different layers
|
||||
static bool canDriverShareSameDatasetAmongLayers( const QString &driverName );
|
||||
};
|
||||
|
||||
|
||||
|
@ -20,6 +20,7 @@ import tempfile
|
||||
from osgeo import gdal, ogr # NOQA
|
||||
from qgis.PyQt.QtCore import QVariant
|
||||
from qgis.core import (QgsApplication,
|
||||
QgsRectangle,
|
||||
QgsFeature, QgsFeatureRequest, QgsField, QgsSettings, QgsDataProvider,
|
||||
QgsVectorDataProvider, QgsVectorLayer, QgsWkbTypes, QgsNetworkAccessManager)
|
||||
from qgis.testing import start_app, unittest
|
||||
@ -433,6 +434,26 @@ class PyQgsOGRProvider(unittest.TestCase):
|
||||
self.assertIn('testDataItems.gpkg|layername=Layer1', children[0].uri())
|
||||
self.assertIn('testDataItems.gpkg|layername=Layer2', children[1].uri())
|
||||
|
||||
def testOSM(self):
|
||||
""" Test that opening several layers of the same OSM datasource works properly """
|
||||
|
||||
datasource = os.path.join(TEST_DATA_DIR, 'test.osm')
|
||||
vl_points = QgsVectorLayer(datasource + "|layername=points", 'test', 'ogr')
|
||||
vl_multipolygons = QgsVectorLayer(datasource + "|layername=multipolygons", 'test', 'ogr')
|
||||
|
||||
f = QgsFeature()
|
||||
|
||||
# When sharing the same dataset handle, the spatial filter of test
|
||||
# points layer would apply to the other layers
|
||||
iter_points = vl_points.getFeatures(QgsFeatureRequest().setFilterRect(QgsRectangle(-200, -200, -200, -200)))
|
||||
self.assertFalse(iter_points.nextFeature(f))
|
||||
|
||||
iter_multipolygons = vl_multipolygons.getFeatures(QgsFeatureRequest())
|
||||
self.assertTrue(iter_multipolygons.nextFeature(f))
|
||||
self.assertTrue(iter_multipolygons.nextFeature(f))
|
||||
self.assertTrue(iter_multipolygons.nextFeature(f))
|
||||
self.assertFalse(iter_multipolygons.nextFeature(f))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
105
tests/testdata/test.osm
vendored
Normal file
105
tests/testdata/test.osm
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<osm version="0.6" generator="hand">
|
||||
<bounds minlat="49" minlon="2" maxlat="50" maxlon="3"/>
|
||||
<node id="1" lat="49" lon="2" user="some_user" uid="1" version="1" changeset="1" timestamp="2012-07-10T00:00:00Z"/>
|
||||
<node id="2" lat="50" lon="3" user="some_user" uid="1" version="1" changeset="1" timestamp="2012-07-10T00:00:00Z"/>
|
||||
<node id="3" lat="49.5" lon="3" user="some_user" uid="1" version="1" changeset="1" timestamp="2012-07-10T00:00:00Z">
|
||||
<tag k="name" v="Some interesting point"/>
|
||||
<tag k="foo" v="bar"/>
|
||||
<tag k="bar" v="baz"/>
|
||||
</node>
|
||||
<node id="4" lat="49" lon="3" user="some_user" uid="1" version="1" changeset="1" timestamp="2012-07-10T00:00:00Z"/>
|
||||
<node id="5" lat="50" lon="2" user="some_user" uid="1" version="1" changeset="1" timestamp="2012-07-10T00:00:00Z"/>
|
||||
<node id="6" lat="49.1" lon="2.1" user="some_user" uid="1" version="1" changeset="1" timestamp="2012-07-10T00:00:00Z"/>
|
||||
<node id="7" lat="49.1" lon="2.2" user="some_user" uid="1" version="1" changeset="1" timestamp="2012-07-10T00:00:00Z"/>
|
||||
<node id="8" lat="49.2" lon="2.2" user="some_user" uid="1" version="1" changeset="1" timestamp="2012-07-10T00:00:00Z"/>
|
||||
<node id="9" lat="49.2" lon="2.1" user="some_user" uid="1" version="1" changeset="1" timestamp="2012-07-10T00:00:00Z"/>
|
||||
<way id="1" user="some_user" uid="1" version="1" changeset="1" timestamp="2012-07-10T00:00:00Z">
|
||||
<nd ref="1"/>
|
||||
<nd ref="2"/>
|
||||
<tag k="highway" v="motorway"/>
|
||||
<tag k="foo" v="bar"/>
|
||||
</way>
|
||||
<way id="2" user="some_user" uid="1" version="1" changeset="1" timestamp="2012-07-10T00:00:00Z">
|
||||
<tag k="area" v="yes"/>
|
||||
<tag k="natural" v="wood"/>
|
||||
<nd ref="1"/>
|
||||
<nd ref="4"/>
|
||||
<nd ref="2"/>
|
||||
<nd ref="5"/>
|
||||
<nd ref="1"/>
|
||||
</way>
|
||||
<way id="3" user="some_user" uid="1" version="1" changeset="1" timestamp="2012-07-10T00:00:00Z">
|
||||
<tag k="area" v="yes"/>
|
||||
<nd ref="6"/>
|
||||
<nd ref="7"/>
|
||||
<nd ref="8"/>
|
||||
<nd ref="9"/>
|
||||
<nd ref="6"/>
|
||||
</way>
|
||||
<way id="4" user="some_user" uid="1" version="1" changeset="1" timestamp="2012-07-10T00:00:00Z">
|
||||
<tag k="name" v="id_4"/>
|
||||
<!-- all nodes missing : skipped way -->
|
||||
<nd ref="600"/>
|
||||
<nd ref="700"/>
|
||||
<nd ref="800"/>
|
||||
<nd ref="900"/>
|
||||
</way>
|
||||
<way id="5" user="some_user" uid="1" version="1" changeset="1" timestamp="2012-07-10T00:00:00Z">
|
||||
<tag k="name" v="id_5"/>
|
||||
<!-- only one node : skipped way -->
|
||||
<nd ref="1"/>
|
||||
</way>
|
||||
<way id="6" user="some_user" uid="1" version="1" changeset="1" timestamp="2012-07-10T00:00:00Z">
|
||||
<tag k="name" v="id_6"/>
|
||||
<nd ref="1"/>
|
||||
<nd ref="4"/>
|
||||
<nd ref="2"/>
|
||||
<nd ref="5"/>
|
||||
<nd ref="900"/> <!-- unexisting node -->
|
||||
<nd ref="1"/>
|
||||
</way>
|
||||
<!-- no tag: will not be reported in lines layer -->
|
||||
<way id="7" user="some_user" uid="1" version="1" changeset="1" timestamp="2012-07-10T00:00:00Z">
|
||||
<nd ref="1"/>
|
||||
<nd ref="2"/>
|
||||
</way>
|
||||
|
||||
<way id="8" user="some_user" uid="1" version="1" changeset="1" timestamp="2012-07-10T00:00:00Z">
|
||||
<tag k="area" v="yes"/>
|
||||
<tag k="name" v="standalone_polygon"/>
|
||||
<nd ref="1"/>
|
||||
<nd ref="4"/>
|
||||
<nd ref="2"/>
|
||||
<nd ref="5"/>
|
||||
<nd ref="1"/>
|
||||
</way>
|
||||
|
||||
<relation id="1" user="some_user" uid="1" version="1" changeset="1" timestamp="2012-07-10T00:00:00Z">
|
||||
<member type="way" ref="2" role="outer"/>
|
||||
<member type="way" ref="3" role="inner"/>
|
||||
<tag k="type" v="multipolygon"/>
|
||||
<tag k="natural" v="forest"/>
|
||||
</relation>
|
||||
<relation id="2" user="some_user" uid="1" version="1" changeset="1" timestamp="2012-07-10T00:00:00Z">
|
||||
<member type="way" ref="2" role="outer"/>
|
||||
<!-- at least, one missing way : skipped whole relation -->
|
||||
<member type="way" ref="300" role="inner"/>
|
||||
<tag k="type" v="multipolygon"/>
|
||||
</relation>
|
||||
<relation id="3" user="some_user" uid="1" version="1" changeset="1" timestamp="2012-07-10T00:00:00Z">
|
||||
<member type="way" ref="1" role=""/>
|
||||
<tag k="type" v="route"/>
|
||||
</relation>
|
||||
<relation id="4" user="some_user" uid="1" version="1" changeset="1" timestamp="2012-07-10T00:00:00Z">
|
||||
<member type="node" ref="1" role=""/>
|
||||
<member type="way" ref="1" role=""/>
|
||||
<tag k="type" v="other_type"/>
|
||||
</relation>
|
||||
<!-- inherit tags from outer way -->
|
||||
<relation id="5" user="some_user" uid="1" version="1" changeset="1" timestamp="2012-07-10T00:00:00Z">
|
||||
<member type="way" ref="2" role="outer"/>
|
||||
<member type="way" ref="3" role="inner"/>
|
||||
<tag k="type" v="multipolygon"/>
|
||||
</relation>
|
||||
</osm>
|
Loading…
x
Reference in New Issue
Block a user