Skip to content

Commit

Permalink
[memory] Fix memory provider does not return correct min/max
Browse files Browse the repository at this point in the history
values after adding or editing features

The cache was not cleared correctly in this case

Fix sponsored by LINZ
  • Loading branch information
nyalldawson committed May 14, 2018
1 parent 8f47691 commit 6b74268
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/core/providers/memory/qgsmemoryprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ bool QgsMemoryProvider::addFeatures( QgsFeatureList &flist, Flags )
mNextFeatureId++;
}

clearMinMaxCache();
return result;
}

Expand All @@ -423,6 +424,7 @@ bool QgsMemoryProvider::deleteFeatures( const QgsFeatureIds &id )
}

updateExtents();
clearMinMaxCache();

return true;
}
Expand Down Expand Up @@ -504,6 +506,7 @@ bool QgsMemoryProvider::deleteAttributes( const QgsAttributeIds &attributes )
f.setAttributes( attr );
}
}
clearMinMaxCache();
return true;
}

Expand All @@ -519,6 +522,7 @@ bool QgsMemoryProvider::changeAttributeValues( const QgsChangedAttributesMap &at
for ( QgsAttributeMap::const_iterator it2 = attrs.constBegin(); it2 != attrs.constEnd(); ++it2 )
fit->setAttribute( it2.key(), it2.value() );
}
clearMinMaxCache();
return true;
}

Expand Down
2 changes: 2 additions & 0 deletions src/core/qgsvectordataprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,8 @@ QVariant QgsVectorDataProvider::aggregate( QgsAggregateCalculator::Aggregate agg
void QgsVectorDataProvider::clearMinMaxCache()
{
mCacheMinMaxDirty = true;
mCacheMinValues.clear();
mCacheMaxValues.clear();
}

void QgsVectorDataProvider::fillMinMaxCache() const
Expand Down
65 changes: 65 additions & 0 deletions tests/src/python/test_provider_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,71 @@ def testThreadSafetyWithIndex(self):
request = QgsFeatureRequest().setFilterRect(extent)
self.assertTrue(QgsTestUtils.testProviderIteratorThreadSafety(self.source, request))

def testMinMaxCache(self):
"""
Test that min/max cache is appropriately cleared
:return:
"""
vl = QgsVectorLayer(
'Point?crs=epsg:4326&field=f1:integer&field=f2:integer',
'test', 'memory')
self.assertTrue(vl.isValid())

f1 = QgsFeature()
f1.setAttributes([5, -200])
f2 = QgsFeature()
f2.setAttributes([3, 300])
f3 = QgsFeature()
f3.setAttributes([1, 100])
f4 = QgsFeature()
f4.setAttributes([2, 200])
f5 = QgsFeature()
f5.setAttributes([4, 400])
res, [f1, f2, f3, f4, f5] = vl.dataProvider().addFeatures([f1, f2, f3, f4, f5])
self.assertTrue(res)

self.assertEqual(vl.dataProvider().minimumValue(0), 1)
self.assertEqual(vl.dataProvider().minimumValue(1), -200)
self.assertEqual(vl.dataProvider().maximumValue(0), 5)
self.assertEqual(vl.dataProvider().maximumValue(1), 400)

# add feature
f6 = QgsFeature()
f6.setAttributes([15, 1400])
res, [f6] = vl.dataProvider().addFeatures([f6])
self.assertTrue(res)
self.assertEqual(vl.dataProvider().minimumValue(0), 1)
self.assertEqual(vl.dataProvider().minimumValue(1), -200)
self.assertEqual(vl.dataProvider().maximumValue(0), 15)
self.assertEqual(vl.dataProvider().maximumValue(1), 1400)
f7 = QgsFeature()
f7.setAttributes([-1, -1400])
res, [f7] = vl.dataProvider().addFeatures([f7])
self.assertTrue(res)
self.assertEqual(vl.dataProvider().minimumValue(0), -1)
self.assertEqual(vl.dataProvider().minimumValue(1), -1400)
self.assertEqual(vl.dataProvider().maximumValue(0), 15)
self.assertEqual(vl.dataProvider().maximumValue(1), 1400)

# change attribute values
self.assertTrue(vl.dataProvider().changeAttributeValues({f6.id(): {0: 3, 1: 150}, f7.id(): {0: 4, 1: -100}}))
self.assertEqual(vl.dataProvider().minimumValue(0), 1)
self.assertEqual(vl.dataProvider().minimumValue(1), -200)
self.assertEqual(vl.dataProvider().maximumValue(0), 5)
self.assertEqual(vl.dataProvider().maximumValue(1), 400)

# delete features
self.assertTrue(vl.dataProvider().deleteFeatures([f4.id(), f1.id()]))
self.assertEqual(vl.dataProvider().minimumValue(0), 1)
self.assertEqual(vl.dataProvider().minimumValue(1), -100)
self.assertEqual(vl.dataProvider().maximumValue(0), 4)
self.assertEqual(vl.dataProvider().maximumValue(1), 400)

# delete attributes
self.assertTrue(vl.dataProvider().deleteAttributes([0]))
self.assertEqual(vl.dataProvider().minimumValue(0), -100)
self.assertEqual(vl.dataProvider().maximumValue(0), 400)


class TestPyQgsMemoryProviderIndexed(unittest.TestCase, ProviderTestCase):

Expand Down

0 comments on commit 6b74268

Please sign in to comment.