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

Generated by: LCOV version 1.14