Skip to content

Commit 5481177

Browse files
committed
[OGR provider] Avoid 'database locked' issues when editing several layers of the same GeoPackage (fixes #17034)
1 parent 18c1597 commit 5481177

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed

src/providers/ogr/qgsogrprovider.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1671,6 +1671,7 @@ bool QgsOgrProvider::changeAttributeValues( const QgsChangedAttributesMap &attr_
16711671
pushError( tr( "Feature %1 for attribute update not found." ).arg( fid ) );
16721672
continue;
16731673
}
1674+
OGR_L_ResetReading( ogrLayer ); // needed for SQLite-based to clear iterator
16741675

16751676
QgsLocaleNumC l;
16761677

@@ -1811,6 +1812,7 @@ bool QgsOgrProvider::changeGeometryValues( const QgsGeometryMap &geometry_map )
18111812
pushError( tr( "OGR error changing geometry: feature %1 not found" ).arg( it.key() ) );
18121813
continue;
18131814
}
1815+
OGR_L_ResetReading( ogrLayer ); // needed for SQLite-based to clear iterator
18141816

18151817
OGRGeometryH newGeometry = nullptr;
18161818
QByteArray wkb = it->exportToWkb();

tests/src/python/test_provider_ogr_gpkg.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,68 @@ def testSimulatedDBManagerImport(self):
451451
self.assertEqual(f['f1'], 3)
452452
features = None
453453

454+
def testGeopackageTwoLayerEdition(self):
455+
''' test https://issues.qgis.org/issues/17034 '''
456+
tmpfile = os.path.join(self.basetestpath, 'testGeopackageTwoLayerEdition.gpkg')
457+
ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
458+
lyr = ds.CreateLayer('layer1', geom_type=ogr.wkbPoint)
459+
lyr.CreateField(ogr.FieldDefn('attr', ogr.OFTInteger))
460+
f = ogr.Feature(lyr.GetLayerDefn())
461+
f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 0)'))
462+
lyr.CreateFeature(f)
463+
f = None
464+
lyr = ds.CreateLayer('layer2', geom_type=ogr.wkbPoint)
465+
lyr.CreateField(ogr.FieldDefn('attr', ogr.OFTInteger))
466+
f = ogr.Feature(lyr.GetLayerDefn())
467+
f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(1 1)'))
468+
lyr.CreateFeature(f)
469+
f = None
470+
ds = None
471+
472+
vl1 = QgsVectorLayer(u'{}'.format(tmpfile) + "|layername=layer1", u'layer1', u'ogr')
473+
vl2 = QgsVectorLayer(u'{}'.format(tmpfile) + "|layername=layer2", u'layer2', u'ogr')
474+
475+
# Edit vl1, vl2 multiple times
476+
self.assertTrue(vl1.startEditing())
477+
self.assertTrue(vl2.startEditing())
478+
self.assertTrue(vl1.changeGeometry(1, QgsGeometry.fromWkt('Point (2 2)')))
479+
self.assertTrue(vl2.changeGeometry(1, QgsGeometry.fromWkt('Point (3 3)')))
480+
self.assertTrue(vl1.commitChanges())
481+
self.assertTrue(vl2.commitChanges())
482+
483+
self.assertTrue(vl1.startEditing())
484+
self.assertTrue(vl2.startEditing())
485+
self.assertTrue(vl1.changeAttributeValue(1, 1, 100))
486+
self.assertTrue(vl2.changeAttributeValue(1, 1, 101))
487+
self.assertTrue(vl1.commitChanges())
488+
self.assertTrue(vl2.commitChanges())
489+
490+
self.assertTrue(vl1.startEditing())
491+
self.assertTrue(vl2.startEditing())
492+
self.assertTrue(vl1.changeGeometry(1, QgsGeometry.fromWkt('Point (4 4)')))
493+
self.assertTrue(vl2.changeGeometry(1, QgsGeometry.fromWkt('Point (5 5)')))
494+
self.assertTrue(vl1.commitChanges())
495+
self.assertTrue(vl2.commitChanges())
496+
497+
vl1 = None
498+
vl2 = None
499+
500+
# Check everything is as expected after re-opening
501+
vl1 = QgsVectorLayer(u'{}'.format(tmpfile) + "|layername=layer1", u'layer1', u'ogr')
502+
vl2 = QgsVectorLayer(u'{}'.format(tmpfile) + "|layername=layer2", u'layer2', u'ogr')
503+
504+
got = [feat for feat in vl1.getFeatures()][0]
505+
got_geom = got.geometry()
506+
self.assertEqual(got['attr'], 100)
507+
reference = QgsGeometry.fromWkt('Point (4 4)')
508+
self.assertEqual(got_geom.exportToWkb(), reference.exportToWkb(), 'Expected {}, got {}'.format(reference.exportToWkt(), got_geom.exportToWkt()))
509+
510+
got = [feat for feat in vl2.getFeatures()][0]
511+
got_geom = got.geometry()
512+
self.assertEqual(got['attr'], 101)
513+
reference = QgsGeometry.fromWkt('Point (5 5)')
514+
self.assertEqual(got_geom.exportToWkb(), reference.exportToWkb(), 'Expected {}, got {}'.format(reference.exportToWkt(), got_geom.exportToWkt()))
515+
454516

455517
if __name__ == '__main__':
456518
unittest.main()

0 commit comments

Comments
 (0)