Skip to content

Commit

Permalink
Fix aggregate expression calculation when used with virtual fields
Browse files Browse the repository at this point in the history
The layer expression context (which is required for aggregate
calculation to work) was not being added to the context used
by vector layer feature iterators.

Fix #15930
  • Loading branch information
nyalldawson committed Jul 14, 2017
1 parent 0639264 commit 3f4d6de
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 1 deletion.
1 change: 1 addition & 0 deletions python/core/qgsvectorlayerfeatureiterator.sip
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class QgsVectorLayerFeatureSource : QgsAbstractFeatureSource




};


Expand Down
5 changes: 4 additions & 1 deletion src/core/qgsvectorlayerfeatureiterator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ QgsVectorLayerFeatureSource::QgsVectorLayerFeatureSource( const QgsVectorLayer *
}
#endif
}

std::unique_ptr< QgsExpressionContextScope > layerScope( QgsExpressionContextUtils::layerScope( layer ) );
mLayerScope = *layerScope;
}

QgsVectorLayerFeatureSource::~QgsVectorLayerFeatureSource()
Expand Down Expand Up @@ -644,7 +647,7 @@ void QgsVectorLayerFeatureIterator::prepareFields()
mExpressionContext.reset( new QgsExpressionContext() );
mExpressionContext->appendScope( QgsExpressionContextUtils::globalScope() );
mExpressionContext->appendScope( QgsExpressionContextUtils::projectScope( QgsProject::instance() ) );
mExpressionContext->setFields( mSource->mFields );
mExpressionContext->appendScope( new QgsExpressionContextScope( mSource->mLayerScope ) );

mFieldsToPrepare = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes ) ? mRequest.subsetOfAttributes() : mSource->mFields.allAttributesList();

Expand Down
2 changes: 2 additions & 0 deletions src/core/qgsvectorlayerfeatureiterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ class CORE_EXPORT QgsVectorLayerFeatureSource : public QgsAbstractFeatureSource

QgsFields mFields;

QgsExpressionContextScope mLayerScope;

bool mHasEditBuffer;

// A deep-copy is only performed, if the original maps change
Expand Down
21 changes: 21 additions & 0 deletions tests/src/python/test_qgsvectorlayer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1829,6 +1829,27 @@ def testAggregate(self):
self.assertTrue(ok)
self.assertEqual(val, 'this is a test')

def testAggregateInVirtualField(self):
"""
Test aggregates in a virtual field
"""
layer = QgsVectorLayer("Point?field=fldint:integer", "layer", "memory")
pr = layer.dataProvider()

int_values = [4, 2, 3, 2, 5, None, 8]
features = []
for i in int_values:
f = QgsFeature()
f.setFields(layer.fields())
f.setAttributes([i])
features.append(f)
assert pr.addFeatures(features)

field = QgsField('virtual', QVariant.Double)
layer.addExpressionField('sum(fldint*2)', field)
vals = [f['virtual'] for f in layer.getFeatures()]
self.assertEqual(vals, [48, 48, 48, 48, 48, 48, 48])

def onLayerOpacityChanged(self, tr):
self.opacityTest = tr

Expand Down

0 comments on commit 3f4d6de

Please sign in to comment.