Skip to content

Commit d748400

Browse files
committedJan 23, 2019
Fix WFS client NULL representation
This was nasty and only reproduceable when features were cached (so, the second time you get them) and was due to a QVariant( type ) default constructor for numeric values being initialized to 0, yielding 0 instead of NULL. Reported in #20961
1 parent cc9ec2d commit d748400

File tree

4 files changed

+158
-4
lines changed

4 files changed

+158
-4
lines changed
 

‎src/providers/spatialite/qgsspatialitefeatureiterator.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,7 @@ QVariant QgsSpatiaLiteFeatureIterator::getFeatureAttribute( sqlite3_stmt *stmt,
584584
}
585585

586586
// assuming NULL
587-
return QVariant( type );
587+
return QVariant( );
588588
}
589589

590590
void QgsSpatiaLiteFeatureIterator::getFeatureGeometry( sqlite3_stmt *stmt, int ic, QgsFeature &feature )

‎src/providers/wfs/qgswfsrequest.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,6 @@ bool QgsWfsRequest::sendPOST( const QUrl &url, const QString &contentTypeHeader,
243243
mForceRefresh = true;
244244
mResponse.clear();
245245

246-
qDebug() << QString::fromUtf8( data );
247-
248246
if ( url.toEncoded().contains( "fake_qgis_http_endpoint" ) )
249247
{
250248
// Hack for testing purposes

‎src/server/services/wfs/qgswfstransaction.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ namespace QgsWfs
412412
if ( field.constraints().constraints() & QgsFieldConstraints::Constraint::ConstraintNotNull )
413413
{
414414
action.error = true;
415-
action.errorMsg = QStringLiteral( "NOT NULL constraint error error on layer '%1', field '%2'" ).arg( typeName, field.name() );
415+
action.errorMsg = QStringLiteral( "NOT NULL constraint error on layer '%1', field '%2'" ).arg( typeName, field.name() );
416416
vlayer->rollBack();
417417
break;
418418
}

‎tests/src/python/test_provider_wfs.py

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3581,6 +3581,162 @@ def testGeometryCollectionAsMultiLineString(self):
35813581
vl_extent = QgsGeometry.fromRect(vl.extent())
35823582
assert QgsGeometry.compare(vl_extent.asPolygon()[0], reference.asPolygon()[0], 0.00001), 'Expected {}, got {}'.format(reference.asWkt(), vl_extent.asWkt())
35833583

3584+
def test_NullValues_regression_20961(self):
3585+
"""Test that provider handles null values, regression #20961"""
3586+
3587+
endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_null_values'
3588+
3589+
with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0'), 'wb') as f:
3590+
f.write("""
3591+
<wfs:WFS_Capabilities version="1.1.0" xmlns="http://www.opengis.net/wfs" xmlns:wfs="http://www.opengis.net/wfs" xmlns:ogc="http://www.opengis.net/ogc" xmlns:ows="http://www.opengis.net/ows" xmlns:gml="http://schemas.opengis.net/gml">
3592+
<FeatureTypeList>
3593+
<FeatureType>
3594+
<Name>points</Name>
3595+
<Title>Title</Title>
3596+
<Abstract>Abstract</Abstract>
3597+
<DefaultCRS>urn:ogc:def:crs:OGC:1.3:CRS84</DefaultCRS>
3598+
<WGS84BoundingBox>
3599+
<LowerCorner>-98.6523 32.7233</LowerCorner>
3600+
<UpperCorner>23.2868 69.9882</UpperCorner>
3601+
</WGS84BoundingBox>
3602+
</FeatureType>
3603+
</FeatureTypeList>
3604+
</wfs:WFS_Capabilities>""".encode('UTF-8'))
3605+
3606+
with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=points'), 'wb') as f:
3607+
f.write("""
3608+
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:gml="http://www.opengis.net/gml" version="1.0" xmlns:ogc="http://www.opengis.net/ogc" xmlns:qgs="http://www.qgis.org/gml" elementFormDefault="qualified" targetNamespace="http://www.qgis.org/gml" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
3609+
<import schemaLocation="http://schemas.opengis.net/gml/3.1.1/base/gml.xsd" namespace="http://www.opengis.net/gml"/>
3610+
<element type="qgs:pointsType" name="points" substitutionGroup="gml:_Feature"/>
3611+
<complexType name="pointsType">
3612+
<complexContent>
3613+
<extension base="gml:AbstractFeatureType">
3614+
<sequence>
3615+
<element type="gml:MultiPointPropertyType" name="geometry" minOccurs="0" maxOccurs="1"/>
3616+
<element type="int" name="id"/>
3617+
<element type="string" name="name"/>
3618+
<element type="int" name="type" nillable="true"/>
3619+
<element type="decimal" name="elevation" nillable="true"/>
3620+
</sequence>
3621+
</extension>
3622+
</complexContent>
3623+
</complexType>
3624+
</schema>
3625+
""".encode('UTF-8'))
3626+
3627+
get_feature_1 = """<wfs:FeatureCollection xmlns:wfs="http://www.opengis.net/wfs" xmlns:ogc="http://www.opengis.net/ogc" xmlns:gml="http://www.opengis.net/gml" xmlns:ows="http://www.opengis.net/ows" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:qgs="http://www.qgis.org/gml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/wfs.xsd http://www.qgis.org/gml http://localhost:8000/ows/bug_20961_server?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0&amp;SERVICE=WFS&amp;VERSION=1.1.0&amp;REQUEST=DescribeFeatureType&amp;TYPENAME=points&amp;OUTPUTFORMAT=text/xml; subtype%3Dgml/3.1.1">
3628+
<gml:boundedBy>
3629+
<gml:Envelope srsName="EPSG:3857">
3630+
<gml:lowerCorner>-10981925.67093 3858635.0686243</gml:lowerCorner>
3631+
<gml:upperCorner>2592274.0488407 11064877.6393476</gml:upperCorner>
3632+
</gml:Envelope>
3633+
</gml:boundedBy>
3634+
<gml:featureMember>
3635+
<qgs:points gml:id="points.177">
3636+
<gml:boundedBy>
3637+
<gml:Envelope srsName="EPSG:3857">
3638+
<gml:lowerCorner>1544231.80343599 5930698.04174612</gml:lowerCorner>
3639+
<gml:upperCorner>1544231.80343599 5930698.04174612</gml:upperCorner>
3640+
</gml:Envelope>
3641+
</gml:boundedBy>
3642+
<qgs:geometry>
3643+
<MultiPoint xmlns="http://www.opengis.net/gml" srsName="EPSG:3857">
3644+
<pointMember xmlns="http://www.opengis.net/gml">
3645+
<Point xmlns="http://www.opengis.net/gml">
3646+
<pos xmlns="http://www.opengis.net/gml" srsDimension="2">1544231.80343599 5930698.04174612</pos>
3647+
</Point>
3648+
</pointMember>
3649+
</MultiPoint>
3650+
</qgs:geometry>
3651+
<qgs:id>177</qgs:id>
3652+
<qgs:name>Xxx</qgs:name>
3653+
<qgs:elevation_source></qgs:elevation_source>
3654+
</qgs:points>
3655+
</gml:featureMember>
3656+
</wfs:FeatureCollection>
3657+
"""
3658+
get_features = """<wfs:FeatureCollection xmlns:wfs="http://www.opengis.net/wfs" xmlns:ogc="http://www.opengis.net/ogc" xmlns:gml="http://www.opengis.net/gml" xmlns:ows="http://www.opengis.net/ows" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:qgs="http://www.qgis.org/gml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/wfs.xsd http://www.qgis.org/gml http://localhost:8000/ows/bug_20961_server?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0&amp;SERVICE=WFS&amp;VERSION=1.1.0&amp;REQUEST=DescribeFeatureType&amp;TYPENAME=points&amp;OUTPUTFORMAT=text/xml; subtype%3Dgml/3.1.1">
3659+
<gml:boundedBy>
3660+
<gml:Envelope srsName="EPSG:3857">
3661+
<gml:lowerCorner>-10981925.67093 3858635.0686243</gml:lowerCorner>
3662+
<gml:upperCorner>2592274.0488407 11064877.6393476</gml:upperCorner>
3663+
</gml:Envelope>
3664+
</gml:boundedBy>
3665+
<gml:featureMember>
3666+
<qgs:points gml:id="points.177">
3667+
<gml:boundedBy>
3668+
<gml:Envelope srsName="EPSG:3857">
3669+
<gml:lowerCorner>1544231.80343599 5930698.04174612</gml:lowerCorner>
3670+
<gml:upperCorner>1544231.80343599 5930698.04174612</gml:upperCorner>
3671+
</gml:Envelope>
3672+
</gml:boundedBy>
3673+
<qgs:geometry>
3674+
<MultiPoint xmlns="http://www.opengis.net/gml" srsName="EPSG:3857">
3675+
<pointMember xmlns="http://www.opengis.net/gml">
3676+
<Point xmlns="http://www.opengis.net/gml">
3677+
<pos xmlns="http://www.opengis.net/gml" srsDimension="2">1544231.80343599 5930698.04174612</pos>
3678+
</Point>
3679+
</pointMember>
3680+
</MultiPoint>
3681+
</qgs:geometry>
3682+
<qgs:id>177</qgs:id>
3683+
<qgs:name>Xxx</qgs:name>
3684+
<qgs:type xsi:nil="true"></qgs:type>
3685+
<qgs:elevation xsi:nil="true"></qgs:elevation>
3686+
</qgs:points>
3687+
</gml:featureMember>
3688+
<gml:featureMember>
3689+
<qgs:points gml:id="points.5">
3690+
<gml:boundedBy>
3691+
<gml:Envelope srsName="EPSG:3857">
3692+
<gml:lowerCorner>-10977033.701121 3897159.3308746</gml:lowerCorner>
3693+
<gml:upperCorner>-10977033.701121 3897159.3308746</gml:upperCorner>
3694+
</gml:Envelope>
3695+
</gml:boundedBy>
3696+
<qgs:geometry>
3697+
<MultiPoint xmlns="http://www.opengis.net/gml" srsName="EPSG:3857">
3698+
<pointMember xmlns="http://www.opengis.net/gml">
3699+
<Point xmlns="http://www.opengis.net/gml">
3700+
<pos xmlns="http://www.opengis.net/gml" srsDimension="2">-10977033.701121 3897159.3308746</pos>
3701+
</Point>
3702+
</pointMember>
3703+
</MultiPoint>
3704+
</qgs:geometry>
3705+
<qgs:id>5</qgs:id>
3706+
<qgs:name>sdf</qgs:name>
3707+
<qgs:type>0</qgs:type>
3708+
<qgs:elevation xsi:nil="true"></qgs:elevation>
3709+
</qgs:points>
3710+
</gml:featureMember>
3711+
</wfs:FeatureCollection>"""
3712+
3713+
with open(sanitize(endpoint, """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=points&MAXFEATURES=1&SRSNAME=urn:ogc:def:crs:EPSG::4326"""), 'wb') as f:
3714+
f.write(get_feature_1.encode('UTF-8'))
3715+
3716+
with open(sanitize(endpoint, """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=points&SRSNAME=urn:ogc:def:crs:EPSG::4326"""), 'wb') as f:
3717+
f.write(get_features.encode('UTF-8'))
3718+
3719+
vl = QgsVectorLayer("url='http://" + endpoint + "' typename='points' version='1.1.0'", 'test', 'WFS')
3720+
self.assertTrue(vl.isValid())
3721+
3722+
got_f = [f for f in vl.getFeatures()]
3723+
self.assertEqual(str(got_f[0]['type']), 'NULL')
3724+
self.assertEqual(str(got_f[0]['elevation']), 'NULL')
3725+
self.assertEqual(str(got_f[0]['name']), 'Xxx')
3726+
self.assertEqual(str(got_f[1]['type']), '0')
3727+
self.assertEqual(str(got_f[1]['elevation']), 'NULL')
3728+
self.assertEqual(str(got_f[1]['name']), 'sdf')
3729+
3730+
# Now iterate ! Regression #20961
3731+
ids = [f.id() for f in got_f]
3732+
got_f2 = [vl.getFeature(id) for id in ids]
3733+
self.assertEqual(str(got_f2[0]['type']), 'NULL')
3734+
self.assertEqual(str(got_f2[0]['elevation']), 'NULL')
3735+
self.assertEqual(str(got_f2[0]['name']), 'Xxx')
3736+
self.assertEqual(str(got_f2[1]['type']), '0')
3737+
self.assertEqual(str(got_f2[1]['elevation']), 'NULL')
3738+
self.assertEqual(str(got_f2[1]['name']), 'sdf')
3739+
35843740

35853741
if __name__ == '__main__':
35863742
unittest.main()

0 commit comments

Comments
 (0)
Please sign in to comment.