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

Generated by: LCOV version 1.14