Skip to content

Commit

Permalink
Merge pull request #39283 from elpaso/bugfix-gh39265-transactions-cra…
Browse files Browse the repository at this point in the history
…sh-on-save

Don't crash on transaction save
  • Loading branch information
elpaso committed Oct 12, 2020
2 parents 1d2bb41 + ea90774 commit 498bbbb
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 8 deletions.
32 changes: 25 additions & 7 deletions src/core/qgstransactiongroup.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "qgsvectorlayer.h" #include "qgsvectorlayer.h"
#include "qgsdatasourceuri.h" #include "qgsdatasourceuri.h"
#include "qgsvectordataprovider.h" #include "qgsvectordataprovider.h"
#include "qgslogger.h"


#include <QTimer> #include <QTimer>


Expand Down Expand Up @@ -102,25 +103,37 @@ void QgsTransactionGroup::onBeforeCommitChanges( bool stopEditing )


mEditingStopping = true; mEditingStopping = true;


QgsVectorLayer *triggeringLayer = qobject_cast<QgsVectorLayer *>( sender() ); const QgsVectorLayer *triggeringLayer = qobject_cast<QgsVectorLayer *>( sender() );


QString errMsg; QString errMsg;
if ( mTransaction->commit( errMsg ) ) if ( mTransaction->commit( errMsg ) )
{ {
const auto constMLayers = mLayers; const auto constMLayers = mLayers;
for ( QgsVectorLayer *layer : constMLayers ) for ( QgsVectorLayer *layer : constMLayers )
{ {
if ( layer != sender() ) if ( layer != triggeringLayer )
{
layer->commitChanges( stopEditing ); layer->commitChanges( stopEditing );
}
}

if ( stopEditing )
{
disableTransaction();
}
else
{
if ( ! mTransaction->begin( errMsg ) )
{
QgsDebugMsg( QStringLiteral( "Could not restart a transaction for %1: %2" ).arg( triggeringLayer->name() ).arg( errMsg ) );
}
} }


disableTransaction();
} }
else else
{ {
emit commitError( errMsg ); emit commitError( errMsg );
// Restart editing the calling layer in the next event loop cycle restartTransaction( triggeringLayer );
QTimer::singleShot( 0, triggeringLayer, &QgsVectorLayer::startEditing );
} }
mEditingStopping = false; mEditingStopping = false;
} }
Expand All @@ -147,8 +160,7 @@ void QgsTransactionGroup::onRollback()
} }
else else
{ {
// Restart editing the calling layer in the next event loop cycle restartTransaction( triggeringLayer );
QTimer::singleShot( 0, triggeringLayer, &QgsVectorLayer::startEditing );
} }
mEditingStopping = false; mEditingStopping = false;
} }
Expand All @@ -165,6 +177,12 @@ void QgsTransactionGroup::disableTransaction()
} }
} }


void QgsTransactionGroup::restartTransaction( const QgsVectorLayer *layer )
{
// Restart editing the calling layer in the next event loop cycle
QTimer::singleShot( 0, layer, &QgsVectorLayer::startEditing );
}

QString QgsTransactionGroup::providerKey() const QString QgsTransactionGroup::providerKey() const
{ {
return mProviderKey; return mProviderKey;
Expand Down
2 changes: 2 additions & 0 deletions src/core/qgstransactiongroup.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ class CORE_EXPORT QgsTransactionGroup : public QObject


void disableTransaction(); void disableTransaction();


void restartTransaction( const QgsVectorLayer *layer );

QSet<QgsVectorLayer *> mLayers; QSet<QgsVectorLayer *> mLayers;
//! Only set while a transaction is active //! Only set while a transaction is active
std::unique_ptr<QgsTransaction> mTransaction; std::unique_ptr<QgsTransaction> mTransaction;
Expand Down
38 changes: 37 additions & 1 deletion tests/src/python/test_provider_ogr_gpkg.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -1728,7 +1728,7 @@ def testExporterWithFIDColumn(self):
self.assertEqual(f.id(), 123) self.assertEqual(f.id(), 123)


def testTransactionGroup(self): def testTransactionGroup(self):
"""Issue https://github.com/qgis/QGIS/issues/36525""" """Test issue GH #36525"""


project = QgsProject() project = QgsProject()
project.setAutoTransaction(True) project.setAutoTransaction(True)
Expand Down Expand Up @@ -1800,6 +1800,42 @@ def testTransactionGroupIterator(self):
# Test that QGIS sees the new changes # Test that QGIS sees the new changes
self.assertEqual(next(vl.getFeatures()).attribute(1), 'new value') self.assertEqual(next(vl.getFeatures()).attribute(1), 'new value')


def testTransactionGroupCrash(self):
"""Test issue GH #39265 segfault"""

project = QgsProject()
project.setAutoTransaction(True)
tmpfile = os.path.join(
self.basetestpath, 'tempGeoPackageTransactionCrash.gpkg')
ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString))

f = ogr.Feature(lyr.GetLayerDefn())
f.SetGeometry(ogr.CreateGeometryFromWkt('POINT (1 1)'))
f.SetField('str_field', 'one')
lyr.CreateFeature(f)

del lyr
del ds

vl = QgsVectorLayer(tmpfile + '|layername=test', 'test', 'ogr')

project.addMapLayers([vl])

feature = next(vl.getFeatures())
feature.setAttributes([None, 'two'])

self.assertTrue(vl.startEditing())
self.assertTrue(vl.addFeature(feature))

# Save without leaving editing
self.assertTrue(vl.commitChanges(False))

# Now add another one
feature.setAttributes([None, 'three'])
self.assertTrue(vl.addFeature(feature))



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

0 comments on commit 498bbbb

Please sign in to comment.