diff --git a/src/providers/wfs/qgswfsshareddata.cpp b/src/providers/wfs/qgswfsshareddata.cpp index 5d0b5da89dc..ae8239a5616 100644 --- a/src/providers/wfs/qgswfsshareddata.cpp +++ b/src/providers/wfs/qgswfsshareddata.cpp @@ -240,15 +240,21 @@ bool QgsWFSSharedData::createCache() cacheFields.append( QgsField( QgsWFSConstants::FIELD_MD5, QVariant::String, "string" ) ); bool ogrWaySuccessful = false; + QString fidName( "__ogc_fid" ); QString geometryFieldname( "__spatialite_geometry" ); #ifdef USE_OGR_FOR_DB_CREATION - // Only GDAL >= 2.0 can use an alternate geometry field name + // Only GDAL >= 2.0 can use an alternate geometry or FID field name + // but QgsVectorFileWriter will refuse anyway to create a ogc_fid, so we will + // do it manually + bool useReservedNames = cacheFields.fieldNameIndex( "ogc_fid" ) >= 0; #if GDAL_VERSION_MAJOR < 2 - const bool hasGeometryField = cacheFields.fieldNameIndex( "geometry" ) >= 0; - if ( !hasGeometryField ) + if ( cacheFields.fieldNameIndex( "geometry" ) >= 0 ) + useReservedNames = true; #endif + if ( !useReservedNames ) { #if GDAL_VERSION_MAJOR < 2 + fidName = "ogc_fid"; geometryFieldname = "GEOMETRY"; #endif // Creating a spatialite database can be quite slow on some file systems @@ -260,6 +266,7 @@ bool QgsWFSSharedData::createCache() datasourceOptions.push_back( "INIT_WITH_EPSG=NO" ); layerOptions.push_back( "LAUNDER=NO" ); // to get exact matches for field names, especially regarding case #if GDAL_VERSION_MAJOR >= 2 + layerOptions.push_back( "FID=__ogc_fid" ); layerOptions.push_back( "GEOMETRY_NAME=__spatialite_geometry" ); #endif vsimemFilename.sprintf( "/vsimem/qgis_wfs_cache_template_%p/features.sqlite", this ); @@ -374,7 +381,7 @@ bool QgsWFSSharedData::createCache() if ( !ogrWaySuccessful ) { mCacheTablename = "features"; - sql = QString( "CREATE TABLE %1 (ogc_fid INTEGER PRIMARY KEY" ).arg( mCacheTablename ); + sql = QString( "CREATE TABLE %1 (%2 INTEGER PRIMARY KEY" ).arg( mCacheTablename ).arg( fidName ); Q_FOREACH ( QgsField field, cacheFields ) { QString type( "VARCHAR" ); @@ -389,17 +396,26 @@ bool QgsWFSSharedData::createCache() sql += ")"; rc = sqlite3_exec( db, sql.toUtf8(), nullptr, nullptr, nullptr ); if ( rc != SQLITE_OK ) + { + QgsDebugMsg( QString( "%1 failed" ).arg( sql ) ); ret = false; + } sql = QString( "SELECT AddGeometryColumn('%1','%2',0,'POLYGON',2)" ).arg( mCacheTablename, geometryFieldname ); rc = sqlite3_exec( db, sql.toUtf8(), nullptr, nullptr, nullptr ); if ( rc != SQLITE_OK ) + { + QgsDebugMsg( QString( "%1 failed" ).arg( sql ) ); ret = false; + } sql = QString( "SELECT CreateSpatialIndex('%1','%2')" ).arg( mCacheTablename, geometryFieldname ); rc = sqlite3_exec( db, sql.toUtf8(), nullptr, nullptr, nullptr ); if ( rc != SQLITE_OK ) + { + QgsDebugMsg( QString( "%1 failed" ).arg( sql ) ); ret = false; + } } // We need an index on the gmlid, since we will check for duplicates, particularly @@ -407,14 +423,20 @@ bool QgsWFSSharedData::createCache() sql = QString( "CREATE INDEX idx_%2 ON %1(%2)" ).arg( mCacheTablename ).arg( QgsWFSConstants::FIELD_GMLID ); rc = sqlite3_exec( db, sql.toUtf8(), nullptr, nullptr, nullptr ); if ( rc != SQLITE_OK ) + { + QgsDebugMsg( QString( "%1 failed" ).arg( sql ) ); ret = false; + } if ( mDistinctSelect ) { sql = QString( "CREATE INDEX idx_%2 ON %1(%2)" ).arg( mCacheTablename ).arg( QgsWFSConstants::FIELD_MD5 ); rc = sqlite3_exec( db, sql.toUtf8(), nullptr, nullptr, nullptr ); if ( rc != SQLITE_OK ) + { + QgsDebugMsg( QString( "%1 failed" ).arg( sql ) ); ret = false; + } } ( void )sqlite3_exec( db, "COMMIT", nullptr, nullptr, nullptr ); @@ -435,7 +457,7 @@ bool QgsWFSSharedData::createCache() // regarding crashes, since this is a temporary DB QgsDataSourceURI dsURI; dsURI.setDatabase( mCacheDbname ); - dsURI.setDataSource( "", mCacheTablename, geometryFieldname, "", "ogc_fid" ); + dsURI.setDataSource( "", mCacheTablename, geometryFieldname, "", fidName ); QStringList pragmas; pragmas << "synchronous=OFF"; pragmas << "journal_mode=WAL"; // WAL is needed to avoid reader to block writers diff --git a/tests/src/python/test_provider_wfs.py b/tests/src/python/test_provider_wfs.py index f5404748a49..3775ff201c3 100644 --- a/tests/src/python/test_provider_wfs.py +++ b/tests/src/python/test_provider_wfs.py @@ -389,7 +389,8 @@ class TestPyQgsWFSProvider(unittest.TestCase, ProviderTestCase): - + + @@ -416,8 +417,9 @@ class TestPyQgsWFSProvider(unittest.TestCase, ProviderTestCase): unknown - - 426858,5427937 + + 426858,5427937 + 1 2 1234567890123 @@ -878,7 +880,8 @@ class TestPyQgsWFSProvider(unittest.TestCase, ProviderTestCase): - + + @@ -903,14 +906,14 @@ class TestPyQgsWFSProvider(unittest.TestCase, ProviderTestCase): 70 -65 - 2 + 2 """.encode('UTF-8')) extent = QgsRectangle(-70, 60, -60, 80) request = QgsFeatureRequest().setFilterRect(extent) - values = [f['id'] for f in vl.getFeatures(request)] + values = [f['ogc_fid'] for f in vl.getFeatures(request)] self.assertEqual(values, [2]) # To show that if we zoom-in, we won't issue a new request @@ -923,14 +926,14 @@ class TestPyQgsWFSProvider(unittest.TestCase, ProviderTestCase): 70 -65 - 200 + 200 """.encode('UTF-8')) extent = QgsRectangle(-66, 62, -62, 78) request = QgsFeatureRequest().setFilterRect(extent) - values = [f['id'] for f in vl.getFeatures(request)] + values = [f['ogc_fid'] for f in vl.getFeatures(request)] self.assertEqual(values, [2]) # Move to a neighbouring area, and reach the download limit @@ -944,18 +947,18 @@ class TestPyQgsWFSProvider(unittest.TestCase, ProviderTestCase): 70 -65 - 2 + 2 85 -65 - 3 + 3 """.encode('UTF-8')) extent = QgsRectangle(-70, 65, -60, 90) request = QgsFeatureRequest().setFilterRect(extent) - values = [f['id'] for f in vl.getFeatures(request)] + values = [f['ogc_fid'] for f in vl.getFeatures(request)] self.assertEqual(values, [2, 3]) # Zoom-in again, and bring more features @@ -969,18 +972,18 @@ class TestPyQgsWFSProvider(unittest.TestCase, ProviderTestCase): 70 -65 - 2 + 2 84 -64 - 4 + 4 """.encode('UTF-8')) extent = QgsRectangle(-69, 66, -61, 89) request = QgsFeatureRequest().setFilterRect(extent) - values = [f['id'] for f in vl.getFeatures(request)] + values = [f['ogc_fid'] for f in vl.getFeatures(request)] self.assertEqual(values, [2, 3, 4]) # Test RESULTTYPE=hits @@ -1003,7 +1006,7 @@ class TestPyQgsWFSProvider(unittest.TestCase, ProviderTestCase): - id + ogc_fid 101 @@ -1018,15 +1021,15 @@ class TestPyQgsWFSProvider(unittest.TestCase, ProviderTestCase): 70 -65 - 101 + 101 """.encode('UTF-8')) - vl.dataProvider().setSubsetString('id = 101') + vl.dataProvider().setSubsetString('ogc_fid = 101') extent = QgsRectangle(-69, 66, -61, 89) request = QgsFeatureRequest().setFilterRect(extent) - values = [f['id'] for f in vl.getFeatures(request)] + values = [f['ogc_fid'] for f in vl.getFeatures(request)] self.assertEqual(values, [101]) def testWFS20TruncatedResponse(self):