From 35d3cb97d077abb90478f9641349999d9e3cd815 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Mon, 21 Oct 2024 01:01:46 +0200 Subject: [PATCH] GPKG: CreateField(): check we are not reaching the max number of fields --- autotest/ogr/ogr_gpkg.py | 18 ++++++++++++++++++ .../gpkg/ogrgeopackagetablelayer.cpp | 13 +++++++++++++ 2 files changed, 31 insertions(+) diff --git a/autotest/ogr/ogr_gpkg.py b/autotest/ogr/ogr_gpkg.py index 0b0c4dadca8f..84fc7557223d 100755 --- a/autotest/ogr/ogr_gpkg.py +++ b/autotest/ogr/ogr_gpkg.py @@ -10692,3 +10692,21 @@ def test_gpkg_create_duplicate_field_names(tmp_vsimem): ): lyr.CreateField(ogr.FieldDefn("geom")) assert lyr.GetLayerDefn().GetFieldCount() == 1 + + +############################################################################### +# Test creating more than 2000 fields + + +@gdaltest.enable_exceptions() +def test_gpkg_create_more_than_2000_fields(tmp_vsimem): + + filename = str(tmp_vsimem / "test_gpkg_create_more_than_2000_fields.gpkg") + with ogr.GetDriverByName("GPKG").CreateDataSource(filename) as ds: + lyr = ds.CreateLayer("test") + + for i in range(2000 - 2): + lyr.CreateField(ogr.FieldDefn(f"foo{i}")) + with pytest.raises(Exception, match="Limit of 2000 columns reached"): + lyr.CreateField(ogr.FieldDefn("foo")) + assert lyr.GetLayerDefn().GetFieldCount() == 2000 - 2 diff --git a/ogr/ogrsf_frmts/gpkg/ogrgeopackagetablelayer.cpp b/ogr/ogrsf_frmts/gpkg/ogrgeopackagetablelayer.cpp index f970a0d53582..7c147b205995 100644 --- a/ogr/ogrsf_frmts/gpkg/ogrgeopackagetablelayer.cpp +++ b/ogr/ogrsf_frmts/gpkg/ogrgeopackagetablelayer.cpp @@ -1761,6 +1761,19 @@ OGRErr OGRGeoPackageTableLayer::CreateField(const OGRFieldDefn *poField, return OGRERR_FAILURE; } + const int nMaxColumns = + sqlite3_limit(m_poDS->GetDB(), SQLITE_LIMIT_COLUMN, -1); + // + 1 for the FID column + if (m_poFeatureDefn->GetFieldCount() + + m_poFeatureDefn->GetGeomFieldCount() + 1 >= + nMaxColumns) + { + CPLError(CE_Failure, CPLE_AppDefined, + "Cannot add field %s. Limit of %d columns reached", + oFieldDefn.GetNameRef(), nMaxColumns); + return OGRERR_FAILURE; + } + if (!m_bDeferredCreation) { CPLString osCommand;