Skip to content

Commit 3a906a1

Browse files
committed
[OGR provider] Force REPACK at the first edit action.
In the case where we deal with a shapefile, it is possible that it has pre-existing holes in the DBF (see #15407), so if using a GDAL version recent enough (>=2.1.2) to have reliable packing, do a packing at the first edit action. Fixes #15407
1 parent 6db9a37 commit 3a906a1

File tree

2 files changed

+56
-0
lines changed

2 files changed

+56
-0
lines changed

src/providers/ogr/qgsogrprovider.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3365,6 +3365,18 @@ void QgsOgrProvider::open( OpenMode mode )
33653365
ogrLayer = ogrOrigLayer = nullptr;
33663366
mValid = false;
33673367

3368+
#if defined(GDAL_COMPUTE_VERSION)
3369+
// In the case where we deal with a shapefile, it is possible that it has
3370+
// pre-existing holes in the DBF (see #15407), so if using a GDAL version
3371+
// recent enough to have reliable packing, do a packing at the first edit
3372+
// action.
3373+
if ( ogrDriverName == "ESRI Shapefile" &&
3374+
atoi( GDALVersionInfo( "VERSION_NUM" ) ) >= GDAL_COMPUTE_VERSION( 2, 1, 2 ) )
3375+
{
3376+
mShapefileMayBeCorrupted = true;
3377+
}
3378+
#endif
3379+
33683380
ogrDataSource = QgsOgrProviderUtils::OGROpenWrapper( TO8F( mFilePath ), false, &ogrDriver );
33693381

33703382
mWriteAccess = false;

tests/src/python/test_provider_shapefile.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,5 +437,49 @@ def testRepackUnderFileLocks(self):
437437
self.assertTrue(ds.GetLayer(0).GetFeatureCount(), feature_count - 1)
438438
ds = None
439439

440+
def testRepackAtFirstSave(self):
441+
''' Test fix for #15407 '''
442+
443+
# This requires a GDAL fix done per https://trac.osgeo.org/gdal/ticket/6672
444+
# but on non-Windows version the test would succeed
445+
if int(osgeo.gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(2, 1, 2):
446+
return
447+
448+
tmpdir = tempfile.mkdtemp()
449+
self.dirs_to_cleanup.append(tmpdir)
450+
srcpath = os.path.join(TEST_DATA_DIR, 'provider')
451+
for file in glob.glob(os.path.join(srcpath, 'shapefile.*')):
452+
shutil.copy(os.path.join(srcpath, file), tmpdir)
453+
datasource = os.path.join(tmpdir, 'shapefile.shp')
454+
455+
ds = osgeo.ogr.Open(datasource)
456+
lyr = ds.GetLayer(0)
457+
original_feature_count = lyr.GetFeatureCount()
458+
lyr.DeleteFeature(2)
459+
ds = None
460+
461+
vl = QgsVectorLayer('{}|layerid=0'.format(datasource), 'test', 'ogr')
462+
463+
self.assertTrue(vl.featureCount(), original_feature_count)
464+
465+
# Edit a feature (attribute change only)
466+
self.assertTrue(vl.startEditing())
467+
self.assertTrue(vl.dataProvider().changeAttributeValues({0: {0: 100}}))
468+
469+
# Commit changes and check no error is emitted
470+
cbk = ErrorReceiver()
471+
vl.dataProvider().raiseError.connect(cbk.receiveError)
472+
self.assertTrue(vl.commitChanges())
473+
self.assertIsNone(cbk.msg)
474+
475+
self.assertTrue(vl.featureCount(), original_feature_count - 1)
476+
477+
vl = None
478+
479+
# Test repacking has been done
480+
ds = osgeo.ogr.Open(datasource)
481+
self.assertTrue(ds.GetLayer(0).GetFeatureCount(), original_feature_count - 1)
482+
ds = None
483+
440484
if __name__ == '__main__':
441485
unittest.main()

0 commit comments

Comments
 (0)