Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[memory] Correctly store converted field values when adding or
changing attributes

If testing for value compatiblity via QgsField::convertCompatibility
only resulted in true because an automatic type conversion happened
then we need to store the auto converted value, not the original.
  • Loading branch information
nyalldawson committed Feb 25, 2021
1 parent 1587117 commit d5eb6b0
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 3 deletions.
10 changes: 8 additions & 2 deletions src/core/providers/memory/qgsmemoryprovider.cpp
Expand Up @@ -430,7 +430,8 @@ bool QgsMemoryProvider::addFeatures( QgsFeatureList &flist, Flags flags )
QString errorMessage;
for ( int i = 0; i < mFields.count(); ++i )
{
QVariant attrValue = it->attribute( i );
const QVariant originalValue = it->attribute( i );
QVariant attrValue = originalValue;
if ( ! attrValue.isNull() && ! mFields.at( i ).convertCompatible( attrValue, &errorMessage ) )
{
// Push first conversion error only
Expand All @@ -443,6 +444,11 @@ bool QgsMemoryProvider::addFeatures( QgsFeatureList &flist, Flags flags )
conversionError = true;
continue;
}
else if ( attrValue.type() != originalValue.type() )
{
// convertCompatible has resulted in a data type conversion
it->setAttribute( i, attrValue );
}
}

// Skip the feature if there is at least one conversion error
Expand Down Expand Up @@ -631,7 +637,7 @@ bool QgsMemoryProvider::changeAttributeValues( const QgsChangedAttributesMap &at
break;
}
rollBackAttrs.insert( it2.key(), fit->attribute( it2.key() ) );
fit->setAttribute( it2.key(), it2.value() );
fit->setAttribute( it2.key(), attrValue );
}
rollBackMap.insert( it.key(), rollBackAttrs );
}
Expand Down
2 changes: 1 addition & 1 deletion tests/src/analysis/testqgsnetworkanalysis.cpp
Expand Up @@ -520,7 +520,7 @@ void TestQgsNetworkAnalysis::testRouteFail()

void TestQgsNetworkAnalysis::testRouteFail2()
{
std::unique_ptr< QgsVectorLayer > network = std::make_unique< QgsVectorLayer >( QStringLiteral( "LineString?crs=epsg:4326&field=cost:int" ), QStringLiteral( "x" ), QStringLiteral( "memory" ) );
std::unique_ptr< QgsVectorLayer > network = std::make_unique< QgsVectorLayer >( QStringLiteral( "LineString?crs=epsg:4326&field=cost:double" ), QStringLiteral( "x" ), QStringLiteral( "memory" ) );

QStringList lines = QStringList() << QStringLiteral( "LineString (11.25044997999680874 48.42605439713970128, 11.25044693759680925 48.42603339773970106, 11.25044760759680962 48.42591690773969759, 11.25052289759680946 48.42589190773969676)" )
<< QStringLiteral( "LineString (11.25052289759680946 48.42589190773969676, 11.25050350759680917 48.42586202773969717, 11.25047190759680937 48.42581754773969749, 11.2504146475968092 48.42573849773970096, 11.25038716759680923 48.42569834773969717, 11.2502920175968093 48.42557470773969897, 11.25019984759680902 48.42560406773969817, 11.25020393759680992 48.42571203773970012, 11.2502482875968095 48.42577478773969801, 11.25021922759680848 48.42578442773969982)" )
Expand Down
21 changes: 21 additions & 0 deletions tests/src/python/test_provider_memory.py
Expand Up @@ -505,6 +505,27 @@ def testCreateMemoryLayer(self):
self.assertEqual(layer.fields()[i].length(), fields[i].length())
self.assertEqual(layer.fields()[i].precision(), fields[i].precision())

def testAddChangeFeatureConvertAttribute(self):
"""
Test add features with attribute values which require conversion
"""
layer = QgsVectorLayer(
'Point?crs=epsg:4326&index=yes&field=pk:integer&field=cnt:int8&field=dt:datetime', 'test', 'memory')
provider = layer.dataProvider()
f = QgsFeature()
# string value specified for datetime field -- must be converted when adding the feature
f.setAttributes([5, -200, '2021-02-10 00:00'])
self.assertTrue(provider.addFeatures([f]))

saved_feature = next(provider.getFeatures())
# saved feature must have a QDateTime value for field, not string
self.assertEqual(saved_feature.attributes(), [5, -200, QDateTime(2021, 2, 10, 0, 0)])

self.assertTrue(provider.changeAttributeValues({saved_feature.id(): {2: '2021-02-12 00:00'}}))
saved_feature = next(provider.getFeatures())
# saved feature must have a QDateTime value for field, not string
self.assertEqual(saved_feature.attributes(), [5, -200, QDateTime(2021, 2, 12, 0, 0)])

def testThreadSafetyWithIndex(self):
layer = QgsVectorLayer(
'Point?crs=epsg:4326&index=yes&field=pk:integer&field=cnt:int8&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk',
Expand Down

0 comments on commit d5eb6b0

Please sign in to comment.