Skip to content

Commit

Permalink
Merge pull request OSGeo#11680 from elpaso/fix-rollback-crash
Browse files Browse the repository at this point in the history
[GPKG] Fix crash in GPKG rollback after PR OSGeo#11609
  • Loading branch information
rouault authored Jan 17, 2025
2 parents eda0808 + 8e4a70b commit f41af17
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 15 deletions.
3 changes: 2 additions & 1 deletion ogr/ogrsf_frmts/gpkg/ogrgeopackagedatasource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9721,7 +9721,8 @@ OGRErr GDALGeoPackageDataset::RollbackTransaction()
}
}

OGRErr eErr = OGRSQLiteBaseDataSource::RollbackTransaction();
const OGRErr eErr = OGRSQLiteBaseDataSource::RollbackTransaction();

#ifdef ENABLE_GPKG_OGR_CONTENTS
if (!abAddTriggers.empty())
{
Expand Down
52 changes: 48 additions & 4 deletions ogr/ogrsf_frmts/gpkg/ogrgeopackagetablelayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1849,10 +1849,12 @@ OGRErr OGRGeoPackageTableLayer::CreateField(const OGRFieldDefn *poField,
{
m_apoFieldDefnChanges.emplace_back(
std::make_unique<OGRFieldDefn>(oFieldDefn),
m_poFeatureDefn->GetFieldCount() - 1, FieldChangeType::ADD_FIELD);
m_poFeatureDefn->GetFieldCount() - 1, FieldChangeType::ADD_FIELD,
/* bGenerated */ false);
}

m_abGeneratedColumns.resize(m_poFeatureDefn->GetFieldCount());
m_abGeneratedColumns.back() = false; // explicit is better than implicit

if (m_pszFidColumn != nullptr &&
EQUAL(oFieldDefn.GetNameRef(), m_pszFidColumn))
Expand Down Expand Up @@ -2029,7 +2031,8 @@ OGRGeoPackageTableLayer::CreateGeomField(const OGRGeomFieldDefn *poGeomFieldIn,
{
m_apoGeomFieldDefnChanges.emplace_back(
std::make_unique<OGRGeomFieldDefn>(oGeomField),
m_poFeatureDefn->GetGeomFieldCount(), FieldChangeType::ADD_FIELD);
m_poFeatureDefn->GetGeomFieldCount(), FieldChangeType::ADD_FIELD,
/* bGenerated */ false);
}

whileUnsealing(m_poFeatureDefn)->AddGeomFieldDefn(&oGeomField);
Expand Down Expand Up @@ -3811,6 +3814,43 @@ bool OGRGeoPackageTableLayer::DoJobAtTransactionRollback()
SyncToDisk();
m_bDeferredSpatialIndexCreation = bDeferredSpatialIndexCreationBackup;
}

// If we are restoring any deleted field or removing any added one we have to
// rebuild the array of generated fields
for (int i = static_cast<int>(m_apoFieldDefnChanges.size()) - 1; i >= 0;
i--)
{
auto &oFieldChange = m_apoFieldDefnChanges[i];
switch (oFieldChange.eChangeType)
{
case FieldChangeType::ADD_FIELD:
{
CPLAssert(oFieldChange.iField <
static_cast<int>(m_abGeneratedColumns.size()));
m_abGeneratedColumns.erase(m_abGeneratedColumns.begin() +
oFieldChange.iField);
break;
};
case FieldChangeType::DELETE_FIELD:
{
CPLAssert(oFieldChange.iField <=
static_cast<int>(m_abGeneratedColumns.size()));
m_abGeneratedColumns.insert(m_abGeneratedColumns.begin() +
oFieldChange.iField,
oFieldChange.bGenerated);
break;
};
case FieldChangeType::ALTER_FIELD:
{
CPLAssert(oFieldChange.iField <
static_cast<int>(m_abGeneratedColumns.size()));
m_abGeneratedColumns[oFieldChange.iField] =
oFieldChange.bGenerated;
break;
};
}
}

ResetReading();
return true;
}
Expand Down Expand Up @@ -6590,7 +6630,8 @@ OGRErr OGRGeoPackageTableLayer::DeleteField(int iFieldToDelete)
{
m_apoFieldDefnChanges.emplace_back(
std::move(poFieldDefn), iFieldToDelete,
FieldChangeType::DELETE_FIELD);
FieldChangeType::DELETE_FIELD,
m_abGeneratedColumns[iFieldToDelete]);
}
else
{
Expand All @@ -6606,6 +6647,8 @@ OGRErr OGRGeoPackageTableLayer::DeleteField(int iFieldToDelete)
if (eErr == OGRERR_NONE)
{
#if SQLITE_VERSION_NUMBER >= 3035005L
CPLAssert(iFieldToDelete <
static_cast<int>(m_abGeneratedColumns.size()));
m_abGeneratedColumns.erase(m_abGeneratedColumns.begin() +
iFieldToDelete);
#else
Expand Down Expand Up @@ -7098,7 +7141,8 @@ OGRErr OGRGeoPackageTableLayer::AlterFieldDefn(int iFieldToAlter,
{
m_apoFieldDefnChanges.emplace_back(
std::make_unique<OGRFieldDefn>(poFieldDefnToAlter),
iFieldToAlter, FieldChangeType::ALTER_FIELD);
iFieldToAlter, FieldChangeType::ALTER_FIELD,
m_abGeneratedColumns[iFieldToAlter]);
}

auto oTemporaryUnsealer(poFieldDefnToAlter->GetTemporaryUnsealer());
Expand Down
10 changes: 6 additions & 4 deletions ogr/ogrsf_frmts/ogrsf_frmts.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,8 @@ class CPL_DLL OGRLayer : public GDALMajorObject

//! @cond Doxygen_Suppress
// Keep field definitions in sync with transactions
void PrepareStartTransaction();
void FinishRollbackTransaction();
virtual void PrepareStartTransaction();
virtual void FinishRollbackTransaction();
//! @endcond

virtual const char *GetFIDColumn();
Expand Down Expand Up @@ -414,15 +414,17 @@ class CPL_DLL OGRLayer : public GDALMajorObject
{

FieldDefnChange(std::unique_ptr<T> &&poFieldDefnIn, int iFieldIn,
FieldChangeType eChangeTypeIn)
FieldChangeType eChangeTypeIn, bool bGeneratedIn)
: poFieldDefn(std::move(poFieldDefnIn)), iField(iFieldIn),
eChangeType(eChangeTypeIn)
eChangeType(eChangeTypeIn), bGenerated(bGeneratedIn)
{
}

std::unique_ptr<T> poFieldDefn;
int iField;
FieldChangeType eChangeType;
// Used by drivers (GPKG) to track generated fields
bool bGenerated;
};

std::vector<FieldDefnChange<OGRFieldDefn>> m_apoFieldDefnChanges{};
Expand Down
8 changes: 6 additions & 2 deletions ogr/ogrsf_frmts/sqlite/ogrsqlitedatasource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4023,6 +4023,12 @@ OGRErr OGRSQLiteBaseDataSource::StartTransaction(CPL_UNUSED int bForce)
return OGRERR_FAILURE;
}

for (int i = 0; i < GetLayerCount(); i++)
{
OGRLayer *poLayer = GetLayer(i);
poLayer->PrepareStartTransaction();
}

OGRErr eErr = SoftStartTransaction();
if (eErr != OGRERR_NONE)
return eErr;
Expand All @@ -4041,8 +4047,6 @@ OGRErr OGRSQLiteDataSource::StartTransaction(int bForce)
cpl::down_cast<OGRSQLiteTableLayer *>(poLayer.get());
poTableLayer->RunDeferredCreationIfNecessary();
}

poLayer->PrepareStartTransaction();
}

return OGRSQLiteBaseDataSource::StartTransaction(bForce);
Expand Down
10 changes: 6 additions & 4 deletions ogr/ogrsf_frmts/sqlite/ogrsqlitetablelayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1617,7 +1617,8 @@ OGRErr OGRSQLiteTableLayer::CreateField(const OGRFieldDefn *poFieldIn,
{
m_apoFieldDefnChanges.emplace_back(
std::make_unique<OGRFieldDefn>(oField),
m_poFeatureDefn->GetFieldCount() - 1, FieldChangeType::ADD_FIELD);
m_poFeatureDefn->GetFieldCount() - 1, FieldChangeType::ADD_FIELD,
/* bGenerated */ false);
}

if (m_pszFIDColumn != nullptr && EQUAL(oField.GetNameRef(), m_pszFIDColumn))
Expand Down Expand Up @@ -1723,7 +1724,8 @@ OGRSQLiteTableLayer::CreateGeomField(const OGRGeomFieldDefn *poGeomFieldIn,
{
m_apoGeomFieldDefnChanges.emplace_back(
std::make_unique<OGRGeomFieldDefn>(*poGeomField),
m_poFeatureDefn->GetGeomFieldCount(), FieldChangeType::ADD_FIELD);
m_poFeatureDefn->GetGeomFieldCount(), FieldChangeType::ADD_FIELD,
/* bGenerated */ false);
}

m_poFeatureDefn->AddGeomFieldDefn(std::move(poGeomField));
Expand Down Expand Up @@ -2177,7 +2179,7 @@ OGRErr OGRSQLiteTableLayer::DeleteField(int iFieldToDelete)
{
m_apoFieldDefnChanges.emplace_back(
std::move(poFieldDefn), iFieldToDelete,
FieldChangeType::DELETE_FIELD);
FieldChangeType::DELETE_FIELD, false);
}
else
{
Expand Down Expand Up @@ -2414,7 +2416,7 @@ OGRErr OGRSQLiteTableLayer::AlterFieldDefn(int iFieldToAlter,
{
m_apoFieldDefnChanges.emplace_back(
std::make_unique<OGRFieldDefn>(poFieldDefn), iFieldToAlter,
FieldChangeType::ALTER_FIELD);
FieldChangeType::ALTER_FIELD, /* bGenerated */ false);
}

if (nActualFlags & ALTER_TYPE_FLAG)
Expand Down

0 comments on commit f41af17

Please sign in to comment.