Coverage Report

Created: 2026-02-14 09:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrsf_frmts/gpkg/ogrgeopackagelayer.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  GeoPackage Translator
4
 * Purpose:  Implements OGRGeoPackageLayer class
5
 * Author:   Paul Ramsey <pramsey@boundlessgeo.com>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2013, Paul Ramsey <pramsey@boundlessgeo.com>
9
 * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "ogr_geopackage.h"
15
#include "ogrgeopackageutility.h"
16
#include "ogrsqliteutility.h"
17
#include "ogr_p.h"
18
#include "ogr_recordbatch.h"
19
#include "ograrrowarrayhelper.h"
20
#include "ogrlayerarrow.h"
21
22
/************************************************************************/
23
/*                         OGRGeoPackageLayer()                         */
24
/************************************************************************/
25
26
OGRGeoPackageLayer::OGRGeoPackageLayer(GDALGeoPackageDataset *poDS)
27
4.63k
    : m_poDS(poDS)
28
4.63k
{
29
4.63k
}
30
31
/************************************************************************/
32
/*                        ~OGRGeoPackageLayer()                         */
33
/************************************************************************/
34
35
OGRGeoPackageLayer::~OGRGeoPackageLayer()
36
4.63k
{
37
38
4.63k
    CPLFree(m_pszFidColumn);
39
40
4.63k
    if (m_poQueryStatement)
41
16
        sqlite3_finalize(m_poQueryStatement);
42
43
4.63k
    if (m_poFeatureDefn)
44
4.63k
        m_poFeatureDefn->Release();
45
4.63k
}
46
47
/************************************************************************/
48
/*                            ResetReading()                            */
49
/************************************************************************/
50
51
void OGRGeoPackageLayer::ResetReading()
52
53
5.04k
{
54
5.04k
    ClearStatement();
55
5.04k
    m_iNextShapeId = 0;
56
5.04k
    m_bEOF = false;
57
5.04k
}
58
59
/************************************************************************/
60
/*                           ClearStatement()                           */
61
/************************************************************************/
62
63
void OGRGeoPackageLayer::ClearStatement()
64
65
8.23k
{
66
8.23k
    if (m_poQueryStatement != nullptr)
67
1.42k
    {
68
1.42k
        CPLDebug("GPKG", "finalize %p", m_poQueryStatement);
69
1.42k
        sqlite3_finalize(m_poQueryStatement);
70
1.42k
        m_poQueryStatement = nullptr;
71
1.42k
    }
72
8.23k
}
73
74
/************************************************************************/
75
/*                           GetNextFeature()                           */
76
/************************************************************************/
77
78
OGRFeature *OGRGeoPackageLayer::GetNextFeature()
79
80
45.5k
{
81
45.5k
    if (m_bEOF)
82
0
        return nullptr;
83
84
45.5k
    if (m_poQueryStatement == nullptr)
85
1.76k
    {
86
1.76k
        ResetStatement();
87
1.76k
        if (m_poQueryStatement == nullptr)
88
327
            return nullptr;
89
1.76k
    }
90
91
45.2k
    for (; true;)
92
45.2k
    {
93
        /* --------------------------------------------------------------------
94
         */
95
        /*      Fetch a record (unless otherwise instructed) */
96
        /* --------------------------------------------------------------------
97
         */
98
45.2k
        if (m_bDoStep)
99
45.2k
        {
100
45.2k
            int rc = sqlite3_step(m_poQueryStatement);
101
45.2k
            if (rc != SQLITE_ROW)
102
1.42k
            {
103
1.42k
                if (rc != SQLITE_DONE)
104
4
                {
105
4
                    sqlite3_reset(m_poQueryStatement);
106
4
                    CPLError(CE_Failure, CPLE_AppDefined,
107
4
                             "In GetNextRawFeature(): sqlite3_step() : %s",
108
4
                             sqlite3_errmsg(m_poDS->GetDB()));
109
4
                }
110
111
1.42k
                ClearStatement();
112
1.42k
                m_bEOF = true;
113
114
1.42k
                return nullptr;
115
1.42k
            }
116
45.2k
        }
117
0
        else
118
0
        {
119
0
            m_bDoStep = true;
120
0
        }
121
122
43.8k
        OGRFeature *poFeature = TranslateFeature(m_poQueryStatement);
123
124
43.8k
        if ((m_poFilterGeom == nullptr ||
125
0
             FilterGeometry(poFeature->GetGeomFieldRef(m_iGeomFieldFilter))) &&
126
43.8k
            (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature)))
127
43.8k
            return poFeature;
128
129
0
        delete poFeature;
130
0
    }
131
45.2k
}
132
133
/************************************************************************/
134
/*                           ParseDateField()                           */
135
/************************************************************************/
136
137
bool OGRGeoPackageLayer::ParseDateField(sqlite3_stmt *hStmt, int iRawField,
138
                                        int nSqlite3ColType, OGRField *psField,
139
                                        const OGRFieldDefn *poFieldDefn,
140
                                        GIntBig nFID)
141
0
{
142
0
    if (nSqlite3ColType == SQLITE_TEXT)
143
0
    {
144
0
        const char *pszTxt = reinterpret_cast<const char *>(
145
0
            sqlite3_column_text(hStmt, iRawField));
146
0
        return ParseDateField(pszTxt, psField, poFieldDefn, nFID);
147
0
    }
148
0
    else
149
0
    {
150
0
        constexpr int line = __LINE__;
151
0
        if (!m_poDS->m_oSetGPKGLayerWarnings[line])
152
0
        {
153
0
            CPLError(CE_Warning, CPLE_AppDefined,
154
0
                     "Unexpected data type for record " CPL_FRMT_GIB
155
0
                     " in column %s",
156
0
                     nFID, poFieldDefn->GetNameRef());
157
0
            m_poDS->m_oSetGPKGLayerWarnings[line] = true;
158
0
        }
159
0
        return false;
160
0
    }
161
0
}
162
163
bool OGRGeoPackageLayer::ParseDateField(const char *pszTxt, OGRField *psField,
164
                                        const OGRFieldDefn *poFieldDefn,
165
                                        GIntBig nFID)
166
0
{
167
0
    if (pszTxt == nullptr)
168
0
    {
169
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s",
170
0
                 sqlite3_errmsg(m_poDS->GetDB()));
171
0
        return false;
172
0
    }
173
0
    const size_t nLen = strlen(pszTxt);
174
    // nominal format: "YYYY-MM-DD" (10 characters)
175
0
    const bool bNominalFormat =
176
0
        (nLen == 10 && pszTxt[4] == '-' && pszTxt[7] == '-' &&
177
0
         static_cast<unsigned>(pszTxt[0] - '0') <= 9 &&
178
0
         static_cast<unsigned>(pszTxt[1] - '0') <= 9 &&
179
0
         static_cast<unsigned>(pszTxt[2] - '0') <= 9 &&
180
0
         static_cast<unsigned>(pszTxt[3] - '0') <= 9 &&
181
0
         static_cast<unsigned>(pszTxt[5] - '0') <= 9 &&
182
0
         static_cast<unsigned>(pszTxt[6] - '0') <= 9 &&
183
0
         static_cast<unsigned>(pszTxt[8] - '0') <= 9 &&
184
0
         static_cast<unsigned>(pszTxt[9] - '0') <= 9);
185
186
0
    bool bError = false;
187
0
    if (bNominalFormat)
188
0
    {
189
0
        psField->Date.Year = static_cast<GUInt16>(
190
0
            ((((pszTxt[0] - '0') * 10 + (pszTxt[1] - '0')) * 10) +
191
0
             (pszTxt[2] - '0')) *
192
0
                10 +
193
0
            (pszTxt[3] - '0'));
194
0
        psField->Date.Month =
195
0
            static_cast<GByte>((pszTxt[5] - '0') * 10 + (pszTxt[6] - '0'));
196
0
        psField->Date.Day =
197
0
            static_cast<GByte>((pszTxt[8] - '0') * 10 + (pszTxt[9] - '0'));
198
0
        psField->Date.Hour = 0;
199
0
        psField->Date.Minute = 0;
200
0
        psField->Date.Second = 0.0f;
201
0
        psField->Date.TZFlag = 0;
202
0
        if (psField->Date.Month == 0 || psField->Date.Month > 12 ||
203
0
            psField->Date.Day == 0 || psField->Date.Day > 31)
204
0
        {
205
0
            bError = true;
206
0
        }
207
0
    }
208
0
    else if (OGRParseDate(pszTxt, psField, OGRPARSEDATE_OPTION_LAX))
209
0
    {
210
0
        constexpr int line = __LINE__;
211
0
        if (!m_poDS->m_oSetGPKGLayerWarnings[line])
212
0
        {
213
0
            CPLError(CE_Warning, CPLE_AppDefined,
214
0
                     "Non-conformant content for record " CPL_FRMT_GIB
215
0
                     " in column %s, %s, "
216
0
                     "successfully parsed",
217
0
                     nFID, poFieldDefn->GetNameRef(), pszTxt);
218
0
            m_poDS->m_oSetGPKGLayerWarnings[line] = true;
219
0
        }
220
0
    }
221
0
    else
222
0
    {
223
0
        bError = true;
224
0
    }
225
226
0
    if (bError)
227
0
    {
228
0
        OGR_RawField_SetUnset(psField);
229
0
        constexpr int line = __LINE__;
230
0
        if (!m_poDS->m_oSetGPKGLayerWarnings[line])
231
0
        {
232
0
            CPLError(CE_Warning, CPLE_AppDefined,
233
0
                     "Invalid content for record " CPL_FRMT_GIB
234
0
                     " in column %s: %s",
235
0
                     nFID, poFieldDefn->GetNameRef(), pszTxt);
236
0
            m_poDS->m_oSetGPKGLayerWarnings[line] = true;
237
0
        }
238
0
        return false;
239
0
    }
240
241
0
    return true;
242
0
}
243
244
/************************************************************************/
245
/*                         ParseDateTimeField()                         */
246
/************************************************************************/
247
248
bool OGRGeoPackageLayer::ParseDateTimeField(sqlite3_stmt *hStmt, int iRawField,
249
                                            int nSqlite3ColType,
250
                                            OGRField *psField,
251
                                            const OGRFieldDefn *poFieldDefn,
252
                                            GIntBig nFID)
253
20
{
254
20
    if (nSqlite3ColType == SQLITE_TEXT)
255
20
    {
256
20
        const char *pszTxt = reinterpret_cast<const char *>(
257
20
            sqlite3_column_text(hStmt, iRawField));
258
20
        return ParseDateTimeField(pszTxt, psField, poFieldDefn, nFID);
259
20
    }
260
0
    else
261
0
    {
262
0
        constexpr int line = __LINE__;
263
0
        if (!m_poDS->m_oSetGPKGLayerWarnings[line])
264
0
        {
265
0
            CPLError(CE_Warning, CPLE_AppDefined,
266
0
                     "Unexpected data type for record " CPL_FRMT_GIB
267
0
                     " in column %s",
268
0
                     nFID, poFieldDefn->GetNameRef());
269
0
            m_poDS->m_oSetGPKGLayerWarnings[line] = true;
270
0
        }
271
0
        return false;
272
0
    }
273
20
}
274
275
bool OGRGeoPackageLayer::ParseDateTimeField(const char *pszTxt,
276
                                            OGRField *psField,
277
                                            const OGRFieldDefn *poFieldDefn,
278
                                            GIntBig nFID)
279
20
{
280
20
    if (pszTxt == nullptr)
281
0
    {
282
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s",
283
0
                 sqlite3_errmsg(m_poDS->GetDB()));
284
0
        return false;
285
0
    }
286
287
20
    std::string_view sInput(pszTxt);
288
289
20
    if (OGRParseDateTimeYYYYMMDDTHHMMSSsssZ(sInput, psField) ||
290
20
        OGRParseDateTimeYYYYMMDDTHHMMSSZ(sInput, psField) ||
291
20
        OGRParseDateTimeYYYYMMDDTHHMMZ(sInput, psField))
292
0
    {
293
        // nominal format is YYYYMMDDTHHMMSSsssZ before GeoPackage 1.4
294
        // GeoPackage 1.4 also accepts omission of seconds and milliseconds
295
0
    }
296
20
    else if (OGRParseDate(pszTxt, psField, OGRPARSEDATE_OPTION_LAX))
297
0
    {
298
0
        constexpr int line = __LINE__;
299
0
        if (!m_poDS->m_oSetGPKGLayerWarnings[line])
300
0
        {
301
0
            CPLError(CE_Warning, CPLE_AppDefined,
302
0
                     "Non-conformant content for record " CPL_FRMT_GIB
303
0
                     " in column %s, %s, "
304
0
                     "successfully parsed",
305
0
                     nFID, poFieldDefn->GetNameRef(), pszTxt);
306
0
            m_poDS->m_oSetGPKGLayerWarnings[line] = true;
307
0
        }
308
0
    }
309
20
    else
310
20
    {
311
20
        OGR_RawField_SetUnset(psField);
312
20
        constexpr int line = __LINE__;
313
20
        if (!m_poDS->m_oSetGPKGLayerWarnings[line])
314
2
        {
315
2
            CPLError(CE_Warning, CPLE_AppDefined,
316
2
                     "Invalid content for record " CPL_FRMT_GIB
317
2
                     " in column %s: %s",
318
2
                     nFID, poFieldDefn->GetNameRef(), pszTxt);
319
2
            m_poDS->m_oSetGPKGLayerWarnings[line] = true;
320
2
        }
321
20
        return false;
322
20
    }
323
324
0
    return true;
325
20
}
326
327
/************************************************************************/
328
/*                          TranslateFeature()                          */
329
/************************************************************************/
330
331
OGRFeature *OGRGeoPackageLayer::TranslateFeature(sqlite3_stmt *hStmt)
332
333
43.8k
{
334
    /* -------------------------------------------------------------------- */
335
    /*      Create a feature from the current result.                       */
336
    /* -------------------------------------------------------------------- */
337
43.8k
    OGRFeature *poFeature = new OGRFeature(m_poFeatureDefn);
338
339
    /* -------------------------------------------------------------------- */
340
    /*      Set FID if we have a column to set it from.                     */
341
    /* -------------------------------------------------------------------- */
342
43.8k
    if (m_iFIDCol >= 0)
343
43.8k
    {
344
43.8k
        poFeature->SetFID(sqlite3_column_int64(hStmt, m_iFIDCol));
345
43.8k
        if (m_pszFidColumn == nullptr && poFeature->GetFID() == 0)
346
1
        {
347
            // Might be the case for views with joins.
348
1
            poFeature->SetFID(m_iNextShapeId);
349
1
        }
350
43.8k
    }
351
0
    else
352
0
        poFeature->SetFID(m_iNextShapeId);
353
354
43.8k
    m_iNextShapeId++;
355
356
43.8k
    m_nFeaturesRead++;
357
358
    /* -------------------------------------------------------------------- */
359
    /*      Process Geometry if we have a column.                           */
360
    /* -------------------------------------------------------------------- */
361
43.8k
    if (m_iGeomCol >= 0)
362
4.24k
    {
363
4.24k
        OGRGeomFieldDefn *poGeomFieldDefn =
364
4.24k
            m_poFeatureDefn->GetGeomFieldDefn(0);
365
4.24k
        if (sqlite3_column_type(hStmt, m_iGeomCol) != SQLITE_NULL &&
366
4.07k
            !poGeomFieldDefn->IsIgnored())
367
4.07k
        {
368
4.07k
            const OGRSpatialReference *poSrs = poGeomFieldDefn->GetSpatialRef();
369
4.07k
            int iGpkgSize = sqlite3_column_bytes(hStmt, m_iGeomCol);
370
            // coverity[tainted_data_return]
371
4.07k
            const GByte *pabyGpkg = static_cast<const GByte *>(
372
4.07k
                sqlite3_column_blob(hStmt, m_iGeomCol));
373
4.07k
            OGRGeometry *poGeom =
374
4.07k
                GPkgGeometryToOGR(pabyGpkg, iGpkgSize, nullptr);
375
4.07k
            if (poGeom == nullptr)
376
1.78k
            {
377
                // Try also spatialite geometry blobs
378
1.78k
                if (OGRSQLiteImportSpatiaLiteGeometry(pabyGpkg, iGpkgSize,
379
1.78k
                                                      &poGeom) != OGRERR_NONE)
380
1.78k
                {
381
1.78k
                    CPLError(CE_Failure, CPLE_AppDefined,
382
1.78k
                             "Unable to read geometry");
383
1.78k
                }
384
1.78k
            }
385
4.07k
            if (poGeom)
386
2.28k
            {
387
2.28k
                if (m_bUndoDiscardCoordLSBOnReading)
388
0
                {
389
0
                    poGeom->roundCoordinates(
390
0
                        poGeomFieldDefn->GetCoordinatePrecision());
391
0
                }
392
2.28k
                poGeom->assignSpatialReference(poSrs);
393
2.28k
            }
394
395
4.07k
            poFeature->SetGeometryDirectly(poGeom);
396
4.07k
        }
397
4.24k
    }
398
399
    /* -------------------------------------------------------------------- */
400
    /*      set the fields.                                                 */
401
    /* -------------------------------------------------------------------- */
402
43.8k
    const int nFieldCount = m_poFeatureDefn->GetFieldCount();
403
122k
    for (int iField = 0; iField < nFieldCount; iField++)
404
78.4k
    {
405
78.4k
        const OGRFieldDefn *poFieldDefn =
406
78.4k
            m_poFeatureDefn->GetFieldDefnUnsafe(iField);
407
78.4k
        if (poFieldDefn->IsIgnored())
408
0
            continue;
409
410
78.4k
        const int iRawField = m_anFieldOrdinals[iField];
411
412
78.4k
        const int nSqlite3ColType = sqlite3_column_type(hStmt, iRawField);
413
78.4k
        if (nSqlite3ColType == SQLITE_NULL)
414
25.8k
        {
415
25.8k
            poFeature->SetFieldNull(iField);
416
25.8k
            continue;
417
25.8k
        }
418
419
52.5k
        switch (poFieldDefn->GetType())
420
52.5k
        {
421
3.36k
            case OFTInteger:
422
3.36k
                poFeature->SetFieldSameTypeUnsafe(
423
3.36k
                    iField, sqlite3_column_int(hStmt, iRawField));
424
3.36k
                break;
425
426
6.00k
            case OFTInteger64:
427
6.00k
                poFeature->SetFieldSameTypeUnsafe(
428
6.00k
                    iField, sqlite3_column_int64(hStmt, iRawField));
429
6.00k
                break;
430
431
32
            case OFTReal:
432
32
                poFeature->SetFieldSameTypeUnsafe(
433
32
                    iField, sqlite3_column_double(hStmt, iRawField));
434
32
                break;
435
436
630
            case OFTBinary:
437
630
            {
438
630
                const int nBytes = sqlite3_column_bytes(hStmt, iRawField);
439
                // coverity[tainted_data_return]
440
630
                const void *pabyData = sqlite3_column_blob(hStmt, iRawField);
441
630
                if (pabyData != nullptr || nBytes == 0)
442
630
                {
443
630
                    poFeature->SetField(iField, nBytes, pabyData);
444
630
                }
445
0
                else
446
0
                {
447
0
                    CPLError(CE_Failure, CPLE_AppDefined, "%s",
448
0
                             sqlite3_errmsg(m_poDS->GetDB()));
449
0
                }
450
630
                break;
451
0
            }
452
453
0
            case OFTDate:
454
0
            {
455
0
                auto psField = poFeature->GetRawFieldRef(iField);
456
0
                CPL_IGNORE_RET_VAL(
457
0
                    ParseDateField(hStmt, iRawField, nSqlite3ColType, psField,
458
0
                                   poFieldDefn, poFeature->GetFID()));
459
0
                break;
460
0
            }
461
462
20
            case OFTDateTime:
463
20
            {
464
20
                auto psField = poFeature->GetRawFieldRef(iField);
465
20
                CPL_IGNORE_RET_VAL(ParseDateTimeField(
466
20
                    hStmt, iRawField, nSqlite3ColType, psField, poFieldDefn,
467
20
                    poFeature->GetFID()));
468
20
                break;
469
0
            }
470
471
42.4k
            case OFTString:
472
42.4k
            {
473
42.4k
                const char *pszTxt = reinterpret_cast<const char *>(
474
42.4k
                    sqlite3_column_text(hStmt, iRawField));
475
42.4k
                if (pszTxt)
476
42.4k
                {
477
42.4k
                    char *pszTxtDup = VSI_STRDUP_VERBOSE(pszTxt);
478
42.4k
                    if (pszTxtDup)
479
42.4k
                    {
480
42.4k
                        poFeature->SetFieldSameTypeUnsafe(iField, pszTxtDup);
481
42.4k
                    }
482
42.4k
                }
483
0
                else
484
0
                {
485
0
                    CPLError(CE_Failure, CPLE_AppDefined, "%s",
486
0
                             sqlite3_errmsg(m_poDS->GetDB()));
487
0
                }
488
42.4k
                break;
489
0
            }
490
491
0
            default:
492
0
                break;
493
52.5k
        }
494
52.5k
    }
495
496
43.8k
    return poFeature;
497
43.8k
}
498
499
/************************************************************************/
500
/*                           GetArrowStream()                           */
501
/************************************************************************/
502
503
bool OGRGeoPackageLayer::GetArrowStream(struct ArrowArrayStream *out_stream,
504
                                        CSLConstList papszOptions)
505
0
{
506
0
    CPLStringList aosOptions;
507
0
    aosOptions.Assign(CSLDuplicate(papszOptions), true);
508
    // GeoPackage are assumed to be in UTC. Even if another timezone is used,
509
    // we'll do the conversion to UTC
510
0
    if (aosOptions.FetchNameValue("TIMEZONE") == nullptr)
511
0
    {
512
0
        aosOptions.SetNameValue("TIMEZONE", "UTC");
513
0
    }
514
0
    return OGRLayer::GetArrowStream(out_stream, aosOptions.List());
515
0
}
516
517
/************************************************************************/
518
/*                         GetNextArrowArray()                          */
519
/************************************************************************/
520
521
int OGRGeoPackageLayer::GetNextArrowArray(struct ArrowArrayStream *stream,
522
                                          struct ArrowArray *out_array)
523
0
{
524
0
    if (CPLTestBool(CPLGetConfigOption("OGR_GPKG_STREAM_BASE_IMPL", "NO")))
525
0
    {
526
0
        return OGRLayer::GetNextArrowArray(stream, out_array);
527
0
    }
528
529
0
    int errorErrno = EIO;
530
0
    memset(out_array, 0, sizeof(*out_array));
531
532
0
    if (m_bEOF)
533
0
        return 0;
534
535
0
    if (m_poQueryStatement == nullptr)
536
0
    {
537
0
        GetLayerDefn();
538
0
        ResetStatement();
539
0
        if (m_poQueryStatement == nullptr)
540
0
            return 0;
541
0
    }
542
0
    sqlite3_stmt *hStmt = m_poQueryStatement;
543
544
0
    OGRArrowArrayHelper sHelper(m_poDS, m_poFeatureDefn,
545
0
                                m_aosArrowArrayStreamOptions, out_array);
546
0
    if (out_array->release == nullptr)
547
0
    {
548
0
        return ENOMEM;
549
0
    }
550
551
0
    struct tm brokenDown;
552
0
    memset(&brokenDown, 0, sizeof(brokenDown));
553
554
0
    const bool bDateTimeAsString = m_aosArrowArrayStreamOptions.FetchBool(
555
0
        GAS_OPT_DATETIME_AS_STRING, false);
556
557
0
    const uint32_t nMemLimit = OGRArrowArrayHelper::GetMemLimit();
558
0
    int iFeat = 0;
559
0
    while (iFeat < sHelper.m_nMaxBatchSize)
560
0
    {
561
        /* --------------------------------------------------------------------
562
         */
563
        /*      Fetch a record (unless otherwise instructed) */
564
        /* --------------------------------------------------------------------
565
         */
566
0
        if (m_bDoStep)
567
0
        {
568
0
            int rc = sqlite3_step(hStmt);
569
0
            if (rc != SQLITE_ROW)
570
0
            {
571
0
                if (rc != SQLITE_DONE)
572
0
                {
573
0
                    sqlite3_reset(hStmt);
574
0
                    CPLError(CE_Failure, CPLE_AppDefined,
575
0
                             "In GetNextArrowArray(): sqlite3_step() : %s",
576
0
                             sqlite3_errmsg(m_poDS->GetDB()));
577
0
                }
578
579
0
                ClearStatement();
580
0
                m_bEOF = true;
581
582
0
                break;
583
0
            }
584
0
        }
585
0
        else
586
0
        {
587
0
            m_bDoStep = true;
588
0
        }
589
590
0
        m_iNextShapeId++;
591
592
0
        m_nFeaturesRead++;
593
594
0
        GIntBig nFID;
595
0
        if (m_iFIDCol >= 0)
596
0
        {
597
0
            nFID = sqlite3_column_int64(hStmt, m_iFIDCol);
598
0
            if (m_pszFidColumn == nullptr && nFID == 0)
599
0
            {
600
                // Might be the case for views with joins.
601
0
                nFID = m_iNextShapeId;
602
0
            }
603
0
        }
604
0
        else
605
0
            nFID = m_iNextShapeId;
606
607
0
        if (sHelper.m_panFIDValues)
608
0
        {
609
0
            sHelper.m_panFIDValues[iFeat] = nFID;
610
0
        }
611
612
        /* --------------------------------------------------------------------
613
         */
614
        /*      Process Geometry if we have a column. */
615
        /* --------------------------------------------------------------------
616
         */
617
0
        if (m_iGeomCol >= 0 && sHelper.m_mapOGRGeomFieldToArrowField[0] >= 0)
618
0
        {
619
0
            const int iArrowField = sHelper.m_mapOGRGeomFieldToArrowField[0];
620
0
            auto psArray = out_array->children[iArrowField];
621
622
0
            size_t nWKBSize = 0;
623
0
            if (sqlite3_column_type(hStmt, m_iGeomCol) != SQLITE_NULL)
624
0
            {
625
0
                std::unique_ptr<OGRGeometry> poGeom;
626
0
                const GByte *pabyWkb = nullptr;
627
0
                const int iGpkgSize = sqlite3_column_bytes(hStmt, m_iGeomCol);
628
                // coverity[tainted_data_return]
629
0
                const GByte *pabyGpkg = static_cast<const GByte *>(
630
0
                    sqlite3_column_blob(hStmt, m_iGeomCol));
631
0
                if (m_poFilterGeom == nullptr && iGpkgSize >= 8 && pabyGpkg &&
632
0
                    pabyGpkg[0] == 'G' && pabyGpkg[1] == 'P' &&
633
0
                    !m_bUndoDiscardCoordLSBOnReading)
634
0
                {
635
0
                    GPkgHeader oHeader;
636
637
                    /* Read header */
638
0
                    OGRErr err =
639
0
                        GPkgHeaderFromWKB(pabyGpkg, iGpkgSize, &oHeader);
640
0
                    if (err == OGRERR_NONE)
641
0
                    {
642
                        /* WKB pointer */
643
0
                        pabyWkb = pabyGpkg + oHeader.nHeaderLen;
644
0
                        nWKBSize = iGpkgSize - oHeader.nHeaderLen;
645
0
                    }
646
0
                }
647
0
                else
648
0
                {
649
0
                    poGeom.reset(
650
0
                        GPkgGeometryToOGR(pabyGpkg, iGpkgSize, nullptr));
651
0
                    if (poGeom == nullptr)
652
0
                    {
653
                        // Try also spatialite geometry blobs
654
0
                        OGRGeometry *poGeomPtr = nullptr;
655
0
                        if (OGRSQLiteImportSpatiaLiteGeometry(
656
0
                                pabyGpkg, iGpkgSize, &poGeomPtr) != OGRERR_NONE)
657
0
                        {
658
0
                            CPLError(CE_Failure, CPLE_AppDefined,
659
0
                                     "Unable to read geometry");
660
0
                        }
661
0
                        poGeom.reset(poGeomPtr);
662
0
                    }
663
0
                    else if (m_bUndoDiscardCoordLSBOnReading)
664
0
                    {
665
0
                        poGeom->roundCoordinates(
666
0
                            m_poFeatureDefn->GetGeomFieldDefn(0)
667
0
                                ->GetCoordinatePrecision());
668
0
                    }
669
0
                    if (poGeom != nullptr)
670
0
                    {
671
0
                        nWKBSize = poGeom->WkbSize();
672
0
                    }
673
0
                    if (m_poFilterGeom != nullptr &&
674
0
                        !FilterGeometry(poGeom.get()))
675
0
                    {
676
0
                        continue;
677
0
                    }
678
0
                }
679
680
0
                if (nWKBSize != 0)
681
0
                {
682
0
                    if (iFeat > 0)
683
0
                    {
684
0
                        auto panOffsets = static_cast<int32_t *>(
685
0
                            const_cast<void *>(psArray->buffers[1]));
686
0
                        const uint32_t nCurLength =
687
0
                            static_cast<uint32_t>(panOffsets[iFeat]);
688
0
                        if (nWKBSize <= nMemLimit &&
689
0
                            nWKBSize > nMemLimit - nCurLength)
690
0
                        {
691
0
                            m_bDoStep = false;
692
0
                            break;
693
0
                        }
694
0
                    }
695
696
0
                    GByte *outPtr = sHelper.GetPtrForStringOrBinary(
697
0
                        iArrowField, iFeat, nWKBSize);
698
0
                    if (outPtr == nullptr)
699
0
                    {
700
0
                        errorErrno = ENOMEM;
701
0
                        goto error;
702
0
                    }
703
0
                    if (poGeom)
704
0
                    {
705
0
                        poGeom->exportToWkb(wkbNDR, outPtr, wkbVariantIso);
706
0
                    }
707
0
                    else
708
0
                    {
709
0
                        memcpy(outPtr, pabyWkb, nWKBSize);
710
0
                    }
711
0
                }
712
0
                else
713
0
                {
714
0
                    sHelper.SetEmptyStringOrBinary(psArray, iFeat);
715
0
                }
716
0
            }
717
718
0
            if (nWKBSize == 0)
719
0
            {
720
0
                if (!sHelper.SetNull(iArrowField, iFeat))
721
0
                {
722
0
                    errorErrno = ENOMEM;
723
0
                    goto error;
724
0
                }
725
0
            }
726
0
        }
727
728
0
        for (int iField = 0; iField < sHelper.m_nFieldCount; iField++)
729
0
        {
730
0
            const int iArrowField = sHelper.m_mapOGRFieldToArrowField[iField];
731
0
            if (iArrowField < 0)
732
0
                continue;
733
0
            const OGRFieldDefn *poFieldDefn =
734
0
                m_poFeatureDefn->GetFieldDefnUnsafe(iField);
735
736
0
            auto psArray = out_array->children[iArrowField];
737
0
            const int iRawField = m_anFieldOrdinals[iField];
738
739
0
            const int nSqlite3ColType = sqlite3_column_type(hStmt, iRawField);
740
0
            if (nSqlite3ColType == SQLITE_NULL)
741
0
            {
742
0
                if (!sHelper.SetNull(iArrowField, iFeat))
743
0
                {
744
0
                    errorErrno = ENOMEM;
745
0
                    goto error;
746
0
                }
747
0
                continue;
748
0
            }
749
750
0
            switch (poFieldDefn->GetType())
751
0
            {
752
0
                case OFTInteger:
753
0
                {
754
0
                    const int nVal = sqlite3_column_int(hStmt, iRawField);
755
0
                    if (poFieldDefn->GetSubType() == OFSTBoolean)
756
0
                    {
757
0
                        if (nVal != 0)
758
0
                        {
759
0
                            sHelper.SetBoolOn(psArray, iFeat);
760
0
                        }
761
0
                    }
762
0
                    else if (poFieldDefn->GetSubType() == OFSTInt16)
763
0
                    {
764
0
                        sHelper.SetInt16(psArray, iFeat,
765
0
                                         static_cast<int16_t>(nVal));
766
0
                    }
767
0
                    else
768
0
                    {
769
0
                        sHelper.SetInt32(psArray, iFeat, nVal);
770
0
                    }
771
0
                    break;
772
0
                }
773
774
0
                case OFTInteger64:
775
0
                {
776
0
                    sHelper.SetInt64(psArray, iFeat,
777
0
                                     sqlite3_column_int64(hStmt, iRawField));
778
0
                    break;
779
0
                }
780
781
0
                case OFTReal:
782
0
                {
783
0
                    const double dfVal =
784
0
                        sqlite3_column_double(hStmt, iRawField);
785
0
                    if (poFieldDefn->GetSubType() == OFSTFloat32)
786
0
                    {
787
0
                        sHelper.SetFloat(psArray, iFeat,
788
0
                                         static_cast<float>(dfVal));
789
0
                    }
790
0
                    else
791
0
                    {
792
0
                        sHelper.SetDouble(psArray, iFeat, dfVal);
793
0
                    }
794
0
                    break;
795
0
                }
796
797
0
                case OFTBinary:
798
0
                {
799
0
                    const uint32_t nBytes = static_cast<uint32_t>(
800
0
                        sqlite3_column_bytes(hStmt, iRawField));
801
                    // coverity[tainted_data_return]
802
0
                    const void *pabyData =
803
0
                        sqlite3_column_blob(hStmt, iRawField);
804
0
                    if (pabyData != nullptr || nBytes == 0)
805
0
                    {
806
0
                        if (iFeat > 0)
807
0
                        {
808
0
                            auto panOffsets = static_cast<int32_t *>(
809
0
                                const_cast<void *>(psArray->buffers[1]));
810
0
                            const uint32_t nCurLength =
811
0
                                static_cast<uint32_t>(panOffsets[iFeat]);
812
0
                            if (nBytes <= nMemLimit &&
813
0
                                nBytes > nMemLimit - nCurLength)
814
0
                            {
815
0
                                m_bDoStep = false;
816
0
                                m_iNextShapeId--;
817
0
                                m_nFeaturesRead--;
818
0
                                goto after_loop;
819
0
                            }
820
0
                        }
821
822
0
                        GByte *outPtr = sHelper.GetPtrForStringOrBinary(
823
0
                            iArrowField, iFeat, nBytes);
824
0
                        if (outPtr == nullptr)
825
0
                        {
826
0
                            errorErrno = ENOMEM;
827
0
                            goto error;
828
0
                        }
829
0
                        if (nBytes)
830
0
                            memcpy(outPtr, pabyData, nBytes);
831
0
                    }
832
0
                    else
833
0
                    {
834
0
                        sHelper.SetEmptyStringOrBinary(psArray, iFeat);
835
0
                    }
836
0
                    break;
837
0
                }
838
839
0
                case OFTDate:
840
0
                {
841
0
                    OGRField ogrField;
842
0
                    if (ParseDateField(hStmt, iRawField, nSqlite3ColType,
843
0
                                       &ogrField, poFieldDefn, nFID))
844
0
                    {
845
0
                        sHelper.SetDate(psArray, iFeat, brokenDown, ogrField);
846
0
                    }
847
0
                    break;
848
0
                }
849
850
0
                case OFTDateTime:
851
0
                {
852
0
                    if (!bDateTimeAsString)
853
0
                    {
854
0
                        OGRField ogrField;
855
0
                        if (ParseDateTimeField(hStmt, iRawField,
856
0
                                               nSqlite3ColType, &ogrField,
857
0
                                               poFieldDefn, nFID))
858
0
                        {
859
0
                            sHelper.SetDateTime(psArray, iFeat, brokenDown,
860
0
                                                sHelper.m_anTZFlags[iField],
861
0
                                                ogrField);
862
0
                        }
863
0
                        break;
864
0
                    }
865
0
                    else
866
0
                    {
867
0
                        [[fallthrough]];
868
0
                    }
869
0
                }
870
871
0
                case OFTString:
872
0
                {
873
0
                    const auto pszTxt = reinterpret_cast<const char *>(
874
0
                        sqlite3_column_text(hStmt, iRawField));
875
0
                    if (pszTxt != nullptr)
876
0
                    {
877
0
                        const size_t nBytes = strlen(pszTxt);
878
0
                        if (iFeat > 0)
879
0
                        {
880
0
                            auto panOffsets = static_cast<int32_t *>(
881
0
                                const_cast<void *>(psArray->buffers[1]));
882
0
                            const uint32_t nCurLength =
883
0
                                static_cast<uint32_t>(panOffsets[iFeat]);
884
0
                            if (nBytes <= nMemLimit &&
885
0
                                nBytes > nMemLimit - nCurLength)
886
0
                            {
887
0
                                m_bDoStep = false;
888
0
                                m_iNextShapeId--;
889
0
                                m_nFeaturesRead--;
890
0
                                goto after_loop;
891
0
                            }
892
0
                        }
893
894
0
                        GByte *outPtr = sHelper.GetPtrForStringOrBinary(
895
0
                            iArrowField, iFeat, nBytes);
896
0
                        if (outPtr == nullptr)
897
0
                        {
898
0
                            errorErrno = ENOMEM;
899
0
                            goto error;
900
0
                        }
901
0
                        if (nBytes)
902
0
                            memcpy(outPtr, pszTxt, nBytes);
903
0
                    }
904
0
                    else
905
0
                    {
906
0
                        sHelper.SetEmptyStringOrBinary(psArray, iFeat);
907
0
                        CPLError(CE_Failure, CPLE_AppDefined, "%s",
908
0
                                 sqlite3_errmsg(m_poDS->GetDB()));
909
0
                    }
910
0
                    break;
911
0
                }
912
913
0
                default:
914
0
                    break;
915
0
            }
916
0
        }
917
918
0
        ++iFeat;
919
0
    }
920
0
after_loop:
921
0
    sHelper.Shrink(iFeat);
922
0
    if (iFeat == 0)
923
0
        sHelper.ClearArray();
924
925
0
    return 0;
926
927
0
error:
928
0
    sHelper.ClearArray();
929
0
    return errorErrno;
930
0
}
931
932
/************************************************************************/
933
/*                            GetFIDColumn()                            */
934
/************************************************************************/
935
936
const char *OGRGeoPackageLayer::GetFIDColumn() const
937
4.89k
{
938
4.89k
    if (!m_pszFidColumn)
939
939
        return "";
940
3.95k
    else
941
3.95k
        return m_pszFidColumn;
942
4.89k
}
943
944
/************************************************************************/
945
/*                           TestCapability()                           */
946
/************************************************************************/
947
948
int OGRGeoPackageLayer::TestCapability(const char *pszCap) const
949
0
{
950
0
    if (EQUAL(pszCap, OLCIgnoreFields))
951
0
        return TRUE;
952
0
    else if (EQUAL(pszCap, OLCStringsAsUTF8))
953
0
        return TRUE;
954
0
    else if (EQUAL(pszCap, OLCFastGetArrowStream))
955
0
        return TRUE;
956
0
    else if (EQUAL(pszCap, OLCZGeometries))
957
0
        return TRUE;
958
0
    else
959
0
        return FALSE;
960
0
}
961
962
/************************************************************************/
963
/*                          BuildFeatureDefn()                          */
964
/*                                                                      */
965
/*      Build feature definition from a set of column definitions       */
966
/*      set on a statement.  Sift out geometry and FID fields.          */
967
/************************************************************************/
968
969
void OGRGeoPackageLayer::BuildFeatureDefn(const char *pszLayerName,
970
                                          sqlite3_stmt *hStmt)
971
972
0
{
973
0
    m_poFeatureDefn = new OGRSQLiteFeatureDefn(pszLayerName);
974
0
    SetDescription(m_poFeatureDefn->GetName());
975
0
    m_poFeatureDefn->SetGeomType(wkbNone);
976
0
    m_poFeatureDefn->Reference();
977
978
0
    const int nRawColumns = sqlite3_column_count(hStmt);
979
980
0
    m_anFieldOrdinals.resize(nRawColumns);
981
982
0
    const bool bPromoteToInteger64 =
983
0
        CPLTestBool(CPLGetConfigOption("OGR_PROMOTE_TO_INTEGER64", "FALSE"));
984
985
0
#ifdef SQLITE_HAS_COLUMN_METADATA
986
    // Check that there are not several FID fields referenced.
987
    // This is not a sufficient condition to ensure that we can get a true FID,
988
    // but when this occurs, we are (almost) sure that this cannot be a FID.
989
0
    int nFIDCandidates = 0;
990
0
    for (int iCol = 0; iCol < nRawColumns; iCol++)
991
0
    {
992
0
        const char *pszTableName = sqlite3_column_table_name(hStmt, iCol);
993
0
        const char *pszOriginName = sqlite3_column_origin_name(hStmt, iCol);
994
0
        if (pszTableName != nullptr && pszOriginName != nullptr)
995
0
        {
996
0
            OGRLayer *poLayer = m_poDS->GetLayerByName(pszTableName);
997
0
            if (poLayer != nullptr)
998
0
            {
999
0
                if (EQUAL(pszOriginName, poLayer->GetFIDColumn()))
1000
0
                {
1001
0
                    nFIDCandidates++;
1002
0
                }
1003
0
            }
1004
0
        }
1005
0
    }
1006
0
#endif
1007
1008
0
    [[maybe_unused]] bool bGeometryColumnGuessed = false;
1009
0
    for (int iCol = 0; iCol < nRawColumns; iCol++)
1010
0
    {
1011
0
        OGRFieldDefn oField(SQLUnescape(sqlite3_column_name(hStmt, iCol)),
1012
0
                            OFTString);
1013
1014
        // In some cases, particularly when there is a real name for
1015
        // the primary key/_rowid_ column we will end up getting the
1016
        // primary key column appearing twice.  Ignore any repeated names.
1017
0
        if (m_poFeatureDefn->GetFieldIndex(oField.GetNameRef()) != -1)
1018
0
            continue;
1019
1020
0
        if (m_pszFidColumn != nullptr &&
1021
0
            EQUAL(m_pszFidColumn, oField.GetNameRef()))
1022
0
            continue;
1023
1024
        // The rowid is for internal use, not a real column.
1025
0
        if (EQUAL(oField.GetNameRef(), "_rowid_"))
1026
0
            continue;
1027
1028
        // this will avoid the old geom field to appear when running something
1029
        // like "select st_buffer(geom,5) as geom, * from my_layer"
1030
0
        if (m_poFeatureDefn->GetGeomFieldCount() &&
1031
0
            EQUAL(oField.GetNameRef(),
1032
0
                  m_poFeatureDefn->GetGeomFieldDefn(0)->GetNameRef()))
1033
0
        {
1034
0
            continue;
1035
0
        }
1036
1037
0
#ifdef SQLITE_HAS_COLUMN_METADATA
1038
0
        const char *pszTableName = sqlite3_column_table_name(hStmt, iCol);
1039
0
        const char *pszOriginName = sqlite3_column_origin_name(hStmt, iCol);
1040
0
        if (pszTableName != nullptr && pszOriginName != nullptr)
1041
0
        {
1042
0
            OGRLayer *poLayer = m_poDS->GetLayerByName(pszTableName);
1043
0
            if (poLayer != nullptr)
1044
0
            {
1045
0
                if (EQUAL(pszOriginName, poLayer->GetGeometryColumn()))
1046
0
                {
1047
0
                    if (bGeometryColumnGuessed ||
1048
0
                        m_poFeatureDefn->GetGeomFieldCount() == 0)
1049
0
                    {
1050
0
                        if (bGeometryColumnGuessed)
1051
0
                            m_poFeatureDefn->DeleteGeomFieldDefn(0);
1052
0
                        OGRGeomFieldDefn oGeomField(
1053
0
                            poLayer->GetLayerDefn()->GetGeomFieldDefn(0));
1054
0
                        oGeomField.SetName(oField.GetNameRef());
1055
0
                        m_poFeatureDefn->AddGeomFieldDefn(&oGeomField);
1056
0
                        m_iGeomCol = iCol;
1057
0
                    }
1058
0
                    continue;
1059
0
                }
1060
0
                else if (EQUAL(pszOriginName, poLayer->GetFIDColumn()) &&
1061
0
                         m_pszFidColumn == nullptr && nFIDCandidates == 1)
1062
0
                {
1063
0
                    m_pszFidColumn = CPLStrdup(oField.GetNameRef());
1064
0
                    m_iFIDCol = iCol;
1065
0
                    continue;
1066
0
                }
1067
0
                int nSrcIdx =
1068
0
                    poLayer->GetLayerDefn()->GetFieldIndex(oField.GetNameRef());
1069
0
                if (nSrcIdx >= 0)
1070
0
                {
1071
0
                    OGRFieldDefn *poSrcField =
1072
0
                        poLayer->GetLayerDefn()->GetFieldDefn(nSrcIdx);
1073
0
                    oField.SetType(poSrcField->GetType());
1074
0
                    oField.SetSubType(poSrcField->GetSubType());
1075
0
                    oField.SetWidth(poSrcField->GetWidth());
1076
0
                    oField.SetPrecision(poSrcField->GetPrecision());
1077
0
                    oField.SetDomainName(poSrcField->GetDomainName());
1078
0
                    m_poFeatureDefn->AddFieldDefn(&oField);
1079
0
                    m_anFieldOrdinals[m_poFeatureDefn->GetFieldCount() - 1] =
1080
0
                        iCol;
1081
0
                    continue;
1082
0
                }
1083
0
            }
1084
0
        }
1085
0
#endif
1086
1087
0
        const int nColType = sqlite3_column_type(hStmt, iCol);
1088
0
        if (m_poFeatureDefn->GetGeomFieldCount() == 0 &&
1089
0
            m_pszFidColumn == nullptr && nColType == SQLITE_INTEGER &&
1090
0
            EQUAL(oField.GetNameRef(), "FID"))
1091
0
        {
1092
0
            m_pszFidColumn = CPLStrdup(oField.GetNameRef());
1093
0
            m_iFIDCol = iCol;
1094
0
            continue;
1095
0
        }
1096
1097
        // Heuristics to help for https://github.com/OSGeo/gdal/issues/8587
1098
0
        if (nColType == SQLITE_NULL && m_iGeomCol < 0
1099
0
#ifdef SQLITE_HAS_COLUMN_METADATA
1100
0
            && !pszTableName && !pszOriginName
1101
0
#endif
1102
0
        )
1103
0
        {
1104
0
            bool bIsLikelyGeomColName = EQUAL(oField.GetNameRef(), "geom") ||
1105
0
                                        EQUAL(oField.GetNameRef(), "geometry");
1106
0
            bool bIsGeomFunction = false;
1107
0
            if (!bIsLikelyGeomColName)
1108
0
                bIsGeomFunction = OGRSQLiteIsSpatialFunctionReturningGeometry(
1109
0
                    oField.GetNameRef());
1110
0
            if (bIsLikelyGeomColName || bIsGeomFunction)
1111
0
            {
1112
0
                bGeometryColumnGuessed = bIsLikelyGeomColName;
1113
0
                OGRGeomFieldDefn oGeomField(oField.GetNameRef(), wkbUnknown);
1114
0
                m_poFeatureDefn->AddGeomFieldDefn(&oGeomField);
1115
0
                m_iGeomCol = iCol;
1116
0
                continue;
1117
0
            }
1118
0
        }
1119
1120
0
        const char *pszDeclType = sqlite3_column_decltype(hStmt, iCol);
1121
1122
        // Recognize a geometry column from trying to build the geometry
1123
0
        if (nColType == SQLITE_BLOB &&
1124
0
            m_poFeatureDefn->GetGeomFieldCount() == 0)
1125
0
        {
1126
0
            const int nBytes = sqlite3_column_bytes(hStmt, iCol);
1127
0
            if (nBytes >= 8)
1128
0
            {
1129
                // coverity[tainted_data_return]
1130
0
                const GByte *pabyGpkg = reinterpret_cast<const GByte *>(
1131
0
                    sqlite3_column_blob(hStmt, iCol));
1132
0
                GPkgHeader oHeader;
1133
0
                OGRGeometry *poGeom = nullptr;
1134
0
                int nSRID = 0;
1135
1136
0
                if (GPkgHeaderFromWKB(pabyGpkg, nBytes, &oHeader) ==
1137
0
                    OGRERR_NONE)
1138
0
                {
1139
0
                    poGeom = GPkgGeometryToOGR(pabyGpkg, nBytes, nullptr);
1140
0
                    nSRID = oHeader.iSrsId;
1141
0
                }
1142
0
                else
1143
0
                {
1144
                    // Try also spatialite geometry blobs
1145
0
                    if (OGRSQLiteImportSpatiaLiteGeometry(
1146
0
                            pabyGpkg, nBytes, &poGeom, &nSRID) != OGRERR_NONE)
1147
0
                    {
1148
0
                        delete poGeom;
1149
0
                        poGeom = nullptr;
1150
0
                    }
1151
0
                }
1152
1153
0
                if (poGeom)
1154
0
                {
1155
0
                    OGRGeomFieldDefn oGeomField(oField.GetNameRef(),
1156
0
                                                wkbUnknown);
1157
1158
                    /* Read the SRS */
1159
0
                    auto poSRS = m_poDS->GetSpatialRef(nSRID, true);
1160
0
                    if (poSRS)
1161
0
                    {
1162
0
                        oGeomField.SetSpatialRef(poSRS.get());
1163
0
                    }
1164
1165
0
                    OGRwkbGeometryType eGeomType = poGeom->getGeometryType();
1166
0
                    if (pszDeclType != nullptr)
1167
0
                    {
1168
0
                        OGRwkbGeometryType eDeclaredGeomType =
1169
0
                            GPkgGeometryTypeToWKB(pszDeclType, false, false);
1170
0
                        if (eDeclaredGeomType != wkbUnknown)
1171
0
                        {
1172
0
                            eGeomType = OGR_GT_SetModifier(
1173
0
                                eDeclaredGeomType, OGR_GT_HasZ(eGeomType),
1174
0
                                OGR_GT_HasM(eGeomType));
1175
0
                        }
1176
0
                    }
1177
0
                    oGeomField.SetType(eGeomType);
1178
1179
0
                    delete poGeom;
1180
0
                    poGeom = nullptr;
1181
1182
0
                    m_poFeatureDefn->AddGeomFieldDefn(&oGeomField);
1183
0
                    m_iGeomCol = iCol;
1184
0
                    continue;
1185
0
                }
1186
0
            }
1187
0
        }
1188
1189
0
        switch (nColType)
1190
0
        {
1191
0
            case SQLITE_INTEGER:
1192
0
                if (bPromoteToInteger64)
1193
0
                    oField.SetType(OFTInteger64);
1194
0
                else
1195
0
                {
1196
0
                    GIntBig nVal = sqlite3_column_int64(hStmt, iCol);
1197
0
                    if (CPL_INT64_FITS_ON_INT32(nVal))
1198
0
                        oField.SetType(OFTInteger);
1199
0
                    else
1200
0
                        oField.SetType(OFTInteger64);
1201
0
                }
1202
0
                break;
1203
1204
0
            case SQLITE_FLOAT:
1205
0
                oField.SetType(OFTReal);
1206
0
                break;
1207
1208
0
            case SQLITE_BLOB:
1209
0
                oField.SetType(OFTBinary);
1210
0
                break;
1211
1212
0
            default:
1213
0
                /* leave it as OFTString */;
1214
0
        }
1215
1216
0
        if (pszDeclType != nullptr)
1217
0
        {
1218
0
            OGRFieldSubType eSubType;
1219
0
            int nMaxWidth = 0;
1220
0
            const int nFieldType =
1221
0
                GPkgFieldToOGR(pszDeclType, eSubType, nMaxWidth);
1222
0
            if (nFieldType <= OFTMaxType)
1223
0
            {
1224
0
                oField.SetType(static_cast<OGRFieldType>(nFieldType));
1225
0
                oField.SetSubType(eSubType);
1226
0
                oField.SetWidth(nMaxWidth);
1227
0
            }
1228
0
        }
1229
1230
0
        m_poFeatureDefn->AddFieldDefn(&oField);
1231
0
        m_anFieldOrdinals[m_poFeatureDefn->GetFieldCount() - 1] = iCol;
1232
0
    }
1233
0
}
1234
1235
/************************************************************************/
1236
/*                          SetIgnoredFields()                          */
1237
/************************************************************************/
1238
1239
OGRErr OGRGeoPackageLayer::SetIgnoredFields(CSLConstList papszFields)
1240
0
{
1241
0
    OGRErr eErr = OGRLayer::SetIgnoredFields(papszFields);
1242
0
    if (eErr == OGRERR_NONE)
1243
0
    {
1244
        // So that OGRGeoPackageTableLayer::BuildColumns() is called
1245
0
        ResetReading();
1246
0
    }
1247
0
    return eErr;
1248
0
}