diff --git a/src/providers/wfs/qgswfsfeatureiterator.cpp b/src/providers/wfs/qgswfsfeatureiterator.cpp
index 640bddf9edd..46a9a43d803 100644
--- a/src/providers/wfs/qgswfsfeatureiterator.cpp
+++ b/src/providers/wfs/qgswfsfeatureiterator.cpp
@@ -991,7 +991,15 @@ QgsFeatureRequest QgsWFSFeatureIterator::buildRequestCache( int genCounter )
{
if ( mRequest.filterType() == QgsFeatureRequest::FilterExpression )
{
+ // Transfer and transform context
requestCache.setFilterExpression( mRequest.filterExpression()->expression() );
+ QgsExpressionContext ctx { *mRequest.expressionContext( ) };
+ QgsExpressionContextScope *scope { ctx.activeScopeForVariable( QgsExpressionContext::EXPR_FIELDS ) };
+ if ( scope )
+ {
+ scope->setVariable( QgsExpressionContext::EXPR_FIELDS, mShared->mCacheDataProvider->fields() );
+ }
+ requestCache.setExpressionContext( ctx );
}
if ( genCounter >= 0 )
{
diff --git a/tests/src/python/test_provider_wfs.py b/tests/src/python/test_provider_wfs.py
index 764a3e6ac5e..5abce65820c 100644
--- a/tests/src/python/test_provider_wfs.py
+++ b/tests/src/python/test_provider_wfs.py
@@ -33,7 +33,10 @@ from qgis.core import (
QgsVectorDataProvider,
QgsFeatureRequest,
QgsApplication,
- QgsSettings
+ QgsSettings,
+ QgsExpression,
+ QgsExpressionContextUtils,
+ QgsExpressionContext,
)
from qgis.testing import (start_app,
unittest
@@ -791,11 +794,11 @@ class TestPyQgsWFSProvider(unittest.TestCase, ProviderTestCase):
self.assertTrue(vl.isValid())
self.assertEqual(vl.dataProvider().capabilities(),
- QgsVectorDataProvider.AddFeatures |
- QgsVectorDataProvider.ChangeAttributeValues |
- QgsVectorDataProvider.ChangeGeometries |
- QgsVectorDataProvider.DeleteFeatures |
- QgsVectorDataProvider.SelectAtId)
+ QgsVectorDataProvider.AddFeatures
+ | QgsVectorDataProvider.ChangeAttributeValues
+ | QgsVectorDataProvider.ChangeGeometries
+ | QgsVectorDataProvider.DeleteFeatures
+ | QgsVectorDataProvider.SelectAtId)
(ret, _) = vl.dataProvider().addFeatures([QgsFeature()])
self.assertFalse(ret)
@@ -3737,6 +3740,166 @@ http://schemas.opengis.net/ows/1.1.0/owsAll.xsd">
self.assertEqual(str(got_f2[1]['elevation']), 'NULL')
self.assertEqual(str(got_f2[1]['name']), 'sdf')
+ def testFilteredFeatureRequests(self):
+ """Test https://issues.qgis.org/issues/21077 """
+
+ endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_filtered_feature_requests'
+
+ with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0'), 'wb') as f:
+ f.write("""
+
+
+
+ points
+ Title
+ Abstract
+ urn:ogc:def:crs:OGC:1.3:CRS84
+
+ -98.6523 32.7233
+ 23.2868 69.9882
+
+
+
+""".encode('UTF-8'))
+
+ with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=points'), 'wb') as f:
+ f.write("""
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+""".encode('UTF-8'))
+
+ get_feature_1 = """
+
+
+ -10981925.67093 3858635.0686243
+ 2592274.0488407 11064877.6393476
+
+
+
+
+
+
+ 1544231.80343599 5930698.04174612
+ 1544231.80343599 5930698.04174612
+
+
+
+
+
+
+ 1544231.80343599 5930698.04174612
+
+
+
+
+ 177
+ Xxx
+
+
+
+
+"""
+ get_features = """
+
+
+ -10981925.67093 3858635.0686243
+ 2592274.0488407 11064877.6393476
+
+
+
+
+
+
+ 1544231.80343599 5930698.04174612
+ 1544231.80343599 5930698.04174612
+
+
+
+
+
+
+ 1544231.80343599 5930698.04174612
+
+
+
+
+ 177
+ Xxx
+
+
+
+
+
+
+
+
+ -10977033.701121 3897159.3308746
+ -10977033.701121 3897159.3308746
+
+
+
+
+
+
+ -10977033.701121 3897159.3308746
+
+
+
+
+ 5
+ qgis
+ 0
+
+
+
+"""
+
+ 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:
+ f.write(get_feature_1.encode('UTF-8'))
+
+ with open(sanitize(endpoint, """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=points&SRSNAME=urn:ogc:def:crs:EPSG::4326"""), 'wb') as f:
+ f.write(get_features.encode('UTF-8'))
+
+ vl = QgsVectorLayer("url='http://" + endpoint + "' typename='points' version='1.1.0'", 'test', 'WFS')
+ self.assertTrue(vl.isValid())
+
+ # Fill the cache
+ [f for f in vl.getFeatures()]
+
+ qgis_feat = next(vl.getFeatures(QgsFeatureRequest(QgsExpression('"name" = \'qgis\''))))
+ other_feat = next(vl.getFeatures(QgsFeatureRequest(QgsExpression('"name" != \'qgis\''))))
+ self.assertEqual(qgis_feat['name'], 'qgis')
+ self.assertEqual(other_feat['name'], 'Xxx')
+
+ form_scope = QgsExpressionContextUtils.formScope(qgis_feat)
+ form_exp = QgsExpression('current_value(\'name\') = "name"')
+ ctx = QgsExpressionContext()
+ ctx.appendScope(form_scope)
+ ctx.setFeature(qgis_feat)
+ self.assertEqual(form_exp.evaluate(ctx), 1)
+ ctx.setFeature(other_feat)
+ self.assertEqual(form_exp.evaluate(ctx), 0)
+
+ # For real now! (this failed in issue 21077)
+ req = QgsFeatureRequest(form_exp)
+ req.setExpressionContext(ctx)
+ qgis_feat = next(vl.getFeatures(req))
+
if __name__ == '__main__':
unittest.main()