Skip to content
Permalink
Browse files

Merge pull request #33958 from rouault/backport_3_10_PR_33927

[Backport 3.10] [BUGFIX] QgsExpression::referencedAttributeIndexes(): only report valid indices
  • Loading branch information
rouault committed Jan 21, 2020
2 parents 3e22260 + 992ad09 commit 2be9fbcad903d118c28fec6ac01d4dad90fb7ca1
@@ -301,7 +301,11 @@ QSet<int> QgsExpression::referencedAttributeIndexes( const QgsFields &fields ) c
referencedIndexes = fields.allAttributesList().toSet();
break;
}
referencedIndexes << fields.lookupField( fieldName );
const int idx = fields.lookupField( fieldName );
if ( idx >= 0 )
{
referencedIndexes << idx;
}
}

return referencedIndexes;
@@ -70,23 +70,22 @@ QgsOracleFeatureIterator::QgsOracleFeatureIterator( QgsOracleFeatureSource *sour
// ensure that all attributes required for expression filter are being fetched
if ( mRequest.filterType() == QgsFeatureRequest::FilterExpression )
{
const auto constReferencedColumns = mRequest.filterExpression()->referencedColumns();
for ( const QString &field : constReferencedColumns )
const QSet<int> attributeIndexes = mRequest.filterExpression()->referencedAttributeIndexes( mSource->mFields );
for ( int attrIdx : attributeIndexes )
{
int attrIdx = mSource->mFields.lookupField( field );
if ( !mAttributeList.contains( attrIdx ) )
mAttributeList << attrIdx;
}
}

// ensure that all attributes required for order by are fetched
const QSet< QString > orderByAttributes = mRequest.orderBy().usedAttributes();
for ( const QString &attr : orderByAttributes )
const auto orderByAttributes = mRequest.orderBy().usedAttributeIndices( mSource->mFields );
for ( int attrIdx : orderByAttributes )
{
int attrIndex = mSource->mFields.lookupField( attr );
if ( !mAttributeList.contains( attrIndex ) )
mAttributeList << attrIndex;
if ( !mAttributeList.contains( attrIdx ) )
mAttributeList << attrIdx;
}

}
else
mAttributeList = mSource->mFields.allAttributesList();
@@ -138,10 +138,9 @@ QgsVirtualLayerFeatureIterator::QgsVirtualLayerFeatureIterator( QgsVirtualLayerF
// ensure that all attributes required for expression filter are being fetched
if ( request.filterType() == QgsFeatureRequest::FilterExpression )
{
const auto constReferencedColumns = request.filterExpression()->referencedColumns();
for ( const QString &field : constReferencedColumns )
const QSet<int> attributeIndexes = request.filterExpression()->referencedAttributeIndexes( mSource->mFields );
for ( int attrIdx : attributeIndexes )
{
int attrIdx = mSource->mFields.lookupField( field );
if ( !mAttributes.contains( attrIdx ) )
mAttributes << attrIdx;
}
@@ -715,3 +715,10 @@ def testMaximumValue(self):
def testAllFeatureIds(self):
ids = set([f.id() for f in self.source.getFeatures()])
self.assertEqual(set(self.source.allFeatureIds()), ids)

def testSubsetOfAttributesWithFilterExprWithNonExistingColumn(self):
""" Test fix for https://github.com/qgis/QGIS/issues/33878 """
request = QgsFeatureRequest().setSubsetOfAttributes([0])
request.setFilterExpression("non_existing = 1")
features = [f for f in self.source.getFeatures(request)]
self.assertEqual(len(features), 0)
@@ -15,7 +15,7 @@
from qgis.PyQt.QtCore import QVariant
from qgis.testing import unittest
from qgis.utils import qgsfunction
from qgis.core import QgsExpression, QgsFeatureRequest, QgsExpressionContext, NULL
from qgis.core import QgsExpression, QgsFeatureRequest, QgsFields, QgsExpressionContext, NULL


class TestQgsExpressionCustomFunctions(unittest.TestCase):
@@ -264,6 +264,12 @@ def testCreateFieldEqualityExpression(self):
res = '"my\'field" = TRUE'
self.assertEqual(e.createFieldEqualityExpression(field, value), res)

def testReferencedAttributeIndexesNonExistingField(self):
e = QgsExpression()
e.setExpression("foo = 1")
self.assertTrue(e.isValid())
self.assertEqual(len(e.referencedAttributeIndexes(QgsFields())), 0)


if __name__ == "__main__":
unittest.main()
Binary file not shown.

0 comments on commit 2be9fbc

Please sign in to comment.
You can’t perform that action at this time.