LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/sqlite - ogrsqlitetablelayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1636 1886 86.7 %
Date: 2026-09-11 05:09:32 Functions: 55 56 98.2 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implements OGRSQLiteTableLayer class, access to an existing table.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2004, Frank Warmerdam
       9             :  * Copyright (c) 2009-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "ogr_sqlite.h"
      16             : #include "ogrsqliteutility.h"
      17             : 
      18             : #include <json.h>  // JSON-C
      19             : 
      20             : #include <climits>
      21             : #include <cstddef>
      22             : #include <cstdio>
      23             : #include <cstdlib>
      24             : #include <cstring>
      25             : #include <ctime>
      26             : #include <limits>
      27             : #include <memory>
      28             : #include <set>
      29             : #include <string>
      30             : #include <utility>
      31             : #include <vector>
      32             : 
      33             : #include "cpl_conv.h"
      34             : #include "cpl_error.h"
      35             : #include "cpl_string.h"
      36             : #include "cpl_time.h"
      37             : #include "ogr_core.h"
      38             : #include "ogrlibjsonutils.h"
      39             : #include "ogr_feature.h"
      40             : #include "ogr_geometry.h"
      41             : #include "ogr_p.h"
      42             : #include "ogr_spatialref.h"
      43             : #include "ogrsf_frmts.h"
      44             : #include "sqlite3.h"
      45             : 
      46             : static const char UNSUPPORTED_OP_READ_ONLY[] =
      47             :     "%s : unsupported operation on a read-only datasource.";
      48             : 
      49             : /************************************************************************/
      50             : /*                        OGRSQLiteTableLayer()                         */
      51             : /************************************************************************/
      52             : 
      53        1978 : OGRSQLiteTableLayer::OGRSQLiteTableLayer(OGRSQLiteDataSource *poDSIn)
      54             :     : OGRSQLiteLayer(poDSIn),
      55             :       m_bSpatialite2D(
      56        5934 :           poDSIn->GetSpatialiteVersionNumber() <
      57        1978 :           OGRSQLiteDataSource::MakeSpatialiteVersionNumber(2, 4, 0)),
      58        1978 :       m_bHasCheckedTriggers(!CPLTestBool(
      59        3956 :           CPLGetConfigOption("OGR_SQLITE_DISABLE_INSERT_TRIGGERS", "YES")))
      60             : {
      61        1978 : }
      62             : 
      63             : /************************************************************************/
      64             : /*                        ~OGRSQLiteTableLayer()                        */
      65             : /************************************************************************/
      66             : 
      67        3954 : OGRSQLiteTableLayer::~OGRSQLiteTableLayer()
      68             : 
      69             : {
      70        1977 :     ClearStatement();
      71        1977 :     ClearInsertStmt();
      72             : 
      73             :     const int nGeomFieldCount =
      74        1977 :         m_poFeatureDefn ? m_poFeatureDefn->GetGeomFieldCount() : 0;
      75        2574 :     for (int i = 0; i < nGeomFieldCount; i++)
      76             :     {
      77             :         OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
      78         597 :             m_poFeatureDefn->myGetGeomFieldDefn(i);
      79             :         // Restore temporarily disabled triggers.
      80        1480 :         for (int j = 0; j < static_cast<int>(
      81         883 :                                 poGeomFieldDefn->m_aosDisabledTriggers.size());
      82             :              j++)
      83             :         {
      84         286 :             CPLDebug("SQLite", "Restoring trigger %s",
      85         286 :                      poGeomFieldDefn->m_aosDisabledTriggers[j].first.c_str());
      86             :             // This may fail since CreateSpatialIndex() reinstalls triggers, so
      87             :             // don't check result.
      88         572 :             CPL_IGNORE_RET_VAL(sqlite3_exec(
      89         286 :                 m_poDS->GetDB(),
      90         286 :                 poGeomFieldDefn->m_aosDisabledTriggers[j].second.c_str(),
      91             :                 nullptr, nullptr, nullptr));
      92             :         }
      93             :     }
      94             : 
      95        1977 :     CPLFree(m_pszTableName);
      96        1977 :     CPLFree(m_pszEscapedTableName);
      97        1977 :     CPLFree(m_pszCreationGeomFormat);
      98        3954 : }
      99             : 
     100             : /************************************************************************/
     101             : /*                   CreateSpatialIndexIfNecessary()                    */
     102             : /************************************************************************/
     103             : 
     104        7300 : void OGRSQLiteTableLayer::CreateSpatialIndexIfNecessary()
     105             : {
     106        7300 :     if (m_bDeferredSpatialIndexCreation)
     107             :     {
     108         274 :         for (int iGeomCol = 0; iGeomCol < m_poFeatureDefn->GetGeomFieldCount();
     109             :              iGeomCol++)
     110         137 :             CreateSpatialIndex(iGeomCol);
     111         137 :         m_bDeferredSpatialIndexCreation = false;
     112             :     }
     113        7300 : }
     114             : 
     115             : /************************************************************************/
     116             : /*                          ClearInsertStmt()                           */
     117             : /************************************************************************/
     118             : 
     119       13740 : void OGRSQLiteTableLayer::ClearInsertStmt()
     120             : {
     121       13740 :     if (m_hInsertStmt != nullptr)
     122             :     {
     123        5436 :         sqlite3_finalize(m_hInsertStmt);
     124        5436 :         m_hInsertStmt = nullptr;
     125             :     }
     126       13740 :     m_osLastInsertStmt = "";
     127       13740 : }
     128             : 
     129             : /************************************************************************/
     130             : /*                             Initialize()                             */
     131             : /************************************************************************/
     132             : 
     133        1978 : CPLErr OGRSQLiteTableLayer::Initialize(const char *m_pszTableNameIn,
     134             :                                        bool bIsTable, bool bIsVirtualShapeIn,
     135             :                                        bool bDeferredCreationIn,
     136             :                                        bool bMayEmitError)
     137             : {
     138        1978 :     SetDescription(m_pszTableNameIn);
     139             : 
     140        1978 :     m_bIsTable = bIsTable;
     141        1978 :     m_bIsVirtualShape = bIsVirtualShapeIn;
     142        1978 :     m_pszTableName = CPLStrdup(m_pszTableNameIn);
     143        1978 :     m_bDeferredCreation = bDeferredCreationIn;
     144        1978 :     m_pszEscapedTableName = CPLStrdup(SQLEscapeLiteral(m_pszTableName));
     145             : 
     146        1978 :     if (!bDeferredCreationIn && strchr(m_pszTableName, '(') != nullptr &&
     147         303 :         m_pszTableName[strlen(m_pszTableName) - 1] == ')')
     148             :     {
     149         303 :         char *pszErrMsg = nullptr;
     150         303 :         int nRowCount = 0, nColCount = 0;
     151         303 :         char **papszResult = nullptr;
     152             :         const char *pszSQL =
     153         303 :             CPLSPrintf("SELECT * FROM sqlite_master WHERE name = '%s'",
     154             :                        m_pszEscapedTableName);
     155         303 :         int rc = sqlite3_get_table(m_poDS->GetDB(), pszSQL, &papszResult,
     156             :                                    &nRowCount, &nColCount, &pszErrMsg);
     157         303 :         int bFound = (rc == SQLITE_OK && nRowCount == 1);
     158         303 :         sqlite3_free_table(papszResult);
     159         303 :         sqlite3_free(pszErrMsg);
     160             : 
     161         303 :         if (!bFound)
     162             :         {
     163         302 :             char *pszGeomCol = CPLStrdup(strchr(m_pszTableName, '(') + 1);
     164         302 :             pszGeomCol[strlen(pszGeomCol) - 1] = 0;
     165         302 :             *strchr(m_pszTableName, '(') = 0;
     166         302 :             CPLFree(m_pszEscapedTableName);
     167         302 :             m_pszEscapedTableName = CPLStrdup(SQLEscapeLiteral(m_pszTableName));
     168         302 :             EstablishFeatureDefn(pszGeomCol, bMayEmitError);
     169         302 :             CPLFree(pszGeomCol);
     170         601 :             if (m_poFeatureDefn == nullptr ||
     171         299 :                 m_poFeatureDefn->GetGeomFieldCount() == 0)
     172         296 :                 return CE_Failure;
     173             :         }
     174             :     }
     175             : 
     176        1682 :     return CE_None;
     177             : }
     178             : 
     179             : /************************************************************************/
     180             : /*                           GetGeomFormat()                            */
     181             : /************************************************************************/
     182             : 
     183         447 : static OGRSQLiteGeomFormat GetGeomFormat(const char *pszGeomFormat)
     184             : {
     185         447 :     OGRSQLiteGeomFormat eGeomFormat = OSGF_Unknown;
     186         447 :     if (pszGeomFormat)
     187             :     {
     188         447 :         if (EQUAL(pszGeomFormat, "WKT"))
     189           2 :             eGeomFormat = OSGF_WKT;
     190         445 :         else if (EQUAL(pszGeomFormat, "WKB"))
     191         296 :             eGeomFormat = OSGF_WKB;
     192         149 :         else if (EQUAL(pszGeomFormat, "FGF"))
     193           1 :             eGeomFormat = OSGF_FGF;
     194         148 :         else if (EQUAL(pszGeomFormat, "SpatiaLite"))
     195         148 :             eGeomFormat = OSGF_SpatiaLite;
     196             :     }
     197         447 :     return eGeomFormat;
     198             : }
     199             : 
     200             : /************************************************************************/
     201             : /*                       SetCreationParameters()                        */
     202             : /************************************************************************/
     203             : 
     204         444 : void OGRSQLiteTableLayer::SetCreationParameters(const char *pszFIDColumnName,
     205             :                                                 OGRwkbGeometryType eGeomType,
     206             :                                                 const char *pszGeomFormat,
     207             :                                                 const char *pszGeometryName,
     208             :                                                 OGRSpatialReference *poSRS,
     209             :                                                 int nSRSId)
     210             : 
     211             : {
     212         444 :     m_pszFIDColumn = CPLStrdup(pszFIDColumnName);
     213         444 :     m_poFeatureDefn = new OGRSQLiteFeatureDefn(m_pszTableName);
     214         444 :     m_poFeatureDefn->SetGeomType(wkbNone);
     215         444 :     m_poFeatureDefn->Reference();
     216         444 :     m_pszCreationGeomFormat =
     217         444 :         (pszGeomFormat) ? CPLStrdup(pszGeomFormat) : nullptr;
     218         444 :     if (eGeomType != wkbNone)
     219             :     {
     220         318 :         if (nSRSId == UNINITIALIZED_SRID)
     221           0 :             nSRSId = m_poDS->GetUndefinedSRID();
     222         318 :         OGRSQLiteGeomFormat eGeomFormat = GetGeomFormat(pszGeomFormat);
     223             :         auto poGeomFieldDefn =
     224         318 :             std::make_unique<OGRSQLiteGeomFieldDefn>(pszGeometryName, -1);
     225         318 :         poGeomFieldDefn->SetType(eGeomType);
     226         318 :         poGeomFieldDefn->m_nSRSId = nSRSId;
     227         318 :         poGeomFieldDefn->m_eGeomFormat = eGeomFormat;
     228         318 :         poGeomFieldDefn->SetSpatialRef(poSRS);
     229         318 :         m_poFeatureDefn->AddGeomFieldDefn(std::move(poGeomFieldDefn));
     230             :     }
     231         444 :     m_poFeatureDefn->Seal(/* bSealFields */ true);
     232         444 : }
     233             : 
     234             : /************************************************************************/
     235             : /*                              GetName()                               */
     236             : /************************************************************************/
     237             : 
     238       15074 : const char *OGRSQLiteTableLayer::GetName() const
     239             : {
     240       15074 :     return GetDescription();
     241             : }
     242             : 
     243             : /************************************************************************/
     244             : /*                            GetMetadata()                             */
     245             : /************************************************************************/
     246             : 
     247          16 : CSLConstList OGRSQLiteTableLayer::GetMetadata(const char *pszDomain)
     248             : 
     249             : {
     250             :     // Update GetMetadataItem() optimization that skips calling GetMetadata()
     251             :     // when key != OLMD_FID64 if we add more metadata items.
     252             : 
     253          16 :     GetLayerDefn();
     254          16 :     if (!m_bHasTriedDetectingFID64 && m_pszFIDColumn != nullptr)
     255             :     {
     256           9 :         m_bHasTriedDetectingFID64 = true;
     257             : 
     258             :         /* --------------------------------------------------------------------
     259             :          */
     260             :         /*      Find if the FID holds 64bit values */
     261             :         /* --------------------------------------------------------------------
     262             :          */
     263             : 
     264             :         // Normally the fid should be AUTOINCREMENT, so check sqlite_sequence
     265           9 :         OGRErr err = OGRERR_NONE;
     266             :         char *pszSQL =
     267           9 :             sqlite3_mprintf("SELECT seq FROM sqlite_sequence WHERE name = '%q'",
     268             :                             m_pszTableName);
     269           9 :         CPLPushErrorHandler(CPLQuietErrorHandler);
     270           9 :         GIntBig nMaxId = SQLGetInteger64(m_poDS->GetDB(), pszSQL, &err);
     271           9 :         CPLPopErrorHandler();
     272           9 :         sqlite3_free(pszSQL);
     273           9 :         if (err != OGRERR_NONE)
     274             :         {
     275           2 :             CPLErrorReset();
     276             : 
     277             :             // In case of error, fallback to taking the MAX of the FID
     278           2 :             pszSQL = sqlite3_mprintf("SELECT MAX(\"%w\") FROM \"%w\"",
     279             :                                      m_pszFIDColumn, m_pszTableName);
     280             : 
     281           2 :             nMaxId = SQLGetInteger64(m_poDS->GetDB(), pszSQL, nullptr);
     282           2 :             sqlite3_free(pszSQL);
     283             :         }
     284           9 :         if (nMaxId > INT_MAX)
     285           2 :             OGRLayer::SetMetadataItem(OLMD_FID64, "YES");
     286             :     }
     287             : 
     288          16 :     return OGRSQLiteLayer::GetMetadata(pszDomain);
     289             : }
     290             : 
     291             : /************************************************************************/
     292             : /*                          GetMetadataItem()                           */
     293             : /************************************************************************/
     294             : 
     295          15 : const char *OGRSQLiteTableLayer::GetMetadataItem(const char *pszName,
     296             :                                                  const char *pszDomain)
     297             : {
     298          15 :     if (!((pszDomain == nullptr || EQUAL(pszDomain, "")) &&
     299          13 :           EQUAL(pszName, OLMD_FID64)))
     300           8 :         return nullptr;
     301           7 :     return CSLFetchNameValue(GetMetadata(pszDomain), pszName);
     302             : }
     303             : 
     304             : /************************************************************************/
     305             : /*                        EstablishFeatureDefn()                        */
     306             : /************************************************************************/
     307             : 
     308        1032 : CPLErr OGRSQLiteTableLayer::EstablishFeatureDefn(const char *pszGeomCol,
     309             :                                                  bool bMayEmitError)
     310             : {
     311        1032 :     sqlite3 *hDB = m_poDS->GetDB();
     312             : 
     313             :     /* -------------------------------------------------------------------- */
     314             :     /*      Get the column definitions for this table.                      */
     315             :     /* -------------------------------------------------------------------- */
     316        1032 :     bool bHasRowId = m_bIsTable;
     317             : 
     318             :     // SELECT .. FROM ... LIMIT ... is broken on VirtualShape tables with
     319             :     // spatialite 5.0.1 and sqlite 3.38.0
     320             :     const char *pszSQLConst =
     321        1032 :         CPLSPrintf(m_bIsVirtualShape ? "SELECT %s* FROM '%s'"
     322             :                                      : "SELECT %s* FROM '%s' LIMIT 1",
     323        1032 :                    m_bIsTable ? "_rowid_, " : "", m_pszEscapedTableName);
     324             : 
     325        1032 :     sqlite3_stmt *hColStmt = nullptr;
     326        1032 :     int rc = sqlite3_prepare_v2(hDB, pszSQLConst, -1, &hColStmt, nullptr);
     327        1032 :     if (rc != SQLITE_OK)
     328             :     {
     329         242 :         const char *pszErrMsg = sqlite3_errmsg(hDB);
     330         242 :         if (m_bIsTable && pszErrMsg && strstr(pszErrMsg, "_rowid_") != nullptr)
     331             :         {
     332             :             // This is likely a table WITHOUT ROWID
     333           1 :             bHasRowId = false;
     334           1 :             sqlite3_finalize(hColStmt);
     335           1 :             hColStmt = nullptr;
     336             :             pszSQLConst =
     337           1 :                 CPLSPrintf("SELECT * FROM '%s' LIMIT 1", m_pszEscapedTableName);
     338           1 :             rc = sqlite3_prepare_v2(hDB, pszSQLConst, -1, &hColStmt, nullptr);
     339             :         }
     340         242 :         if (rc != SQLITE_OK)
     341             :         {
     342         241 :             if (bMayEmitError)
     343             :             {
     344         238 :                 CPLError(
     345             :                     CE_Failure, CPLE_AppDefined,
     346             :                     "Unable to query table %s for column definitions : %s.",
     347             :                     m_pszTableName, sqlite3_errmsg(hDB));
     348             :             }
     349         241 :             return CE_Failure;
     350             :         }
     351             :     }
     352             : 
     353         791 :     rc = sqlite3_step(hColStmt);
     354         791 :     if (rc != SQLITE_DONE && rc != SQLITE_ROW)
     355             :     {
     356         102 :         CPLError(CE_Failure, CPLE_AppDefined,
     357             :                  "In Initialize(): sqlite3_step(%s):\n  %s", pszSQLConst,
     358             :                  sqlite3_errmsg(hDB));
     359         102 :         sqlite3_finalize(hColStmt);
     360         102 :         return CE_Failure;
     361             :     }
     362             : 
     363             :     /* -------------------------------------------------------------------- */
     364             :     /*      What should we use as FID?  If there is a primary key           */
     365             :     /*      integer field, then this will be used as the _rowid_, and we    */
     366             :     /*      will pick up the real column name here.                         */
     367             :     /*                                                                      */
     368             :     /*      Note that the select _rowid_ will return the real column        */
     369             :     /*      name if the rowid corresponds to another primary key            */
     370             :     /*      column.                                                         */
     371             :     /* -------------------------------------------------------------------- */
     372         689 :     if (bHasRowId)
     373             :     {
     374         687 :         CPLFree(m_pszFIDColumn);
     375         687 :         m_pszFIDColumn =
     376         687 :             CPLStrdup(SQLUnescape(sqlite3_column_name(hColStmt, 0)));
     377             :     }
     378             : 
     379             :     /* -------------------------------------------------------------------- */
     380             :     /*      Collect the rest of the fields.                                 */
     381             :     /* -------------------------------------------------------------------- */
     382         689 :     if (pszGeomCol)
     383             :     {
     384         598 :         std::set<CPLString> aosGeomCols;
     385         299 :         aosGeomCols.insert(pszGeomCol);
     386             :         std::set<CPLString> aosIgnoredCols(
     387         598 :             m_poDS->GetGeomColsForTable(m_pszTableName));
     388         299 :         aosIgnoredCols.erase(pszGeomCol);
     389         299 :         BuildFeatureDefn(GetDescription(), false, hColStmt, &aosGeomCols,
     390             :                          aosIgnoredCols);
     391             :     }
     392             :     else
     393             :     {
     394         780 :         std::set<CPLString> aosIgnoredCols;
     395             :         const std::set<CPLString> &aosGeomCols(
     396         390 :             m_poDS->GetGeomColsForTable(m_pszTableName));
     397         390 :         BuildFeatureDefn(GetDescription(), false, hColStmt,
     398         390 :                          (m_bIsVirtualShape) ? nullptr : &aosGeomCols,
     399             :                          aosIgnoredCols);
     400             :     }
     401         689 :     sqlite3_finalize(hColStmt);
     402             : 
     403             :     /* -------------------------------------------------------------------- */
     404             :     /*      Set the properties of the geometry column.                      */
     405             :     /* -------------------------------------------------------------------- */
     406         689 :     bool bHasSpatialiteCol = false;
     407         950 :     for (int i = 0; i < m_poFeatureDefn->GetGeomFieldCount(); i++)
     408             :     {
     409             :         OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
     410         261 :             m_poFeatureDefn->myGetGeomFieldDefn(i);
     411         261 :         poGeomFieldDefn->m_nSRSId = m_poDS->GetUndefinedSRID();
     412             : 
     413         261 :         if (m_poDS->IsSpatialiteDB())
     414             :         {
     415         144 :             if (m_poDS->HasSpatialite4Layout())
     416             :             {
     417         141 :                 pszSQLConst = CPLSPrintf(
     418             :                     "SELECT srid, geometry_type, coord_dimension, "
     419             :                     "spatial_index_enabled FROM geometry_columns WHERE "
     420             :                     "lower(f_table_name) = lower('%s') AND "
     421             :                     "lower(f_geometry_column) = lower('%s')",
     422             :                     m_pszEscapedTableName,
     423         282 :                     SQLEscapeLiteral(poGeomFieldDefn->GetNameRef()).c_str());
     424             :             }
     425             :             else
     426             :             {
     427           3 :                 pszSQLConst = CPLSPrintf(
     428             :                     "SELECT srid, type, coord_dimension, spatial_index_enabled "
     429             :                     "FROM geometry_columns WHERE lower(f_table_name) = "
     430             :                     "lower('%s') AND lower(f_geometry_column) = lower('%s')",
     431             :                     m_pszEscapedTableName,
     432           6 :                     SQLEscapeLiteral(poGeomFieldDefn->GetNameRef()).c_str());
     433             :             }
     434             :         }
     435             :         else
     436             :         {
     437         117 :             pszSQLConst = CPLSPrintf(
     438             :                 "SELECT srid, geometry_type, coord_dimension, geometry_format "
     439             :                 "FROM geometry_columns WHERE lower(f_table_name) = lower('%s') "
     440             :                 "AND lower(f_geometry_column) = lower('%s')",
     441             :                 m_pszEscapedTableName,
     442         234 :                 SQLEscapeLiteral(poGeomFieldDefn->GetNameRef()).c_str());
     443             :         }
     444         261 :         char *pszErrMsg = nullptr;
     445         261 :         int nRowCount = 0, nColCount = 0;
     446         261 :         char **papszResult = nullptr;
     447         261 :         rc = sqlite3_get_table(hDB, pszSQLConst, &papszResult, &nRowCount,
     448             :                                &nColCount, &pszErrMsg);
     449         261 :         OGRwkbGeometryType eGeomType = wkbUnknown;
     450         261 :         OGRSQLiteGeomFormat eGeomFormat = OSGF_Unknown;
     451         261 :         if (rc == SQLITE_OK && nRowCount == 1)
     452             :         {
     453         258 :             char **papszRow = papszResult + nColCount;
     454         258 :             if (papszRow[1] == nullptr || papszRow[2] == nullptr)
     455             :             {
     456           0 :                 CPLDebug("SQLite", "Did not get expected col value");
     457           0 :                 sqlite3_free_table(papszResult);
     458           0 :                 continue;
     459             :             }
     460         258 :             if (papszRow[0] != nullptr)
     461         160 :                 poGeomFieldDefn->m_nSRSId = atoi(papszRow[0]);
     462         258 :             if (m_poDS->IsSpatialiteDB())
     463             :             {
     464         141 :                 if (papszRow[3] != nullptr)
     465         141 :                     poGeomFieldDefn->m_bHasSpatialIndex =
     466         141 :                         atoi(papszRow[3]) != 0;
     467         141 :                 if (m_poDS->HasSpatialite4Layout())
     468             :                 {
     469         138 :                     int nGeomType = atoi(papszRow[1]);
     470             : 
     471         138 :                     if (nGeomType >= static_cast<int>(wkbPoint) &&
     472             :                         nGeomType <=
     473             :                             static_cast<int>(wkbGeometryCollection)) /* XY */
     474          66 :                         eGeomType = static_cast<OGRwkbGeometryType>(nGeomType);
     475          72 :                     else if (nGeomType >= 1000 && nGeomType <= 1007) /* XYZ */
     476          29 :                         eGeomType = wkbSetZ(wkbFlatten(nGeomType));
     477          43 :                     else if (nGeomType >= 2000 && nGeomType <= 2007) /* XYM */
     478          16 :                         eGeomType = wkbSetM(wkbFlatten(nGeomType));
     479          27 :                     else if (nGeomType >= 3000 && nGeomType <= 3007) /* XYZM */
     480          16 :                         eGeomType = wkbSetM(wkbSetZ(wkbFlatten(nGeomType)));
     481             :                 }
     482             :                 else
     483             :                 {
     484           3 :                     eGeomType = OGRFromOGCGeomType(papszRow[1]);
     485             : 
     486           3 :                     if (strcmp(papszRow[2], "XYZ") == 0 ||
     487           3 :                         strcmp(papszRow[2], "3") ==
     488             :                             0)  // SpatiaLite's own 3D geometries
     489           0 :                         eGeomType = wkbSetZ(eGeomType);
     490           3 :                     else if (strcmp(papszRow[2], "XYM") == 0)
     491           0 :                         eGeomType = wkbSetM(eGeomType);
     492           3 :                     else if (strcmp(papszRow[2], "XYZM") ==
     493             :                              0)  // M coordinate declared
     494           0 :                         eGeomType = wkbSetM(wkbSetZ(eGeomType));
     495             :                 }
     496         141 :                 eGeomFormat = OSGF_SpatiaLite;
     497             :             }
     498             :             else
     499             :             {
     500         117 :                 eGeomType = static_cast<OGRwkbGeometryType>(atoi(papszRow[1]));
     501         117 :                 if (atoi(papszRow[2]) > 2)
     502           7 :                     eGeomType = wkbSetZ(eGeomType);
     503         117 :                 eGeomFormat = GetGeomFormat(papszRow[3]);
     504             :             }
     505             :         }
     506         261 :         sqlite3_free_table(papszResult);
     507         261 :         sqlite3_free(pszErrMsg);
     508             : 
     509         261 :         poGeomFieldDefn->m_eGeomFormat = eGeomFormat;
     510         261 :         poGeomFieldDefn->SetType(eGeomType);
     511         522 :         poGeomFieldDefn->SetSpatialRef(
     512         261 :             m_poDS->FetchSRS(poGeomFieldDefn->m_nSRSId));
     513             : 
     514             :         // cppcheck-suppress knownConditionTrueFalse
     515         261 :         if (eGeomFormat == OSGF_SpatiaLite)
     516         142 :             bHasSpatialiteCol = true;
     517             :     }
     518             : 
     519         280 :     if (bHasSpatialiteCol && m_poDS->IsSpatialiteLoaded() &&
     520         140 :         m_poDS->GetSpatialiteVersionNumber() <
     521         969 :             OGRSQLiteDataSource::MakeSpatialiteVersionNumber(2, 4, 0) &&
     522           0 :         m_poDS->GetUpdate())
     523             :     {
     524             :         // we need to test version required by Spatialite TRIGGERs
     525             :         // hColStmt = NULL;
     526             :         pszSQLConst =
     527           0 :             CPLSPrintf("SELECT sql FROM sqlite_master WHERE type = 'trigger' "
     528             :                        "AND tbl_name = '%s' AND sql LIKE '%%RTreeAlign%%'",
     529             :                        m_pszEscapedTableName);
     530             : 
     531             :         int nRowTriggerCount, nColTriggerCount;
     532             :         char **papszTriggerResult, *pszErrMsg;
     533             : 
     534           0 :         /* rc = */ sqlite3_get_table(hDB, pszSQLConst, &papszTriggerResult,
     535             :                                      &nRowTriggerCount, &nColTriggerCount,
     536             :                                      &pszErrMsg);
     537           0 :         if (nRowTriggerCount >= 1)
     538             :         {
     539             :             // obsolete library version not supporting new triggers
     540             :             // enforcing ReadOnly mode
     541           0 :             CPLDebug("SQLITE", "Enforcing ReadOnly mode : obsolete library "
     542             :                                "version not supporting new triggers");
     543           0 :             m_poDS->DisableUpdate();
     544             :         }
     545             : 
     546           0 :         sqlite3_free_table(papszTriggerResult);
     547             :     }
     548             :     /* -------------------------------------------------------------------- */
     549             :     /*      Check if there are default values and nullable status           */
     550             :     /* -------------------------------------------------------------------- */
     551             : 
     552         689 :     char **papszResult = nullptr;
     553         689 :     int nRowCount = 0;
     554         689 :     int nColCount = 0;
     555         689 :     char *pszErrMsg = nullptr;
     556             :     /*  #|name|type|notnull|default|pk */
     557         689 :     char *pszSQL = sqlite3_mprintf("PRAGMA table_info('%q')", m_pszTableName);
     558         689 :     rc = sqlite3_get_table(hDB, pszSQL, &papszResult, &nRowCount, &nColCount,
     559             :                            &pszErrMsg);
     560         689 :     sqlite3_free(pszSQL);
     561         689 :     if (rc != SQLITE_OK)
     562             :     {
     563           0 :         sqlite3_free(pszErrMsg);
     564             :     }
     565             :     else
     566             :     {
     567         689 :         if (nColCount == 6)
     568             :         {
     569             :             const std::set<std::string> uniqueFieldsUC(
     570        1378 :                 SQLGetUniqueFieldUCConstraints(hDB, m_pszTableName));
     571             : 
     572         689 :             const int nFieldCount = m_poFeatureDefn->GetFieldCount();
     573        1378 :             std::map<std::string, int> oMapNametoIdx;
     574        2122 :             for (int i = 0; i < nFieldCount; ++i)
     575        1433 :                 oMapNametoIdx[m_poFeatureDefn->GetFieldDefnUnsafe(i)
     576        1433 :                                   ->GetNameRef()] = i;
     577             : 
     578        3063 :             for (int i = 0; i < nRowCount; i++)
     579             :             {
     580        2374 :                 const char *pszName = papszResult[(i + 1) * 6 + 1];
     581        2374 :                 if (!pszName)
     582           0 :                     continue;  // should normally never happen
     583        2374 :                 const char *pszNotNull = papszResult[(i + 1) * 6 + 3];
     584        2374 :                 const char *pszDefault = papszResult[(i + 1) * 6 + 4];
     585        2374 :                 int idx = -1;
     586        2374 :                 const auto oIter = oMapNametoIdx.find(pszName);
     587        2374 :                 if (oIter != oMapNametoIdx.end())
     588        1433 :                     idx = oIter->second;
     589        2374 :                 if (pszDefault != nullptr)
     590             :                 {
     591          18 :                     if (idx >= 0)
     592             :                     {
     593             :                         OGRFieldDefn *poFieldDefn =
     594          17 :                             m_poFeatureDefn->GetFieldDefnUnsafe(idx);
     595          17 :                         if (poFieldDefn->GetType() == OFTString &&
     596           3 :                             !EQUAL(pszDefault, "NULL") &&
     597           3 :                             !STARTS_WITH_CI(pszDefault, "CURRENT_") &&
     598          20 :                             pszDefault[0] != '(' && pszDefault[0] != '\'' &&
     599           0 :                             CPLGetValueType(pszDefault) == CPL_VALUE_STRING)
     600             :                         {
     601           0 :                             CPLString osDefault("'");
     602             :                             char *pszTmp =
     603           0 :                                 CPLEscapeString(pszDefault, -1, CPLES_SQL);
     604           0 :                             osDefault += pszTmp;
     605           0 :                             CPLFree(pszTmp);
     606           0 :                             osDefault += "'";
     607           0 :                             poFieldDefn->SetDefault(osDefault);
     608             :                         }
     609          32 :                         else if ((poFieldDefn->GetType() == OFTDate ||
     610          15 :                                   poFieldDefn->GetType() == OFTDateTime) &&
     611           9 :                                  !EQUAL(pszDefault, "NULL") &&
     612           9 :                                  !STARTS_WITH_CI(pszDefault, "CURRENT_") &&
     613           5 :                                  pszDefault[0] != '(' &&
     614           5 :                                  pszDefault[0] != '\'' &&
     615           1 :                                  !(pszDefault[0] >= '0' &&
     616          35 :                                    pszDefault[0] <= '9') &&
     617           1 :                                  CPLGetValueType(pszDefault) ==
     618             :                                      CPL_VALUE_STRING)
     619             :                         {
     620           2 :                             CPLString osDefault("(");
     621           1 :                             osDefault += pszDefault;
     622           1 :                             osDefault += ")";
     623           1 :                             poFieldDefn->SetDefault(osDefault);
     624             :                         }
     625             :                         else
     626          16 :                             poFieldDefn->SetDefault(pszDefault);
     627             :                     }
     628             :                 }
     629        2374 :                 if (pszNotNull != nullptr && EQUAL(pszNotNull, "1"))
     630             :                 {
     631          55 :                     if (idx >= 0)
     632          51 :                         m_poFeatureDefn->GetFieldDefnUnsafe(idx)->SetNullable(
     633             :                             0);
     634             :                     else
     635             :                     {
     636             :                         const int geomFieldIdx =
     637           4 :                             m_poFeatureDefn->GetGeomFieldIndex(pszName);
     638           4 :                         if (geomFieldIdx >= 0)
     639           3 :                             m_poFeatureDefn->GetGeomFieldDefn(geomFieldIdx)
     640           3 :                                 ->SetNullable(0);
     641             :                     }
     642             :                 }
     643        3807 :                 if (idx >= 0 &&
     644        3807 :                     uniqueFieldsUC.find(CPLString(pszName).toupper()) !=
     645        3807 :                         uniqueFieldsUC.end())
     646             :                 {
     647           9 :                     m_poFeatureDefn->GetFieldDefnUnsafe(idx)->SetUnique(TRUE);
     648             :                 }
     649             :             }
     650             :         }
     651         689 :         sqlite3_free_table(papszResult);
     652             :     }
     653             : 
     654         689 :     nRowCount = 0;
     655         689 :     nColCount = 0;
     656         689 :     papszResult = nullptr;
     657             : 
     658         689 :     pszSQL = sqlite3_mprintf(
     659             :         "SELECT sql FROM sqlite_master WHERE type='table' AND name='%q'",
     660             :         m_pszTableName);
     661         689 :     rc = sqlite3_get_table(hDB, pszSQL, &papszResult, &nRowCount, &nColCount,
     662             :                            nullptr);
     663         689 :     sqlite3_free(pszSQL);
     664         689 :     if (rc == SQLITE_OK && nRowCount == 1 && nColCount == 1)
     665             :     {
     666         688 :         const char *pszCreateTableSQL = papszResult[1];
     667         688 :         const char *pszLastParenthesis = strrchr(pszCreateTableSQL, ')');
     668         688 :         if (pszLastParenthesis)
     669             :         {
     670         688 :             m_bStrict = CPLString(pszLastParenthesis + 1).ifind("STRICT") !=
     671             :                         std::string::npos;
     672             : #ifdef DEBUG_VERBOSE
     673             :             if (m_bStrict)
     674             :                 CPLDebug("SQLite", "Table %s has STRICT mode", m_pszTableName);
     675             : #endif
     676             :         }
     677             : 
     678         688 :         const int nFieldCount = m_poFeatureDefn->GetFieldCount();
     679        2120 :         for (int i = 0; i < nFieldCount; ++i)
     680             :         {
     681        1432 :             auto poFieldDefn = m_poFeatureDefn->GetFieldDefn(i);
     682        1432 :             if (poFieldDefn->GetType() == OFTInteger)
     683             :             {
     684             :                 // In strict mode, the number of allowed types is severely
     685             :                 // restricted, so interpret INTEGER as Int64 by default, unless
     686             :                 // a check constraint makes it clear it is Int32
     687         178 :                 if (m_bStrict)
     688           4 :                     poFieldDefn->SetType(OFTInteger64);
     689         178 :                 if (strstr(pszCreateTableSQL,
     690           0 :                            ("CHECK (\"" +
     691         356 :                             CPLString(poFieldDefn->GetNameRef())
     692         356 :                                 .replaceAll('"', "\"\"") +
     693             :                             "\" BETWEEN -2147483648 AND 2147483647)")
     694         178 :                                .c_str()))
     695             :                 {
     696           2 :                     poFieldDefn->SetType(OFTInteger);
     697             :                 }
     698         176 :                 else if (strstr(pszCreateTableSQL,
     699           0 :                                 ("CHECK (\"" +
     700         352 :                                  CPLString(poFieldDefn->GetNameRef())
     701         352 :                                      .replaceAll('"', "\"\"") +
     702             :                                  "\" BETWEEN -9223372036854775808 AND "
     703             :                                  "9223372036854775807)")
     704         176 :                                     .c_str()))
     705             :                 {
     706           2 :                     poFieldDefn->SetType(OFTInteger64);
     707             :                 }
     708             :             }
     709        1254 :             else if (poFieldDefn->GetType() == OFTString)
     710             :             {
     711         757 :                 if (strstr(pszCreateTableSQL,
     712           0 :                            ("CHECK (\"" +
     713        1514 :                             CPLString(poFieldDefn->GetNameRef())
     714        1514 :                                 .replaceAll('"', "\"\"") +
     715             :                             "\" LIKE "
     716             :                             "'[0-9][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9]T[0-2]["
     717             :                             "0-9]:[0-5][0-9]:[0-6][0-9]*')")
     718         757 :                                .c_str()))
     719             :                 {
     720           1 :                     poFieldDefn->SetType(OFTDateTime);
     721             :                 }
     722         756 :                 else if (strstr(
     723             :                              pszCreateTableSQL,
     724           0 :                              ("CHECK (\"" +
     725        1512 :                               CPLString(poFieldDefn->GetNameRef())
     726        1512 :                                   .replaceAll('"', "\"\"") +
     727             :                               "\" LIKE "
     728             :                               "'[0-9][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9]T')")
     729         756 :                                  .c_str()))
     730             :                 {
     731           1 :                     poFieldDefn->SetType(OFTDate);
     732             :                 }
     733         755 :                 else if (strstr(pszCreateTableSQL,
     734           0 :                                 ("CHECK (\"" +
     735        1510 :                                  CPLString(poFieldDefn->GetNameRef())
     736        1510 :                                      .replaceAll('"', "\"\"") +
     737             :                                  "\" LIKE '[0-2][0-9]:[0-5][0-9]:[0-6][0-9]*')")
     738         755 :                                     .c_str()))
     739             :                 {
     740           1 :                     poFieldDefn->SetType(OFTTime);
     741             :                 }
     742             :             }
     743             :         }
     744             :     }
     745         689 :     sqlite3_free_table(papszResult);
     746             : 
     747         689 :     return CE_None;
     748             : }
     749             : 
     750             : /************************************************************************/
     751             : /*                         RecomputeOrdinals()                          */
     752             : /************************************************************************/
     753             : 
     754         636 : OGRErr OGRSQLiteTableLayer::RecomputeOrdinals()
     755             : {
     756         636 :     sqlite3 *hDB = m_poDS->GetDB();
     757         636 :     sqlite3_stmt *hColStmt = nullptr;
     758             :     /* -------------------------------------------------------------------- */
     759             :     /*      Get the column definitions for this table.                      */
     760             :     /* -------------------------------------------------------------------- */
     761             : 
     762         636 :     const char *pszSQL = CPLSPrintf(
     763             :         "SELECT %s* FROM '%s' LIMIT 1",
     764         636 :         m_pszFIDColumn != nullptr ? "_rowid_, " : "", m_pszEscapedTableName);
     765             : 
     766         636 :     int rc = sqlite3_prepare_v2(hDB, pszSQL, -1, &hColStmt, nullptr);
     767         636 :     if (rc != SQLITE_OK)
     768             :     {
     769           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     770             :                  "Unable to query table %s for column definitions : %s.",
     771             :                  m_pszTableName, sqlite3_errmsg(hDB));
     772             : 
     773           0 :         return OGRERR_FAILURE;
     774             :     }
     775             : 
     776         636 :     rc = sqlite3_step(hColStmt);
     777         636 :     if (rc != SQLITE_DONE && rc != SQLITE_ROW)
     778             :     {
     779           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     780             :                  "In Initialize(): sqlite3_step(%s):\n  %s", pszSQL,
     781             :                  sqlite3_errmsg(hDB));
     782           0 :         sqlite3_finalize(hColStmt);
     783           0 :         return OGRERR_FAILURE;
     784             :     }
     785             : 
     786         636 :     int nRawColumns = sqlite3_column_count(hColStmt);
     787             : 
     788         636 :     CPLFree(m_panFieldOrdinals);
     789         636 :     m_panFieldOrdinals = static_cast<int *>(
     790         636 :         CPLMalloc(sizeof(int) * m_poFeatureDefn->GetFieldCount()));
     791         636 :     int nCountFieldOrdinals = 0;
     792         636 :     int nCountGeomFieldOrdinals = 0;
     793         636 :     m_iFIDCol = -1;
     794             : 
     795        4144 :     for (int iCol = 0; iCol < nRawColumns; iCol++)
     796             :     {
     797        3508 :         CPLString osName = SQLUnescape(sqlite3_column_name(hColStmt, iCol));
     798        3508 :         int nIdx = m_poFeatureDefn->GetFieldIndex(osName);
     799        3508 :         if (m_pszFIDColumn != nullptr && strcmp(osName, m_pszFIDColumn) == 0)
     800             :         {
     801        1272 :             if (m_iFIDCol < 0)
     802             :             {
     803         636 :                 m_iFIDCol = iCol;
     804         636 :                 if (nIdx >=
     805             :                     0) /* in case it has also been created as a regular field */
     806           1 :                     nCountFieldOrdinals++;
     807             :             }
     808        1272 :             continue;
     809             :         }
     810        2236 :         if (nIdx >= 0)
     811             :         {
     812        1708 :             m_panFieldOrdinals[nIdx] = iCol;
     813        1708 :             nCountFieldOrdinals++;
     814             :         }
     815             :         else
     816             :         {
     817         528 :             nIdx = m_poFeatureDefn->GetGeomFieldIndex(osName);
     818         528 :             if (nIdx >= 0)
     819             :             {
     820             :                 OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
     821         528 :                     m_poFeatureDefn->myGetGeomFieldDefn(nIdx);
     822         528 :                 poGeomFieldDefn->m_iCol = iCol;
     823         528 :                 nCountGeomFieldOrdinals++;
     824             :             }
     825             :         }
     826             :     }
     827             :     (void)nCountFieldOrdinals;
     828         636 :     CPLAssert(nCountFieldOrdinals == m_poFeatureDefn->GetFieldCount());
     829             :     (void)nCountGeomFieldOrdinals;
     830         636 :     CPLAssert(nCountGeomFieldOrdinals == m_poFeatureDefn->GetGeomFieldCount());
     831         636 :     CPLAssert(m_pszFIDColumn == nullptr || m_iFIDCol >= 0);
     832             : 
     833         636 :     sqlite3_finalize(hColStmt);
     834             : 
     835         636 :     return OGRERR_NONE;
     836             : }
     837             : 
     838             : /************************************************************************/
     839             : /*                            GetLayerDefn()                            */
     840             : /************************************************************************/
     841             : 
     842       27806 : const OGRFeatureDefn *OGRSQLiteTableLayer::GetLayerDefn() const
     843             : {
     844       27806 :     if (!m_poFeatureDefn)
     845             :     {
     846         730 :         const_cast<OGRSQLiteTableLayer *>(this)->BuildLayerDefn();
     847             :     }
     848       27806 :     return m_poFeatureDefn;
     849             : }
     850             : 
     851             : /************************************************************************/
     852             : /*                           BuildLayerDefn()                           */
     853             : /************************************************************************/
     854             : 
     855         730 : void OGRSQLiteTableLayer::BuildLayerDefn()
     856             : {
     857         730 :     EstablishFeatureDefn(nullptr, /* bMayEmitError = */ true);
     858             : 
     859         730 :     if (m_poFeatureDefn == nullptr)
     860             :     {
     861         340 :         m_bLayerDefnError = true;
     862             : 
     863         340 :         m_poFeatureDefn = new OGRSQLiteFeatureDefn(GetDescription());
     864         340 :         m_poFeatureDefn->Reference();
     865             :     }
     866             :     else
     867         390 :         LoadStatistics();
     868             : 
     869         730 :     m_poFeatureDefn->Seal(/* bSealFields */ true);
     870         730 : }
     871             : 
     872             : /************************************************************************/
     873             : /*                           ResetStatement()                           */
     874             : /************************************************************************/
     875             : 
     876         886 : OGRErr OGRSQLiteTableLayer::ResetStatement()
     877             : 
     878             : {
     879        1772 :     CPLString osSQL;
     880             : 
     881         886 :     if (m_bDeferredCreation)
     882           0 :         RunDeferredCreationIfNecessary();
     883             : 
     884         886 :     ClearStatement();
     885             : 
     886         886 :     m_iNextShapeId = 0;
     887             : 
     888             :     osSQL.Printf("SELECT %s* FROM '%s' %s",
     889         886 :                  m_pszFIDColumn != nullptr ? "_rowid_, " : "",
     890         886 :                  m_pszEscapedTableName, m_osWHERE.c_str());
     891             : #ifdef DEBUG_VERBOSE
     892             :     CPLDebug("SQLite", "%s", osSQL.c_str());
     893             : #endif
     894             : 
     895             :     const int rc =
     896         886 :         sqlite3_prepare_v2(m_poDS->GetDB(), osSQL, -1, &m_hStmt, nullptr);
     897         886 :     if (rc == SQLITE_OK)
     898             :     {
     899         885 :         return OGRERR_NONE;
     900             :     }
     901             : 
     902           1 :     CPLError(CE_Failure, CPLE_AppDefined,
     903             :              "In ResetStatement(): sqlite3_prepare_v2(%s):\n  %s",
     904           1 :              osSQL.c_str(), sqlite3_errmsg(m_poDS->GetDB()));
     905           1 :     m_hStmt = nullptr;
     906           1 :     return OGRERR_FAILURE;
     907             : }
     908             : 
     909             : /************************************************************************/
     910             : /*                           GetNextFeature()                           */
     911             : /************************************************************************/
     912             : 
     913        3477 : OGRFeature *OGRSQLiteTableLayer::GetNextFeature()
     914             : 
     915             : {
     916        3477 :     if (m_bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE)
     917           0 :         return nullptr;
     918             : 
     919        3477 :     if (HasLayerDefnError())
     920           1 :         return nullptr;
     921             : 
     922        3476 :     OGRFeature *poFeature = OGRSQLiteLayer::GetNextFeature();
     923        3476 :     if (poFeature && m_iFIDAsRegularColumnIndex >= 0)
     924             :     {
     925           1 :         poFeature->SetField(m_iFIDAsRegularColumnIndex, poFeature->GetFID());
     926             :     }
     927        3476 :     return poFeature;
     928             : }
     929             : 
     930             : /************************************************************************/
     931             : /*                             GetFeature()                             */
     932             : /************************************************************************/
     933             : 
     934          66 : OGRFeature *OGRSQLiteTableLayer::GetFeature(GIntBig nFeatureId)
     935             : 
     936             : {
     937          66 :     if (m_bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE)
     938           0 :         return nullptr;
     939             : 
     940          66 :     if (HasLayerDefnError())
     941           0 :         return nullptr;
     942             : 
     943             :     /* -------------------------------------------------------------------- */
     944             :     /*      If we don't have an explicit FID column, just read through      */
     945             :     /*      the result set iteratively to find our target.                  */
     946             :     /* -------------------------------------------------------------------- */
     947          66 :     if (m_pszFIDColumn == nullptr)
     948           1 :         return OGRSQLiteLayer::GetFeature(nFeatureId);
     949             : 
     950             :     /* -------------------------------------------------------------------- */
     951             :     /*      Setup explicit query statement to fetch the record we want.     */
     952             :     /* -------------------------------------------------------------------- */
     953         130 :     CPLString osSQL;
     954             : 
     955          65 :     ClearStatement();
     956             : 
     957          65 :     m_iNextShapeId = nFeatureId;
     958             : 
     959             :     osSQL.Printf("SELECT _rowid_, * FROM '%s' WHERE \"%s\" = " CPL_FRMT_GIB,
     960             :                  m_pszEscapedTableName,
     961          65 :                  SQLEscapeLiteral(m_pszFIDColumn).c_str(), nFeatureId);
     962             : 
     963          65 :     CPLDebug("OGR_SQLITE", "exec(%s)", osSQL.c_str());
     964             : 
     965             :     const int rc =
     966          65 :         sqlite3_prepare_v2(m_poDS->GetDB(), osSQL,
     967          65 :                            static_cast<int>(osSQL.size()), &m_hStmt, nullptr);
     968          65 :     if (rc != SQLITE_OK)
     969             :     {
     970           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     971             :                  "In GetFeature(): sqlite3_prepare_v2(%s):\n  %s",
     972           0 :                  osSQL.c_str(), sqlite3_errmsg(m_poDS->GetDB()));
     973             : 
     974           0 :         return nullptr;
     975             :     }
     976             :     /* -------------------------------------------------------------------- */
     977             :     /*      Get the feature if possible.                                    */
     978             :     /* -------------------------------------------------------------------- */
     979          65 :     OGRFeature *poFeature = GetNextRawFeature();
     980             : 
     981          65 :     ResetReading();
     982             : 
     983          65 :     return poFeature;
     984             : }
     985             : 
     986             : /************************************************************************/
     987             : /*                         SetAttributeFilter()                         */
     988             : /************************************************************************/
     989             : 
     990         523 : OGRErr OGRSQLiteTableLayer::SetAttributeFilter(const char *pszQuery)
     991             : 
     992             : {
     993         523 :     CPLFree(m_pszAttrQueryString);
     994         523 :     m_pszAttrQueryString = (pszQuery) ? CPLStrdup(pszQuery) : nullptr;
     995             : 
     996         523 :     if (pszQuery == nullptr)
     997          60 :         m_osQuery = "";
     998             :     else
     999         463 :         m_osQuery = pszQuery;
    1000             : 
    1001         523 :     BuildWhere();
    1002             : 
    1003         523 :     ResetReading();
    1004             : 
    1005         523 :     return OGRERR_NONE;
    1006             : }
    1007             : 
    1008             : /************************************************************************/
    1009             : /*                         ISetSpatialFilter()                          */
    1010             : /************************************************************************/
    1011             : 
    1012          62 : OGRErr OGRSQLiteTableLayer::ISetSpatialFilter(int iGeomField,
    1013             :                                               const OGRGeometry *poGeomIn)
    1014             : 
    1015             : {
    1016          62 :     m_iGeomFieldFilter = iGeomField;
    1017          62 :     if (InstallFilter(poGeomIn))
    1018             :     {
    1019          31 :         BuildWhere();
    1020             : 
    1021          31 :         ResetReading();
    1022             :     }
    1023          62 :     return OGRERR_NONE;
    1024             : }
    1025             : 
    1026             : /************************************************************************/
    1027             : /*                       CheckSpatialIndexTable()                       */
    1028             : /************************************************************************/
    1029             : 
    1030         104 : bool OGRSQLiteTableLayer::CheckSpatialIndexTable(int iGeomCol)
    1031             : {
    1032         104 :     GetLayerDefn();
    1033         104 :     if (iGeomCol < 0 || iGeomCol >= m_poFeatureDefn->GetGeomFieldCount())
    1034           0 :         return false;
    1035             :     OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
    1036         104 :         m_poFeatureDefn->myGetGeomFieldDefn(iGeomCol);
    1037         203 :     if (HasSpatialIndex(iGeomCol) &&
    1038          99 :         !poGeomFieldDefn->m_bHasCheckedSpatialIndexTable)
    1039             :     {
    1040          10 :         poGeomFieldDefn->m_bHasCheckedSpatialIndexTable = true;
    1041          10 :         char **papszResult = nullptr;
    1042          10 :         int nRowCount = 0;
    1043          10 :         int nColCount = 0;
    1044          10 :         char *pszErrMsg = nullptr;
    1045             : 
    1046          20 :         CPLString osSQL;
    1047             : 
    1048             :         /* This will ensure that RTree support is available */
    1049             :         osSQL.Printf("SELECT pkid FROM 'idx_%s_%s' WHERE xmax > 0 AND xmin < 0 "
    1050             :                      "AND ymax > 0 AND ymin < 0",
    1051             :                      m_pszEscapedTableName,
    1052          10 :                      SQLEscapeLiteral(poGeomFieldDefn->GetNameRef()).c_str());
    1053             : 
    1054          10 :         int rc = sqlite3_get_table(m_poDS->GetDB(), osSQL.c_str(), &papszResult,
    1055             :                                    &nRowCount, &nColCount, &pszErrMsg);
    1056             : 
    1057          10 :         if (rc != SQLITE_OK)
    1058             :         {
    1059           0 :             CPLDebug("SQLITE",
    1060             :                      "Count not find or use idx_%s_%s layer (%s). Disabling "
    1061             :                      "spatial index",
    1062             :                      m_pszEscapedTableName, poGeomFieldDefn->GetNameRef(),
    1063             :                      pszErrMsg);
    1064           0 :             sqlite3_free(pszErrMsg);
    1065           0 :             poGeomFieldDefn->m_bHasSpatialIndex = false;
    1066             :         }
    1067             :         else
    1068             :         {
    1069          10 :             sqlite3_free_table(papszResult);
    1070             :         }
    1071             :     }
    1072             : 
    1073         104 :     return poGeomFieldDefn->m_bHasSpatialIndex;
    1074             : }
    1075             : 
    1076             : /************************************************************************/
    1077             : /*                        HasFastSpatialFilter()                        */
    1078             : /************************************************************************/
    1079             : 
    1080           8 : bool OGRSQLiteTableLayer::HasFastSpatialFilter(int iGeomCol)
    1081             : {
    1082          16 :     OGRPolygon oFakePoly;
    1083           8 :     const char *pszWKT = "POLYGON((0 0,0 1,1 1,1 0,0 0))";
    1084           8 :     oFakePoly.importFromWkt(&pszWKT);
    1085           8 :     CPLString osSpatialWhere = GetSpatialWhere(iGeomCol, &oFakePoly);
    1086          16 :     return osSpatialWhere.find("ROWID") == 0;
    1087             : }
    1088             : 
    1089             : /************************************************************************/
    1090             : /*                          GetSpatialWhere()                           */
    1091             : /************************************************************************/
    1092             : 
    1093         672 : CPLString OGRSQLiteTableLayer::GetSpatialWhere(int iGeomCol,
    1094             :                                                OGRGeometry *poFilterGeom)
    1095             : {
    1096         795 :     if (!m_poDS->IsSpatialiteDB() || iGeomCol < 0 ||
    1097         123 :         iGeomCol >= GetLayerDefn()->GetGeomFieldCount())
    1098         549 :         return "";
    1099             : 
    1100             :     OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
    1101         123 :         m_poFeatureDefn->myGetGeomFieldDefn(iGeomCol);
    1102         123 :     if (poFilterGeom != nullptr && CheckSpatialIndexTable(iGeomCol))
    1103             :     {
    1104             :         return FormatSpatialFilterFromRTree(
    1105          87 :             poFilterGeom, "ROWID", m_pszEscapedTableName,
    1106         174 :             SQLEscapeLiteral(poGeomFieldDefn->GetNameRef()).c_str());
    1107             :     }
    1108             : 
    1109          40 :     if (poFilterGeom != nullptr && m_poDS->IsSpatialiteLoaded() &&
    1110           4 :         !poGeomFieldDefn->m_bHasSpatialIndex)
    1111             :     {
    1112             :         return FormatSpatialFilterFromMBR(
    1113           8 :             poFilterGeom, SQLEscapeName(poGeomFieldDefn->GetNameRef()).c_str());
    1114             :     }
    1115             : 
    1116          32 :     return "";
    1117             : }
    1118             : 
    1119             : /************************************************************************/
    1120             : /*                             BuildWhere()                             */
    1121             : /*                                                                      */
    1122             : /*      Build the WHERE statement appropriate to the current set of     */
    1123             : /*      criteria (spatial and attribute queries).                       */
    1124             : /************************************************************************/
    1125             : 
    1126         554 : void OGRSQLiteTableLayer::BuildWhere()
    1127             : 
    1128             : {
    1129         554 :     m_osWHERE = "";
    1130             : 
    1131             :     CPLString osSpatialWHERE =
    1132        1108 :         GetSpatialWhere(m_iGeomFieldFilter, m_poFilterGeom);
    1133         554 :     if (!osSpatialWHERE.empty())
    1134             :     {
    1135          22 :         m_osWHERE = "WHERE ";
    1136          22 :         m_osWHERE += osSpatialWHERE;
    1137             :     }
    1138             : 
    1139         554 :     if (!m_osQuery.empty())
    1140             :     {
    1141         461 :         if (m_osWHERE.empty())
    1142             :         {
    1143         457 :             m_osWHERE = "WHERE ";
    1144         457 :             m_osWHERE += m_osQuery;
    1145             :         }
    1146             :         else
    1147             :         {
    1148           4 :             m_osWHERE += " AND (";
    1149           4 :             m_osWHERE += m_osQuery;
    1150           4 :             m_osWHERE += ")";
    1151             :         }
    1152             :     }
    1153         554 : }
    1154             : 
    1155             : /************************************************************************/
    1156             : /*                           TestCapability()                           */
    1157             : /************************************************************************/
    1158             : 
    1159        1388 : bool OGRSQLiteTableLayer::TestCapability(const char *pszCap) const
    1160             : 
    1161             : {
    1162        1388 :     if (EQUAL(pszCap, OLCFastFeatureCount))
    1163         101 :         return m_poFilterGeom == nullptr || HasSpatialIndex(0);
    1164             : 
    1165        1287 :     else if (EQUAL(pszCap, OLCFastSpatialFilter))
    1166           2 :         return HasSpatialIndex(0);
    1167             : 
    1168        1285 :     else if (EQUAL(pszCap, OLCFastGetExtent))
    1169             :     {
    1170          12 :         return GetLayerDefn()->GetGeomFieldCount() >= 1 &&
    1171          12 :                myGetLayerDefn()->myGetGeomFieldDefn(0)->m_bCachedExtentIsValid;
    1172             :     }
    1173             : 
    1174        1279 :     else if (EQUAL(pszCap, OLCRandomRead))
    1175           6 :         return m_pszFIDColumn != nullptr;
    1176             : 
    1177        1273 :     else if (EQUAL(pszCap, OLCSequentialWrite) || EQUAL(pszCap, OLCRandomWrite))
    1178             :     {
    1179          44 :         return m_poDS->GetUpdate();
    1180             :     }
    1181             : 
    1182        1229 :     else if (EQUAL(pszCap, OLCDeleteFeature))
    1183             :     {
    1184           6 :         return m_poDS->GetUpdate() && m_pszFIDColumn != nullptr;
    1185             :     }
    1186             : 
    1187        1223 :     else if (EQUAL(pszCap, OLCCreateField) || EQUAL(pszCap, OLCCreateGeomField))
    1188          38 :         return m_poDS->GetUpdate();
    1189             : 
    1190        1185 :     else if (EQUAL(pszCap, OLCDeleteField))
    1191           7 :         return m_poDS->GetUpdate();
    1192             : 
    1193        1178 :     else if (EQUAL(pszCap, OLCAlterFieldDefn))
    1194           7 :         return m_poDS->GetUpdate();
    1195             : 
    1196        1171 :     else if (EQUAL(pszCap, OLCReorderFields))
    1197           7 :         return m_poDS->GetUpdate();
    1198             : 
    1199        1164 :     else if (EQUAL(pszCap, OLCCurveGeometries))
    1200         513 :         return m_poDS->TestCapability(ODsCCurveGeometries);
    1201             : 
    1202         651 :     else if (EQUAL(pszCap, OLCMeasuredGeometries))
    1203         513 :         return m_poDS->TestCapability(ODsCMeasuredGeometries);
    1204             : 
    1205         138 :     else if (EQUAL(pszCap, OLCZGeometries))
    1206         114 :         return true;
    1207             : 
    1208             :     else
    1209          24 :         return OGRSQLiteLayer::TestCapability(pszCap);
    1210             : }
    1211             : 
    1212             : /************************************************************************/
    1213             : /*                          GetFeatureCount()                           */
    1214             : /************************************************************************/
    1215             : 
    1216          96 : GIntBig OGRSQLiteTableLayer::GetFeatureCount(int bForce)
    1217             : 
    1218             : {
    1219          96 :     if (HasLayerDefnError())
    1220           0 :         return 0;
    1221             : 
    1222          96 :     if (!TestCapability(OLCFastFeatureCount))
    1223           7 :         return OGRSQLiteLayer::GetFeatureCount(bForce);
    1224             : 
    1225          89 :     if (m_nFeatureCount >= 0 && m_poFilterGeom == nullptr && m_osQuery.empty())
    1226             :     {
    1227          45 :         return m_nFeatureCount;
    1228             :     }
    1229             : 
    1230             :     /* -------------------------------------------------------------------- */
    1231             :     /*      Form count SQL.                                                 */
    1232             :     /* -------------------------------------------------------------------- */
    1233          44 :     const char *pszSQL = nullptr;
    1234             : 
    1235          97 :     if (m_poFilterGeom != nullptr &&
    1236          44 :         CheckSpatialIndexTable(m_iGeomFieldFilter) && m_osQuery.empty())
    1237             :     {
    1238           5 :         OGREnvelope sEnvelope;
    1239             : 
    1240           5 :         m_poFilterGeom->getEnvelope(&sEnvelope);
    1241             :         const char *pszGeomCol =
    1242           5 :             m_poFeatureDefn->GetGeomFieldDefn(m_iGeomFieldFilter)->GetNameRef();
    1243           5 :         pszSQL = CPLSPrintf("SELECT count(*) FROM 'idx_%s_%s' WHERE "
    1244             :                             "xmax >= %.12f AND xmin <= %.12f AND ymax >= %.12f "
    1245             :                             "AND ymin <= %.12f",
    1246             :                             m_pszEscapedTableName,
    1247           5 :                             SQLEscapeLiteral(pszGeomCol).c_str(),
    1248           5 :                             sEnvelope.MinX - 1e-11, sEnvelope.MaxX + 1e-11,
    1249           5 :                             sEnvelope.MinY - 1e-11, sEnvelope.MaxY + 1e-11);
    1250             :     }
    1251             :     else
    1252             :     {
    1253          39 :         pszSQL = CPLSPrintf("SELECT count(*) FROM '%s' %s",
    1254             :                             m_pszEscapedTableName, m_osWHERE.c_str());
    1255             :     }
    1256             : 
    1257          44 :     CPLDebug("SQLITE", "Running %s", pszSQL);
    1258             : 
    1259             :     /* -------------------------------------------------------------------- */
    1260             :     /*      Execute.                                                        */
    1261             :     /* -------------------------------------------------------------------- */
    1262          44 :     OGRErr eErr = OGRERR_NONE;
    1263          44 :     GIntBig nResult = SQLGetInteger64(m_poDS->GetDB(), pszSQL, &eErr);
    1264          44 :     if (eErr == OGRERR_FAILURE)
    1265             :     {
    1266           0 :         nResult = -1;
    1267             :     }
    1268             :     else
    1269             :     {
    1270          44 :         if (m_poFilterGeom == nullptr && m_osQuery.empty())
    1271             :         {
    1272          28 :             m_nFeatureCount = nResult;
    1273          28 :             if (m_poDS->GetUpdate())
    1274          12 :                 ForceStatisticsToBeFlushed();
    1275             :         }
    1276             :     }
    1277             : 
    1278          44 :     return nResult;
    1279             : }
    1280             : 
    1281             : /************************************************************************/
    1282             : /*                             IGetExtent()                             */
    1283             : /************************************************************************/
    1284             : 
    1285          20 : OGRErr OGRSQLiteTableLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent,
    1286             :                                        bool bForce)
    1287             : {
    1288          20 :     if (HasLayerDefnError())
    1289           0 :         return OGRERR_FAILURE;
    1290             : 
    1291             :     OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
    1292          20 :         m_poFeatureDefn->myGetGeomFieldDefn(iGeomField);
    1293          20 :     if (poGeomFieldDefn->m_bCachedExtentIsValid)
    1294             :     {
    1295          16 :         *psExtent = poGeomFieldDefn->m_oCachedExtent;
    1296          16 :         return OGRERR_NONE;
    1297             :     }
    1298             : 
    1299           7 :     if (CheckSpatialIndexTable(iGeomField) &&
    1300           3 :         !CPLTestBool(CPLGetConfigOption("OGR_SQLITE_EXACT_EXTENT", "NO")))
    1301             :     {
    1302             :         const char *pszSQL =
    1303           3 :             CPLSPrintf("SELECT MIN(xmin), MIN(ymin), "
    1304             :                        "MAX(xmax), MAX(ymax) FROM 'idx_%s_%s'",
    1305             :                        m_pszEscapedTableName,
    1306           6 :                        SQLEscapeLiteral(poGeomFieldDefn->GetNameRef()).c_str());
    1307             : 
    1308           3 :         CPLDebug("SQLITE", "Running %s", pszSQL);
    1309             : 
    1310             :         /* --------------------------------------------------------------------
    1311             :          */
    1312             :         /*      Execute. */
    1313             :         /* --------------------------------------------------------------------
    1314             :          */
    1315           3 :         char **papszResult = nullptr;
    1316             :         char *pszErrMsg;
    1317           3 :         int nRowCount = 0;
    1318           3 :         int nColCount = 0;
    1319             : 
    1320           3 :         if (sqlite3_get_table(m_poDS->GetDB(), pszSQL, &papszResult, &nRowCount,
    1321           3 :                               &nColCount, &pszErrMsg) != SQLITE_OK)
    1322           3 :             return OGRSQLiteLayer::IGetExtent(iGeomField, psExtent, bForce);
    1323             : 
    1324           3 :         OGRErr eErr = OGRERR_FAILURE;
    1325             : 
    1326           3 :         if (nRowCount == 1 && nColCount == 4 && papszResult[4 + 0] != nullptr &&
    1327           3 :             papszResult[4 + 1] != nullptr && papszResult[4 + 2] != nullptr &&
    1328           3 :             papszResult[4 + 3] != nullptr)
    1329             :         {
    1330           3 :             psExtent->MinX = CPLAtof(papszResult[4 + 0]);
    1331           3 :             psExtent->MinY = CPLAtof(papszResult[4 + 1]);
    1332           3 :             psExtent->MaxX = CPLAtof(papszResult[4 + 2]);
    1333           3 :             psExtent->MaxY = CPLAtof(papszResult[4 + 3]);
    1334           3 :             eErr = OGRERR_NONE;
    1335             : 
    1336           3 :             if (m_poFilterGeom == nullptr && m_osQuery.empty())
    1337             :             {
    1338           3 :                 poGeomFieldDefn->m_bCachedExtentIsValid = true;
    1339           3 :                 if (m_poDS->GetUpdate())
    1340           1 :                     ForceStatisticsToBeFlushed();
    1341           3 :                 poGeomFieldDefn->m_oCachedExtent = *psExtent;
    1342             :             }
    1343             :         }
    1344             : 
    1345           3 :         sqlite3_free_table(papszResult);
    1346             : 
    1347           3 :         if (eErr == OGRERR_NONE)
    1348           3 :             return eErr;
    1349             :     }
    1350             : 
    1351           1 :     OGRErr eErr = OGRSQLiteLayer::IGetExtent(iGeomField, psExtent, bForce);
    1352           1 :     if (eErr == OGRERR_NONE && m_poFilterGeom == nullptr && m_osQuery.empty())
    1353             :     {
    1354           1 :         poGeomFieldDefn->m_bCachedExtentIsValid = true;
    1355           1 :         ForceStatisticsToBeFlushed();
    1356           1 :         poGeomFieldDefn->m_oCachedExtent = *psExtent;
    1357             :     }
    1358           1 :     return eErr;
    1359             : }
    1360             : 
    1361             : /************************************************************************/
    1362             : /*                OGRSQLiteFieldDefnToSQliteFieldDefn()                 */
    1363             : /************************************************************************/
    1364             : 
    1365        5421 : CPLString OGRSQLiteFieldDefnToSQliteFieldDefn(const OGRFieldDefn *poFieldDefn,
    1366             :                                               bool bSQLiteDialectInternalUse,
    1367             :                                               bool bStrict)
    1368             : {
    1369        5421 :     if (bStrict)
    1370             :     {
    1371           8 :         switch (poFieldDefn->GetType())
    1372             :         {
    1373           1 :             case OFTInteger:
    1374           0 :                 return "INTEGER CHECK (\"" +
    1375           2 :                        CPLString(poFieldDefn->GetNameRef())
    1376           2 :                            .replaceAll('"', "\"\"") +
    1377           1 :                        "\" BETWEEN -2147483648 AND 2147483647)";
    1378           1 :             case OFTInteger64:
    1379           0 :                 return "INTEGER CHECK (\"" +
    1380           2 :                        CPLString(poFieldDefn->GetNameRef())
    1381           2 :                            .replaceAll('"', "\"\"") +
    1382             :                        "\" BETWEEN -9223372036854775808 AND "
    1383           1 :                        "9223372036854775807)";
    1384           1 :             case OFTReal:
    1385           1 :                 return "REAL";
    1386           1 :             case OFTBinary:
    1387           1 :                 return "BLOB";
    1388           1 :             case OFTDateTime:
    1389           0 :                 return "TEXT CHECK (\"" +
    1390           2 :                        CPLString(poFieldDefn->GetNameRef())
    1391           2 :                            .replaceAll('"', "\"\"") +
    1392             :                        "\" LIKE "
    1393             :                        "'[0-9][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9]T[0-2][0-9]:"
    1394           1 :                        "[0-5][0-9]:[0-6][0-9]*')";
    1395           1 :             case OFTDate:
    1396           0 :                 return "TEXT CHECK (\"" +
    1397           2 :                        CPLString(poFieldDefn->GetNameRef())
    1398           2 :                            .replaceAll('"', "\"\"") +
    1399           1 :                        "\" LIKE '[0-9][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9]T')";
    1400           1 :             case OFTTime:
    1401           0 :                 return "TEXT CHECK (\"" +
    1402           2 :                        CPLString(poFieldDefn->GetNameRef())
    1403           2 :                            .replaceAll('"', "\"\"") +
    1404           1 :                        "\" LIKE '[0-2][0-9]:[0-5][0-9]:[0-6][0-9]*')";
    1405           1 :             default:
    1406           1 :                 return "TEXT";
    1407             :         }
    1408             :     }
    1409             : 
    1410        5413 :     switch (poFieldDefn->GetType())
    1411             :     {
    1412        1159 :         case OFTInteger:
    1413             :         {
    1414        1159 :             if (poFieldDefn->GetSubType() == OFSTBoolean)
    1415         245 :                 return "INTEGER_BOOLEAN";
    1416         914 :             else if (poFieldDefn->GetSubType() == OFSTInt16)
    1417         213 :                 return "INTEGER_INT16";
    1418         701 :             return "INTEGER";
    1419             :         }
    1420         275 :         case OFTInteger64:
    1421         275 :             return "BIGINT";
    1422         609 :         case OFTReal:
    1423             :         {
    1424        1120 :             if (bSQLiteDialectInternalUse &&
    1425         511 :                 poFieldDefn->GetSubType() == OFSTFloat32)
    1426         210 :                 return "FLOAT_FLOAT32";
    1427         399 :             return "FLOAT";
    1428             :         }
    1429         237 :         case OFTBinary:
    1430         237 :             return "BLOB";
    1431             : 
    1432        1407 :         case OFTString:
    1433             :         {
    1434        1407 :             if (poFieldDefn->GetWidth() > 0)
    1435          73 :                 return CPLSPrintf("VARCHAR(%d)", poFieldDefn->GetWidth());
    1436        1334 :             return "VARCHAR";
    1437             :         }
    1438         352 :         case OFTDateTime:
    1439         352 :             return "TIMESTAMP";
    1440             : 
    1441         251 :         case OFTDate:
    1442         251 :             return "DATE";
    1443             : 
    1444         219 :         case OFTTime:
    1445         219 :             return "TIME";
    1446             : 
    1447         231 :         case OFTIntegerList:
    1448         231 :             return "JSONINTEGERLIST";
    1449             : 
    1450         219 :         case OFTInteger64List:
    1451         219 :             return "JSONINTEGER64LIST";
    1452             : 
    1453         222 :         case OFTRealList:
    1454         222 :             return "JSONREALLIST";
    1455             : 
    1456         232 :         case OFTStringList:
    1457         232 :             return "JSONSTRINGLIST";
    1458             : 
    1459           0 :         default:
    1460           0 :             break;
    1461             :     }
    1462           0 :     return "VARCHAR";
    1463             : }
    1464             : 
    1465             : /************************************************************************/
    1466             : /*                     FieldDefnToSQliteFieldDefn()                     */
    1467             : /************************************************************************/
    1468             : 
    1469             : CPLString
    1470        1359 : OGRSQLiteTableLayer::FieldDefnToSQliteFieldDefn(OGRFieldDefn *poFieldDefn)
    1471             : {
    1472             :     CPLString osRet =
    1473        1359 :         OGRSQLiteFieldDefnToSQliteFieldDefn(poFieldDefn, false, m_bStrict);
    1474        2175 :     if (!m_bStrict && poFieldDefn->GetType() == OFTString &&
    1475         816 :         CSLFindString(m_papszCompressedColumns, poFieldDefn->GetNameRef()) >= 0)
    1476           8 :         osRet += "_deflate";
    1477             : 
    1478        1359 :     return osRet;
    1479             : }
    1480             : 
    1481             : /************************************************************************/
    1482             : /*                            CreateField()                             */
    1483             : /************************************************************************/
    1484             : 
    1485        1260 : OGRErr OGRSQLiteTableLayer::CreateField(const OGRFieldDefn *poFieldIn,
    1486             :                                         CPL_UNUSED int bApproxOK)
    1487             : {
    1488        2520 :     OGRFieldDefn oField(poFieldIn);
    1489             : 
    1490        1260 :     if (HasLayerDefnError())
    1491           0 :         return OGRERR_FAILURE;
    1492             : 
    1493        1260 :     if (!m_poDS->GetUpdate())
    1494             :     {
    1495           0 :         CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
    1496             :                  "CreateField");
    1497           0 :         return OGRERR_FAILURE;
    1498             :     }
    1499             : 
    1500        3780 :     if (m_pszFIDColumn != nullptr &&
    1501        1262 :         EQUAL(oField.GetNameRef(), m_pszFIDColumn) &&
    1502        2522 :         oField.GetType() != OFTInteger && oField.GetType() != OFTInteger64)
    1503             :     {
    1504           1 :         CPLError(CE_Failure, CPLE_AppDefined, "Wrong field type for %s",
    1505             :                  oField.GetNameRef());
    1506           1 :         return OGRERR_FAILURE;
    1507             :     }
    1508             : 
    1509        1259 :     ClearInsertStmt();
    1510             : 
    1511        1259 :     if (m_poDS->IsSpatialiteDB() && EQUAL(oField.GetNameRef(), "ROWID") &&
    1512           0 :         !(m_pszFIDColumn != nullptr &&
    1513           0 :           EQUAL(oField.GetNameRef(), m_pszFIDColumn)))
    1514             :     {
    1515           0 :         CPLError(CE_Warning, CPLE_AppDefined,
    1516             :                  "In a Spatialite DB, a 'ROWID' column that is not the integer "
    1517             :                  "primary key can corrupt spatial index. "
    1518             :                  "See "
    1519             :                  "https://www.gaia-gis.it/fossil/libspatialite/"
    1520             :                  "wiki?name=Shadowed+ROWID+issues");
    1521             :     }
    1522             : 
    1523             :     /* -------------------------------------------------------------------- */
    1524             :     /*      Do we want to "launder" the column names into SQLite            */
    1525             :     /*      friendly format?                                                */
    1526             :     /* -------------------------------------------------------------------- */
    1527        1259 :     if (m_bLaunderColumnNames)
    1528             :     {
    1529        1257 :         char *pszSafeName = m_poDS->LaunderName(oField.GetNameRef());
    1530             : 
    1531        1257 :         oField.SetName(pszSafeName);
    1532        1257 :         CPLFree(pszSafeName);
    1533             :     }
    1534             : 
    1535        3721 :     if ((oField.GetType() == OFTTime || oField.GetType() == OFTDate ||
    1536        3729 :          oField.GetType() == OFTDateTime) &&
    1537         109 :         !(CPLTestBool(CPLGetConfigOption("OGR_SQLITE_ENABLE_DATETIME", "YES"))))
    1538             :     {
    1539           0 :         oField.SetType(OFTString);
    1540             :     }
    1541             : 
    1542        1259 :     if (!m_bDeferredCreation)
    1543             :     {
    1544          25 :         CPLString osCommand;
    1545             : 
    1546          25 :         CPLString osFieldType(FieldDefnToSQliteFieldDefn(&oField));
    1547             :         osCommand.Printf(
    1548             :             "ALTER TABLE '%s' ADD COLUMN '%s' %s", m_pszEscapedTableName,
    1549          25 :             SQLEscapeLiteral(oField.GetNameRef()).c_str(), osFieldType.c_str());
    1550          25 :         if (!oField.IsNullable())
    1551             :         {
    1552           0 :             osCommand += " NOT NULL";
    1553             :         }
    1554          25 :         if (oField.IsUnique())
    1555             :         {
    1556           0 :             osCommand += " UNIQUE";
    1557             :         }
    1558          25 :         if (oField.GetDefault() != nullptr && !oField.IsDefaultDriverSpecific())
    1559             :         {
    1560           0 :             osCommand += " DEFAULT ";
    1561           0 :             osCommand += oField.GetDefault();
    1562             :         }
    1563          25 :         else if (!oField.IsNullable())
    1564             :         {
    1565             :             // This is kind of dumb, but SQLite mandates a DEFAULT value
    1566             :             // when adding a NOT NULL column in an ALTER TABLE ADD COLUMN
    1567             :             // statement, which defeats the purpose of NOT NULL,
    1568             :             // whereas it doesn't in CREATE TABLE
    1569           0 :             osCommand += " DEFAULT ''";
    1570             :         }
    1571             : 
    1572             : #ifdef DEBUG
    1573          25 :         CPLDebug("OGR_SQLITE", "exec(%s)", osCommand.c_str());
    1574             : #endif
    1575             : 
    1576          25 :         if (SQLCommand(m_poDS->GetDB(), osCommand) != OGRERR_NONE)
    1577           0 :             return OGRERR_FAILURE;
    1578             :     }
    1579             : 
    1580             :     /* -------------------------------------------------------------------- */
    1581             :     /*      Add the field to the OGRFeatureDefn.                            */
    1582             :     /* -------------------------------------------------------------------- */
    1583        1259 :     whileUnsealing(m_poFeatureDefn)->AddFieldDefn(&oField);
    1584             : 
    1585        1259 :     if (m_poDS->IsInTransaction())
    1586             :     {
    1587             :         m_apoFieldDefnChanges.emplace_back(
    1588         597 :             std::make_unique<OGRFieldDefn>(oField),
    1589         597 :             m_poFeatureDefn->GetFieldCount() - 1, FieldChangeType::ADD_FIELD,
    1590        1791 :             m_poDS->GetCurrentSavepoint());
    1591             :     }
    1592             : 
    1593        1259 :     if (m_pszFIDColumn != nullptr && EQUAL(oField.GetNameRef(), m_pszFIDColumn))
    1594             :     {
    1595           1 :         m_iFIDAsRegularColumnIndex = m_poFeatureDefn->GetFieldCount() - 1;
    1596             :     }
    1597             : 
    1598        1259 :     if (!m_bDeferredCreation)
    1599          25 :         RecomputeOrdinals();
    1600             : 
    1601        1259 :     return OGRERR_NONE;
    1602             : }
    1603             : 
    1604             : /************************************************************************/
    1605             : /*                          CreateGeomField()                           */
    1606             : /************************************************************************/
    1607             : 
    1608             : OGRErr
    1609          19 : OGRSQLiteTableLayer::CreateGeomField(const OGRGeomFieldDefn *poGeomFieldIn,
    1610             :                                      CPL_UNUSED int bApproxOK)
    1611             : {
    1612          19 :     OGRwkbGeometryType eType = poGeomFieldIn->GetType();
    1613          19 :     if (eType == wkbNone)
    1614             :     {
    1615           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1616             :                  "Cannot create geometry field of type wkbNone");
    1617           0 :         return OGRERR_FAILURE;
    1618             :     }
    1619          19 :     if (m_poDS->IsSpatialiteDB())
    1620             :     {
    1621             :         // We need to catch this right now as AddGeometryColumn does not
    1622             :         // return an error
    1623           7 :         OGRwkbGeometryType eFType = wkbFlatten(eType);
    1624           7 :         if (eFType > wkbGeometryCollection)
    1625             :         {
    1626           1 :             CPLError(CE_Failure, CPLE_NotSupported,
    1627             :                      "Cannot create geometry field of type %s",
    1628             :                      OGRToOGCGeomType(eType));
    1629           1 :             return OGRERR_FAILURE;
    1630             :         }
    1631             :     }
    1632             : 
    1633             :     auto poGeomField = std::make_unique<OGRSQLiteGeomFieldDefn>(
    1634          36 :         poGeomFieldIn->GetNameRef(), -1);
    1635          18 :     if (EQUAL(poGeomField->GetNameRef(), ""))
    1636             :     {
    1637           0 :         if (m_poFeatureDefn->GetGeomFieldCount() == 0)
    1638           0 :             poGeomField->SetName("GEOMETRY");
    1639             :         else
    1640           0 :             poGeomField->SetName(CPLSPrintf(
    1641           0 :                 "GEOMETRY%d", m_poFeatureDefn->GetGeomFieldCount() + 1));
    1642             :     }
    1643          18 :     auto poSRSIn = poGeomFieldIn->GetSpatialRef();
    1644          18 :     if (poSRSIn)
    1645             :     {
    1646          18 :         auto l_poSRS = OGRSpatialReferenceRefCountedPtr::makeClone(poSRSIn);
    1647           9 :         l_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    1648           9 :         poGeomField->SetSpatialRef(l_poSRS.get());
    1649             :     }
    1650             : 
    1651             :     /* -------------------------------------------------------------------- */
    1652             :     /*      Do we want to "launder" the column names into Postgres          */
    1653             :     /*      friendly format?                                                */
    1654             :     /* -------------------------------------------------------------------- */
    1655          18 :     if (m_bLaunderColumnNames)
    1656             :     {
    1657          18 :         char *pszSafeName = m_poDS->LaunderName(poGeomField->GetNameRef());
    1658             : 
    1659          18 :         poGeomField->SetName(pszSafeName);
    1660          18 :         CPLFree(pszSafeName);
    1661             :     }
    1662             : 
    1663          18 :     const OGRSpatialReference *poSRS = poGeomField->GetSpatialRef();
    1664          18 :     int nSRSId = -1;
    1665          18 :     if (poSRS != nullptr)
    1666           9 :         nSRSId = m_poDS->FetchSRSId(poSRS);
    1667             : 
    1668          18 :     poGeomField->SetType(eType);
    1669          18 :     poGeomField->SetNullable(poGeomFieldIn->IsNullable());
    1670          18 :     poGeomField->m_nSRSId = nSRSId;
    1671          18 :     if (m_poDS->IsSpatialiteDB())
    1672           6 :         poGeomField->m_eGeomFormat = OSGF_SpatiaLite;
    1673          12 :     else if (m_pszCreationGeomFormat)
    1674          12 :         poGeomField->m_eGeomFormat = GetGeomFormat(m_pszCreationGeomFormat);
    1675             :     else
    1676           0 :         poGeomField->m_eGeomFormat = OSGF_WKB;
    1677             : 
    1678             :     /* -------------------------------------------------------------------- */
    1679             :     /*      Create the new field.                                           */
    1680             :     /* -------------------------------------------------------------------- */
    1681          18 :     if (!m_bDeferredCreation)
    1682             :     {
    1683           0 :         if (RunAddGeometryColumn(poGeomField.get(), true) != OGRERR_NONE)
    1684             :         {
    1685           0 :             return OGRERR_FAILURE;
    1686             :         }
    1687             :     }
    1688             : 
    1689             :     // Add to the list of changes BEFORE adding it to the feature definition
    1690             :     // because poGeomField is a unique ptr.
    1691          18 :     if (m_poDS->IsInTransaction())
    1692             :     {
    1693             :         m_apoGeomFieldDefnChanges.emplace_back(
    1694          16 :             std::make_unique<OGRGeomFieldDefn>(*poGeomField),
    1695          24 :             m_poFeatureDefn->GetGeomFieldCount(), FieldChangeType::ADD_FIELD);
    1696             :     }
    1697             : 
    1698          18 :     m_poFeatureDefn->AddGeomFieldDefn(std::move(poGeomField));
    1699             : 
    1700          18 :     if (!m_bDeferredCreation)
    1701           0 :         RecomputeOrdinals();
    1702             : 
    1703          18 :     return OGRERR_NONE;
    1704             : }
    1705             : 
    1706             : /************************************************************************/
    1707             : /*                        RunAddGeometryColumn()                        */
    1708             : /************************************************************************/
    1709             : 
    1710         335 : OGRErr OGRSQLiteTableLayer::RunAddGeometryColumn(
    1711             :     const OGRSQLiteGeomFieldDefn *poGeomFieldDefn,
    1712             :     bool bAddColumnsForNonSpatialite)
    1713             : {
    1714         335 :     OGRwkbGeometryType eType = poGeomFieldDefn->GetType();
    1715         335 :     const char *pszGeomCol = poGeomFieldDefn->GetNameRef();
    1716         335 :     int nSRSId = poGeomFieldDefn->m_nSRSId;
    1717             : 
    1718         335 :     const int nCoordDim = eType == wkbFlatten(eType) ? 2 : 3;
    1719             : 
    1720         335 :     if (bAddColumnsForNonSpatialite && !m_poDS->IsSpatialiteDB())
    1721             :     {
    1722             :         CPLString osCommand =
    1723           0 :             CPLSPrintf("ALTER TABLE '%s' ADD COLUMN ", m_pszEscapedTableName);
    1724           0 :         if (poGeomFieldDefn->m_eGeomFormat == OSGF_WKT)
    1725             :         {
    1726             :             osCommand += CPLSPrintf(
    1727             :                 " '%s' VARCHAR",
    1728           0 :                 SQLEscapeLiteral(poGeomFieldDefn->GetNameRef()).c_str());
    1729             :         }
    1730             :         else
    1731             :         {
    1732             :             osCommand += CPLSPrintf(
    1733             :                 " '%s' BLOB",
    1734           0 :                 SQLEscapeLiteral(poGeomFieldDefn->GetNameRef()).c_str());
    1735             :         }
    1736           0 :         if (!poGeomFieldDefn->IsNullable())
    1737           0 :             osCommand += " NOT NULL DEFAULT ''";
    1738             : 
    1739             : #ifdef DEBUG
    1740           0 :         CPLDebug("OGR_SQLITE", "exec(%s)", osCommand.c_str());
    1741             : #endif
    1742             : 
    1743           0 :         if (SQLCommand(m_poDS->GetDB(), osCommand) != OGRERR_NONE)
    1744           0 :             return OGRERR_FAILURE;
    1745             :     }
    1746             : 
    1747         670 :     CPLString osCommand;
    1748             : 
    1749         335 :     if (m_poDS->IsSpatialiteDB())
    1750             :     {
    1751             :         /*
    1752             :         / SpatiaLite full support: calling AddGeometryColumn()
    1753             :         /
    1754             :         / IMPORTANT NOTICE: on SpatiaLite any attempt aimed
    1755             :         / to directly INSERT a row into GEOMETRY_COLUMNS
    1756             :         / [by-passing AddGeometryColumn() as absolutely required]
    1757             :         / will severely [and irremediably] corrupt the DB !!!
    1758             :         */
    1759         152 :         const char *pszType = OGRToOGCGeomType(eType);
    1760         152 :         if (pszType[0] == '\0')
    1761           0 :             pszType = "GEOMETRY";
    1762             : 
    1763             :         /*
    1764             :         / SpatiaLite v.2.4.0 (or any subsequent) is required
    1765             :         / to support 2.5D: if an obsolete version of the library
    1766             :         / is found we'll unconditionally activate 2D casting mode
    1767             :         */
    1768         152 :         int iSpatialiteVersion = m_poDS->GetSpatialiteVersionNumber();
    1769         152 :         const char *pszCoordDim = "2";
    1770         152 :         if (iSpatialiteVersion <
    1771         152 :                 OGRSQLiteDataSource::MakeSpatialiteVersionNumber(2, 4, 0) &&
    1772             :             nCoordDim == 3)
    1773             :         {
    1774           0 :             CPLDebug("SQLITE", "Spatialite < 2.4.0 --> 2.5D geometry not "
    1775             :                                "supported. Casting to 2D");
    1776             :         }
    1777         152 :         else if (OGR_GT_HasM(eType))
    1778             :         {
    1779          32 :             pszCoordDim = (OGR_GT_HasZ(eType)) ? "'XYZM'" : "'XYM'";
    1780             :         }
    1781         120 :         else if (OGR_GT_HasZ(eType))
    1782             :         {
    1783          36 :             pszCoordDim = "3";
    1784             :         }
    1785             :         osCommand.Printf("SELECT AddGeometryColumn("
    1786             :                          "'%s', '%s', %d, '%s', %s",
    1787             :                          m_pszEscapedTableName,
    1788         304 :                          SQLEscapeLiteral(pszGeomCol).c_str(), nSRSId, pszType,
    1789         152 :                          pszCoordDim);
    1790         152 :         if (iSpatialiteVersion >=
    1791         304 :                 OGRSQLiteDataSource::MakeSpatialiteVersionNumber(3, 0, 0) &&
    1792         152 :             !poGeomFieldDefn->IsNullable())
    1793           1 :             osCommand += ", 1";
    1794         152 :         osCommand += ")";
    1795             :     }
    1796             :     else
    1797             :     {
    1798         183 :         const char *pszGeomFormat =
    1799         365 :             (poGeomFieldDefn->m_eGeomFormat == OSGF_WKT)   ? "WKT"
    1800         183 :             : (poGeomFieldDefn->m_eGeomFormat == OSGF_WKB) ? "WKB"
    1801           1 :             : (poGeomFieldDefn->m_eGeomFormat == OSGF_FGF) ? "FGF"
    1802             :                                                            : "Spatialite";
    1803         183 :         if (nSRSId > 0)
    1804             :         {
    1805             :             osCommand.Printf(
    1806             :                 "INSERT INTO geometry_columns "
    1807             :                 "(f_table_name, f_geometry_column, geometry_format, "
    1808             :                 "geometry_type, coord_dimension, srid) VALUES "
    1809             :                 "('%s','%s','%s', %d, %d, %d)",
    1810          19 :                 m_pszEscapedTableName, SQLEscapeLiteral(pszGeomCol).c_str(),
    1811          19 :                 pszGeomFormat, static_cast<int>(wkbFlatten(eType)), nCoordDim,
    1812          19 :                 nSRSId);
    1813             :         }
    1814             :         else
    1815             :         {
    1816             :             osCommand.Printf(
    1817             :                 "INSERT INTO geometry_columns "
    1818             :                 "(f_table_name, f_geometry_column, geometry_format, "
    1819             :                 "geometry_type, coord_dimension) VALUES "
    1820             :                 "('%s','%s','%s', %d, %d)",
    1821         164 :                 m_pszEscapedTableName, SQLEscapeLiteral(pszGeomCol).c_str(),
    1822         164 :                 pszGeomFormat, static_cast<int>(wkbFlatten(eType)), nCoordDim);
    1823             :         }
    1824             :     }
    1825             : 
    1826             : #ifdef DEBUG
    1827         335 :     CPLDebug("OGR_SQLITE", "exec(%s)", osCommand.c_str());
    1828             : #endif
    1829             : 
    1830         335 :     return SQLCommand(m_poDS->GetDB(), osCommand);
    1831             : }
    1832             : 
    1833             : /************************************************************************/
    1834             : /*                     InitFieldListForRecrerate()                      */
    1835             : /************************************************************************/
    1836             : 
    1837          25 : void OGRSQLiteTableLayer::InitFieldListForRecrerate(
    1838             :     char *&pszNewFieldList, char *&pszFieldListForSelect, size_t &nBufLenOut,
    1839             :     int nExtraSpace)
    1840             : {
    1841          25 :     size_t nFieldListLen = 100 + 2 * nExtraSpace;
    1842             : 
    1843         126 :     for (int iField = 0; iField < m_poFeatureDefn->GetFieldCount(); iField++)
    1844             :     {
    1845         101 :         OGRFieldDefn *poFieldDefn = m_poFeatureDefn->GetFieldDefn(iField);
    1846         101 :         nFieldListLen += 2 * strlen(poFieldDefn->GetNameRef()) + 70;
    1847         101 :         nFieldListLen += strlen(" UNIQUE");
    1848         101 :         if (poFieldDefn->GetDefault() != nullptr)
    1849          18 :             nFieldListLen += 10 + strlen(poFieldDefn->GetDefault());
    1850             :     }
    1851             : 
    1852          25 :     nFieldListLen +=
    1853          25 :         50 + (m_pszFIDColumn ? 2 * strlen(m_pszFIDColumn) : strlen("OGC_FID"));
    1854          48 :     for (int iField = 0; iField < m_poFeatureDefn->GetGeomFieldCount();
    1855             :          iField++)
    1856             :     {
    1857          23 :         nFieldListLen +=
    1858          23 :             70 +
    1859          23 :             2 * strlen(m_poFeatureDefn->GetGeomFieldDefn(iField)->GetNameRef());
    1860             :     }
    1861             : 
    1862          25 :     nBufLenOut = nFieldListLen;
    1863          25 :     pszFieldListForSelect = static_cast<char *>(CPLCalloc(1, nFieldListLen));
    1864          25 :     pszNewFieldList = static_cast<char *>(CPLCalloc(1, nFieldListLen));
    1865             : 
    1866             :     /* -------------------------------------------------------------------- */
    1867             :     /*      Build list of old fields, and the list of new fields.           */
    1868             :     /* -------------------------------------------------------------------- */
    1869           0 :     snprintf(pszFieldListForSelect, nFieldListLen, "\"%s\"",
    1870          25 :              m_pszFIDColumn ? SQLEscapeName(m_pszFIDColumn).c_str()
    1871             :                             : "OGC_FID");
    1872           0 :     snprintf(pszNewFieldList, nFieldListLen, "\"%s\" INTEGER PRIMARY KEY",
    1873          25 :              m_pszFIDColumn ? SQLEscapeName(m_pszFIDColumn).c_str()
    1874             :                             : "OGC_FID");
    1875             : 
    1876          48 :     for (int iField = 0; iField < m_poFeatureDefn->GetGeomFieldCount();
    1877             :          iField++)
    1878             :     {
    1879             :         OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
    1880          23 :             m_poFeatureDefn->myGetGeomFieldDefn(iField);
    1881          23 :         strcat(pszFieldListForSelect, ",");
    1882          23 :         strcat(pszNewFieldList, ",");
    1883             : 
    1884          23 :         strcat(pszFieldListForSelect, "\"");
    1885          23 :         strcat(pszFieldListForSelect,
    1886          46 :                SQLEscapeName(poGeomFieldDefn->GetNameRef()));
    1887          23 :         strcat(pszFieldListForSelect, "\"");
    1888             : 
    1889          23 :         strcat(pszNewFieldList, "\"");
    1890          23 :         strcat(pszNewFieldList, SQLEscapeName(poGeomFieldDefn->GetNameRef()));
    1891          23 :         strcat(pszNewFieldList, "\"");
    1892             : 
    1893          23 :         if (poGeomFieldDefn->m_eGeomFormat == OSGF_WKT)
    1894           0 :             strcat(pszNewFieldList, " VARCHAR");
    1895             :         else
    1896          23 :             strcat(pszNewFieldList, " BLOB");
    1897          23 :         if (!poGeomFieldDefn->IsNullable())
    1898           2 :             strcat(pszNewFieldList, " NOT NULL");
    1899             :     }
    1900          25 : }
    1901             : 
    1902             : /************************************************************************/
    1903             : /*                            AddColumnDef()                            */
    1904             : /************************************************************************/
    1905             : 
    1906          88 : void OGRSQLiteTableLayer::AddColumnDef(char *pszNewFieldList, size_t nBufLen,
    1907             :                                        OGRFieldDefn *poFldDefn)
    1908             : {
    1909         176 :     snprintf(pszNewFieldList + strlen(pszNewFieldList),
    1910          88 :              nBufLen - strlen(pszNewFieldList), ", '%s' %s",
    1911         176 :              SQLEscapeLiteral(poFldDefn->GetNameRef()).c_str(),
    1912         176 :              FieldDefnToSQliteFieldDefn(poFldDefn).c_str());
    1913          88 :     if (!poFldDefn->IsNullable())
    1914           0 :         snprintf(pszNewFieldList + strlen(pszNewFieldList),
    1915           0 :                  nBufLen - strlen(pszNewFieldList), " NOT NULL");
    1916          88 :     if (poFldDefn->IsUnique())
    1917           0 :         snprintf(pszNewFieldList + strlen(pszNewFieldList),
    1918           0 :                  nBufLen - strlen(pszNewFieldList), " UNIQUE");
    1919         104 :     if (poFldDefn->GetDefault() != nullptr &&
    1920          16 :         !poFldDefn->IsDefaultDriverSpecific())
    1921             :     {
    1922          14 :         snprintf(pszNewFieldList + strlen(pszNewFieldList),
    1923          14 :                  nBufLen - strlen(pszNewFieldList), " DEFAULT %s",
    1924             :                  poFldDefn->GetDefault());
    1925             :     }
    1926          88 : }
    1927             : 
    1928             : /************************************************************************/
    1929             : /*                           RecreateTable()                            */
    1930             : /************************************************************************/
    1931             : 
    1932          25 : OGRErr OGRSQLiteTableLayer::RecreateTable(const char *pszFieldListForSelect,
    1933             :                                           const char *pszNewFieldList,
    1934             :                                           const char *pszGenericErrorMessage,
    1935             :                                           const char *pszAdditionalDef)
    1936             : {
    1937             :     /* -------------------------------------------------------------------- */
    1938             :     /*      Do this all in a transaction.                                   */
    1939             :     /* -------------------------------------------------------------------- */
    1940          25 :     m_poDS->SoftStartTransaction();
    1941             : 
    1942             :     /* -------------------------------------------------------------------- */
    1943             :     /*      Save existing related triggers and index                        */
    1944             :     /* -------------------------------------------------------------------- */
    1945          25 :     char *pszErrMsg = nullptr;
    1946          25 :     sqlite3 *hDB = m_poDS->GetDB();
    1947          50 :     CPLString osSQL;
    1948             : 
    1949             :     osSQL.Printf("SELECT sql FROM sqlite_master WHERE type IN "
    1950             :                  "('trigger','index') AND tbl_name='%s'",
    1951          25 :                  m_pszEscapedTableName);
    1952             : 
    1953             :     int nRowTriggerIndexCount, nColTriggerIndexCount;
    1954          25 :     char **papszTriggerIndexResult = nullptr;
    1955          25 :     int rc = sqlite3_get_table(hDB, osSQL.c_str(), &papszTriggerIndexResult,
    1956             :                                &nRowTriggerIndexCount, &nColTriggerIndexCount,
    1957             :                                &pszErrMsg);
    1958             : 
    1959             :     /* -------------------------------------------------------------------- */
    1960             :     /*      Make a backup of the table.                                     */
    1961             :     /* -------------------------------------------------------------------- */
    1962             : 
    1963          25 :     if (rc == SQLITE_OK)
    1964          27 :         rc = sqlite3_exec(
    1965             :             hDB,
    1966             :             CPLSPrintf("CREATE TABLE t1_back(%s %s)%s", pszNewFieldList,
    1967             :                        pszAdditionalDef
    1968          27 :                            ? (std::string(", ") + pszAdditionalDef).c_str()
    1969             :                            : "",
    1970          25 :                        m_bStrict ? " STRICT" : ""),
    1971             :             nullptr, nullptr, &pszErrMsg);
    1972             : 
    1973          25 :     if (rc == SQLITE_OK)
    1974          25 :         rc = sqlite3_exec(hDB,
    1975             :                           CPLSPrintf("INSERT INTO t1_back SELECT %s FROM '%s'",
    1976             :                                      pszFieldListForSelect,
    1977             :                                      m_pszEscapedTableName),
    1978             :                           nullptr, nullptr, &pszErrMsg);
    1979             : 
    1980             :     /* -------------------------------------------------------------------- */
    1981             :     /*      Drop the original table                                         */
    1982             :     /* -------------------------------------------------------------------- */
    1983          25 :     if (rc == SQLITE_OK)
    1984          25 :         rc = sqlite3_exec(hDB,
    1985             :                           CPLSPrintf("DROP TABLE '%s'", m_pszEscapedTableName),
    1986             :                           nullptr, nullptr, &pszErrMsg);
    1987             : 
    1988             :     /* -------------------------------------------------------------------- */
    1989             :     /*      Rename backup table as new table                                */
    1990             :     /* -------------------------------------------------------------------- */
    1991          25 :     if (rc == SQLITE_OK)
    1992             :     {
    1993          25 :         const char *pszCmd = CPLSPrintf("ALTER TABLE t1_back RENAME TO '%s'",
    1994             :                                         m_pszEscapedTableName);
    1995          25 :         rc = sqlite3_exec(hDB, pszCmd, nullptr, nullptr, &pszErrMsg);
    1996             :     }
    1997             : 
    1998             :     /* -------------------------------------------------------------------- */
    1999             :     /*      Recreate existing related tables, triggers and index            */
    2000             :     /* -------------------------------------------------------------------- */
    2001             : 
    2002          25 :     if (rc == SQLITE_OK)
    2003             :     {
    2004          25 :         for (int i = 1; i <= nRowTriggerIndexCount &&
    2005          25 :                         nColTriggerIndexCount == 1 && rc == SQLITE_OK;
    2006             :              i++)
    2007             :         {
    2008           0 :             if (papszTriggerIndexResult[i] != nullptr &&
    2009           0 :                 papszTriggerIndexResult[i][0] != '\0')
    2010           0 :                 rc = sqlite3_exec(hDB, papszTriggerIndexResult[i], nullptr,
    2011             :                                   nullptr, &pszErrMsg);
    2012             :         }
    2013             :     }
    2014             : 
    2015             :     /* -------------------------------------------------------------------- */
    2016             :     /*      COMMIT on success or ROLLBACK on failure.                       */
    2017             :     /* -------------------------------------------------------------------- */
    2018             : 
    2019          25 :     sqlite3_free_table(papszTriggerIndexResult);
    2020             : 
    2021          25 :     if (rc == SQLITE_OK)
    2022             :     {
    2023          25 :         m_poDS->SoftCommitTransaction();
    2024             : 
    2025          25 :         return OGRERR_NONE;
    2026             :     }
    2027             :     else
    2028             :     {
    2029           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s:\n %s",
    2030             :                  pszGenericErrorMessage, pszErrMsg);
    2031           0 :         sqlite3_free(pszErrMsg);
    2032             : 
    2033           0 :         m_poDS->SoftRollbackTransaction();
    2034             : 
    2035           0 :         return OGRERR_FAILURE;
    2036             :     }
    2037             : }
    2038             : 
    2039             : /************************************************************************/
    2040             : /*                            DeleteField()                             */
    2041             : /************************************************************************/
    2042             : 
    2043         159 : OGRErr OGRSQLiteTableLayer::DeleteField(int iFieldToDelete)
    2044             : {
    2045         159 :     if (HasLayerDefnError())
    2046           0 :         return OGRERR_FAILURE;
    2047             : 
    2048         159 :     if (!m_poDS->GetUpdate())
    2049             :     {
    2050           0 :         CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
    2051             :                  "DeleteField");
    2052           0 :         return OGRERR_FAILURE;
    2053             :     }
    2054             : 
    2055         317 :     if (iFieldToDelete < 0 ||
    2056         158 :         iFieldToDelete >= m_poFeatureDefn->GetFieldCount())
    2057             :     {
    2058           2 :         CPLError(CE_Failure, CPLE_NotSupported, "Invalid field index");
    2059           2 :         return OGRERR_FAILURE;
    2060             :     }
    2061             : 
    2062         157 :     ResetReading();
    2063             : 
    2064         157 :     if (m_poDS->SoftStartTransaction() != OGRERR_NONE)
    2065           0 :         return OGRERR_FAILURE;
    2066             : 
    2067             :     // ALTER TABLE ... DROP COLUMN ... was first implemented in 3.35.0 but
    2068             :     // there was bug fixes related to it until 3.35.5
    2069             : #if SQLITE_VERSION_NUMBER >= 3035005L
    2070             :     const char *pszFieldName =
    2071         157 :         m_poFeatureDefn->GetFieldDefn(iFieldToDelete)->GetNameRef();
    2072         157 :     OGRErr eErr = SQLCommand(
    2073         314 :         m_poDS->GetDB(), CPLString()
    2074             :                              .Printf("ALTER TABLE \"%s\" DROP COLUMN \"%s\"",
    2075         314 :                                      SQLEscapeName(m_pszTableName).c_str(),
    2076         471 :                                      SQLEscapeName(pszFieldName).c_str())
    2077             :                              .c_str());
    2078             : #else
    2079             :     /* -------------------------------------------------------------------- */
    2080             :     /*      Build list of old fields, and the list of new fields.           */
    2081             :     /* -------------------------------------------------------------------- */
    2082             :     char *pszNewFieldList = nullptr;
    2083             :     char *pszFieldListForSelect = nullptr;
    2084             :     size_t nBufLen = 0;
    2085             : 
    2086             :     InitFieldListForRecrerate(pszNewFieldList, pszFieldListForSelect, nBufLen);
    2087             : 
    2088             :     for (int iField = 0; iField < m_poFeatureDefn->GetFieldCount(); iField++)
    2089             :     {
    2090             :         OGRFieldDefn *poFldDefn = m_poFeatureDefn->GetFieldDefn(iField);
    2091             : 
    2092             :         if (iField == iFieldToDelete)
    2093             :             continue;
    2094             : 
    2095             :         snprintf(pszFieldListForSelect + strlen(pszFieldListForSelect),
    2096             :                  nBufLen - strlen(pszFieldListForSelect), ", \"%s\"",
    2097             :                  SQLEscapeName(poFldDefn->GetNameRef()).c_str());
    2098             : 
    2099             :         AddColumnDef(pszNewFieldList, nBufLen, poFldDefn);
    2100             :     }
    2101             : 
    2102             :     /* -------------------------------------------------------------------- */
    2103             :     /*      Recreate table.                                                 */
    2104             :     /* -------------------------------------------------------------------- */
    2105             :     CPLString osErrorMsg;
    2106             :     osErrorMsg.Printf(
    2107             :         "Failed to remove field %s from table %s",
    2108             :         m_poFeatureDefn->GetFieldDefn(iFieldToDelete)->GetNameRef(),
    2109             :         m_poFeatureDefn->GetName());
    2110             : 
    2111             :     OGRErr eErr = RecreateTable(pszFieldListForSelect, pszNewFieldList,
    2112             :                                 osErrorMsg.c_str());
    2113             : 
    2114             :     CPLFree(pszFieldListForSelect);
    2115             :     CPLFree(pszNewFieldList);
    2116             : #endif
    2117             : 
    2118             :     /* -------------------------------------------------------------------- */
    2119             :     /*      Check foreign key integrity if enforcement of foreign keys      */
    2120             :     /*      constraint is enabled.                                          */
    2121             :     /* -------------------------------------------------------------------- */
    2122         314 :     if (eErr == OGRERR_NONE &&
    2123         157 :         SQLGetInteger(m_poDS->GetDB(), "PRAGMA foreign_keys", nullptr))
    2124             :     {
    2125           0 :         CPLDebug("SQLite", "Running PRAGMA foreign_key_check");
    2126           0 :         eErr = m_poDS->PragmaCheck("foreign_key_check", "", 0);
    2127             :     }
    2128             : 
    2129             :     /* -------------------------------------------------------------------- */
    2130             :     /*      Finish                                                          */
    2131             :     /* -------------------------------------------------------------------- */
    2132             : 
    2133         157 :     if (eErr == OGRERR_NONE)
    2134             :     {
    2135         157 :         eErr = m_poDS->SoftCommitTransaction();
    2136         157 :         if (eErr == OGRERR_NONE)
    2137             :         {
    2138             : 
    2139             :             // Keep the field definition alive until a new transaction is started
    2140             :             // or the layer is destroyed.
    2141         157 :             if (m_poDS->IsInTransaction())
    2142             :             {
    2143         152 :                 std::unique_ptr<OGRFieldDefn> poFieldDefn;
    2144         152 :                 poFieldDefn = whileUnsealing(m_poFeatureDefn)
    2145         152 :                                   ->StealFieldDefn(iFieldToDelete);
    2146         152 :                 if (poFieldDefn)
    2147             :                 {
    2148             :                     m_apoFieldDefnChanges.emplace_back(
    2149         152 :                         std::move(poFieldDefn), iFieldToDelete,
    2150         152 :                         FieldChangeType::DELETE_FIELD,
    2151         304 :                         m_poDS->GetCurrentSavepoint());
    2152             :                 }
    2153             :                 else
    2154             :                 {
    2155           0 :                     eErr = OGRERR_FAILURE;
    2156             :                 }
    2157             :             }
    2158             :             else
    2159             :             {
    2160          10 :                 eErr = whileUnsealing(m_poFeatureDefn)
    2161           5 :                            ->DeleteFieldDefn(iFieldToDelete);
    2162             :             }
    2163             : 
    2164         157 :             RecomputeOrdinals();
    2165             : 
    2166         157 :             ResetReading();
    2167             :         }
    2168             :     }
    2169             :     else
    2170             :     {
    2171           0 :         m_poDS->SoftRollbackTransaction();
    2172             :     }
    2173             : 
    2174         157 :     return eErr;
    2175             : }
    2176             : 
    2177             : /************************************************************************/
    2178             : /*                           AlterFieldDefn()                           */
    2179             : /************************************************************************/
    2180             : 
    2181          16 : OGRErr OGRSQLiteTableLayer::AlterFieldDefn(int iFieldToAlter,
    2182             :                                            OGRFieldDefn *poNewFieldDefn,
    2183             :                                            int nFlagsIn)
    2184             : {
    2185          16 :     if (HasLayerDefnError())
    2186           0 :         return OGRERR_FAILURE;
    2187             : 
    2188          16 :     if (!m_poDS->GetUpdate())
    2189             :     {
    2190           0 :         CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
    2191             :                  "AlterFieldDefn");
    2192           0 :         return OGRERR_FAILURE;
    2193             :     }
    2194             : 
    2195          16 :     if (iFieldToAlter < 0 || iFieldToAlter >= m_poFeatureDefn->GetFieldCount())
    2196             :     {
    2197           2 :         CPLError(CE_Failure, CPLE_NotSupported, "Invalid field index");
    2198           2 :         return OGRERR_FAILURE;
    2199             :     }
    2200             : 
    2201          14 :     ClearInsertStmt();
    2202          14 :     ResetReading();
    2203             : 
    2204             :     /* -------------------------------------------------------------------- */
    2205             :     /*      Check that the new column name is not a duplicate.              */
    2206             :     /* -------------------------------------------------------------------- */
    2207             : 
    2208             :     OGRFieldDefn *poFieldDefnToAlter =
    2209          14 :         m_poFeatureDefn->GetFieldDefn(iFieldToAlter);
    2210          28 :     const CPLString osOldColName(poFieldDefnToAlter->GetNameRef());
    2211          14 :     const CPLString osNewColName((nFlagsIn & ALTER_NAME_FLAG)
    2212             :                                      ? CPLString(poNewFieldDefn->GetNameRef())
    2213          28 :                                      : osOldColName);
    2214             : 
    2215          14 :     const bool bRenameCol = osOldColName != osNewColName;
    2216          14 :     if (bRenameCol)
    2217             :     {
    2218          33 :         if ((m_pszFIDColumn &&
    2219          11 :              strcmp(poNewFieldDefn->GetNameRef(), m_pszFIDColumn) == 0) ||
    2220          11 :             (GetGeomType() != wkbNone &&
    2221          11 :              strcmp(poNewFieldDefn->GetNameRef(),
    2222          33 :                     m_poFeatureDefn->GetGeomFieldDefn(0)->GetNameRef()) == 0) ||
    2223          11 :             m_poFeatureDefn->GetFieldIndex(poNewFieldDefn->GetNameRef()) >= 0)
    2224             :         {
    2225           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    2226             :                      "Field name %s is already used for another field",
    2227             :                      poNewFieldDefn->GetNameRef());
    2228           0 :             return OGRERR_FAILURE;
    2229             :         }
    2230             :     }
    2231             : 
    2232             :     /* -------------------------------------------------------------------- */
    2233             :     /*      Build the modified field definition from the flags.             */
    2234             :     /* -------------------------------------------------------------------- */
    2235          28 :     OGRFieldDefn oTmpFieldDefn(poFieldDefnToAlter);
    2236          14 :     int nActualFlags = 0;
    2237          14 :     if (bRenameCol)
    2238             :     {
    2239          11 :         nActualFlags |= ALTER_NAME_FLAG;
    2240          11 :         oTmpFieldDefn.SetName(poNewFieldDefn->GetNameRef());
    2241             :     }
    2242          26 :     if ((nFlagsIn & ALTER_TYPE_FLAG) != 0 &&
    2243          12 :         (poFieldDefnToAlter->GetType() != poNewFieldDefn->GetType() ||
    2244           6 :          poFieldDefnToAlter->GetSubType() != poNewFieldDefn->GetSubType()))
    2245             :     {
    2246           6 :         nActualFlags |= ALTER_TYPE_FLAG;
    2247           6 :         oTmpFieldDefn.SetSubType(OFSTNone);
    2248           6 :         oTmpFieldDefn.SetType(poNewFieldDefn->GetType());
    2249           6 :         oTmpFieldDefn.SetSubType(poNewFieldDefn->GetSubType());
    2250             :     }
    2251          33 :     if ((nFlagsIn & ALTER_WIDTH_PRECISION_FLAG) != 0 &&
    2252          19 :         (poFieldDefnToAlter->GetWidth() != poNewFieldDefn->GetWidth() ||
    2253           7 :          poFieldDefnToAlter->GetPrecision() != poNewFieldDefn->GetPrecision()))
    2254             :     {
    2255           5 :         nActualFlags |= ALTER_WIDTH_PRECISION_FLAG;
    2256           5 :         oTmpFieldDefn.SetWidth(poNewFieldDefn->GetWidth());
    2257           5 :         oTmpFieldDefn.SetPrecision(poNewFieldDefn->GetPrecision());
    2258             :     }
    2259          26 :     if ((nFlagsIn & ALTER_NULLABLE_FLAG) != 0 &&
    2260          12 :         poFieldDefnToAlter->IsNullable() != poNewFieldDefn->IsNullable())
    2261             :     {
    2262           2 :         nActualFlags |= ALTER_NULLABLE_FLAG;
    2263           2 :         oTmpFieldDefn.SetNullable(poNewFieldDefn->IsNullable());
    2264             :     }
    2265          28 :     if ((nFlagsIn & ALTER_DEFAULT_FLAG) != 0 &&
    2266          14 :         !((poFieldDefnToAlter->GetDefault() == nullptr &&
    2267          12 :            poNewFieldDefn->GetDefault() == nullptr) ||
    2268           2 :           (poFieldDefnToAlter->GetDefault() != nullptr &&
    2269           2 :            poNewFieldDefn->GetDefault() != nullptr &&
    2270           1 :            strcmp(poFieldDefnToAlter->GetDefault(),
    2271             :                   poNewFieldDefn->GetDefault()) == 0)))
    2272             :     {
    2273           2 :         nActualFlags |= ALTER_DEFAULT_FLAG;
    2274           2 :         oTmpFieldDefn.SetDefault(poNewFieldDefn->GetDefault());
    2275             :     }
    2276          26 :     if ((nFlagsIn & ALTER_UNIQUE_FLAG) != 0 &&
    2277          12 :         poFieldDefnToAlter->IsUnique() != poNewFieldDefn->IsUnique())
    2278             :     {
    2279           0 :         nActualFlags |= ALTER_UNIQUE_FLAG;
    2280           0 :         oTmpFieldDefn.SetUnique(poNewFieldDefn->IsUnique());
    2281             :     }
    2282             : 
    2283          14 :     int nActualFlagsToApplyWithSQL = nActualFlags;
    2284             : 
    2285             : #if SQLITE_VERSION_NUMBER >= 3053000L
    2286             :     if ((nActualFlagsToApplyWithSQL & ALTER_NULLABLE_FLAG) != 0)
    2287             :     {
    2288             :         OGRErr eErr =
    2289             :             SQLCommand(m_poDS->GetDB(),
    2290             :                        CPLString().Printf(
    2291             :                            "ALTER TABLE \"%s\" ALTER COLUMN \"%s\" %s NOT NULL",
    2292             :                            SQLEscapeName(m_pszTableName).c_str(),
    2293             :                            SQLEscapeName(osOldColName).c_str(),
    2294             :                            poNewFieldDefn->IsNullable() ? "DROP" : "SET"));
    2295             : 
    2296             :         if (eErr != OGRERR_NONE)
    2297             :             return eErr;
    2298             : 
    2299             :         nActualFlagsToApplyWithSQL &= ~ALTER_NULLABLE_FLAG;
    2300             :     }
    2301             : #endif
    2302             : 
    2303          14 :     if (nActualFlagsToApplyWithSQL == ALTER_NAME_FLAG)
    2304             :     {
    2305           1 :         CPLDebug("SQLite", "Running ALTER TABLE RENAME COLUMN");
    2306           1 :         OGRErr eErr = SQLCommand(
    2307           1 :             m_poDS->GetDB(),
    2308           1 :             CPLString()
    2309             :                 .Printf("ALTER TABLE \"%s\" RENAME COLUMN \"%s\" TO \"%s\"",
    2310           2 :                         SQLEscapeName(m_pszTableName).c_str(),
    2311           2 :                         SQLEscapeName(osOldColName).c_str(),
    2312           4 :                         SQLEscapeName(osNewColName).c_str())
    2313             :                 .c_str());
    2314             : 
    2315           1 :         if (eErr != OGRERR_NONE)
    2316           0 :             return eErr;
    2317             :     }
    2318          13 :     else if (nActualFlagsToApplyWithSQL != 0)
    2319             :     {
    2320             :         /* --------------------------------------------------------------------
    2321             :          */
    2322             :         /*      Build list of old fields, and the list of new fields. */
    2323             :         /* --------------------------------------------------------------------
    2324             :          */
    2325          13 :         char *pszNewFieldList = nullptr;
    2326          13 :         char *pszFieldListForSelect = nullptr;
    2327          13 :         size_t nBufLen = 0;
    2328             : 
    2329          13 :         InitFieldListForRecrerate(
    2330             :             pszNewFieldList, pszFieldListForSelect, nBufLen,
    2331          13 :             static_cast<int>(strlen(poNewFieldDefn->GetNameRef())) + 50 +
    2332          13 :                 (poNewFieldDefn->GetDefault()
    2333          13 :                      ? static_cast<int>(strlen(poNewFieldDefn->GetDefault()))
    2334             :                      : 0));
    2335             : 
    2336          68 :         for (int iField = 0; iField < m_poFeatureDefn->GetFieldCount();
    2337             :              iField++)
    2338             :         {
    2339          55 :             OGRFieldDefn *poFldDefn = m_poFeatureDefn->GetFieldDefn(iField);
    2340             : 
    2341          55 :             snprintf(pszFieldListForSelect + strlen(pszFieldListForSelect),
    2342          55 :                      nBufLen - strlen(pszFieldListForSelect), ", \"%s\"",
    2343         110 :                      SQLEscapeName(poFldDefn->GetNameRef()).c_str());
    2344             : 
    2345          55 :             if (iField == iFieldToAlter)
    2346             :             {
    2347          26 :                 snprintf(pszNewFieldList + strlen(pszNewFieldList),
    2348          13 :                          nBufLen - strlen(pszNewFieldList), ", '%s' %s",
    2349          26 :                          SQLEscapeLiteral(oTmpFieldDefn.GetNameRef()).c_str(),
    2350          26 :                          FieldDefnToSQliteFieldDefn(&oTmpFieldDefn).c_str());
    2351          11 :                 if ((nFlagsIn & ALTER_NAME_FLAG) &&
    2352          24 :                     oTmpFieldDefn.GetType() == OFTString &&
    2353           6 :                     CSLFindString(m_papszCompressedColumns,
    2354             :                                   poFldDefn->GetNameRef()) >= 0)
    2355             :                 {
    2356           0 :                     snprintf(pszNewFieldList + strlen(pszNewFieldList),
    2357           0 :                              nBufLen - strlen(pszNewFieldList), "_deflate");
    2358             :                 }
    2359          13 :                 if (!oTmpFieldDefn.IsNullable())
    2360           1 :                     snprintf(pszNewFieldList + strlen(pszNewFieldList),
    2361           1 :                              nBufLen - strlen(pszNewFieldList), " NOT NULL");
    2362          13 :                 if (oTmpFieldDefn.IsUnique())
    2363           0 :                     snprintf(pszNewFieldList + strlen(pszNewFieldList),
    2364           0 :                              nBufLen - strlen(pszNewFieldList), " UNIQUE");
    2365          13 :                 if (oTmpFieldDefn.GetDefault())
    2366             :                 {
    2367           1 :                     snprintf(pszNewFieldList + strlen(pszNewFieldList),
    2368           1 :                              nBufLen - strlen(pszNewFieldList), " DEFAULT %s",
    2369             :                              oTmpFieldDefn.GetDefault());
    2370             :                 }
    2371             :             }
    2372             :             else
    2373             :             {
    2374          42 :                 AddColumnDef(pszNewFieldList, nBufLen, poFldDefn);
    2375             :             }
    2376             :         }
    2377             : 
    2378             :         /* --------------------------------------------------------------------
    2379             :          */
    2380             :         /*      Recreate table. */
    2381             :         /* --------------------------------------------------------------------
    2382             :          */
    2383          13 :         CPLString osErrorMsg;
    2384             :         osErrorMsg.Printf(
    2385             :             "Failed to alter field %s from table %s",
    2386          13 :             m_poFeatureDefn->GetFieldDefn(iFieldToAlter)->GetNameRef(),
    2387          13 :             m_poFeatureDefn->GetName());
    2388             : 
    2389          13 :         OGRErr eErr = RecreateTable(pszFieldListForSelect, pszNewFieldList,
    2390             :                                     osErrorMsg.c_str());
    2391             : 
    2392          13 :         CPLFree(pszFieldListForSelect);
    2393          13 :         CPLFree(pszNewFieldList);
    2394             : 
    2395          13 :         if (eErr != OGRERR_NONE)
    2396           0 :             return eErr;
    2397             :     }
    2398             : 
    2399             :     /* -------------------------------------------------------------------- */
    2400             :     /*      Finish                                                          */
    2401             :     /* -------------------------------------------------------------------- */
    2402             : 
    2403          14 :     auto oTemporaryUnsealer(m_poFeatureDefn->GetTemporaryUnsealer());
    2404          14 :     OGRFieldDefn *poFieldDefn = m_poFeatureDefn->GetFieldDefn(iFieldToAlter);
    2405             : 
    2406          14 :     if (m_poDS->IsInTransaction())
    2407             :     {
    2408             :         m_apoFieldDefnChanges.emplace_back(
    2409           4 :             std::make_unique<OGRFieldDefn>(poFieldDefn), iFieldToAlter,
    2410           8 :             FieldChangeType::ALTER_FIELD, m_poDS->GetCurrentSavepoint());
    2411             :     }
    2412             : 
    2413          14 :     if (nActualFlags & ALTER_TYPE_FLAG)
    2414             :     {
    2415           6 :         int iIdx = 0;
    2416          10 :         if (poNewFieldDefn->GetType() != OFTString &&
    2417           4 :             (iIdx = CSLFindString(m_papszCompressedColumns,
    2418             :                                   poFieldDefn->GetNameRef())) >= 0)
    2419             :         {
    2420           0 :             m_papszCompressedColumns =
    2421           0 :                 CSLRemoveStrings(m_papszCompressedColumns, iIdx, 1, nullptr);
    2422             :         }
    2423           6 :         poFieldDefn->SetSubType(OFSTNone);
    2424           6 :         poFieldDefn->SetType(poNewFieldDefn->GetType());
    2425           6 :         poFieldDefn->SetSubType(poNewFieldDefn->GetSubType());
    2426             :     }
    2427          14 :     if (nActualFlags & ALTER_NAME_FLAG)
    2428             :     {
    2429             :         const int iIdx =
    2430          11 :             CSLFindString(m_papszCompressedColumns, poFieldDefn->GetNameRef());
    2431          11 :         if (iIdx >= 0)
    2432             :         {
    2433           0 :             CPLFree(m_papszCompressedColumns[iIdx]);
    2434           0 :             m_papszCompressedColumns[iIdx] =
    2435           0 :                 CPLStrdup(poNewFieldDefn->GetNameRef());
    2436             :         }
    2437          11 :         poFieldDefn->SetName(poNewFieldDefn->GetNameRef());
    2438             :     }
    2439          14 :     if (nActualFlags & ALTER_WIDTH_PRECISION_FLAG)
    2440             :     {
    2441           5 :         poFieldDefn->SetWidth(poNewFieldDefn->GetWidth());
    2442           5 :         poFieldDefn->SetPrecision(poNewFieldDefn->GetPrecision());
    2443             :     }
    2444          14 :     if (nActualFlags & ALTER_NULLABLE_FLAG)
    2445           2 :         poFieldDefn->SetNullable(poNewFieldDefn->IsNullable());
    2446          14 :     if (nActualFlags & ALTER_DEFAULT_FLAG)
    2447           2 :         poFieldDefn->SetDefault(poNewFieldDefn->GetDefault());
    2448             : 
    2449          14 :     return OGRERR_NONE;
    2450             : }
    2451             : 
    2452             : /************************************************************************/
    2453             : /*                       AddForeignKeysToTable()                        */
    2454             : /************************************************************************/
    2455             : 
    2456           2 : OGRErr OGRSQLiteTableLayer::AddForeignKeysToTable(const char *pszKeys)
    2457             : {
    2458           2 :     if (HasLayerDefnError())
    2459           0 :         return OGRERR_FAILURE;
    2460             : 
    2461           2 :     if (!m_poDS->GetUpdate())
    2462             :     {
    2463           0 :         CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
    2464             :                  "AddForeignKeysToTable");
    2465           0 :         return OGRERR_FAILURE;
    2466             :     }
    2467             : 
    2468           2 :     ClearInsertStmt();
    2469           2 :     ResetReading();
    2470             : 
    2471             :     /* -------------------------------------------------------------------- */
    2472             :     /*      Build list of old fields, and the list of new fields.           */
    2473             :     /* -------------------------------------------------------------------- */
    2474           2 :     char *pszNewFieldList = nullptr;
    2475           2 :     char *pszFieldListForSelect = nullptr;
    2476           2 :     size_t nBufLen = 0;
    2477             : 
    2478           2 :     InitFieldListForRecrerate(pszNewFieldList, pszFieldListForSelect, nBufLen,
    2479             :                               0);
    2480             : 
    2481           6 :     for (int iField = 0; iField < m_poFeatureDefn->GetFieldCount(); iField++)
    2482             :     {
    2483           4 :         OGRFieldDefn *poFldDefn = m_poFeatureDefn->GetFieldDefn(iField);
    2484             : 
    2485           4 :         snprintf(pszFieldListForSelect + strlen(pszFieldListForSelect),
    2486           4 :                  nBufLen - strlen(pszFieldListForSelect), ", \"%s\"",
    2487           8 :                  SQLEscapeName(poFldDefn->GetNameRef()).c_str());
    2488             : 
    2489           4 :         AddColumnDef(pszNewFieldList, nBufLen, poFldDefn);
    2490             :     }
    2491             : 
    2492             :     /* -------------------------------------------------------------------- */
    2493             :     /*      Recreate table.                                                 */
    2494             :     /* -------------------------------------------------------------------- */
    2495           4 :     CPLString osErrorMsg;
    2496             :     osErrorMsg.Printf("Failed to add foreign keys to table %s",
    2497           2 :                       m_poFeatureDefn->GetName());
    2498             : 
    2499           2 :     OGRErr eErr = RecreateTable(pszFieldListForSelect, pszNewFieldList,
    2500             :                                 osErrorMsg.c_str(), pszKeys);
    2501             : 
    2502           2 :     CPLFree(pszFieldListForSelect);
    2503           2 :     CPLFree(pszNewFieldList);
    2504             : 
    2505           2 :     if (eErr != OGRERR_NONE)
    2506           0 :         return eErr;
    2507             : 
    2508             :     /* -------------------------------------------------------------------- */
    2509             :     /*      Finish                                                          */
    2510             :     /* -------------------------------------------------------------------- */
    2511             : 
    2512           2 :     return OGRERR_NONE;
    2513             : }
    2514             : 
    2515             : /************************************************************************/
    2516             : /*                           ReorderFields()                            */
    2517             : /************************************************************************/
    2518             : 
    2519          15 : OGRErr OGRSQLiteTableLayer::ReorderFields(int *panMap)
    2520             : {
    2521          15 :     if (HasLayerDefnError())
    2522           0 :         return OGRERR_FAILURE;
    2523             : 
    2524          15 :     if (!m_poDS->GetUpdate())
    2525             :     {
    2526           0 :         CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
    2527             :                  "ReorderFields");
    2528           0 :         return OGRERR_FAILURE;
    2529             :     }
    2530             : 
    2531          15 :     if (m_poFeatureDefn->GetFieldCount() == 0)
    2532           4 :         return OGRERR_NONE;
    2533             : 
    2534          11 :     OGRErr eErr = OGRCheckPermutation(panMap, m_poFeatureDefn->GetFieldCount());
    2535          11 :     if (eErr != OGRERR_NONE)
    2536           1 :         return eErr;
    2537             : 
    2538          10 :     ClearInsertStmt();
    2539          10 :     ResetReading();
    2540             : 
    2541             :     /* -------------------------------------------------------------------- */
    2542             :     /*      Build list of old fields, and the list of new fields.           */
    2543             :     /* -------------------------------------------------------------------- */
    2544          10 :     char *pszNewFieldList = nullptr;
    2545          10 :     char *pszFieldListForSelect = nullptr;
    2546          10 :     size_t nBufLen = 0;
    2547             : 
    2548          10 :     InitFieldListForRecrerate(pszNewFieldList, pszFieldListForSelect, nBufLen);
    2549             : 
    2550          52 :     for (int iField = 0; iField < m_poFeatureDefn->GetFieldCount(); iField++)
    2551             :     {
    2552          42 :         OGRFieldDefn *poFldDefn = m_poFeatureDefn->GetFieldDefn(panMap[iField]);
    2553             : 
    2554          42 :         snprintf(pszFieldListForSelect + strlen(pszFieldListForSelect),
    2555          42 :                  nBufLen - strlen(pszFieldListForSelect), ", \"%s\"",
    2556          84 :                  SQLEscapeName(poFldDefn->GetNameRef()).c_str());
    2557             : 
    2558          42 :         AddColumnDef(pszNewFieldList, nBufLen, poFldDefn);
    2559             :     }
    2560             : 
    2561             :     /* -------------------------------------------------------------------- */
    2562             :     /*      Recreate table.                                                 */
    2563             :     /* -------------------------------------------------------------------- */
    2564          20 :     CPLString osErrorMsg;
    2565             :     osErrorMsg.Printf("Failed to reorder fields from table %s",
    2566          10 :                       m_poFeatureDefn->GetName());
    2567             : 
    2568          10 :     eErr = RecreateTable(pszFieldListForSelect, pszNewFieldList,
    2569             :                          osErrorMsg.c_str());
    2570             : 
    2571          10 :     CPLFree(pszFieldListForSelect);
    2572          10 :     CPLFree(pszNewFieldList);
    2573             : 
    2574          10 :     if (eErr != OGRERR_NONE)
    2575           0 :         return eErr;
    2576             : 
    2577             :     /* -------------------------------------------------------------------- */
    2578             :     /*      Finish                                                          */
    2579             :     /* -------------------------------------------------------------------- */
    2580             : 
    2581          10 :     eErr = whileUnsealing(m_poFeatureDefn)->ReorderFieldDefns(panMap);
    2582             : 
    2583          10 :     RecomputeOrdinals();
    2584             : 
    2585          10 :     return eErr;
    2586             : }
    2587             : 
    2588             : /************************************************************************/
    2589             : /*                             BindValues()                             */
    2590             : /************************************************************************/
    2591             : 
    2592             : /* the bBindNullValues is set to TRUE by SetFeature() for UPDATE statements, */
    2593             : /* and to FALSE by CreateFeature() for INSERT statements; */
    2594             : 
    2595        6561 : OGRErr OGRSQLiteTableLayer::BindValues(OGRFeature *poFeature,
    2596             :                                        sqlite3_stmt *m_hStmtIn,
    2597             :                                        bool bBindUnsetAsNull)
    2598             : {
    2599        6561 :     sqlite3 *hDB = m_poDS->GetDB();
    2600             : 
    2601             :     /* -------------------------------------------------------------------- */
    2602             :     /*      Bind the geometry                                               */
    2603             :     /* -------------------------------------------------------------------- */
    2604        6561 :     int nBindField = 1;
    2605        6561 :     int nFieldCount = m_poFeatureDefn->GetGeomFieldCount();
    2606       12313 :     for (int iField = 0; iField < nFieldCount; iField++)
    2607             :     {
    2608             :         OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
    2609        5752 :             m_poFeatureDefn->myGetGeomFieldDefn(iField);
    2610        5752 :         OGRSQLiteGeomFormat eGeomFormat = poGeomFieldDefn->m_eGeomFormat;
    2611        5752 :         if (eGeomFormat == OSGF_FGF)
    2612           0 :             continue;
    2613        5752 :         OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iField);
    2614        5752 :         int rc = SQLITE_OK;
    2615        5752 :         if (poGeom != nullptr)
    2616             :         {
    2617        5592 :             if (eGeomFormat == OSGF_WKT)
    2618             :             {
    2619           1 :                 char *pszWKT = nullptr;
    2620           1 :                 poGeom->exportToWkt(&pszWKT);
    2621           1 :                 rc = sqlite3_bind_text(m_hStmtIn, nBindField++, pszWKT, -1,
    2622             :                                        CPLFree);
    2623             :             }
    2624        5591 :             else if (eGeomFormat == OSGF_WKB)
    2625             :             {
    2626        5309 :                 const size_t nWKBLen = poGeom->WkbSize();
    2627        5309 :                 if (nWKBLen >
    2628        5309 :                     static_cast<size_t>(std::numeric_limits<int>::max()))
    2629             :                 {
    2630           0 :                     CPLError(CE_Failure, CPLE_NotSupported,
    2631             :                              "Too large geometry");
    2632           0 :                     return OGRERR_FAILURE;
    2633             :                 }
    2634             :                 GByte *pabyWKB =
    2635        5309 :                     static_cast<GByte *>(VSI_MALLOC_VERBOSE(nWKBLen));
    2636        5309 :                 if (pabyWKB)
    2637             :                 {
    2638        5309 :                     poGeom->exportToWkb(wkbNDR, pabyWKB);
    2639        5309 :                     rc = sqlite3_bind_blob(m_hStmtIn, nBindField++, pabyWKB,
    2640             :                                            static_cast<int>(nWKBLen), CPLFree);
    2641             :                 }
    2642             :                 else
    2643             :                 {
    2644           0 :                     return OGRERR_FAILURE;
    2645             :                 }
    2646             :             }
    2647         282 :             else if (eGeomFormat == OSGF_SpatiaLite)
    2648             :             {
    2649         282 :                 int nBLOBLen = 0;
    2650         282 :                 GByte *pabySLBLOB = nullptr;
    2651             : 
    2652         282 :                 const int nSRSId = poGeomFieldDefn->m_nSRSId;
    2653         282 :                 CPL_IGNORE_RET_VAL(ExportSpatiaLiteGeometry(
    2654         282 :                     poGeom, nSRSId, wkbNDR, m_bSpatialite2D, m_bUseComprGeom,
    2655             :                     &pabySLBLOB, &nBLOBLen));
    2656         282 :                 rc = sqlite3_bind_blob(m_hStmtIn, nBindField++, pabySLBLOB,
    2657             :                                        nBLOBLen, CPLFree);
    2658             :             }
    2659             :             else
    2660             :             {
    2661           0 :                 rc = SQLITE_OK;
    2662           0 :                 CPL_IGNORE_RET_VAL(rc);
    2663           0 :                 CPLAssert(false);
    2664             :             }
    2665             :         }
    2666             :         else
    2667             :         {
    2668         160 :             rc = sqlite3_bind_null(m_hStmtIn, nBindField++);
    2669             :         }
    2670             : 
    2671        5752 :         if (rc != SQLITE_OK)
    2672             :         {
    2673           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    2674             :                      "sqlite3_bind_blob/text() failed:\n  %s",
    2675             :                      sqlite3_errmsg(hDB));
    2676           0 :             return OGRERR_FAILURE;
    2677             :         }
    2678             :     }
    2679             : 
    2680             :     /* -------------------------------------------------------------------- */
    2681             :     /*      Bind field values.                                              */
    2682             :     /* -------------------------------------------------------------------- */
    2683        6561 :     nFieldCount = m_poFeatureDefn->GetFieldCount();
    2684       77101 :     for (int iField = 0; iField < nFieldCount; iField++)
    2685             :     {
    2686       70540 :         if (iField == m_iFIDAsRegularColumnIndex)
    2687           3 :             continue;
    2688       70537 :         if (!bBindUnsetAsNull && !poFeature->IsFieldSet(iField))
    2689          10 :             continue;
    2690             : 
    2691       70527 :         int rc = SQLITE_OK;
    2692             : 
    2693      132423 :         if ((bBindUnsetAsNull && !poFeature->IsFieldSet(iField)) ||
    2694       61896 :             poFeature->IsFieldNull(iField))
    2695             :         {
    2696        8685 :             rc = sqlite3_bind_null(m_hStmtIn, nBindField++);
    2697             :         }
    2698             :         else
    2699             :         {
    2700             :             const OGRFieldDefn *poFieldDefn =
    2701       61842 :                 m_poFeatureDefn->GetFieldDefnUnsafe(iField);
    2702       61842 :             switch (poFieldDefn->GetType())
    2703             :             {
    2704        6982 :                 case OFTInteger:
    2705             :                 {
    2706        6982 :                     int nFieldVal = poFeature->GetFieldAsIntegerUnsafe(iField);
    2707        6982 :                     rc = sqlite3_bind_int(m_hStmtIn, nBindField++, nFieldVal);
    2708        6982 :                     break;
    2709             :                 }
    2710             : 
    2711        5223 :                 case OFTInteger64:
    2712             :                 {
    2713             :                     GIntBig nFieldVal =
    2714        5223 :                         poFeature->GetFieldAsInteger64Unsafe(iField);
    2715        5223 :                     rc = sqlite3_bind_int64(m_hStmtIn, nBindField++, nFieldVal);
    2716        5223 :                     break;
    2717             :                 }
    2718             : 
    2719        5364 :                 case OFTReal:
    2720             :                 {
    2721             :                     double dfFieldVal =
    2722        5364 :                         poFeature->GetFieldAsDoubleUnsafe(iField);
    2723        5364 :                     rc = sqlite3_bind_double(m_hStmtIn, nBindField++,
    2724             :                                              dfFieldVal);
    2725        5364 :                     break;
    2726             :                 }
    2727             : 
    2728        5008 :                 case OFTBinary:
    2729             :                 {
    2730        5008 :                     int nDataLength = 0;
    2731             :                     GByte *pabyData =
    2732        5008 :                         poFeature->GetFieldAsBinary(iField, &nDataLength);
    2733        5008 :                     rc = sqlite3_bind_blob(m_hStmtIn, nBindField++, pabyData,
    2734             :                                            nDataLength, SQLITE_TRANSIENT);
    2735        5008 :                     break;
    2736             :                 }
    2737             : 
    2738        5134 :                 case OFTDateTime:
    2739             :                 {
    2740             :                     char *pszStr =
    2741        5134 :                         OGRGetXMLDateTime(poFeature->GetRawFieldRef(iField));
    2742        5134 :                     rc = sqlite3_bind_text(m_hStmtIn, nBindField++, pszStr, -1,
    2743             :                                            SQLITE_TRANSIENT);
    2744        5134 :                     CPLFree(pszStr);
    2745        5134 :                     break;
    2746             :                 }
    2747             : 
    2748        5086 :                 case OFTDate:
    2749             :                 {
    2750        5086 :                     int nYear = 0;
    2751        5086 :                     int nMonth = 0;
    2752        5086 :                     int nDay = 0;
    2753        5086 :                     int nHour = 0;
    2754        5086 :                     int nMinute = 0;
    2755        5086 :                     int nSecond = 0;
    2756        5086 :                     int nTZ = 0;
    2757        5086 :                     poFeature->GetFieldAsDateTime(iField, &nYear, &nMonth,
    2758             :                                                   &nDay, &nHour, &nMinute,
    2759             :                                                   &nSecond, &nTZ);
    2760             :                     char szBuffer[64];
    2761        5086 :                     snprintf(szBuffer, sizeof(szBuffer), "%04d-%02d-%02d",
    2762             :                              nYear, nMonth, nDay);
    2763        5086 :                     rc = sqlite3_bind_text(m_hStmtIn, nBindField++, szBuffer,
    2764             :                                            -1, SQLITE_TRANSIENT);
    2765        5086 :                     break;
    2766             :                 }
    2767             : 
    2768        5004 :                 case OFTTime:
    2769             :                 {
    2770        5004 :                     int nYear = 0;
    2771        5004 :                     int nMonth = 0;
    2772        5004 :                     int nDay = 0;
    2773        5004 :                     int nHour = 0;
    2774        5004 :                     int nMinute = 0;
    2775        5004 :                     int nTZ = 0;
    2776        5004 :                     float fSecond = 0.0f;
    2777        5004 :                     poFeature->GetFieldAsDateTime(iField, &nYear, &nMonth,
    2778             :                                                   &nDay, &nHour, &nMinute,
    2779             :                                                   &fSecond, &nTZ);
    2780             :                     char szBuffer[64];
    2781        5004 :                     if (OGR_GET_MS(fSecond) != 0)
    2782        5000 :                         snprintf(szBuffer, sizeof(szBuffer), "%02d:%02d:%06.3f",
    2783             :                                  nHour, nMinute, fSecond);
    2784             :                     else
    2785           4 :                         snprintf(szBuffer, sizeof(szBuffer), "%02d:%02d:%02d",
    2786             :                                  nHour, nMinute, static_cast<int>(fSecond));
    2787        5004 :                     rc = sqlite3_bind_text(m_hStmtIn, nBindField++, szBuffer,
    2788             :                                            -1, SQLITE_TRANSIENT);
    2789        5004 :                     break;
    2790             :                 }
    2791             : 
    2792       15058 :                 case OFTStringList:
    2793             :                 case OFTIntegerList:
    2794             :                 case OFTInteger64List:
    2795             :                 case OFTRealList:
    2796             :                 {
    2797       15058 :                     char *pszJSon = poFeature->GetFieldAsSerializedJSon(iField);
    2798       15058 :                     rc = sqlite3_bind_text(m_hStmtIn, nBindField++, pszJSon, -1,
    2799             :                                            SQLITE_TRANSIENT);
    2800       15058 :                     CPLFree(pszJSon);
    2801       15058 :                     break;
    2802             :                 }
    2803             : 
    2804        8983 :                 default:
    2805             :                 {
    2806             :                     const char *pszRawValue =
    2807        8983 :                         poFeature->GetFieldAsString(iField);
    2808       17966 :                     std::string osValue(pszRawValue);
    2809             : 
    2810             :                     // If the field subtype is JSON and the current value cannot
    2811             :                     // be parsed as a valid JSON, encode it as a JSON string.
    2812       17966 :                     if (poFieldDefn->GetType() == OFTString &&
    2813        8983 :                         poFieldDefn->GetSubType() == OFSTJSON)
    2814             :                     {
    2815           5 :                         json_object *poObjProp = nullptr;
    2816           5 :                         if (!OGRJSonParse(
    2817             :                                 osValue.c_str(), &poObjProp, false,
    2818           5 :                                 static_cast<int>(osValue.length() + 1)))
    2819             :                         {
    2820             :                             // Emit warning once
    2821           1 :                             CPLErrorOnce(
    2822             :                                 CE_Warning, CPLE_AppDefined,
    2823             :                                 "Field %s is declared as JSON but the "
    2824             :                                 "value is not a valid JSON. Storing as "
    2825             :                                 "string.",
    2826             :                                 poFieldDefn->GetNameRef());
    2827             :                             // Escape and quote
    2828             :                             osValue =
    2829           2 :                                 CPLJSONObject(pszRawValue)
    2830           1 :                                     .Format(CPLJSONObject::PrettyFormat::Plain);
    2831             :                         }
    2832             :                         else
    2833             :                         {
    2834           4 :                             osValue = json_object_to_json_string(poObjProp);
    2835             :                         }
    2836           5 :                         json_object_put(poObjProp);
    2837             :                     }
    2838             : 
    2839        8983 :                     if (CSLFindString(m_papszCompressedColumns,
    2840        8983 :                                       m_poFeatureDefn->GetFieldDefn(iField)
    2841        8983 :                                           ->GetNameRef()) >= 0)
    2842             :                     {
    2843          17 :                         size_t nBytesOut = 0;
    2844          17 :                         void *pOut = CPLZLibDeflate(osValue.c_str(),
    2845             :                                                     strlen(osValue.c_str()), -1,
    2846             :                                                     nullptr, 0, &nBytesOut);
    2847          17 :                         if (pOut != nullptr)
    2848             :                         {
    2849          17 :                             rc = sqlite3_bind_blob(
    2850             :                                 m_hStmtIn, nBindField++, pOut,
    2851             :                                 static_cast<int>(nBytesOut), CPLFree);
    2852             :                         }
    2853             :                         else
    2854           0 :                             rc = SQLITE_ERROR;
    2855             :                     }
    2856             :                     else
    2857             :                     {
    2858        8966 :                         rc = sqlite3_bind_text(m_hStmtIn, nBindField++,
    2859             :                                                osValue.c_str(), -1,
    2860             :                                                SQLITE_TRANSIENT);
    2861             :                     }
    2862        8983 :                     break;
    2863             :                 }
    2864             :             }
    2865             :         }
    2866             : 
    2867       70527 :         if (rc != SQLITE_OK)
    2868             :         {
    2869           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    2870             :                      "sqlite3_bind_() for column %s failed:\n  %s",
    2871           0 :                      m_poFeatureDefn->GetFieldDefn(iField)->GetNameRef(),
    2872             :                      sqlite3_errmsg(hDB));
    2873           0 :             return OGRERR_FAILURE;
    2874             :         }
    2875             :     }
    2876             : 
    2877        6561 :     return OGRERR_NONE;
    2878             : }
    2879             : 
    2880             : /************************************************************************/
    2881             : /*                            ISetFeature()                             */
    2882             : /************************************************************************/
    2883             : 
    2884          32 : OGRErr OGRSQLiteTableLayer::ISetFeature(OGRFeature *poFeature)
    2885             : 
    2886             : {
    2887          32 :     if (HasLayerDefnError())
    2888           0 :         return OGRERR_FAILURE;
    2889             : 
    2890          32 :     if (m_pszFIDColumn == nullptr)
    2891             :     {
    2892           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    2893             :                  "SetFeature() without any FID column.");
    2894           0 :         return OGRERR_FAILURE;
    2895             :     }
    2896             : 
    2897          32 :     if (poFeature->GetFID() == OGRNullFID)
    2898             :     {
    2899           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    2900             :                  "SetFeature() with unset FID fails.");
    2901           0 :         return OGRERR_FAILURE;
    2902             :     }
    2903             : 
    2904          32 :     if (!m_poDS->GetUpdate())
    2905             :     {
    2906           0 :         CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
    2907             :                  "SetFeature");
    2908           0 :         return OGRERR_FAILURE;
    2909             :     }
    2910             : 
    2911             :     /* In case the FID column has also been created as a regular field */
    2912          32 :     if (m_iFIDAsRegularColumnIndex >= 0)
    2913             :     {
    2914           5 :         if (!poFeature->IsFieldSetAndNotNull(m_iFIDAsRegularColumnIndex) ||
    2915           2 :             poFeature->GetFieldAsInteger64(m_iFIDAsRegularColumnIndex) !=
    2916           2 :                 poFeature->GetFID())
    2917             :         {
    2918           2 :             CPLError(CE_Failure, CPLE_AppDefined,
    2919             :                      "Inconsistent values of FID and field of same name");
    2920           2 :             return OGRERR_FAILURE;
    2921             :         }
    2922             :     }
    2923             : 
    2924          30 :     if (m_bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE)
    2925           0 :         return OGRERR_FAILURE;
    2926             : 
    2927          30 :     sqlite3 *hDB = m_poDS->GetDB();
    2928          30 :     int bNeedComma = false;
    2929             : 
    2930             :     /* -------------------------------------------------------------------- */
    2931             :     /*      Form the UPDATE command.                                        */
    2932             :     /* -------------------------------------------------------------------- */
    2933          60 :     CPLString osCommand = CPLSPrintf("UPDATE '%s' SET ", m_pszEscapedTableName);
    2934             : 
    2935             :     /* -------------------------------------------------------------------- */
    2936             :     /*      Add geometry field name.                                        */
    2937             :     /* -------------------------------------------------------------------- */
    2938          30 :     int nFieldCount = m_poFeatureDefn->GetGeomFieldCount();
    2939          60 :     for (int iField = 0; iField < nFieldCount; iField++)
    2940             :     {
    2941             :         OGRSQLiteGeomFormat eGeomFormat =
    2942          30 :             m_poFeatureDefn->myGetGeomFieldDefn(iField)->m_eGeomFormat;
    2943          30 :         if (eGeomFormat == OSGF_FGF)
    2944           0 :             continue;
    2945          30 :         if (bNeedComma)
    2946           1 :             osCommand += ",";
    2947             : 
    2948          30 :         osCommand += "\"";
    2949          60 :         osCommand += SQLEscapeName(
    2950          60 :             m_poFeatureDefn->GetGeomFieldDefn(iField)->GetNameRef());
    2951          30 :         osCommand += "\" = ?";
    2952             : 
    2953          30 :         bNeedComma = true;
    2954             :     }
    2955             : 
    2956             :     /* -------------------------------------------------------------------- */
    2957             :     /*      Add field names.                                                */
    2958             :     /* -------------------------------------------------------------------- */
    2959          30 :     nFieldCount = m_poFeatureDefn->GetFieldCount();
    2960         123 :     for (int iField = 0; iField < nFieldCount; iField++)
    2961             :     {
    2962          93 :         if (iField == m_iFIDAsRegularColumnIndex)
    2963           1 :             continue;
    2964          92 :         if (!poFeature->IsFieldSet(iField))
    2965           0 :             continue;
    2966          92 :         if (bNeedComma)
    2967          91 :             osCommand += ",";
    2968             : 
    2969          92 :         osCommand += "\"";
    2970             :         osCommand +=
    2971          92 :             SQLEscapeName(m_poFeatureDefn->GetFieldDefn(iField)->GetNameRef());
    2972          92 :         osCommand += "\" = ?";
    2973             : 
    2974          92 :         bNeedComma = true;
    2975             :     }
    2976             : 
    2977          30 :     if (!bNeedComma)
    2978           0 :         return OGRERR_NONE;
    2979             : 
    2980             :     /* -------------------------------------------------------------------- */
    2981             :     /*      Merge final command.                                            */
    2982             :     /* -------------------------------------------------------------------- */
    2983          30 :     osCommand += " WHERE \"";
    2984          30 :     osCommand += SQLEscapeName(m_pszFIDColumn);
    2985          30 :     osCommand += CPLSPrintf("\" = " CPL_FRMT_GIB, poFeature->GetFID());
    2986             : 
    2987             : /* -------------------------------------------------------------------- */
    2988             : /*      Prepare the statement.                                          */
    2989             : /* -------------------------------------------------------------------- */
    2990             : #ifdef DEBUG_VERBOSE
    2991             :     CPLDebug("OGR_SQLITE", "prepare_v2(%s)", osCommand.c_str());
    2992             : #endif
    2993             : 
    2994          30 :     sqlite3_stmt *hUpdateStmt = nullptr;
    2995          30 :     int rc = sqlite3_prepare_v2(hDB, osCommand, -1, &hUpdateStmt, nullptr);
    2996             : 
    2997          30 :     if (rc != SQLITE_OK)
    2998             :     {
    2999           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    3000             :                  "In SetFeature(): sqlite3_prepare_v2(%s):\n  %s",
    3001             :                  osCommand.c_str(), sqlite3_errmsg(hDB));
    3002             : 
    3003           0 :         return OGRERR_FAILURE;
    3004             :     }
    3005             : 
    3006             :     /* -------------------------------------------------------------------- */
    3007             :     /*      Bind values.                                                   */
    3008             :     /* -------------------------------------------------------------------- */
    3009          30 :     OGRErr eErr = BindValues(poFeature, hUpdateStmt, false);
    3010          30 :     if (eErr != OGRERR_NONE)
    3011             :     {
    3012           0 :         sqlite3_finalize(hUpdateStmt);
    3013           0 :         return eErr;
    3014             :     }
    3015             : 
    3016             :     /* -------------------------------------------------------------------- */
    3017             :     /*      Execute the update.                                             */
    3018             :     /* -------------------------------------------------------------------- */
    3019          30 :     rc = sqlite3_step(hUpdateStmt);
    3020             : 
    3021          30 :     if (rc != SQLITE_OK && rc != SQLITE_DONE)
    3022             :     {
    3023           0 :         CPLError(CE_Failure, CPLE_AppDefined, "sqlite3_step() failed:\n  %s",
    3024             :                  sqlite3_errmsg(hDB));
    3025             : 
    3026           0 :         sqlite3_finalize(hUpdateStmt);
    3027           0 :         return OGRERR_FAILURE;
    3028             :     }
    3029             : 
    3030          30 :     sqlite3_finalize(hUpdateStmt);
    3031             : 
    3032          30 :     eErr =
    3033          30 :         (sqlite3_changes(hDB) > 0) ? OGRERR_NONE : OGRERR_NON_EXISTING_FEATURE;
    3034          30 :     if (eErr == OGRERR_NONE)
    3035             :     {
    3036          26 :         nFieldCount = m_poFeatureDefn->GetGeomFieldCount();
    3037          52 :         for (int iField = 0; iField < nFieldCount; iField++)
    3038             :         {
    3039             :             OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
    3040          26 :                 m_poFeatureDefn->myGetGeomFieldDefn(iField);
    3041          26 :             OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iField);
    3042          30 :             if (poGeomFieldDefn->m_bCachedExtentIsValid && poGeom != nullptr &&
    3043           4 :                 !poGeom->IsEmpty())
    3044             :             {
    3045           4 :                 OGREnvelope sGeomEnvelope;
    3046           4 :                 poGeom->getEnvelope(&sGeomEnvelope);
    3047           4 :                 poGeomFieldDefn->m_oCachedExtent.Merge(sGeomEnvelope);
    3048             :             }
    3049             :         }
    3050          26 :         ForceStatisticsToBeFlushed();
    3051             :     }
    3052             : 
    3053          30 :     return eErr;
    3054             : }
    3055             : 
    3056             : /************************************************************************/
    3057             : /*                          AreTriggersSimilar                          */
    3058             : /************************************************************************/
    3059             : 
    3060         286 : static int AreTriggersSimilar(const char *pszExpectedTrigger,
    3061             :                               const char *pszTriggerSQL)
    3062             : {
    3063         286 :     int i = 0;  // Used after for.
    3064       96180 :     for (; pszTriggerSQL[i] != '\0' && pszExpectedTrigger[i] != '\0'; i++)
    3065             :     {
    3066       95894 :         if (pszTriggerSQL[i] == pszExpectedTrigger[i])
    3067       94464 :             continue;
    3068        1430 :         if (pszTriggerSQL[i] == '\n' && pszExpectedTrigger[i] == ' ')
    3069        1430 :             continue;
    3070           0 :         if (pszTriggerSQL[i] == ' ' && pszExpectedTrigger[i] == '\n')
    3071           0 :             continue;
    3072           0 :         return FALSE;
    3073             :     }
    3074         286 :     return pszTriggerSQL[i] == '\0' && pszExpectedTrigger[i] == '\0';
    3075             : }
    3076             : 
    3077             : /************************************************************************/
    3078             : /*                           ICreateFeature()                           */
    3079             : /************************************************************************/
    3080             : 
    3081        6546 : OGRErr OGRSQLiteTableLayer::ICreateFeature(OGRFeature *poFeature)
    3082             : 
    3083             : {
    3084        6546 :     sqlite3 *hDB = m_poDS->GetDB();
    3085       13092 :     CPLString osCommand;
    3086        6546 :     bool bNeedComma = false;
    3087             : 
    3088        6546 :     if (HasLayerDefnError())
    3089           0 :         return OGRERR_FAILURE;
    3090             : 
    3091        6546 :     if (!m_poDS->GetUpdate())
    3092             :     {
    3093           0 :         CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
    3094             :                  "CreateFeature");
    3095           0 :         return OGRERR_FAILURE;
    3096             :     }
    3097             : 
    3098        6546 :     if (m_bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE)
    3099           0 :         return OGRERR_FAILURE;
    3100             : 
    3101             :     // For speed-up, disable Spatialite triggers that :
    3102             :     // * check the geometry type
    3103             :     // * update the last_insert columns in geometry_columns_time and the spatial
    3104             :     // index We do that only if there's no spatial index currently active We'll
    3105             :     // check ourselves the first constraint and update last_insert at layer
    3106             :     // closing
    3107        6696 :     if (!m_bHasCheckedTriggers && m_poDS->HasSpatialite4Layout() &&
    3108         150 :         m_poFeatureDefn->GetGeomFieldCount() > 0)
    3109             :     {
    3110         144 :         m_bHasCheckedTriggers = true;
    3111             : 
    3112         144 :         char *pszErrMsg = nullptr;
    3113             : 
    3114             :         // Backup INSERT ON triggers
    3115         144 :         int nRowCount = 0, nColCount = 0;
    3116         144 :         char **papszResult = nullptr;
    3117             :         char *pszSQL3 =
    3118         144 :             sqlite3_mprintf("SELECT name, sql FROM sqlite_master WHERE "
    3119             :                             "tbl_name = '%q' AND type = 'trigger' AND (name "
    3120             :                             "LIKE 'ggi_%%' OR name LIKE 'tmi_%%')",
    3121             :                             m_pszTableName);
    3122         144 :         sqlite3_get_table(m_poDS->GetDB(), pszSQL3, &papszResult, &nRowCount,
    3123             :                           &nColCount, &pszErrMsg);
    3124         144 :         sqlite3_free(pszSQL3);
    3125             : 
    3126         144 :         if (pszErrMsg)
    3127           0 :             sqlite3_free(pszErrMsg);
    3128         144 :         pszErrMsg = nullptr;
    3129             : 
    3130         290 :         for (int j = 0; j < m_poFeatureDefn->GetGeomFieldCount(); j++)
    3131             :         {
    3132             :             OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
    3133         146 :                 m_poFeatureDefn->myGetGeomFieldDefn(j);
    3134         146 :             if (!((m_bDeferredSpatialIndexCreation ||
    3135           3 :                    !poGeomFieldDefn->m_bHasSpatialIndex)))
    3136           3 :                 continue;
    3137         143 :             const char *pszGeomCol = poGeomFieldDefn->GetNameRef();
    3138             : 
    3139         437 :             for (int i = 0; i < nRowCount; i++)
    3140             :             {
    3141         294 :                 const char *pszTriggerName = papszResult[2 * (i + 1) + 0];
    3142         294 :                 const char *pszTriggerSQL = papszResult[2 * (i + 1) + 1];
    3143         588 :                 if (pszTriggerName != nullptr && pszTriggerSQL != nullptr &&
    3144         588 :                     CPLString(pszTriggerName)
    3145         294 :                             .tolower()
    3146         588 :                             .find(CPLString(pszGeomCol).tolower()) !=
    3147             :                         std::string::npos)
    3148             :                 {
    3149         286 :                     const char *pszExpectedTrigger = nullptr;
    3150         286 :                     if (STARTS_WITH(pszTriggerName, "ggi_"))
    3151             :                     {
    3152         143 :                         pszExpectedTrigger = CPLSPrintf(
    3153             :                             "CREATE TRIGGER \"ggi_%s_%s\" BEFORE INSERT ON "
    3154             :                             "\"%s\" "
    3155             :                             "FOR EACH ROW BEGIN "
    3156             :                             "SELECT RAISE(ROLLBACK, '%s.%s violates Geometry "
    3157             :                             "constraint [geom-type or SRID not allowed]') "
    3158             :                             "WHERE (SELECT geometry_type FROM geometry_columns "
    3159             :                             "WHERE Lower(f_table_name) = Lower('%s') AND "
    3160             :                             "Lower(f_geometry_column) = Lower('%s') "
    3161             :                             "AND GeometryConstraints(NEW.\"%s\", "
    3162             :                             "geometry_type, srid) = 1) IS NULL; "
    3163             :                             "END",
    3164             :                             m_pszTableName, pszGeomCol, m_pszTableName,
    3165             :                             m_pszTableName, pszGeomCol, m_pszTableName,
    3166             :                             pszGeomCol, pszGeomCol);
    3167             :                     }
    3168         143 :                     else if (STARTS_WITH(pszTriggerName, "tmi_"))
    3169             :                     {
    3170         143 :                         pszExpectedTrigger = CPLSPrintf(
    3171             :                             "CREATE TRIGGER \"tmi_%s_%s\" AFTER INSERT ON "
    3172             :                             "\"%s\" "
    3173             :                             "FOR EACH ROW BEGIN "
    3174             :                             "UPDATE geometry_columns_time SET last_insert = "
    3175             :                             "strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
    3176             :                             "WHERE Lower(f_table_name) = Lower('%s') AND "
    3177             :                             "Lower(f_geometry_column) = Lower('%s'); "
    3178             :                             "END",
    3179             :                             m_pszTableName, pszGeomCol, m_pszTableName,
    3180             :                             m_pszTableName, pszGeomCol);
    3181             :                     }
    3182             :                     /* Cannot happen due to the tests that lead to that code
    3183             :                      * path */
    3184             :                     /* that check there's no spatial index active */
    3185             :                     /* A further potential optimization would be to rebuild the
    3186             :                      * spatial index */
    3187             :                     /* afterwards... */
    3188             :                     /*else if( STARTS_WITH(pszTriggerName, "gii_") )
    3189             :                     {
    3190             :                         pszExpectedTrigger = CPLSPrintf(
    3191             :                         "CREATE TRIGGER \"gii_%s_%s\" AFTER INSERT ON \"%s\" "
    3192             :                         "FOR EACH ROW BEGIN "
    3193             :                         "UPDATE geometry_columns_time SET last_insert =
    3194             :                     strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') " "WHERE
    3195             :                     Lower(f_table_name) = Lower('%s') AND
    3196             :                     Lower(f_geometry_column) = Lower('%s'); " "DELETE FROM
    3197             :                     \"idx_%s_%s\" WHERE pkid=NEW.ROWID; " "SELECT
    3198             :                     RTreeAlign('idx_%s_%s', NEW.ROWID, NEW.\"%s\"); " "END",
    3199             :                         m_pszTableName, pszGeomCol, m_pszTableName,
    3200             :                         m_pszTableName, pszGeomCol,
    3201             :                         m_pszTableName, pszGeomCol,
    3202             :                         m_pszTableName, pszGeomCol, pszGeomCol);
    3203             :                     }*/
    3204             : 
    3205         572 :                     if (pszExpectedTrigger != nullptr &&
    3206         286 :                         AreTriggersSimilar(pszExpectedTrigger, pszTriggerSQL))
    3207             :                     {
    3208             :                         // And drop them
    3209             :                         pszSQL3 =
    3210         286 :                             sqlite3_mprintf("DROP TRIGGER %s", pszTriggerName);
    3211         286 :                         int rc = sqlite3_exec(m_poDS->GetDB(), pszSQL3, nullptr,
    3212             :                                               nullptr, &pszErrMsg);
    3213         286 :                         if (rc != SQLITE_OK)
    3214           0 :                             CPLDebug("SQLITE", "Error %s",
    3215           0 :                                      pszErrMsg ? pszErrMsg : "");
    3216             :                         else
    3217             :                         {
    3218         286 :                             CPLDebug("SQLite", "Dropping trigger %s",
    3219             :                                      pszTriggerName);
    3220         286 :                             poGeomFieldDefn->m_aosDisabledTriggers.push_back(
    3221         572 :                                 std::pair<CPLString, CPLString>(pszTriggerName,
    3222             :                                                                 pszTriggerSQL));
    3223             :                         }
    3224         286 :                         sqlite3_free(pszSQL3);
    3225         286 :                         if (pszErrMsg)
    3226           0 :                             sqlite3_free(pszErrMsg);
    3227         286 :                         pszErrMsg = nullptr;
    3228             :                     }
    3229             :                     else
    3230             :                     {
    3231           0 :                         CPLDebug("SQLite",
    3232             :                                  "Cannot drop %s trigger. Doesn't match "
    3233             :                                  "expected definition",
    3234             :                                  pszTriggerName);
    3235             :                     }
    3236             :                 }
    3237             :             }
    3238             :         }
    3239             : 
    3240         144 :         sqlite3_free_table(papszResult);
    3241             :     }
    3242             : 
    3243        6546 :     ResetReading();
    3244             : 
    3245       12268 :     for (int j = 0; j < m_poFeatureDefn->GetGeomFieldCount(); j++)
    3246             :     {
    3247             :         OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
    3248        5736 :             m_poFeatureDefn->myGetGeomFieldDefn(j);
    3249        5736 :         OGRGeometry *poGeom = poFeature->GetGeomFieldRef(j);
    3250        5736 :         if (!poGeomFieldDefn->m_aosDisabledTriggers.empty() &&
    3251             :             poGeom != nullptr)
    3252             :         {
    3253         261 :             OGRwkbGeometryType eGeomType = poGeomFieldDefn->GetType();
    3254         411 :             if (eGeomType != wkbUnknown &&
    3255         150 :                 poGeom->getGeometryType() != eGeomType)
    3256             :             {
    3257          42 :                 CPLError(CE_Failure, CPLE_AppDefined,
    3258             :                          "Cannot insert feature with geometry of type %s%s in "
    3259             :                          "column %s. Type %s%s expected",
    3260          14 :                          OGRToOGCGeomType(poGeom->getGeometryType()),
    3261          14 :                          (wkbFlatten(poGeom->getGeometryType()) !=
    3262          14 :                           poGeom->getGeometryType())
    3263             :                              ? "Z"
    3264             :                              : "",
    3265             :                          poGeomFieldDefn->GetNameRef(),
    3266             :                          OGRToOGCGeomType(eGeomType),
    3267          14 :                          (wkbFlatten(eGeomType) != eGeomType) ? "Z" : "");
    3268          14 :                 return OGRERR_FAILURE;
    3269             :             }
    3270             :         }
    3271             :     }
    3272             : 
    3273        6532 :     int bReuseStmt = false;
    3274             : 
    3275             :     /* If there's a unset field with a default value, then we must create */
    3276             :     /* a specific INSERT statement to avoid unset fields to be bound to NULL */
    3277        6532 :     bool bHasDefaultValue = false;
    3278        6532 :     int nFieldCount = m_poFeatureDefn->GetFieldCount();
    3279       76972 :     for (int iField = 0; iField < nFieldCount; iField++)
    3280             :     {
    3281       79076 :         if (!poFeature->IsFieldSet(iField) &&
    3282        8635 :             poFeature->GetFieldDefnRef(iField)->GetDefault() != nullptr)
    3283             :         {
    3284           1 :             bHasDefaultValue = true;
    3285           1 :             break;
    3286             :         }
    3287             :     }
    3288             : 
    3289             :     /* In case the FID column has also been created as a regular field */
    3290        6532 :     if (m_iFIDAsRegularColumnIndex >= 0)
    3291             :     {
    3292           3 :         if (poFeature->GetFID() == OGRNullFID)
    3293             :         {
    3294           2 :             if (poFeature->IsFieldSetAndNotNull(m_iFIDAsRegularColumnIndex))
    3295             :             {
    3296           1 :                 poFeature->SetFID(
    3297           1 :                     poFeature->GetFieldAsInteger64(m_iFIDAsRegularColumnIndex));
    3298             :             }
    3299             :         }
    3300             :         else
    3301             :         {
    3302           2 :             if (!poFeature->IsFieldSetAndNotNull(m_iFIDAsRegularColumnIndex) ||
    3303           1 :                 poFeature->GetFieldAsInteger64(m_iFIDAsRegularColumnIndex) !=
    3304           1 :                     poFeature->GetFID())
    3305             :             {
    3306           1 :                 CPLError(CE_Failure, CPLE_AppDefined,
    3307             :                          "Inconsistent values of FID and field of same name");
    3308           1 :                 return OGRERR_FAILURE;
    3309             :             }
    3310             :         }
    3311             :     }
    3312             : 
    3313             :     int bTemporaryStatement =
    3314        6531 :         (poFeature->GetFID() != OGRNullFID || bHasDefaultValue);
    3315        6531 :     if (m_hInsertStmt == nullptr || bTemporaryStatement)
    3316             :     {
    3317       10872 :         CPLString osValues;
    3318             : 
    3319             :         /* --------------------------------------------------------------------
    3320             :          */
    3321             :         /*      Form the INSERT command. */
    3322             :         /* --------------------------------------------------------------------
    3323             :          */
    3324        5436 :         osCommand += CPLSPrintf("INSERT INTO '%s' (", m_pszEscapedTableName);
    3325             : 
    3326             :         /* --------------------------------------------------------------------
    3327             :          */
    3328             :         /*      Add FID if we have a cleartext FID column. */
    3329             :         /* --------------------------------------------------------------------
    3330             :          */
    3331        5436 :         if (m_pszFIDColumn != nullptr && poFeature->GetFID() != OGRNullFID)
    3332             :         {
    3333        5039 :             osCommand += "\"";
    3334        5039 :             osCommand += SQLEscapeName(m_pszFIDColumn);
    3335        5039 :             osCommand += "\"";
    3336             : 
    3337        5039 :             osValues += CPLSPrintf(CPL_FRMT_GIB, poFeature->GetFID());
    3338        5039 :             bNeedComma = true;
    3339             :         }
    3340             : 
    3341             :         /* --------------------------------------------------------------------
    3342             :          */
    3343             :         /*      Add geometry. */
    3344             :         /* --------------------------------------------------------------------
    3345             :          */
    3346        5436 :         nFieldCount = m_poFeatureDefn->GetGeomFieldCount();
    3347       10764 :         for (int iField = 0; iField < nFieldCount; iField++)
    3348             :         {
    3349             :             OGRSQLiteGeomFormat eGeomFormat =
    3350        5328 :                 m_poFeatureDefn->myGetGeomFieldDefn(iField)->m_eGeomFormat;
    3351        5328 :             if (eGeomFormat == OSGF_FGF)
    3352           0 :                 continue;
    3353        5328 :             if (bHasDefaultValue &&
    3354           0 :                 poFeature->GetGeomFieldRef(iField) == nullptr)
    3355           0 :                 continue;
    3356        5328 :             if (bNeedComma)
    3357             :             {
    3358        5048 :                 osCommand += ",";
    3359        5048 :                 osValues += ",";
    3360             :             }
    3361             : 
    3362        5328 :             osCommand += "\"";
    3363       10656 :             osCommand += SQLEscapeName(
    3364       10656 :                 m_poFeatureDefn->GetGeomFieldDefn(iField)->GetNameRef());
    3365        5328 :             osCommand += "\"";
    3366             : 
    3367        5328 :             osValues += "?";
    3368             : 
    3369        5328 :             bNeedComma = true;
    3370             :         }
    3371             : 
    3372             :         /* --------------------------------------------------------------------
    3373             :          */
    3374             :         /*      Add field values. */
    3375             :         /* --------------------------------------------------------------------
    3376             :          */
    3377        5436 :         nFieldCount = m_poFeatureDefn->GetFieldCount();
    3378       66837 :         for (int iField = 0; iField < nFieldCount; iField++)
    3379             :         {
    3380       61401 :             if (iField == m_iFIDAsRegularColumnIndex)
    3381           2 :                 continue;
    3382       61399 :             if (bHasDefaultValue && !poFeature->IsFieldSet(iField))
    3383          10 :                 continue;
    3384             : 
    3385       61389 :             if (bNeedComma)
    3386             :             {
    3387       61274 :                 osCommand += ",";
    3388       61274 :                 osValues += ",";
    3389             :             }
    3390             : 
    3391       61389 :             osCommand += "\"";
    3392      122778 :             osCommand += SQLEscapeName(
    3393      122778 :                 m_poFeatureDefn->GetFieldDefn(iField)->GetNameRef());
    3394       61389 :             osCommand += "\"";
    3395             : 
    3396       61389 :             osValues += "?";
    3397             : 
    3398       61389 :             bNeedComma = true;
    3399             :         }
    3400             : 
    3401             :         /* --------------------------------------------------------------------
    3402             :          */
    3403             :         /*      Merge final command. */
    3404             :         /* --------------------------------------------------------------------
    3405             :          */
    3406        5436 :         osCommand += ") VALUES (";
    3407        5436 :         osCommand += osValues;
    3408        5436 :         osCommand += ")";
    3409             : 
    3410        5436 :         if (bNeedComma == false)
    3411             :             osCommand = CPLSPrintf("INSERT INTO '%s' DEFAULT VALUES",
    3412        5438 :                                    m_pszEscapedTableName);
    3413             :     }
    3414             :     else
    3415             :     {
    3416        1095 :         bReuseStmt = true;
    3417             :     }
    3418             : 
    3419             :     /* -------------------------------------------------------------------- */
    3420             :     /*      Prepare the statement.                                          */
    3421             :     /* -------------------------------------------------------------------- */
    3422       11967 :     if (!bReuseStmt &&
    3423        5436 :         (m_hInsertStmt == nullptr || osCommand != m_osLastInsertStmt))
    3424             :     {
    3425             : #ifdef DEBUG
    3426        5436 :         CPLDebug("OGR_SQLITE", "prepare_v2(%s)", osCommand.c_str());
    3427             : #endif
    3428             : 
    3429        5436 :         ClearInsertStmt();
    3430        5436 :         if (poFeature->GetFID() == OGRNullFID)
    3431         397 :             m_osLastInsertStmt = osCommand;
    3432             : 
    3433             :         const int rc =
    3434        5436 :             sqlite3_prepare_v2(hDB, osCommand, -1, &m_hInsertStmt, nullptr);
    3435        5436 :         if (rc != SQLITE_OK)
    3436             :         {
    3437           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    3438             :                      "In CreateFeature(): sqlite3_prepare_v2(%s):\n  %s",
    3439             :                      osCommand.c_str(), sqlite3_errmsg(hDB));
    3440             : 
    3441           0 :             ClearInsertStmt();
    3442           0 :             return OGRERR_FAILURE;
    3443             :         }
    3444             :     }
    3445             : 
    3446             :     /* -------------------------------------------------------------------- */
    3447             :     /*      Bind values.                                                   */
    3448             :     /* -------------------------------------------------------------------- */
    3449        6531 :     OGRErr eErr = BindValues(poFeature, m_hInsertStmt, !bHasDefaultValue);
    3450        6531 :     if (eErr != OGRERR_NONE)
    3451             :     {
    3452           0 :         sqlite3_reset(m_hInsertStmt);
    3453           0 :         return eErr;
    3454             :     }
    3455             : 
    3456             :     /* -------------------------------------------------------------------- */
    3457             :     /*      Execute the insert.                                             */
    3458             :     /* -------------------------------------------------------------------- */
    3459        6531 :     const int rc = sqlite3_step(m_hInsertStmt);
    3460             : 
    3461        6531 :     if (rc != SQLITE_OK && rc != SQLITE_DONE)
    3462             :     {
    3463           3 :         CPLError(CE_Failure, CPLE_AppDefined,
    3464             :                  "sqlite3_step() failed:\n  %s (%d)", sqlite3_errmsg(hDB), rc);
    3465           3 :         sqlite3_reset(m_hInsertStmt);
    3466           3 :         ClearInsertStmt();
    3467           3 :         return OGRERR_FAILURE;
    3468             :     }
    3469             : 
    3470             :     /* -------------------------------------------------------------------- */
    3471             :     /*      Capture the FID/rowid.                                          */
    3472             :     /* -------------------------------------------------------------------- */
    3473        6528 :     const sqlite_int64 nFID = sqlite3_last_insert_rowid(hDB);
    3474        6528 :     if (nFID > 0)
    3475             :     {
    3476        6524 :         poFeature->SetFID(nFID);
    3477        6524 :         if (m_iFIDAsRegularColumnIndex >= 0)
    3478           2 :             poFeature->SetField(m_iFIDAsRegularColumnIndex, nFID);
    3479             :     }
    3480             : 
    3481        6528 :     sqlite3_reset(m_hInsertStmt);
    3482             : 
    3483        6528 :     if (bTemporaryStatement)
    3484        5039 :         ClearInsertStmt();
    3485             : 
    3486        6528 :     nFieldCount = m_poFeatureDefn->GetGeomFieldCount();
    3487       12245 :     for (int iField = 0; iField < nFieldCount; iField++)
    3488             :     {
    3489             :         OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
    3490        5717 :             m_poFeatureDefn->myGetGeomFieldDefn(iField);
    3491        5717 :         OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iField);
    3492             : 
    3493        5717 :         if ((poGeomFieldDefn->m_bCachedExtentIsValid || m_nFeatureCount == 0) &&
    3494       11434 :             poGeom != nullptr && !poGeom->IsEmpty())
    3495             :         {
    3496        5496 :             OGREnvelope sGeomEnvelope;
    3497        5496 :             poGeom->getEnvelope(&sGeomEnvelope);
    3498        5496 :             poGeomFieldDefn->m_oCachedExtent.Merge(sGeomEnvelope);
    3499        5496 :             poGeomFieldDefn->m_bCachedExtentIsValid = true;
    3500        5496 :             ForceStatisticsToBeFlushed();
    3501             :         }
    3502             :     }
    3503             : 
    3504        6528 :     if (m_nFeatureCount >= 0)
    3505             :     {
    3506        6500 :         ForceStatisticsToBeFlushed();
    3507        6500 :         m_nFeatureCount++;
    3508             :     }
    3509             : 
    3510        6528 :     return OGRERR_NONE;
    3511             : }
    3512             : 
    3513             : /************************************************************************/
    3514             : /*                           DeleteFeature()                            */
    3515             : /************************************************************************/
    3516             : 
    3517          13 : OGRErr OGRSQLiteTableLayer::DeleteFeature(GIntBig nFID)
    3518             : 
    3519             : {
    3520          26 :     CPLString osSQL;
    3521             : 
    3522          13 :     if (HasLayerDefnError())
    3523           0 :         return OGRERR_FAILURE;
    3524             : 
    3525          13 :     if (m_pszFIDColumn == nullptr)
    3526             :     {
    3527           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    3528             :                  "Can't delete feature on a layer without FID column.");
    3529           0 :         return OGRERR_FAILURE;
    3530             :     }
    3531             : 
    3532          13 :     if (!m_poDS->GetUpdate())
    3533             :     {
    3534           0 :         CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
    3535             :                  "DeleteFeature");
    3536           0 :         return OGRERR_FAILURE;
    3537             :     }
    3538             : 
    3539          13 :     if (m_bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE)
    3540           0 :         return OGRERR_FAILURE;
    3541             : 
    3542          13 :     ResetReading();
    3543             : 
    3544             :     osSQL.Printf("DELETE FROM '%s' WHERE \"%s\" = " CPL_FRMT_GIB,
    3545          26 :                  m_pszEscapedTableName, SQLEscapeName(m_pszFIDColumn).c_str(),
    3546          13 :                  nFID);
    3547             : 
    3548          13 :     CPLDebug("OGR_SQLITE", "exec(%s)", osSQL.c_str());
    3549             : 
    3550          13 :     if (SQLCommand(m_poDS->GetDB(), osSQL) != OGRERR_NONE)
    3551           0 :         return OGRERR_FAILURE;
    3552             : 
    3553          13 :     OGRErr eErr = (sqlite3_changes(m_poDS->GetDB()) > 0)
    3554          13 :                       ? OGRERR_NONE
    3555          13 :                       : OGRERR_NON_EXISTING_FEATURE;
    3556          13 :     if (eErr == OGRERR_NONE)
    3557             :     {
    3558           6 :         int nFieldCount = m_poFeatureDefn->GetGeomFieldCount();
    3559          12 :         for (int iField = 0; iField < nFieldCount; iField++)
    3560             :         {
    3561             :             OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
    3562           6 :                 m_poFeatureDefn->myGetGeomFieldDefn(iField);
    3563           6 :             poGeomFieldDefn->m_bCachedExtentIsValid = false;
    3564             :         }
    3565           6 :         m_nFeatureCount--;
    3566           6 :         ForceStatisticsToBeFlushed();
    3567             :     }
    3568             : 
    3569          13 :     return eErr;
    3570             : }
    3571             : 
    3572             : /************************************************************************/
    3573             : /*                         CreateSpatialIndex()                         */
    3574             : /************************************************************************/
    3575             : 
    3576         137 : int OGRSQLiteTableLayer::CreateSpatialIndex(int iGeomCol)
    3577             : {
    3578         274 :     CPLString osCommand;
    3579             : 
    3580         137 :     if (m_bDeferredCreation)
    3581           0 :         RunDeferredCreationIfNecessary();
    3582             : 
    3583         137 :     if (iGeomCol < 0 || iGeomCol >= m_poFeatureDefn->GetGeomFieldCount())
    3584           0 :         return FALSE;
    3585             : 
    3586             :     osCommand.Printf(
    3587             :         "SELECT CreateSpatialIndex('%s', '%s')", m_pszEscapedTableName,
    3588         274 :         SQLEscapeLiteral(
    3589         137 :             m_poFeatureDefn->GetGeomFieldDefn(iGeomCol)->GetNameRef())
    3590         137 :             .c_str());
    3591             : 
    3592         137 :     char *pszErrMsg = nullptr;
    3593         137 :     sqlite3 *hDB = m_poDS->GetDB();
    3594             : #ifdef DEBUG
    3595         137 :     CPLDebug("OGR_SQLITE", "exec(%s)", osCommand.c_str());
    3596             : #endif
    3597         137 :     int rc = sqlite3_exec(hDB, osCommand, nullptr, nullptr, &pszErrMsg);
    3598         137 :     if (rc != SQLITE_OK)
    3599             :     {
    3600           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    3601             :                  "Unable to create spatial index:\n%s", pszErrMsg);
    3602           0 :         sqlite3_free(pszErrMsg);
    3603           0 :         return FALSE;
    3604             :     }
    3605             : 
    3606         137 :     m_poFeatureDefn->myGetGeomFieldDefn(iGeomCol)->m_bHasSpatialIndex = true;
    3607         137 :     return TRUE;
    3608             : }
    3609             : 
    3610             : /************************************************************************/
    3611             : /*                   RunDeferredCreationIfNecessary()                   */
    3612             : /************************************************************************/
    3613             : 
    3614       11325 : OGRErr OGRSQLiteTableLayer::RunDeferredCreationIfNecessary()
    3615             : {
    3616       11325 :     if (!m_bDeferredCreation)
    3617       10881 :         return OGRERR_NONE;
    3618         444 :     m_bDeferredCreation = false;
    3619             : 
    3620         888 :     CPLString osCommand;
    3621             : 
    3622             :     osCommand.Printf(
    3623             :         "CREATE TABLE '%s' ( \"%s\" INTEGER PRIMARY KEY AUTOINCREMENT",
    3624         444 :         m_pszEscapedTableName, SQLEscapeName(m_pszFIDColumn).c_str());
    3625             : 
    3626         444 :     if (!m_poDS->IsSpatialiteDB())
    3627             :     {
    3628         475 :         for (int i = 0; i < m_poFeatureDefn->GetGeomFieldCount(); i++)
    3629             :         {
    3630             :             OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
    3631         184 :                 m_poFeatureDefn->myGetGeomFieldDefn(i);
    3632             : 
    3633         184 :             if (poGeomFieldDefn->m_eGeomFormat == OSGF_WKT)
    3634             :             {
    3635             :                 osCommand += CPLSPrintf(
    3636             :                     ", '%s' VARCHAR",
    3637           1 :                     SQLEscapeLiteral(poGeomFieldDefn->GetNameRef()).c_str());
    3638             :             }
    3639             :             else
    3640             :             {
    3641             :                 osCommand += CPLSPrintf(
    3642             :                     ", '%s' BLOB",
    3643         183 :                     SQLEscapeLiteral(poGeomFieldDefn->GetNameRef()).c_str());
    3644             :             }
    3645         184 :             if (!poGeomFieldDefn->IsNullable())
    3646             :             {
    3647           1 :                 osCommand += " NOT NULL";
    3648             :             }
    3649             :         }
    3650             :     }
    3651             : 
    3652        1678 :     for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); i++)
    3653             :     {
    3654        1234 :         OGRFieldDefn *poFieldDefn = m_poFeatureDefn->GetFieldDefn(i);
    3655        1234 :         if (i == m_iFIDAsRegularColumnIndex)
    3656           1 :             continue;
    3657        2466 :         CPLString osFieldType(FieldDefnToSQliteFieldDefn(poFieldDefn));
    3658             :         osCommand += CPLSPrintf(
    3659        2466 :             ", '%s' %s", SQLEscapeLiteral(poFieldDefn->GetNameRef()).c_str(),
    3660        2466 :             osFieldType.c_str());
    3661        1233 :         if (!poFieldDefn->IsNullable())
    3662             :         {
    3663         302 :             osCommand += " NOT NULL";
    3664             :         }
    3665        1233 :         if (poFieldDefn->IsUnique())
    3666             :         {
    3667           3 :             osCommand += " UNIQUE";
    3668             :         }
    3669        1233 :         const char *pszDefault = poFieldDefn->GetDefault();
    3670        1254 :         if (pszDefault != nullptr &&
    3671          21 :             (!poFieldDefn->IsDefaultDriverSpecific() ||
    3672           1 :              (pszDefault[0] == '(' &&
    3673           1 :               pszDefault[strlen(pszDefault) - 1] == ')' &&
    3674           1 :               (STARTS_WITH_CI(pszDefault + 1, "strftime") ||
    3675           0 :                STARTS_WITH_CI(pszDefault + 1, " strftime")))))
    3676             :         {
    3677          21 :             osCommand += " DEFAULT ";
    3678          21 :             osCommand += poFieldDefn->GetDefault();
    3679             :         }
    3680             :     }
    3681         444 :     osCommand += ")";
    3682         444 :     if (m_bStrict)
    3683           1 :         osCommand += " STRICT";
    3684             : 
    3685             : #ifdef DEBUG
    3686         444 :     CPLDebug("OGR_SQLITE", "exec(%s)", osCommand.c_str());
    3687             : #endif
    3688             : 
    3689         444 :     if (SQLCommand(m_poDS->GetDB(), osCommand) != OGRERR_NONE)
    3690           0 :         return OGRERR_FAILURE;
    3691             : 
    3692             :     /* -------------------------------------------------------------------- */
    3693             :     /*      Eventually we should be adding this table to a table of         */
    3694             :     /*      "geometric layers", capturing the WKT projection, and           */
    3695             :     /*      perhaps some other housekeeping.                                */
    3696             :     /* -------------------------------------------------------------------- */
    3697         444 :     if (m_poDS->HasGeometryColumns())
    3698             :     {
    3699             :         /* Sometimes there is an old cruft entry in the geometry_columns
    3700             :          * table if things were not properly cleaned up before.  We make
    3701             :          * an effort to clean out such cruft.
    3702             :          */
    3703             :         osCommand.Printf(
    3704             :             "DELETE FROM geometry_columns WHERE f_table_name = '%s'",
    3705         435 :             m_pszEscapedTableName);
    3706             : 
    3707             : #ifdef DEBUG
    3708         435 :         CPLDebug("OGR_SQLITE", "exec(%s)", osCommand.c_str());
    3709             : #endif
    3710         435 :         if (SQLCommand(m_poDS->GetDB(), osCommand) != OGRERR_NONE)
    3711           0 :             return OGRERR_FAILURE;
    3712             : 
    3713         770 :         for (int i = 0; i < m_poFeatureDefn->GetGeomFieldCount(); i++)
    3714             :         {
    3715             :             OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
    3716         335 :                 m_poFeatureDefn->myGetGeomFieldDefn(i);
    3717         335 :             if (RunAddGeometryColumn(poGeomFieldDefn, false) != OGRERR_NONE)
    3718           0 :                 return OGRERR_FAILURE;
    3719             :         }
    3720             :     }
    3721             : 
    3722         444 :     if (RecomputeOrdinals() != OGRERR_NONE)
    3723           0 :         return OGRERR_FAILURE;
    3724             : 
    3725         444 :     if (m_poDS->IsSpatialiteDB() && m_poDS->GetLayerCount() == 1)
    3726             :     {
    3727             :         /* To create the layer_statistics and spatialite_history tables */
    3728          40 :         if (SQLCommand(m_poDS->GetDB(), "SELECT UpdateLayerStatistics()") !=
    3729             :             OGRERR_NONE)
    3730           0 :             return OGRERR_FAILURE;
    3731             :     }
    3732             : 
    3733         444 :     return OGRERR_NONE;
    3734             : }
    3735             : 
    3736             : /************************************************************************/
    3737             : /*                          HasSpatialIndex()                           */
    3738             : /************************************************************************/
    3739             : 
    3740         128 : bool OGRSQLiteTableLayer::HasSpatialIndex(int iGeomCol) const
    3741             : {
    3742         128 :     GetLayerDefn();
    3743         128 :     if (iGeomCol < 0 || iGeomCol >= m_poFeatureDefn->GetGeomFieldCount())
    3744           0 :         return false;
    3745             :     const OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
    3746         128 :         m_poFeatureDefn->myGetGeomFieldDefn(iGeomCol);
    3747             : 
    3748         128 :     const_cast<OGRSQLiteTableLayer *>(this)->CreateSpatialIndexIfNecessary();
    3749             : 
    3750         128 :     return poGeomFieldDefn->m_bHasSpatialIndex;
    3751             : }
    3752             : 
    3753             : /************************************************************************/
    3754             : /*                          InitFeatureCount()                          */
    3755             : /************************************************************************/
    3756             : 
    3757         444 : void OGRSQLiteTableLayer::InitFeatureCount()
    3758             : {
    3759         444 :     m_nFeatureCount = 0;
    3760         444 :     ForceStatisticsToBeFlushed();
    3761         444 : }
    3762             : 
    3763             : /************************************************************************/
    3764             : /*               InvalidateCachedFeatureCountAndExtent()                */
    3765             : /************************************************************************/
    3766             : 
    3767          70 : void OGRSQLiteTableLayer::InvalidateCachedFeatureCountAndExtent()
    3768             : {
    3769          70 :     m_nFeatureCount = -1;
    3770         126 :     for (int iGeomCol = 0; iGeomCol < GetLayerDefn()->GetGeomFieldCount();
    3771             :          iGeomCol++)
    3772          56 :         m_poFeatureDefn->myGetGeomFieldDefn(iGeomCol)->m_bCachedExtentIsValid =
    3773             :             false;
    3774          70 :     ForceStatisticsToBeFlushed();
    3775          70 : }
    3776             : 
    3777             : /************************************************************************/
    3778             : /*                    DoStatisticsNeedToBeFlushed()                     */
    3779             : /************************************************************************/
    3780             : 
    3781           0 : bool OGRSQLiteTableLayer::DoStatisticsNeedToBeFlushed()
    3782             : {
    3783           0 :     return m_bStatisticsNeedsToBeFlushed && m_poDS->IsSpatialiteDB() &&
    3784           0 :            m_poDS->IsSpatialiteLoaded();
    3785             : }
    3786             : 
    3787             : /************************************************************************/
    3788             : /*                     ForceStatisticsToBeFlushed()                     */
    3789             : /************************************************************************/
    3790             : 
    3791       12556 : void OGRSQLiteTableLayer::ForceStatisticsToBeFlushed()
    3792             : {
    3793       12556 :     m_bStatisticsNeedsToBeFlushed = true;
    3794       12556 : }
    3795             : 
    3796             : /************************************************************************/
    3797             : /*                         AreStatisticsValid()                         */
    3798             : /************************************************************************/
    3799             : 
    3800           1 : bool OGRSQLiteTableLayer::AreStatisticsValid()
    3801             : {
    3802           1 :     return m_nFeatureCount >= 0;
    3803             : }
    3804             : 
    3805             : /************************************************************************/
    3806             : /*                    LoadStatisticsSpatialite4DB()                     */
    3807             : /************************************************************************/
    3808             : 
    3809         136 : void OGRSQLiteTableLayer::LoadStatisticsSpatialite4DB()
    3810             : {
    3811         264 :     for (int iCol = 0; iCol < GetLayerDefn()->GetGeomFieldCount(); iCol++)
    3812             :     {
    3813             :         OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
    3814         137 :             m_poFeatureDefn->myGetGeomFieldDefn(iCol);
    3815         137 :         const char *pszGeomCol = poGeomFieldDefn->GetNameRef();
    3816             : 
    3817         137 :         CPLString osSQL;
    3818         137 :         CPLString osLastEvtDate;
    3819             :         osSQL.Printf(
    3820             :             "SELECT MAX(last_insert, last_update, last_delete) FROM "
    3821             :             "geometry_columns_time WHERE "
    3822             :             "(f_table_name = lower('%s') AND f_geometry_column = lower('%s'))"
    3823             : #ifdef WORKAROUND_SQLITE3_BUGS
    3824             :             " OR 0"
    3825             : #endif
    3826             :             ,
    3827         137 :             m_pszEscapedTableName, SQLEscapeLiteral(pszGeomCol).c_str());
    3828             : 
    3829         137 :         sqlite3 *hDB = m_poDS->GetDB();
    3830         137 :         int nRowCount = 0;
    3831         137 :         int nColCount = 0;
    3832         137 :         char **papszResult = nullptr;
    3833             : 
    3834         137 :         sqlite3_get_table(hDB, osSQL.c_str(), &papszResult, &nRowCount,
    3835             :                           &nColCount, nullptr);
    3836             : 
    3837             :         /* Make it a Unix timestamp */
    3838         137 :         int nYear = 0;
    3839         137 :         int nMonth = 0;
    3840         137 :         int nDay = 0;
    3841         137 :         char chSep = 0;
    3842         137 :         int nHour = 0;
    3843         137 :         int nMinute = 0;
    3844         137 :         float fSecond = 0.0f;
    3845         265 :         if (nRowCount == 1 && nColCount == 1 && papszResult[1] != nullptr &&
    3846         128 :             sscanf(papszResult[1], "%04d-%02d-%02d%c%02d:%02d:%f", &nYear,
    3847             :                    &nMonth, &nDay, &chSep, &nHour, &nMinute, &fSecond) == 7)
    3848             :         {
    3849         128 :             osLastEvtDate = papszResult[1];
    3850             :         }
    3851             : 
    3852         137 :         sqlite3_free_table(papszResult);
    3853         137 :         papszResult = nullptr;
    3854             : 
    3855         137 :         if (osLastEvtDate.empty())
    3856           9 :             return;
    3857             : 
    3858             :         osSQL.Printf(
    3859             :             "SELECT last_verified, row_count, extent_min_x, extent_min_y, "
    3860             :             "extent_max_x, extent_max_y FROM geometry_columns_statistics WHERE "
    3861             :             "(f_table_name = lower('%s') AND f_geometry_column = lower('%s'))"
    3862             : #ifdef WORKAROUND_SQLITE3_BUGS
    3863             :             " OR 0"
    3864             : #endif
    3865             :             ,
    3866         128 :             m_pszEscapedTableName, SQLEscapeLiteral(pszGeomCol).c_str());
    3867             : 
    3868         128 :         nRowCount = 0;
    3869         128 :         nColCount = 0;
    3870         128 :         sqlite3_get_table(hDB, osSQL.c_str(), &papszResult, &nRowCount,
    3871             :                           &nColCount, nullptr);
    3872             : 
    3873         164 :         if (nRowCount == 1 && nColCount == 6 && papszResult[6] != nullptr &&
    3874          36 :             sscanf(papszResult[6], "%04d-%02d-%02d%c%02d:%02d:%f", &nYear,
    3875             :                    &nMonth, &nDay, &chSep, &nHour, &nMinute, &fSecond) == 7)
    3876             :         {
    3877          72 :             CPLString osLastVerified(papszResult[6]);
    3878             : 
    3879             :             /* Check that the information in geometry_columns_statistics is more
    3880             :              */
    3881             :             /* recent than geometry_columns_time */
    3882          36 :             if (osLastVerified.compare(osLastEvtDate) > 0)
    3883             :             {
    3884          14 :                 char **papszRow = papszResult + 6;
    3885          14 :                 const char *pszRowCount = papszRow[1];
    3886          14 :                 const char *pszMinX = papszRow[2];
    3887          14 :                 const char *pszMinY = papszRow[3];
    3888          14 :                 const char *pszMaxX = papszRow[4];
    3889          14 :                 const char *pszMaxY = papszRow[5];
    3890             : 
    3891          14 :                 CPLDebug("SQLITE", "Loading statistics for %s,%s",
    3892             :                          m_pszTableName, pszGeomCol);
    3893             : 
    3894          14 :                 if (pszRowCount != nullptr)
    3895             :                 {
    3896          14 :                     m_nFeatureCount = CPLAtoGIntBig(pszRowCount);
    3897          14 :                     if (m_nFeatureCount == 0)
    3898             :                     {
    3899          11 :                         m_nFeatureCount = -1;
    3900          11 :                         pszMinX = nullptr;
    3901             :                     }
    3902             :                     else
    3903             :                     {
    3904           3 :                         CPLDebug("SQLITE",
    3905             :                                  "Layer %s feature count : " CPL_FRMT_GIB,
    3906             :                                  m_pszTableName, m_nFeatureCount);
    3907             :                     }
    3908             :                 }
    3909             : 
    3910          14 :                 if (pszMinX != nullptr && pszMinY != nullptr &&
    3911           3 :                     pszMaxX != nullptr && pszMaxY != nullptr)
    3912             :                 {
    3913           3 :                     poGeomFieldDefn->m_bCachedExtentIsValid = true;
    3914           3 :                     poGeomFieldDefn->m_oCachedExtent.MinX = CPLAtof(pszMinX);
    3915           3 :                     poGeomFieldDefn->m_oCachedExtent.MinY = CPLAtof(pszMinY);
    3916           3 :                     poGeomFieldDefn->m_oCachedExtent.MaxX = CPLAtof(pszMaxX);
    3917           3 :                     poGeomFieldDefn->m_oCachedExtent.MaxY = CPLAtof(pszMaxY);
    3918           3 :                     CPLDebug("SQLITE", "Layer %s extent : %s,%s,%s,%s",
    3919             :                              m_pszTableName, pszMinX, pszMinY, pszMaxX,
    3920             :                              pszMaxY);
    3921             :                 }
    3922             :             }
    3923             :             else
    3924             :             {
    3925          22 :                 CPLDebug("SQLite", "Statistics in %s is not up-to-date",
    3926             :                          m_pszTableName);
    3927             :             }
    3928             :         }
    3929             : 
    3930         128 :         sqlite3_free_table(papszResult);
    3931         128 :         papszResult = nullptr;
    3932             :     }
    3933             : }
    3934             : 
    3935             : /************************************************************************/
    3936             : /*                           LoadStatistics()                           */
    3937             : /************************************************************************/
    3938             : 
    3939         390 : void OGRSQLiteTableLayer::LoadStatistics()
    3940             : {
    3941         390 :     if (!m_poDS->IsSpatialiteDB() || !m_poDS->IsSpatialiteLoaded())
    3942         387 :         return;
    3943             : 
    3944         139 :     if (m_poDS->HasSpatialite4Layout())
    3945             :     {
    3946         136 :         LoadStatisticsSpatialite4DB();
    3947         136 :         return;
    3948             :     }
    3949             : 
    3950           3 :     if (GetLayerDefn()->GetGeomFieldCount() != 1)
    3951           0 :         return;
    3952           3 :     const char *pszGeomCol = m_poFeatureDefn->GetGeomFieldDefn(0)->GetNameRef();
    3953             : 
    3954           3 :     GIntBig nFileTimestamp = m_poDS->GetFileTimestamp();
    3955           3 :     if (nFileTimestamp == 0)
    3956           0 :         return;
    3957             : 
    3958             :     /* Find the most recent event in the 'spatialite_history' that is */
    3959             :     /* a UpdateLayerStatistics event on all tables and geometry columns */
    3960           6 :     CPLString osSQL;
    3961             :     osSQL.Printf("SELECT MAX(timestamp) FROM spatialite_history WHERE "
    3962             :                  "((table_name = '%s' AND geometry_column = '%s') OR "
    3963             :                  "(table_name = 'ALL-TABLES' AND geometry_column = "
    3964             :                  "'ALL-GEOMETRY-COLUMNS')) AND "
    3965             :                  "event = 'UpdateLayerStatistics'",
    3966           3 :                  m_pszEscapedTableName, SQLEscapeLiteral(pszGeomCol).c_str());
    3967             : 
    3968           3 :     sqlite3 *hDB = m_poDS->GetDB();
    3969           3 :     int nRowCount = 0, nColCount = 0;
    3970           3 :     char **papszResult = nullptr, *pszErrMsg = nullptr;
    3971             : 
    3972           3 :     sqlite3_get_table(hDB, osSQL.c_str(), &papszResult, &nRowCount, &nColCount,
    3973             :                       &pszErrMsg);
    3974             : 
    3975             :     /* Make it a Unix timestamp */
    3976             :     int nYear, nMonth, nDay, nHour, nMinute, nSecond;
    3977             :     struct tm brokendown;
    3978           3 :     GIntBig nTS = -1;
    3979           3 :     if (nRowCount >= 1 && nColCount == 1 && papszResult[1] != nullptr &&
    3980           0 :         sscanf(papszResult[1], "%04d-%02d-%02d %02d:%02d:%02d", &nYear, &nMonth,
    3981             :                &nDay, &nHour, &nMinute, &nSecond) == 6)
    3982             :     {
    3983           0 :         brokendown.tm_year = nYear - 1900;
    3984           0 :         brokendown.tm_mon = nMonth - 1;
    3985           0 :         brokendown.tm_mday = nDay;
    3986           0 :         brokendown.tm_hour = nHour;
    3987           0 :         brokendown.tm_min = nMinute;
    3988           0 :         brokendown.tm_sec = nSecond;
    3989           0 :         nTS = CPLYMDHMSToUnixTime(&brokendown);
    3990             :     }
    3991             : 
    3992             :     /* If it is equal to the modified timestamp of the DB (as a file) */
    3993             :     /* then we can safely use the data from the layer_statistics, since */
    3994             :     /* it will be up-to-date */
    3995             :     // cppcheck-suppress knownConditionTrueFalse
    3996           3 :     if (nFileTimestamp == nTS || nFileTimestamp == nTS + 1)
    3997             :     {
    3998             :         osSQL.Printf("SELECT row_count, extent_min_x, extent_min_y, "
    3999             :                      "extent_max_x, extent_max_y "
    4000             :                      "FROM layer_statistics WHERE table_name = '%s' AND "
    4001             :                      "geometry_column = '%s'",
    4002             :                      m_pszEscapedTableName,
    4003           0 :                      SQLEscapeLiteral(pszGeomCol).c_str());
    4004             : 
    4005           0 :         sqlite3_free_table(papszResult);
    4006           0 :         papszResult = nullptr;
    4007             : 
    4008           0 :         sqlite3_get_table(hDB, osSQL.c_str(), &papszResult, &nRowCount,
    4009             :                           &nColCount, &pszErrMsg);
    4010             : 
    4011           0 :         if (nRowCount == 1)
    4012             :         {
    4013           0 :             char **papszRow = papszResult + 5;
    4014           0 :             const char *pszRowCount = papszRow[0];
    4015           0 :             const char *pszMinX = papszRow[1];
    4016           0 :             const char *pszMinY = papszRow[2];
    4017           0 :             const char *pszMaxX = papszRow[3];
    4018           0 :             const char *pszMaxY = papszRow[4];
    4019             : 
    4020           0 :             CPLDebug("SQLITE",
    4021             :                      "File timestamp matches layer statistics timestamp. "
    4022             :                      "Loading statistics for %s",
    4023             :                      m_pszTableName);
    4024             : 
    4025           0 :             if (pszRowCount != nullptr)
    4026             :             {
    4027           0 :                 m_nFeatureCount = CPLAtoGIntBig(pszRowCount);
    4028           0 :                 CPLDebug("SQLITE", "Layer %s feature count : " CPL_FRMT_GIB,
    4029             :                          m_pszTableName, m_nFeatureCount);
    4030             :             }
    4031             : 
    4032           0 :             if (pszMinX != nullptr && pszMinY != nullptr &&
    4033           0 :                 pszMaxX != nullptr && pszMaxY != nullptr)
    4034             :             {
    4035             :                 OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
    4036           0 :                     m_poFeatureDefn->myGetGeomFieldDefn(0);
    4037           0 :                 poGeomFieldDefn->m_bCachedExtentIsValid = true;
    4038           0 :                 poGeomFieldDefn->m_oCachedExtent.MinX = CPLAtof(pszMinX);
    4039           0 :                 poGeomFieldDefn->m_oCachedExtent.MinY = CPLAtof(pszMinY);
    4040           0 :                 poGeomFieldDefn->m_oCachedExtent.MaxX = CPLAtof(pszMaxX);
    4041           0 :                 poGeomFieldDefn->m_oCachedExtent.MaxY = CPLAtof(pszMaxY);
    4042           0 :                 CPLDebug("SQLITE", "Layer %s extent : %s,%s,%s,%s",
    4043             :                          m_pszTableName, pszMinX, pszMinY, pszMaxX, pszMaxY);
    4044             :             }
    4045             :         }
    4046             :     }
    4047             : 
    4048           3 :     if (pszErrMsg)
    4049           0 :         sqlite3_free(pszErrMsg);
    4050             : 
    4051           3 :     sqlite3_free_table(papszResult);
    4052             : }
    4053             : 
    4054             : /************************************************************************/
    4055             : /*                           SaveStatistics()                           */
    4056             : /************************************************************************/
    4057             : 
    4058         345 : int OGRSQLiteTableLayer::SaveStatistics()
    4059             : {
    4060         138 :     if (!m_bStatisticsNeedsToBeFlushed || !m_poDS->IsSpatialiteDB() ||
    4061         483 :         !m_poDS->IsSpatialiteLoaded() || !m_poDS->GetUpdate())
    4062         207 :         return -1;
    4063         138 :     if (GetLayerDefn()->GetGeomFieldCount() != 1)
    4064           4 :         return -1;
    4065             :     OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
    4066         134 :         m_poFeatureDefn->myGetGeomFieldDefn(0);
    4067         134 :     const char *pszGeomCol = poGeomFieldDefn->GetNameRef();
    4068             : 
    4069         268 :     CPLString osSQL;
    4070         134 :     sqlite3 *hDB = m_poDS->GetDB();
    4071         134 :     char *pszErrMsg = nullptr;
    4072             : 
    4073             :     // Update geometry_columns_time.
    4074         134 :     if (!poGeomFieldDefn->m_aosDisabledTriggers.empty())
    4075             :     {
    4076         123 :         char *pszSQL3 = sqlite3_mprintf(
    4077             :             "UPDATE geometry_columns_time "
    4078             :             "SET last_insert = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
    4079             :             "WHERE Lower(f_table_name) = Lower('%q') AND "
    4080             :             "Lower(f_geometry_column) = Lower('%q')",
    4081             :             m_pszTableName, poGeomFieldDefn->GetNameRef());
    4082         123 :         if (sqlite3_exec(m_poDS->GetDB(), pszSQL3, nullptr, nullptr,
    4083         123 :                          &pszErrMsg) != SQLITE_OK)
    4084             :         {
    4085           0 :             CPLDebug("SQLITE", "%s: error %s", pszSQL3,
    4086           0 :                      pszErrMsg ? pszErrMsg : "unknown");
    4087           0 :             sqlite3_free(pszErrMsg);
    4088           0 :             pszErrMsg = nullptr;
    4089             :         }
    4090         123 :         sqlite3_free(pszSQL3);
    4091             :     }
    4092             : 
    4093         134 :     const char *pszStatTableName = m_poDS->HasSpatialite4Layout()
    4094         134 :                                        ? "geometry_columns_statistics"
    4095         134 :                                        : "layer_statistics";
    4096         134 :     if (SQLGetInteger(m_poDS->GetDB(),
    4097             :                       CPLSPrintf("SELECT 1 FROM sqlite_master WHERE type IN "
    4098             :                                  "('view', 'table') AND name = '%s'",
    4099             :                                  pszStatTableName),
    4100         134 :                       nullptr) == 0)
    4101             :     {
    4102           1 :         return TRUE;
    4103             :     }
    4104             :     const char *pszFTableName =
    4105         133 :         m_poDS->HasSpatialite4Layout() ? "f_table_name" : "table_name";
    4106         133 :     const char *pszFGeometryColumn = m_poDS->HasSpatialite4Layout()
    4107         133 :                                          ? "f_geometry_column"
    4108         133 :                                          : "geometry_column";
    4109         266 :     CPLString osTableName(m_pszTableName);
    4110         266 :     CPLString osGeomCol(pszGeomCol);
    4111         133 :     const char *pszNowValue = "";
    4112         133 :     if (m_poDS->HasSpatialite4Layout())
    4113             :     {
    4114         133 :         osTableName = osTableName.tolower();
    4115         133 :         osGeomCol = osGeomCol.tolower();
    4116         133 :         pszNowValue = ", strftime('%Y-%m-%dT%H:%M:%fZ','now')";
    4117             :     }
    4118             : 
    4119         133 :     if (m_nFeatureCount >= 0)
    4120             :     {
    4121             :         /* Update or add entry in the layer_statistics table */
    4122         129 :         if (poGeomFieldDefn->m_bCachedExtentIsValid)
    4123             :         {
    4124             :             osSQL.Printf("INSERT OR REPLACE INTO %s (%s"
    4125             :                          "%s, %s, row_count, extent_min_x, "
    4126             :                          "extent_min_y, extent_max_x, extent_max_y%s) VALUES ("
    4127             :                          "%s'%s', '%s', " CPL_FRMT_GIB ", ?, ?, ?, ?%s)",
    4128             :                          pszStatTableName,
    4129         109 :                          m_poDS->HasSpatialite4Layout() ? "" : "raster_layer, ",
    4130             :                          pszFTableName, pszFGeometryColumn,
    4131         109 :                          m_poDS->HasSpatialite4Layout() ? ", last_verified"
    4132             :                                                         : "",
    4133         109 :                          m_poDS->HasSpatialite4Layout() ? "" : "0 ,",
    4134         218 :                          SQLEscapeLiteral(osTableName).c_str(),
    4135         218 :                          SQLEscapeLiteral(osGeomCol).c_str(), m_nFeatureCount,
    4136         654 :                          pszNowValue);
    4137             : 
    4138         109 :             sqlite3_stmt *m_hStmtInsert = nullptr;
    4139             :             int rc =
    4140         109 :                 sqlite3_prepare_v2(hDB, osSQL, -1, &m_hStmtInsert, nullptr);
    4141         109 :             if (rc == SQLITE_OK)
    4142         109 :                 rc = sqlite3_bind_double(m_hStmtInsert, 1,
    4143             :                                          poGeomFieldDefn->m_oCachedExtent.MinX);
    4144         109 :             if (rc == SQLITE_OK)
    4145         109 :                 rc = sqlite3_bind_double(m_hStmtInsert, 2,
    4146             :                                          poGeomFieldDefn->m_oCachedExtent.MinY);
    4147         109 :             if (rc == SQLITE_OK)
    4148         109 :                 rc = sqlite3_bind_double(m_hStmtInsert, 3,
    4149             :                                          poGeomFieldDefn->m_oCachedExtent.MaxX);
    4150         109 :             if (rc == SQLITE_OK)
    4151         109 :                 rc = sqlite3_bind_double(m_hStmtInsert, 4,
    4152             :                                          poGeomFieldDefn->m_oCachedExtent.MaxY);
    4153         109 :             if (rc == SQLITE_OK)
    4154         109 :                 rc = sqlite3_step(m_hStmtInsert);
    4155         109 :             if (rc != SQLITE_DONE)
    4156             :             {
    4157           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    4158             :                          "In Initialize(): sqlite3_step(%s):\n  %s",
    4159             :                          osSQL.c_str(), sqlite3_errmsg(hDB));
    4160             :             }
    4161         109 :             sqlite3_finalize(m_hStmtInsert);
    4162         109 :             return rc == SQLITE_DONE;
    4163             :         }
    4164             :         else
    4165             :         {
    4166             :             osSQL.Printf(
    4167             :                 "INSERT OR REPLACE INTO %s (%s"
    4168             :                 "%s, %s, row_count, extent_min_x, "
    4169             :                 "extent_min_y, extent_max_x, extent_max_y%s) VALUES ("
    4170             :                 "%s'%s', '%s', " CPL_FRMT_GIB ", NULL, NULL, NULL, NULL%s)",
    4171             :                 pszStatTableName,
    4172          20 :                 m_poDS->HasSpatialite4Layout() ? "" : "raster_layer, ",
    4173             :                 pszFTableName, pszFGeometryColumn,
    4174          20 :                 m_poDS->HasSpatialite4Layout() ? ", last_verified" : "",
    4175          20 :                 m_poDS->HasSpatialite4Layout() ? "" : "0 ,",
    4176          40 :                 SQLEscapeLiteral(osTableName).c_str(),
    4177          40 :                 SQLEscapeLiteral(osGeomCol).c_str(), m_nFeatureCount,
    4178         120 :                 pszNowValue);
    4179          20 :             return SQLCommand(hDB, osSQL) == OGRERR_NONE;
    4180             :         }
    4181             :     }
    4182             :     else
    4183             :     {
    4184             :         /* Remove any existing entry in layer_statistics if for some reason */
    4185             :         /* we know that it will out-of-sync */
    4186             :         osSQL.Printf("DELETE FROM %s WHERE "
    4187             :                      "%s = '%s' AND %s = '%s'",
    4188             :                      pszStatTableName, pszFTableName,
    4189           8 :                      SQLEscapeLiteral(osTableName).c_str(), pszFGeometryColumn,
    4190          12 :                      SQLEscapeLiteral(osGeomCol).c_str());
    4191           4 :         return SQLCommand(hDB, osSQL) == OGRERR_NONE;
    4192             :     }
    4193             : }
    4194             : 
    4195             : /************************************************************************/
    4196             : /*                        SetCompressedColumns()                        */
    4197             : /************************************************************************/
    4198             : 
    4199         444 : void OGRSQLiteTableLayer::SetCompressedColumns(const char *pszCompressedColumns)
    4200             : {
    4201         444 :     m_papszCompressedColumns =
    4202         444 :         CSLTokenizeString2(pszCompressedColumns, ",", CSLT_HONOURSTRINGS);
    4203         444 : }

Generated by: LCOV version 1.14