Skip to content

Commit 7d235d2

Browse files
committed
Merge pull request #2987 from rouault/wfs_uppercase_attribute
[WFS] Fix support of attribute names in upper-case
2 parents f90f999 + a72fcb8 commit 7d235d2

File tree

2 files changed

+64
-43
lines changed

2 files changed

+64
-43
lines changed

src/providers/wfs/qgswfsshareddata.cpp

+55-39
Original file line numberDiff line numberDiff line change
@@ -166,49 +166,65 @@ bool QgsWFSSharedData::createCache()
166166
cacheFields.append( QgsField( QgsWFSConstants::FIELD_HEXWKB_GEOM, QVariant::String, "string" ) );
167167

168168
bool ogrWaySuccessfull = false;
169+
QString geometryFieldname( "__spatialite_geometry" );
169170
#ifdef USE_OGR_FOR_DB_CREATION
170-
// Creating a spatialite database can be quite slow on some file systems
171-
// so we create a GDAL in-memory file, and then copy it on
172-
// the file system.
173-
QString vsimemFilename;
174-
QStringList datasourceOptions;
175-
datasourceOptions.push_back( "INIT_WITH_EPSG=NO" );
176-
vsimemFilename.sprintf( "/vsimem/qgis_wfs_cache_template_%p/features.sqlite", this );
177-
mCacheTablename = CPLGetBasename( vsimemFilename.toStdString().c_str() );
178-
VSIUnlink( vsimemFilename.toStdString().c_str() );
179-
QgsVectorFileWriter* writer = new QgsVectorFileWriter( vsimemFilename, "",
180-
cacheFields, QGis::WKBPolygon, nullptr, "SpatiaLite", datasourceOptions );
181-
if ( writer->hasError() == QgsVectorFileWriter::NoError )
171+
// Only GDAL >= 2.0 can use an alternate geometry field name
172+
#if GDAL_VERSION_MAJOR < 2
173+
const bool hasGeometryField = cacheFields.fieldNameIndex( "geometry" ) >= 0;
174+
if ( !hasGeometryField )
175+
#endif
182176
{
183-
delete writer;
184-
185-
// Copy the temporary database back to disk
186-
vsi_l_offset nLength = 0;
187-
GByte* pabyData = VSIGetMemFileBuffer( vsimemFilename.toStdString().c_str(), &nLength, TRUE );
188-
VSILFILE* fp = VSIFOpenL( mCacheDbname.toStdString().c_str(), "wb " );
189-
if ( fp != nullptr )
177+
#if GDAL_VERSION_MAJOR < 2
178+
geometryFieldname = "GEOMETRY";
179+
#endif
180+
// Creating a spatialite database can be quite slow on some file systems
181+
// so we create a GDAL in-memory file, and then copy it on
182+
// the file system.
183+
QString vsimemFilename;
184+
QStringList datasourceOptions;
185+
QStringList layerOptions;
186+
datasourceOptions.push_back( "INIT_WITH_EPSG=NO" );
187+
layerOptions.push_back( "LAUNDER=NO" ); // to get exact matches for field names, especially regarding case
188+
#if GDAL_VERSION_MAJOR >= 2
189+
layerOptions.push_back( "GEOMETRY_NAME=__spatialite_geometry" );
190+
#endif
191+
vsimemFilename.sprintf( "/vsimem/qgis_wfs_cache_template_%p/features.sqlite", this );
192+
mCacheTablename = CPLGetBasename( vsimemFilename.toStdString().c_str() );
193+
VSIUnlink( vsimemFilename.toStdString().c_str() );
194+
QgsVectorFileWriter* writer = new QgsVectorFileWriter( vsimemFilename, "",
195+
cacheFields, QGis::WKBPolygon, nullptr, "SpatiaLite", datasourceOptions, layerOptions );
196+
if ( writer->hasError() == QgsVectorFileWriter::NoError )
190197
{
191-
VSIFWriteL( pabyData, 1, nLength, fp );
192-
VSIFCloseL( fp );
193-
CPLFree( pabyData );
198+
delete writer;
199+
200+
// Copy the temporary database back to disk
201+
vsi_l_offset nLength = 0;
202+
GByte* pabyData = VSIGetMemFileBuffer( vsimemFilename.toStdString().c_str(), &nLength, TRUE );
203+
VSILFILE* fp = VSIFOpenL( mCacheDbname.toStdString().c_str(), "wb " );
204+
if ( fp != nullptr )
205+
{
206+
VSIFWriteL( pabyData, 1, nLength, fp );
207+
VSIFCloseL( fp );
208+
CPLFree( pabyData );
209+
}
210+
else
211+
{
212+
CPLFree( pabyData );
213+
QgsMessageLog::logMessage( tr( "Cannot create temporary SpatiaLite cache" ), tr( "WFS" ) );
214+
return false;
215+
}
216+
217+
ogrWaySuccessfull = true;
194218
}
195219
else
196220
{
197-
CPLFree( pabyData );
198-
QgsMessageLog::logMessage( tr( "Cannot create temporary SpatiaLite cache" ), tr( "WFS" ) );
199-
return false;
221+
// Be tolerant on failures. Some (Windows) GDAL >= 1.11 builds may
222+
// not define SPATIALITE_412_OR_LATER, and thus the call to
223+
// spatialite_init() may cause failures, which will require using the
224+
// slower method
225+
delete writer;
226+
VSIUnlink( vsimemFilename.toStdString().c_str() );
200227
}
201-
202-
ogrWaySuccessfull = true;
203-
}
204-
else
205-
{
206-
// Be tolerant on failures. Some (Windows) GDAL >= 1.11 builds may
207-
// not define SPATIALITE_412_OR_LATER, and thus the call to
208-
// spatialite_init() may cause failures, which will require using the
209-
// slower method
210-
delete writer;
211-
VSIUnlink( vsimemFilename.toStdString().c_str() );
212228
}
213229
#endif
214230
if ( !ogrWaySuccessfull )
@@ -300,12 +316,12 @@ bool QgsWFSSharedData::createCache()
300316
if ( rc != SQLITE_OK )
301317
ret = false;
302318

303-
sql = QString( "SELECT AddGeometryColumn('%1','geometry',0,'POLYGON',2)" ).arg( mCacheTablename );
319+
sql = QString( "SELECT AddGeometryColumn('%1','%2',0,'POLYGON',2)" ).arg( mCacheTablename ).arg( geometryFieldname );
304320
rc = sqlite3_exec( db, sql.toUtf8(), nullptr, nullptr, nullptr );
305321
if ( rc != SQLITE_OK )
306322
ret = false;
307323

308-
sql = QString( "SELECT CreateSpatialIndex('%1','geometry')" ).arg( mCacheTablename );
324+
sql = QString( "SELECT CreateSpatialIndex('%1','%2')" ).arg( mCacheTablename ).arg( geometryFieldname );
309325
rc = sqlite3_exec( db, sql.toUtf8(), nullptr, nullptr, nullptr );
310326
if ( rc != SQLITE_OK )
311327
ret = false;
@@ -336,7 +352,7 @@ bool QgsWFSSharedData::createCache()
336352
// regarding crashes, since this is a temporary DB
337353
QgsDataSourceURI dsURI;
338354
dsURI.setDatabase( mCacheDbname );
339-
dsURI.setDataSource( "", mCacheTablename, "geometry", "", "ogc_fid" );
355+
dsURI.setDataSource( "", mCacheTablename, geometryFieldname, "", "ogc_fid" );
340356
QStringList pragmas;
341357
pragmas << "synchronous=OFF";
342358
pragmas << "journal_mode=MEMORY";

tests/src/python/test_provider_wfs.py

+9-4
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,8 @@ def testWFS10(self):
276276
<xsd:complexContent>
277277
<xsd:extension base="gml:AbstractFeatureType">
278278
<xsd:sequence>
279-
<xsd:element maxOccurs="1" minOccurs="0" name="intfield" nillable="true" type="xsd:int"/>
279+
<xsd:element maxOccurs="1" minOccurs="0" name="INTFIELD" nillable="true" type="xsd:int"/>
280+
<xsd:element maxOccurs="1" minOccurs="0" name="GEOMETRY" nillable="true" type="xsd:int"/>
280281
<xsd:element maxOccurs="1" minOccurs="0" name="longfield" nillable="true" type="xsd:long"/>
281282
<xsd:element maxOccurs="1" minOccurs="0" name="stringfield" nillable="true" type="xsd:string"/>
282283
<xsd:element maxOccurs="1" minOccurs="0" name="geometryProperty" nillable="true" type="gml:PointPropertyType"/>
@@ -291,7 +292,7 @@ def testWFS10(self):
291292
vl = QgsVectorLayer(u"url='http://" + endpoint + u"' typename='my:typename' version='1.0.0'", u'test', u'WFS')
292293
assert vl.isValid()
293294
self.assertEquals(vl.wkbType(), QgsWKBTypes.Point)
294-
self.assertEquals(len(vl.fields()), 3)
295+
self.assertEquals(len(vl.fields()), 4)
295296
self.assertEquals(vl.featureCount(), 0)
296297
reference = QgsGeometry.fromRect(
297298
QgsRectangle(-71.123, 66.33, -65.32, 78.3))
@@ -309,16 +310,20 @@ def testWFS10(self):
309310
<my:typename fid="typename.0">
310311
<my:geometryProperty>
311312
<gml:Point srsName="http://www.opengis.net/gml/srs/epsg.xml#4326"><gml:coordinates decimal="." cs="," ts=" ">2,49</gml:coordinates></gml:Point></my:geometryProperty>
312-
<my:intfield>1</my:intfield>
313+
<my:INTFIELD>1</my:INTFIELD>
314+
<my:GEOMETRY>2</my:GEOMETRY>
313315
<my:longfield>1234567890123</my:longfield>
314316
<my:stringfield>foo</my:stringfield>
315317
</my:typename>
316318
</gml:featureMember>
317319
</wfs:FeatureCollection>""")
318320

319-
values = [f['intfield'] for f in vl.getFeatures()]
321+
values = [f['INTFIELD'] for f in vl.getFeatures()]
320322
self.assertEquals(values, [1])
321323

324+
values = [f['GEOMETRY'] for f in vl.getFeatures()]
325+
self.assertEquals(values, [2])
326+
322327
values = [f['longfield'] for f in vl.getFeatures()]
323328
self.assertEquals(values, [1234567890123])
324329

0 commit comments

Comments
 (0)