Skip to content

Commit b6585ff

Browse files
authoredApr 3, 2025
Merge pull request OSGeo#12049 from rouault/gpkg_modernize
GPKG: more vector and unique_ptr use
2 parents 2d0cc3c + 39969fd commit b6585ff

File tree

9 files changed

+248
-246
lines changed

9 files changed

+248
-246
lines changed
 

Diff for: ‎autotest/gdrivers/gpkg.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -2863,7 +2863,7 @@ def test_gpkg_39():
28632863
ds.ReleaseResultSet(sql_lyr)
28642864
sql_lyr = ds.ExecuteSQL("PRAGMA user_version")
28652865
f = sql_lyr.GetNextFeature()
2866-
if f["user_version"] != 10200:
2866+
if f["user_version"] != 10400:
28672867
f.DumpReadable()
28682868
pytest.fail()
28692869
ds.ReleaseResultSet(sql_lyr)
@@ -3389,7 +3389,7 @@ def test_gpkg_40():
33893389
ds.ReleaseResultSet(sql_lyr)
33903390
sql_lyr = ds.ExecuteSQL("PRAGMA user_version")
33913391
f = sql_lyr.GetNextFeature()
3392-
if f["user_version"] != 10200:
3392+
if f["user_version"] != 10400:
33933393
f.DumpReadable()
33943394
pytest.fail()
33953395
ds.ReleaseResultSet(sql_lyr)
@@ -3778,11 +3778,12 @@ def test_gpkg_match_overview_factor():
37783778
###############################################################################
37793779

37803780

3781-
def test_gpkg_wkt2():
3781+
@pytest.mark.parametrize("version", ["1.2", "1.4"])
3782+
def test_gpkg_wkt2(version):
37823783

37833784
# WKT2-only compatible SRS with EPSG code
37843785
filename = "/vsimem/test_gpkg_wkt2.gpkg"
3785-
ds = gdaltest.gpkg_dr.Create(filename, 1, 1)
3786+
ds = gdaltest.gpkg_dr.Create(filename, 1, 1, options=["VERSION=" + version])
37863787
sr = osr.SpatialReference()
37873788
sr.ImportFromEPSG(4979) # WGS 84 3D
37883789
sr.SetAxisMappingStrategy(osr.OAMS_TRADITIONAL_GIS_ORDER)
@@ -3825,7 +3826,7 @@ def test_gpkg_wkt2():
38253826
lyr = ds.ExecuteSQL(
38263827
"SELECT * FROM gpkg_extensions WHERE extension_name = 'gpkg_crs_wkt'"
38273828
)
3828-
assert lyr.GetFeatureCount() == 1
3829+
assert lyr.GetFeatureCount() == (1 if version == "1.2" else 0)
38293830
ds.ReleaseResultSet(lyr)
38303831

38313832
ds = None

Diff for: ‎autotest/ogr/data/gpkg/poly_golden_gpkg_1_4.gpkg

104 KB
Binary file not shown.

Diff for: ‎autotest/ogr/ogr_gpkg.py

+80-14
Original file line numberDiff line numberDiff line change
@@ -309,14 +309,14 @@ def test_ogr_gpkg_1(gpkg_ds, tmp_path):
309309

310310
def test_ogr_gpkg_2(gpkg_ds):
311311

312-
# Should default to GPKG 1.2
312+
# Should default to GPKG 1.4
313313
with gpkg_ds.ExecuteSQL("PRAGMA application_id") as sql_lyr:
314314
f = sql_lyr.GetNextFeature()
315315
assert f["application_id"] == 1196444487
316316

317317
with gpkg_ds.ExecuteSQL("PRAGMA user_version") as sql_lyr:
318318
f = sql_lyr.GetNextFeature()
319-
assert f["user_version"] == 10200
319+
assert f["user_version"] == 10400
320320

321321

322322
###############################################################################
@@ -4758,6 +4758,30 @@ def test_ogr_gpkg_47c(tmp_vsimem):
47584758
assert gdal.GetLastErrorMsg() == ""
47594759

47604760

4761+
def test_ogr_gpkg_47c2(tmp_vsimem):
4762+
4763+
dbname = tmp_vsimem / "ogr_gpkg_47.gpkg"
4764+
4765+
# Set GPKG 1.4.0
4766+
gdaltest.gpkg_dr.CreateDataSource(dbname, options={"VERSION": "1.4"})
4767+
# Check user_version
4768+
fp = gdal.VSIFOpenL(dbname, "rb")
4769+
gdal.VSIFSeekL(fp, 60, 0)
4770+
assert struct.unpack(">I", gdal.VSIFReadL(4, 1, fp))[0] == 10400
4771+
gdal.VSIFCloseL(fp)
4772+
4773+
gdal.ErrorReset()
4774+
ds = ogr.Open(dbname, update=1)
4775+
assert ds is not None
4776+
assert gdal.GetLastErrorMsg() == ""
4777+
ds = None
4778+
4779+
gdal.ErrorReset()
4780+
with gdal.config_option("GPKG_WARN_UNRECOGNIZED_APPLICATION_ID", "NO"):
4781+
ogr.Open(dbname)
4782+
assert gdal.GetLastErrorMsg() == ""
4783+
4784+
47614785
def test_ogr_gpkg_47d(tmp_vsimem):
47624786

47634787
dbname = tmp_vsimem / "ogr_gpkg_47.gpkg"
@@ -5897,7 +5921,9 @@ def test_ogr_gpkg_prelude_statements_after_spatialite_loading(tmp_vsimem):
58975921
def test_ogr_gpkg_datetime_timezones(tmp_vsimem):
58985922

58995923
filename = tmp_vsimem / "test_ogr_gpkg_datetime_timezones.gpkg"
5900-
ds = gdaltest.gpkg_dr.CreateDataSource(filename, options=["DATETIME_FORMAT=UTC"])
5924+
ds = gdaltest.gpkg_dr.CreateDataSource(
5925+
filename, options=["DATETIME_FORMAT=UTC", "VERSION=1.2"]
5926+
)
59015927
lyr = ds.CreateLayer("test")
59025928
lyr.CreateField(ogr.FieldDefn("dt", ogr.OFTDateTime))
59035929
for val in [
@@ -5926,6 +5952,44 @@ def test_ogr_gpkg_datetime_timezones(tmp_vsimem):
59265952
ds = None
59275953

59285954

5955+
###############################################################################
5956+
# Test DATETIME_FORMAT
5957+
5958+
5959+
def test_ogr_gpkg_datetime_timezones_gpkg_1_4(tmp_vsimem):
5960+
5961+
filename = tmp_vsimem / "test_ogr_gpkg_datetime_timezones.gpkg"
5962+
ds = gdaltest.gpkg_dr.CreateDataSource(
5963+
filename, options=["DATETIME_FORMAT=UTC", "VERSION=1.4"]
5964+
)
5965+
lyr = ds.CreateLayer("test")
5966+
lyr.CreateField(ogr.FieldDefn("dt", ogr.OFTDateTime))
5967+
for val in [
5968+
"2020/01/01 01:34:56",
5969+
"2020/01/01 01:34:56+00",
5970+
"2020/01/01 01:34:56.789+02",
5971+
]:
5972+
f = ogr.Feature(lyr.GetLayerDefn())
5973+
f.SetField("dt", val)
5974+
lyr.CreateFeature(f)
5975+
ds = None
5976+
5977+
ds = ogr.Open(filename)
5978+
lyr = ds.GetLayer(0)
5979+
f = lyr.GetNextFeature()
5980+
assert f.GetField("dt") == "2020/01/01 01:34:56+00"
5981+
f = lyr.GetNextFeature()
5982+
assert f.GetField("dt") == "2020/01/01 01:34:56+00"
5983+
f = lyr.GetNextFeature()
5984+
assert f.GetField("dt") == "2019/12/31 23:34:56.789+00"
5985+
5986+
with ds.ExecuteSQL("SELECT dt || '' FROM test") as sql_lyr:
5987+
f = sql_lyr.GetNextFeature()
5988+
# check that milliseconds are not written, since it is not required since GPKG 1.4
5989+
assert f.GetField(0) == "2020-01-01T01:34:56Z"
5990+
ds = None
5991+
5992+
59295993
###############################################################################
59305994
# Test AbortSQL
59315995

@@ -10825,17 +10889,19 @@ def test_gpkg_secure_delete(tmp_vsimem):
1082510889

1082610890

1082710891
@pytest.mark.parametrize(
10828-
"src_filename",
10892+
"src_filename,options",
1082910893
[
10830-
# Generated with: ogr2ogr autotest/ogr/data/gpkg/poly_golden.gpkg autotest/ogr/data/poly.shp --config OGR_CURRENT_DATE="2000-01-01T:00:00:00.000Z" -nomd
10831-
"data/gpkg/poly_golden.gpkg",
10894+
# Generated with: ogr2ogr autotest/ogr/data/gpkg/poly_golden.gpkg autotest/ogr/data/poly.shp --config OGR_CURRENT_DATE="2000-01-01T:00:00:00.000Z" -nomd -dsco VERSION=1.2
10895+
("data/gpkg/poly_golden.gpkg", ["VERSION=1.2"]),
10896+
# Generated with: ogr2ogr autotest/ogr/data/gpkg/poly_golden_gpkg_1_4.gpkg autotest/ogr/data/poly.shp --config OGR_CURRENT_DATE="2000-01-01T:00:00:00.000Z" -nomd -dsco VERSION=1.4
10897+
("data/gpkg/poly_golden_gpkg_1_4.gpkg", ["VERSION=1.4"]),
1083210898
],
1083310899
)
10834-
def test_ogr_gpkg_write_check_golden_file(tmp_path, src_filename):
10900+
def test_ogr_gpkg_write_check_golden_file(tmp_path, src_filename, options):
1083510901

1083610902
out_filename = str(tmp_path / "test.gpkg")
1083710903
with gdal.config_option("OGR_CURRENT_DATE", "2000-01-01T:00:00:00.000Z"):
10838-
gdal.VectorTranslate(out_filename, src_filename)
10904+
gdal.VectorTranslate(out_filename, src_filename, datasetCreationOptions=options)
1083910905

1084010906
# Compare first sqlite3 dump if sqlite3 binary available
1084110907
import subprocess
@@ -10902,8 +10968,8 @@ def test_ogr_gpkg_arrow_stream_numpy_datetime_as_string(tmp_vsimem):
1090210968
assert len(batch["datetime"]) == 4
1090310969
assert batch["datetime"][0] == b""
1090410970
assert batch["datetime"][1] == b"2022-05-31T12:34:56.789Z"
10905-
assert batch["datetime"][2] == b"2022-05-31T12:34:56.000"
10906-
assert batch["datetime"][3] == b"2022-05-31T12:34:56.000+12:30"
10971+
assert batch["datetime"][2] == b"2022-05-31T12:34:56"
10972+
assert batch["datetime"][3] == b"2022-05-31T12:34:56+12:30"
1090710973

1090810974
# Setting a filer tests the use of the less optimized
1090910975
# OGRGeoPackageTableLayer::GetNextArray() implementation
@@ -10918,8 +10984,8 @@ def test_ogr_gpkg_arrow_stream_numpy_datetime_as_string(tmp_vsimem):
1091810984
assert len(batch["datetime"]) == 4
1091910985
assert batch["datetime"][0] == b""
1092010986
assert batch["datetime"][1] == b"2022-05-31T12:34:56.789Z"
10921-
assert batch["datetime"][2] == b"2022-05-31T12:34:56.000"
10922-
assert batch["datetime"][3] == b"2022-05-31T12:34:56.000+12:30"
10987+
assert batch["datetime"][2] == b"2022-05-31T12:34:56"
10988+
assert batch["datetime"][3] == b"2022-05-31T12:34:56+12:30"
1092310989

1092410990
with ds.ExecuteSQL("SELECT * FROM test") as sql_lyr:
1092510991
stream = sql_lyr.GetArrowStreamAsNumPy(
@@ -10931,8 +10997,8 @@ def test_ogr_gpkg_arrow_stream_numpy_datetime_as_string(tmp_vsimem):
1093110997
assert len(batch["datetime"]) == 4
1093210998
assert batch["datetime"][0] == b""
1093310999
assert batch["datetime"][1] == b"2022-05-31T12:34:56.789Z"
10934-
assert batch["datetime"][2] == b"2022-05-31T12:34:56.000"
10935-
assert batch["datetime"][3] == b"2022-05-31T12:34:56.000+12:30"
11000+
assert batch["datetime"][2] == b"2022-05-31T12:34:56"
11001+
assert batch["datetime"][3] == b"2022-05-31T12:34:56+12:30"
1093611002

1093711003

1093811004
###############################################################################

Diff for: ‎doc/source/drivers/raster/gpkg.rst

+3-2
Original file line numberDiff line numberDiff line change
@@ -573,13 +573,14 @@ The following creation options are available:
573573
when AREA_OR_POINT metadata item is not set.
574574

575575
- .. co:: VERSION
576-
:choices: AUTO, 1.0, 1.1, 1.2, 1.3
576+
:choices: AUTO, 1.0, 1.1, 1.2, 1.3, 1.4
577577
:since: 2.2
578578

579579
Set GeoPackage version
580580
(for application_id and user_version fields). In AUTO mode, this will
581-
be equivalent to 1.2 starting with GDAL 2.3.
581+
be equivalent to 1.4 starting with GDAL 3.11 (1.2 in prior versions)
582582
1.3 is available starting with GDAL 3.3
583+
1.4 is available starting with GDAL 3.7.1
583584

584585
- .. co:: ADD_GPKG_OGR_CONTENTS
585586
:choices: YES, NO

Diff for: ‎doc/source/drivers/vector/gpkg.rst

+5-8
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,9 @@ Driver capabilities
4444
Specification version
4545
---------------------
4646

47-
Starting with GDAL 2.2, the driver is able to create GeoPackage
48-
databases following the 1.0/1.0.1, 1.1 or 1.2 versions. For GDAL 2.2, it
49-
will automatically adjust to the minimum version required for the
50-
features of GeoPackage used. For GDAL 2.3 or later, it will default to
51-
1.2. Explicit version choice can be done by specifying the VERSION
52-
dataset creation option.
47+
GeoPackage version 1.0, 1.1, 1.2, 1.3 or 1.4 can be specified through the
48+
VERSION dataset creation option. Starting with GDAL 3.11, it defaults to 1.4.
49+
For earlier versions, it defaults to 1.2.
5350

5451
Limitations
5552
-----------
@@ -281,11 +278,11 @@ raster) are available:
281278

282279
- .. dsco:: VERSION
283280
:choices: AUTO, 1.0, 1.1, 1.2, 1.3, 1.4
284-
:Since: 2.2
281+
:since: 2.2
285282

286283
Set GeoPackage version
287284
(for application_id and user_version fields). In AUTO mode, this will
288-
be equivalent to 1.2 starting with GDAL 2.3.
285+
be equivalent to 1.4 starting with GDAL 3.11 (1.2 in prior versions)
289286
1.3 is available starting with GDAL 3.3
290287
1.4 is available starting with GDAL 3.7.1
291288

Diff for: ‎ogr/ogrsf_frmts/gpkg/gdalgeopackagerasterband.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -3669,7 +3669,7 @@ int GDALGeoPackageRasterBand::GetOverviewCount()
36693669
{
36703670
GDALGeoPackageDataset *poGDS =
36713671
cpl::down_cast<GDALGeoPackageDataset *>(poDS);
3672-
return poGDS->m_nOverviewCount;
3672+
return static_cast<int>(poGDS->m_apoOverviewDS.size());
36733673
}
36743674

36753675
/************************************************************************/
@@ -3680,9 +3680,9 @@ GDALRasterBand *GDALGeoPackageRasterBand::GetOverview(int nIdx)
36803680
{
36813681
GDALGeoPackageDataset *poGDS =
36823682
reinterpret_cast<GDALGeoPackageDataset *>(poDS);
3683-
if (nIdx < 0 || nIdx >= poGDS->m_nOverviewCount)
3683+
if (nIdx < 0 || nIdx >= static_cast<int>(poGDS->m_apoOverviewDS.size()))
36843684
return nullptr;
3685-
return poGDS->m_papoOverviewDS[nIdx]->GetRasterBand(nBand);
3685+
return poGDS->m_apoOverviewDS[nIdx]->GetRasterBand(nBand);
36863686
}
36873687

36883688
/************************************************************************/

Diff for: ‎ogr/ogrsf_frmts/gpkg/ogr_geopackage.h

+8-9
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "ogr_p.h"
2323
#include "ogr_wkb.h"
2424

25+
#include <array>
2526
#include <condition_variable>
2627
#include <limits>
2728
#include <mutex>
@@ -128,9 +129,8 @@ class GDALGeoPackageDataset final : public OGRSQLiteBaseDataSource,
128129
std::string m_osFilenameInZip{};
129130
void *m_pSQLFunctionData = nullptr;
130131
GUInt32 m_nApplicationId = GPKG_APPLICATION_ID;
131-
GUInt32 m_nUserVersion = GPKG_1_2_VERSION;
132-
OGRGeoPackageTableLayer **m_papoLayers = nullptr;
133-
int m_nLayers = 0;
132+
GUInt32 m_nUserVersion = GPKG_1_4_VERSION;
133+
std::vector<std::unique_ptr<OGRGeoPackageTableLayer>> m_apoLayers{};
134134
void CheckUnknownExtensions(bool bCheckRasterTable = false);
135135
#ifdef ENABLE_GPKG_OGR_CONTENTS
136136
bool m_bHasGPKGOGRContents = false;
@@ -157,7 +157,7 @@ class GDALGeoPackageDataset final : public OGRSQLiteBaseDataSource,
157157
OGRSpatialReference m_oSRS{};
158158
bool m_bRecordInsertedInGPKGContent = false;
159159
bool m_bGeoTransformValid = false;
160-
double m_adfGeoTransform[6];
160+
std::array<double, 6> m_adfGeoTransform = {0, 0, 0, 0, 0, 0};
161161
int m_nSRID = -1; // Unknown Cartesain
162162
double m_dfTMSMinX = 0.0;
163163
double m_dfTMSMaxY = 0.0;
@@ -173,8 +173,7 @@ class GDALGeoPackageDataset final : public OGRSQLiteBaseDataSource,
173173
OGRWKBTransformCache m_oWKBTransformCache{};
174174
std::vector<GByte> m_abyWKBTransformCache{};
175175

176-
int m_nOverviewCount = 0;
177-
GDALGeoPackageDataset **m_papoOverviewDS = nullptr;
176+
std::vector<std::unique_ptr<GDALGeoPackageDataset>> m_apoOverviewDS{};
178177
bool m_bZoomOther = false;
179178

180179
bool m_bInFlushCache = false;
@@ -293,7 +292,7 @@ class GDALGeoPackageDataset final : public OGRSQLiteBaseDataSource,
293292
CPL_DISALLOW_COPY_ASSIGN(GDALGeoPackageDataset)
294293

295294
public:
296-
GDALGeoPackageDataset();
295+
GDALGeoPackageDataset() = default;
297296
virtual ~GDALGeoPackageDataset();
298297

299298
char **GetFileList(void) override;
@@ -320,7 +319,7 @@ class GDALGeoPackageDataset final : public OGRSQLiteBaseDataSource,
320319

321320
virtual int GetLayerCount() override
322321
{
323-
return m_nLayers;
322+
return static_cast<int>(m_apoLayers.size());
324323
}
325324

326325
int Open(GDALOpenInfo *poOpenInfo, const std::string &osFilenameInZip);
@@ -670,7 +669,7 @@ class OGRGeoPackageTableLayer final : public OGRGeoPackageLayer
670669
int m_nZFlag = 0;
671670
int m_nMFlag = 0;
672671
OGRGeomCoordinateBinaryPrecision m_sBinaryPrecision{};
673-
OGREnvelope *m_poExtent = nullptr;
672+
std::unique_ptr<OGREnvelope> m_poExtent{};
674673
#ifdef ENABLE_GPKG_OGR_CONTENTS
675674
GIntBig m_nTotalFeatureCount = -1;
676675
bool m_bOGRFeatureCountTriggersEnabled = false;

0 commit comments

Comments
 (0)
Failed to load comments.