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