From 9993f332f2bba77f63751c56ddae670fb0ebb9a6 Mon Sep 17 00:00:00 2001 From: Alessandro Pasotti Date: Mon, 15 May 2023 11:59:14 +0200 Subject: [PATCH] Fix vector iterator number of attributes returned with virtual fields Fix the issue of wrong number of attributes returned when the feature request has setSubsetOfAttributes set, in that case the virtual fields were not returned causing an inconsistency in the API response. With this patch the virtual fields are always returned (possibly Null). --- .../vector/qgsvectorlayerfeatureiterator.cpp | 7 +++++ tests/src/python/test_qgsvectorlayer.py | 28 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/core/vector/qgsvectorlayerfeatureiterator.cpp b/src/core/vector/qgsvectorlayerfeatureiterator.cpp index f6e21c2a0820..e1cf3fb8998e 100644 --- a/src/core/vector/qgsvectorlayerfeatureiterator.cpp +++ b/src/core/vector/qgsvectorlayerfeatureiterator.cpp @@ -551,6 +551,8 @@ bool QgsVectorLayerFeatureIterator::fetchFeature( QgsFeature &f ) if ( mHasVirtualAttributes ) addVirtualAttributes( f ); + else + f.padAttributes( mSource->mFields.count() - f.attributeCount() ); if ( mRequest.filterType() == QgsFeatureRequest::FilterExpression && mProviderRequest.filterType() != QgsFeatureRequest::FilterExpression ) { @@ -664,6 +666,8 @@ void QgsVectorLayerFeatureIterator::useAddedFeature( const QgsFeature &src, QgsF if ( mHasVirtualAttributes ) addVirtualAttributes( f ); + else + f.padAttributes( mSource->mFields.count() - f.attributeCount() ); } @@ -918,6 +922,7 @@ void QgsVectorLayerFeatureIterator::prepareFields() { createOrderedJoinList(); } + } void QgsVectorLayerFeatureIterator::createOrderedJoinList() @@ -1292,6 +1297,8 @@ bool QgsVectorLayerFeatureIterator::nextFeatureFid( QgsFeature &f ) if ( mHasVirtualAttributes ) addVirtualAttributes( f ); + else + f.padAttributes( mSource->mFields.count() - f.attributeCount() ); return true; } diff --git a/tests/src/python/test_qgsvectorlayer.py b/tests/src/python/test_qgsvectorlayer.py index 66f2a609872e..0b65f0bd7f85 100644 --- a/tests/src/python/test_qgsvectorlayer.py +++ b/tests/src/python/test_qgsvectorlayer.py @@ -2658,6 +2658,34 @@ def testReselect(self): layer.reselect() self.assertCountEqual(layer.selectedFeatureIds(), [5]) + def testGetFeaturesVirtualFieldsSubset(self): + """Test that when a subset is requested virtual fields are returned nullified""" + + vl = QgsVectorLayer(os.path.join(unitTestDataPath(), 'points.shp'), 'Points', 'ogr') + virt_field_idx = vl.addExpressionField('\'Importance: \' || Importance', QgsField('virt_1', QVariant.String)) + + self.assertEqual(vl.fields().lookupField('virt_1'), virt_field_idx) + + req = QgsFeatureRequest() + req.setSubsetOfAttributes([0, 1]) + attrs = next(vl.getFeatures(req)).attributes() + self.assertEqual(attrs, ['Jet', 90, None, None, None, None, None]) + + attrs = next(vl.getFeatures()).attributes() + self.assertEqual(attrs, ['Jet', 90, 3.0, 2, 0, 2, 'Importance: 3']) + + req.setSubsetOfAttributes([0, 2]) + attrs = next(vl.getFeatures(req)).attributes() + self.assertEqual(attrs, ['Jet', None, 3.0, None, None, None, None]) + + req.setSubsetOfAttributes([0, 1, 6]) + attrs = next(vl.getFeatures(req)).attributes() + self.assertEqual(attrs, ['Jet', 90, 3.0, None, None, None, 'Importance: 3']) + + req.setSubsetOfAttributes([6]) + attrs = next(vl.getFeatures(req)).attributes() + self.assertEqual(attrs, [None, None, 3.0, None, None, None, 'Importance: 3']) + def testAggregate(self): """ Test aggregate calculation """ layer = QgsVectorLayer("Point?field=fldint:integer", "layer", "memory")