LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/gpkg - ogrgeopackagelayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 509 569 89.5 %
Date: 2024-05-02 00:41:30 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             :  * 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             : }

Generated by: LCOV version 1.14