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