LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/gpkg - ogrgeopackagelayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 508 568 89.4 %
Date: 2024-11-21 22:18:42 Functions: 16 17 94.1 %

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

Generated by: LCOV version 1.14