LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/sqlite - ogrsqlitedatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1605 1951 82.3 %
Date: 2026-03-25 17:52:11 Functions: 76 78 97.4 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implements OGRSQLiteDataSource class.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  *
       9             :  * Contributor: Alessandro Furieri, a.furieri@lqt.it
      10             :  * Portions of this module properly supporting SpatiaLite Table/Geom creation
      11             :  * Developed for Faunalia ( http://www.faunalia.it) with funding from
      12             :  * Regione Toscana - Settore SISTEMA INFORMATIVO TERRITORIALE ED AMBIENTALE
      13             :  *
      14             :  ******************************************************************************
      15             :  * Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.com>
      16             :  * Copyright (c) 2009-2013, Even Rouault <even dot rouault at spatialys.com>
      17             :  *
      18             :  * SPDX-License-Identifier: MIT
      19             :  ****************************************************************************/
      20             : 
      21             : #include "cpl_port.h"
      22             : #include "ogr_sqlite.h"
      23             : #include "ogrsqlitevirtualogr.h"
      24             : #include "ogrsqliteutility.h"
      25             : #include "ogrsqlitevfs.h"
      26             : 
      27             : #include <cctype>
      28             : #include <cstddef>
      29             : #include <cstdio>
      30             : #include <cstdlib>
      31             : #include <cstring>
      32             : #include <sys/stat.h>
      33             : #include <map>
      34             : #include <mutex>
      35             : #include <set>
      36             : #include <sstream>
      37             : #include <string>
      38             : #include <utility>
      39             : #include <vector>
      40             : 
      41             : #include "cpl_conv.h"
      42             : #include "cpl_error.h"
      43             : #include "cpl_hash_set.h"
      44             : #include "cpl_multiproc.h"
      45             : #include "cpl_string.h"
      46             : #include "cpl_vsi.h"
      47             : #include "gdal.h"
      48             : #include "gdal_pam.h"
      49             : #include "gdal_priv.h"
      50             : #include "ogr_core.h"
      51             : #include "ogr_feature.h"
      52             : #include "ogr_geometry.h"
      53             : #include "ogr_spatialref.h"
      54             : #include "ogr_schema_override.h"
      55             : #include "ogrsf_frmts.h"
      56             : #include "sqlite3.h"
      57             : 
      58             : #include "proj.h"
      59             : #include "ogr_proj_p.h"
      60             : 
      61             : #ifdef __clang__
      62             : #pragma clang diagnostic push
      63             : #pragma clang diagnostic ignored "-Wunknown-pragmas"
      64             : #pragma clang diagnostic ignored "-Wdocumentation"
      65             : #pragma clang diagnostic ignored "-Wdocumentation-unknown-command"
      66             : #endif
      67             : 
      68             : #if defined(HAVE_SPATIALITE) && !defined(SPATIALITE_DLOPEN)
      69             : #include "spatialite.h"
      70             : #endif
      71             : 
      72             : #ifdef __clang__
      73             : #pragma clang diagnostic pop
      74             : #endif
      75             : 
      76             : #undef SQLITE_STATIC
      77             : #define SQLITE_STATIC (static_cast<sqlite3_destructor_type>(nullptr))
      78             : 
      79             : // Keep in sync prototype of those 2 functions between gdalopeninfo.cpp,
      80             : // ogrsqlitedatasource.cpp and ogrgeopackagedatasource.cpp
      81             : void GDALOpenInfoDeclareFileNotToOpen(const char *pszFilename,
      82             :                                       const GByte *pabyHeader,
      83             :                                       int nHeaderBytes);
      84             : void GDALOpenInfoUnDeclareFileNotToOpen(const char *pszFilename);
      85             : 
      86             : #ifdef HAVE_SPATIALITE
      87             : 
      88             : #ifdef SPATIALITE_DLOPEN
      89             : static CPLMutex *hMutexLoadSpatialiteSymbols = nullptr;
      90             : static void *(*pfn_spatialite_alloc_connection)(void) = nullptr;
      91             : static void (*pfn_spatialite_shutdown)(void) = nullptr;
      92             : static void (*pfn_spatialite_init_ex)(sqlite3 *, const void *, int) = nullptr;
      93             : static void (*pfn_spatialite_cleanup_ex)(const void *) = nullptr;
      94             : static const char *(*pfn_spatialite_version)(void) = nullptr;
      95             : #else
      96             : static void *(*pfn_spatialite_alloc_connection)(void) =
      97             :     spatialite_alloc_connection;
      98             : static void (*pfn_spatialite_shutdown)(void) = spatialite_shutdown;
      99             : static void (*pfn_spatialite_init_ex)(sqlite3 *, const void *,
     100             :                                       int) = spatialite_init_ex;
     101             : static void (*pfn_spatialite_cleanup_ex)(const void *) = spatialite_cleanup_ex;
     102             : static const char *(*pfn_spatialite_version)(void) = spatialite_version;
     103             : #endif
     104             : 
     105             : #ifndef SPATIALITE_SONAME
     106             : #define SPATIALITE_SONAME "libspatialite.so"
     107             : #endif
     108             : 
     109             : #ifdef SPATIALITE_DLOPEN
     110             : static bool OGRSQLiteLoadSpatialiteSymbols()
     111             : {
     112             :     static bool bInitializationDone = false;
     113             :     CPLMutexHolderD(&hMutexLoadSpatialiteSymbols);
     114             :     if (bInitializationDone)
     115             :         return pfn_spatialite_alloc_connection != nullptr;
     116             :     bInitializationDone = true;
     117             : 
     118             :     const char *pszLibName =
     119             :         CPLGetConfigOption("SPATIALITESO", SPATIALITE_SONAME);
     120             :     CPLPushErrorHandler(CPLQuietErrorHandler);
     121             : 
     122             :     /* coverity[tainted_string] */
     123             :     pfn_spatialite_alloc_connection = (void *(*)(void))CPLGetSymbol(
     124             :         pszLibName, "spatialite_alloc_connection");
     125             :     CPLPopErrorHandler();
     126             : 
     127             :     if (pfn_spatialite_alloc_connection == nullptr)
     128             :     {
     129             :         CPLDebug("SQLITE", "Cannot find %s in %s",
     130             :                  "spatialite_alloc_connection", pszLibName);
     131             :         return false;
     132             :     }
     133             : 
     134             :     pfn_spatialite_shutdown =
     135             :         (void (*)(void))CPLGetSymbol(pszLibName, "spatialite_shutdown");
     136             :     pfn_spatialite_init_ex =
     137             :         (void (*)(sqlite3 *, const void *, int))CPLGetSymbol(
     138             :             pszLibName, "spatialite_init_ex");
     139             :     pfn_spatialite_cleanup_ex = (void (*)(const void *))CPLGetSymbol(
     140             :         pszLibName, "spatialite_cleanup_ex");
     141             :     pfn_spatialite_version =
     142             :         (const char *(*)(void))CPLGetSymbol(pszLibName, "spatialite_version");
     143             :     if (pfn_spatialite_shutdown == nullptr ||
     144             :         pfn_spatialite_init_ex == nullptr ||
     145             :         pfn_spatialite_cleanup_ex == nullptr ||
     146             :         pfn_spatialite_version == nullptr)
     147             :     {
     148             :         pfn_spatialite_shutdown = nullptr;
     149             :         pfn_spatialite_init_ex = nullptr;
     150             :         pfn_spatialite_cleanup_ex = nullptr;
     151             :         pfn_spatialite_version = nullptr;
     152             :         return false;
     153             :     }
     154             :     return true;
     155             : }
     156             : #endif
     157             : 
     158             : /************************************************************************/
     159             : /*                           InitSpatialite()                           */
     160             : /************************************************************************/
     161             : 
     162        4034 : bool OGRSQLiteBaseDataSource::InitSpatialite()
     163             : {
     164        7605 :     if (hSpatialiteCtxt == nullptr &&
     165        3571 :         CPLTestBool(CPLGetConfigOption("SPATIALITE_LOAD", "TRUE")))
     166             :     {
     167             : #ifdef SPATIALITE_DLOPEN
     168             :         if (!OGRSQLiteLoadSpatialiteSymbols())
     169             :             return false;
     170             : #endif
     171        3571 :         CPLAssert(hSpatialiteCtxt == nullptr);
     172        3571 :         hSpatialiteCtxt = pfn_spatialite_alloc_connection();
     173        3571 :         if (hSpatialiteCtxt != nullptr)
     174             :         {
     175        7142 :             pfn_spatialite_init_ex(hDB, hSpatialiteCtxt,
     176        3571 :                                    CPLTestBool(CPLGetConfigOption(
     177             :                                        "SPATIALITE_INIT_VERBOSE", "FALSE")));
     178             :         }
     179             :     }
     180        4034 :     return hSpatialiteCtxt != nullptr;
     181             : }
     182             : 
     183             : /************************************************************************/
     184             : /*                          FinishSpatialite()                          */
     185             : /************************************************************************/
     186             : 
     187        4049 : void OGRSQLiteBaseDataSource::FinishSpatialite()
     188             : {
     189             :     // Current implementation of spatialite_cleanup_ex() (as of libspatialite 5.1)
     190             :     // is not re-entrant due to the use of xmlCleanupParser()
     191             :     // Cf https://groups.google.com/g/spatialite-users/c/tsfZ_GDrRKs/m/aj-Dt4xoBQAJ?utm_medium=email&utm_source=footer
     192             :     static std::mutex oCleanupMutex;
     193        8098 :     std::lock_guard oLock(oCleanupMutex);
     194             : 
     195        4049 :     if (hSpatialiteCtxt != nullptr)
     196             :     {
     197        3570 :         pfn_spatialite_cleanup_ex(hSpatialiteCtxt);
     198        3570 :         hSpatialiteCtxt = nullptr;
     199             :     }
     200        4049 : }
     201             : 
     202             : /************************************************************************/
     203             : /*                         IsSpatialiteLoaded()                         */
     204             : /************************************************************************/
     205             : 
     206       11865 : bool OGRSQLiteBaseDataSource::IsSpatialiteLoaded()
     207             : {
     208       11865 :     return hSpatialiteCtxt != nullptr;
     209             : }
     210             : 
     211             : #else
     212             : 
     213             : bool OGRSQLiteBaseDataSource::InitSpatialite()
     214             : {
     215             :     return false;
     216             : }
     217             : 
     218             : void OGRSQLiteBaseDataSource::FinishSpatialite()
     219             : {
     220             : }
     221             : 
     222             : bool OGRSQLiteBaseDataSource::IsSpatialiteLoaded()
     223             : {
     224             :     return false;
     225             : }
     226             : 
     227             : #endif
     228             : 
     229             : /************************************************************************/
     230             : /*                       OGRSQLiteDriverUnload()                        */
     231             : /************************************************************************/
     232             : 
     233        1131 : void OGRSQLiteDriverUnload(GDALDriver *)
     234             : {
     235             : #ifdef HAVE_SPATIALITE
     236        1131 :     if (pfn_spatialite_shutdown != nullptr)
     237        1131 :         pfn_spatialite_shutdown();
     238             : #ifdef SPATIALITE_DLOPEN
     239             :     if (hMutexLoadSpatialiteSymbols != nullptr)
     240             :     {
     241             :         CPLDestroyMutex(hMutexLoadSpatialiteSymbols);
     242             :         hMutexLoadSpatialiteSymbols = nullptr;
     243             :     }
     244             : #endif
     245             : #endif
     246        1131 : }
     247             : 
     248             : /************************************************************************/
     249             : /*                    DealWithOgrSchemaOpenOption()                     */
     250             : /************************************************************************/
     251        1193 : bool OGRSQLiteBaseDataSource::DealWithOgrSchemaOpenOption(
     252             :     CSLConstList papszOpenOptionsIn)
     253             : {
     254             :     const std::string osFieldsSchemaOverrideParam =
     255        2386 :         CSLFetchNameValueDef(papszOpenOptionsIn, "OGR_SCHEMA", "");
     256             : 
     257        1193 :     if (!osFieldsSchemaOverrideParam.empty())
     258             :     {
     259           9 :         if (GetUpdate())
     260             :         {
     261           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     262             :                      "OGR_SCHEMA open option is not supported in update mode.");
     263           4 :             return false;
     264             :         }
     265             : 
     266           9 :         OGRSchemaOverride oSchemaOverride;
     267           9 :         const auto nErrorCount = CPLGetErrorCounter();
     268          17 :         if (!oSchemaOverride.LoadFromJSON(osFieldsSchemaOverrideParam) ||
     269           8 :             !oSchemaOverride.IsValid())
     270             :         {
     271           1 :             if (nErrorCount == CPLGetErrorCounter())
     272             :             {
     273           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     274             :                          "Content of OGR_SCHEMA in %s is not valid",
     275             :                          osFieldsSchemaOverrideParam.c_str());
     276             :             }
     277           1 :             return false;
     278             :         }
     279             : 
     280           8 :         if (!oSchemaOverride.DefaultApply(this, "SQLite"))
     281           3 :             return false;
     282             :     }
     283        1189 :     return true;
     284             : }
     285             : 
     286             : /************************************************************************/
     287             : /*                     GetSpatialiteVersionNumber()                     */
     288             : /************************************************************************/
     289             : 
     290        5496 : int OGRSQLiteBaseDataSource::GetSpatialiteVersionNumber()
     291             : {
     292        5496 :     int v = 0;
     293             : #ifdef HAVE_SPATIALITE
     294        5496 :     if (IsSpatialiteLoaded())
     295             :     {
     296             :         const CPLStringList aosTokens(
     297       10876 :             CSLTokenizeString2(pfn_spatialite_version(), ".", 0));
     298        5438 :         if (aosTokens.size() >= 2)
     299             :         {
     300        5438 :             v = MakeSpatialiteVersionNumber(
     301             :                 atoi(aosTokens[0]), atoi(aosTokens[1]),
     302        5438 :                 aosTokens.size() == 3 ? atoi(aosTokens[2]) : 0);
     303             :         }
     304             :     }
     305             : #endif
     306        5496 :     return v;
     307             : }
     308             : 
     309             : /************************************************************************/
     310             : /*                          AddRelationship()                           */
     311             : /************************************************************************/
     312             : 
     313          15 : bool OGRSQLiteDataSource::AddRelationship(
     314             :     std::unique_ptr<GDALRelationship> &&relationship,
     315             :     std::string &failureReason)
     316             : {
     317          15 :     if (!GetUpdate())
     318             :     {
     319           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     320             :                  "AddRelationship() not supported on read-only dataset");
     321           0 :         return false;
     322             :     }
     323             : 
     324          15 :     if (!ValidateRelationship(relationship.get(), failureReason))
     325             :     {
     326          12 :         return false;
     327             :     }
     328             : 
     329           3 :     const std::string &osLeftTableName = relationship->GetLeftTableName();
     330           3 :     const std::string &osRightTableName = relationship->GetRightTableName();
     331           3 :     const auto &aosLeftTableFields = relationship->GetLeftTableFields();
     332           3 :     const auto &aosRightTableFields = relationship->GetRightTableFields();
     333             : 
     334           3 :     bool bBaseKeyIsUnique = false;
     335             :     {
     336             :         const std::set<std::string> uniqueBaseFieldsUC =
     337           6 :             SQLGetUniqueFieldUCConstraints(GetDB(), osLeftTableName.c_str());
     338           9 :         if (cpl::contains(uniqueBaseFieldsUC,
     339           3 :                           CPLString(aosLeftTableFields[0]).toupper()))
     340             :         {
     341           2 :             bBaseKeyIsUnique = true;
     342             :         }
     343             :     }
     344           3 :     if (!bBaseKeyIsUnique)
     345             :     {
     346             :         failureReason = "Base table field must be a primary key field or have "
     347           1 :                         "a unique constraint set";
     348           1 :         return false;
     349             :     }
     350             : 
     351           0 :     OGRSQLiteTableLayer *poRightTable = dynamic_cast<OGRSQLiteTableLayer *>(
     352           2 :         GetLayerByName(osRightTableName.c_str()));
     353           2 :     if (!poRightTable)
     354             :     {
     355           0 :         failureReason = ("Right table " + osRightTableName +
     356             :                          " is not an existing layer in the dataset")
     357           0 :                             .c_str();
     358           0 :         return false;
     359             :     }
     360             : 
     361           2 :     char *pszForeignKeySQL = nullptr;
     362           2 :     if (relationship->GetType() == GDALRelationshipType::GRT_ASSOCIATION)
     363             :     {
     364           2 :         pszForeignKeySQL = sqlite3_mprintf(
     365             :             "FOREIGN KEY(\"%w\") REFERENCES \"%w\"(\"%w\") DEFERRABLE "
     366             :             "INITIALLY DEFERRED",
     367           1 :             aosRightTableFields[0].c_str(), osLeftTableName.c_str(),
     368           1 :             aosLeftTableFields[0].c_str());
     369             :     }
     370             :     else
     371             :     {
     372           2 :         pszForeignKeySQL = sqlite3_mprintf(
     373             :             "FOREIGN KEY(\"%w\") REFERENCES \"%w\"(\"%w\") ON DELETE CASCADE "
     374             :             "ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED",
     375           1 :             aosRightTableFields[0].c_str(), osLeftTableName.c_str(),
     376           1 :             aosLeftTableFields[0].c_str());
     377             :     }
     378             : 
     379           2 :     int eErr = poRightTable->AddForeignKeysToTable(pszForeignKeySQL);
     380           2 :     sqlite3_free(pszForeignKeySQL);
     381           2 :     if (eErr != OGRERR_NONE)
     382             :     {
     383           0 :         failureReason = "Could not add foreign keys to table";
     384           0 :         return false;
     385             :     }
     386             : 
     387           2 :     char *pszSQL = sqlite3_mprintf(
     388             :         "CREATE INDEX \"idx_%qw_related_id\" ON \"%w\" (\"%w\");",
     389             :         osRightTableName.c_str(), osRightTableName.c_str(),
     390           2 :         aosRightTableFields[0].c_str());
     391           2 :     eErr = SQLCommand(hDB, pszSQL);
     392           2 :     sqlite3_free(pszSQL);
     393           2 :     if (eErr != OGRERR_NONE)
     394             :     {
     395           0 :         failureReason = ("Could not create index for " + osRightTableName +
     396           0 :                          " " + aosRightTableFields[0])
     397           0 :                             .c_str();
     398           0 :         return false;
     399             :     }
     400             : 
     401           2 :     m_bHasPopulatedRelationships = false;
     402           2 :     m_osMapRelationships.clear();
     403           2 :     return true;
     404             : }
     405             : 
     406             : /************************************************************************/
     407             : /*                        ValidateRelationship()                        */
     408             : /************************************************************************/
     409             : 
     410          15 : bool OGRSQLiteDataSource::ValidateRelationship(
     411             :     const GDALRelationship *poRelationship, std::string &failureReason)
     412             : {
     413             : 
     414          15 :     if (poRelationship->GetCardinality() !=
     415             :         GDALRelationshipCardinality::GRC_ONE_TO_MANY)
     416             :     {
     417             :         failureReason = "Only one to many relationships are supported for "
     418           3 :                         "SQLITE datasources";
     419           3 :         return false;
     420             :     }
     421             : 
     422          23 :     if (poRelationship->GetType() != GDALRelationshipType::GRT_COMPOSITE &&
     423          11 :         poRelationship->GetType() != GDALRelationshipType::GRT_ASSOCIATION)
     424             :     {
     425             :         failureReason = "Only association and composite relationship types are "
     426           0 :                         "supported for SQLITE datasources";
     427           0 :         return false;
     428             :     }
     429             : 
     430          12 :     const std::string &osLeftTableName = poRelationship->GetLeftTableName();
     431          12 :     OGRLayer *poLeftTable = GetLayerByName(osLeftTableName.c_str());
     432          12 :     if (!poLeftTable)
     433             :     {
     434           2 :         failureReason = ("Left table " + osLeftTableName +
     435             :                          " is not an existing layer in the dataset")
     436           1 :                             .c_str();
     437           1 :         return false;
     438             :     }
     439          11 :     const std::string &osRightTableName = poRelationship->GetRightTableName();
     440          11 :     OGRLayer *poRightTable = GetLayerByName(osRightTableName.c_str());
     441          11 :     if (!poRightTable)
     442             :     {
     443           2 :         failureReason = ("Right table " + osRightTableName +
     444             :                          " is not an existing layer in the dataset")
     445           1 :                             .c_str();
     446           1 :         return false;
     447             :     }
     448             : 
     449          10 :     const auto &aosLeftTableFields = poRelationship->GetLeftTableFields();
     450          10 :     if (aosLeftTableFields.empty())
     451             :     {
     452           1 :         failureReason = "No left table fields were specified";
     453           1 :         return false;
     454             :     }
     455           9 :     else if (aosLeftTableFields.size() > 1)
     456             :     {
     457             :         failureReason = "Only a single left table field is permitted for the "
     458           1 :                         "SQLITE relationships";
     459           1 :         return false;
     460             :     }
     461             :     else
     462             :     {
     463             :         // validate left field exists
     464          16 :         if (poLeftTable->GetLayerDefn()->GetFieldIndex(
     465          17 :                 aosLeftTableFields[0].c_str()) < 0 &&
     466           1 :             !EQUAL(poLeftTable->GetFIDColumn(), aosLeftTableFields[0].c_str()))
     467             :         {
     468           2 :             failureReason = ("Left table field " + aosLeftTableFields[0] +
     469           2 :                              " does not exist in " + osLeftTableName)
     470           1 :                                 .c_str();
     471           1 :             return false;
     472             :         }
     473             :     }
     474             : 
     475           7 :     const auto &aosRightTableFields = poRelationship->GetRightTableFields();
     476           7 :     if (aosRightTableFields.empty())
     477             :     {
     478           1 :         failureReason = "No right table fields were specified";
     479           1 :         return false;
     480             :     }
     481           6 :     else if (aosRightTableFields.size() > 1)
     482             :     {
     483             :         failureReason = "Only a single right table field is permitted for the "
     484           1 :                         "SQLITE relationships";
     485           1 :         return false;
     486             :     }
     487             :     else
     488             :     {
     489             :         // validate right field exists
     490          10 :         if (poRightTable->GetLayerDefn()->GetFieldIndex(
     491          11 :                 aosRightTableFields[0].c_str()) < 0 &&
     492           1 :             !EQUAL(poRightTable->GetFIDColumn(),
     493             :                    aosRightTableFields[0].c_str()))
     494             :         {
     495           2 :             failureReason = ("Right table field " + aosRightTableFields[0] +
     496           2 :                              " does not exist in " + osRightTableName)
     497           1 :                                 .c_str();
     498           1 :             return false;
     499             :         }
     500             :     }
     501             : 
     502             :     // ensure relationship is different from existing relationships
     503           4 :     for (const auto &kv : m_osMapRelationships)
     504             :     {
     505           2 :         if (osLeftTableName == kv.second->GetLeftTableName() &&
     506           1 :             osRightTableName == kv.second->GetRightTableName() &&
     507           3 :             aosLeftTableFields == kv.second->GetLeftTableFields() &&
     508           1 :             aosRightTableFields == kv.second->GetRightTableFields())
     509             :         {
     510             :             failureReason =
     511           1 :                 "A relationship between these tables and fields already exists";
     512           1 :             return false;
     513             :         }
     514             :     }
     515             : 
     516           3 :     return true;
     517             : }
     518             : 
     519             : /************************************************************************/
     520             : /*                      OGRSQLiteBaseDataSource()                       */
     521             : /************************************************************************/
     522             : 
     523             : OGRSQLiteBaseDataSource::OGRSQLiteBaseDataSource() = default;
     524             : 
     525             : /************************************************************************/
     526             : /*                      ~OGRSQLiteBaseDataSource()                      */
     527             : /************************************************************************/
     528             : 
     529        4038 : OGRSQLiteBaseDataSource::~OGRSQLiteBaseDataSource()
     530             : 
     531             : {
     532        4038 :     CloseDB();
     533             : 
     534        4038 :     FinishSpatialite();
     535             : 
     536        4038 :     if (m_bCallUndeclareFileNotToOpen)
     537             :     {
     538        1922 :         GDALOpenInfoUnDeclareFileNotToOpen(m_pszFilename);
     539             :     }
     540             : 
     541        4038 :     if (!m_osFinalFilename.empty())
     542             :     {
     543           4 :         if (!bSuppressOnClose)
     544             :         {
     545           4 :             CPLDebug("SQLITE", "Copying temporary file %s onto %s",
     546             :                      m_pszFilename, m_osFinalFilename.c_str());
     547           4 :             if (CPLCopyFile(m_osFinalFilename.c_str(), m_pszFilename) != 0)
     548             :             {
     549           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     550             :                          "Copy temporary file %s onto %s failed", m_pszFilename,
     551             :                          m_osFinalFilename.c_str());
     552             :             }
     553             :         }
     554           4 :         CPLDebug("SQLITE", "Deleting temporary file %s", m_pszFilename);
     555           4 :         if (VSIUnlink(m_pszFilename) != 0)
     556             :         {
     557           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     558             :                      "Deleting temporary file %s failed", m_pszFilename);
     559             :         }
     560             :     }
     561             : 
     562        4038 :     CPLFree(m_pszFilename);
     563        4038 : }
     564             : 
     565             : /************************************************************************/
     566             : /*                              CloseDB()                               */
     567             : /************************************************************************/
     568             : 
     569        8088 : bool OGRSQLiteBaseDataSource::CloseDB()
     570             : {
     571        8088 :     bool bOK = true;
     572        8088 :     if (hDB != nullptr)
     573             :     {
     574        3684 :         bOK = (sqlite3_close(hDB) == SQLITE_OK);
     575        3684 :         hDB = nullptr;
     576             : 
     577             :         // If we opened the DB in read-only mode, there might be spurious
     578             :         // -wal and -shm files that we can make disappear by reopening in
     579             :         // read-write
     580             :         VSIStatBufL sStat;
     581        8750 :         if (eAccess == GA_ReadOnly &&
     582        1382 :             !(STARTS_WITH(m_pszFilename, "/vsicurl/") ||
     583        1378 :               STARTS_WITH(m_pszFilename, "/vsitar/") ||
     584        6439 :               STARTS_WITH(m_pszFilename, "/vsizip/")) &&
     585        1373 :             VSIStatL(CPLSPrintf("%s-wal", m_pszFilename), &sStat) == 0)
     586             :         {
     587           4 :             if (sqlite3_open(m_pszFilename, &hDB) != SQLITE_OK)
     588             :             {
     589           0 :                 sqlite3_close(hDB);
     590           0 :                 hDB = nullptr;
     591             :             }
     592           4 :             else if (hDB != nullptr)
     593             :             {
     594             : #ifdef SQLITE_FCNTL_PERSIST_WAL
     595           4 :                 int nPersistentWAL = -1;
     596           4 :                 sqlite3_file_control(hDB, "main", SQLITE_FCNTL_PERSIST_WAL,
     597             :                                      &nPersistentWAL);
     598           4 :                 if (nPersistentWAL == 1)
     599             :                 {
     600           0 :                     nPersistentWAL = 0;
     601           0 :                     if (sqlite3_file_control(hDB, "main",
     602             :                                              SQLITE_FCNTL_PERSIST_WAL,
     603           0 :                                              &nPersistentWAL) == SQLITE_OK)
     604             :                     {
     605           0 :                         CPLDebug("SQLITE",
     606             :                                  "Disabling persistent WAL succeeded");
     607             :                     }
     608             :                     else
     609             :                     {
     610           0 :                         CPLDebug("SQLITE", "Could not disable persistent WAL");
     611             :                     }
     612             :                 }
     613             : #endif
     614             : 
     615             :                 // Dummy request
     616           4 :                 int nRowCount = 0, nColCount = 0;
     617           4 :                 char **papszResult = nullptr;
     618           4 :                 sqlite3_get_table(hDB, "SELECT name FROM sqlite_master WHERE 0",
     619             :                                   &papszResult, &nRowCount, &nColCount,
     620             :                                   nullptr);
     621           4 :                 sqlite3_free_table(papszResult);
     622             : 
     623           4 :                 sqlite3_close(hDB);
     624           4 :                 hDB = nullptr;
     625             : #ifdef DEBUG_VERBOSE
     626             :                 if (VSIStatL(CPLSPrintf("%s-wal", m_pszFilename), &sStat) != 0)
     627             :                 {
     628             :                     CPLDebug("SQLite", "%s-wal file has been removed",
     629             :                              m_pszFilename);
     630             :                 }
     631             : #endif
     632             :             }
     633             :         }
     634             :     }
     635             : 
     636        8088 :     if (pMyVFS)
     637             :     {
     638        2968 :         sqlite3_vfs_unregister(pMyVFS);
     639        2968 :         CPLFree(pMyVFS->pAppData);
     640        2968 :         CPLFree(pMyVFS);
     641        2968 :         pMyVFS = nullptr;
     642             :     }
     643             : 
     644        8088 :     return bOK;
     645             : }
     646             : 
     647             : /* Returns the first row of first column of SQL as integer */
     648          75 : OGRErr OGRSQLiteBaseDataSource::PragmaCheck(const char *pszPragma,
     649             :                                             const char *pszExpected,
     650             :                                             int nRowsExpected)
     651             : {
     652          75 :     CPLAssert(pszPragma != nullptr);
     653          75 :     CPLAssert(pszExpected != nullptr);
     654          75 :     CPLAssert(nRowsExpected >= 0);
     655             : 
     656          75 :     char **papszResult = nullptr;
     657          75 :     int nRowCount = 0;
     658          75 :     int nColCount = 0;
     659          75 :     char *pszErrMsg = nullptr;
     660             : 
     661             :     int rc =
     662          75 :         sqlite3_get_table(hDB, CPLSPrintf("PRAGMA %s", pszPragma), &papszResult,
     663             :                           &nRowCount, &nColCount, &pszErrMsg);
     664             : 
     665          75 :     if (rc != SQLITE_OK)
     666             :     {
     667           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Unable to execute PRAGMA %s: %s",
     668           0 :                  pszPragma, pszErrMsg ? pszErrMsg : "(null)");
     669           0 :         sqlite3_free(pszErrMsg);
     670           0 :         return OGRERR_FAILURE;
     671             :     }
     672             : 
     673          75 :     if (nRowCount != nRowsExpected)
     674             :     {
     675           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     676             :                  "bad result for PRAGMA %s, got %d rows, expected %d",
     677             :                  pszPragma, nRowCount, nRowsExpected);
     678           0 :         sqlite3_free_table(papszResult);
     679           0 :         return OGRERR_FAILURE;
     680             :     }
     681             : 
     682          75 :     if (nRowCount > 0 && !EQUAL(papszResult[1], pszExpected))
     683             :     {
     684           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     685             :                  "invalid %s (expected '%s', got '%s')", pszPragma, pszExpected,
     686           0 :                  papszResult[1]);
     687           0 :         sqlite3_free_table(papszResult);
     688           0 :         return OGRERR_FAILURE;
     689             :     }
     690             : 
     691          75 :     sqlite3_free_table(papszResult);
     692             : 
     693          75 :     return OGRERR_NONE;
     694             : }
     695             : 
     696             : /************************************************************************/
     697             : /*                         LoadRelationships()                          */
     698             : /************************************************************************/
     699             : 
     700           8 : void OGRSQLiteBaseDataSource::LoadRelationships() const
     701             : 
     702             : {
     703           8 :     m_osMapRelationships.clear();
     704           8 :     LoadRelationshipsFromForeignKeys({});
     705           8 :     m_bHasPopulatedRelationships = true;
     706           8 : }
     707             : 
     708             : /************************************************************************/
     709             : /*                  LoadRelationshipsFromForeignKeys()                  */
     710             : /************************************************************************/
     711             : 
     712         107 : void OGRSQLiteBaseDataSource::LoadRelationshipsFromForeignKeys(
     713             :     const std::vector<std::string> &excludedTables) const
     714             : 
     715             : {
     716         107 :     if (hDB)
     717             :     {
     718             :         std::string osSQL =
     719             :             "SELECT m.name, p.id, p.seq, p.\"table\" AS base_table_name, "
     720             :             "p.\"from\", p.\"to\", "
     721             :             "p.on_delete FROM sqlite_master m "
     722             :             "JOIN pragma_foreign_key_list(m.name) p ON m.name != p.\"table\" "
     723             :             "WHERE m.type = 'table' "
     724             :             // skip over foreign keys which relate to private GPKG tables
     725             :             "AND base_table_name NOT LIKE 'gpkg_%' "
     726             :             // Same with NGA GeoInt system tables
     727             :             "AND base_table_name NOT LIKE 'nga_%' "
     728             :             // Same with Spatialite system tables
     729             :             "AND base_table_name NOT IN ('geometry_columns', "
     730             :             "'spatial_ref_sys', 'views_geometry_columns', "
     731         107 :             "'virts_geometry_columns') ";
     732         107 :         if (!excludedTables.empty())
     733             :         {
     734          36 :             std::string oExcludedTablesList;
     735          93 :             for (const auto &osExcludedTable : excludedTables)
     736             :             {
     737          57 :                 oExcludedTablesList += !oExcludedTablesList.empty() ? "," : "";
     738             :                 char *pszEscapedName =
     739          57 :                     sqlite3_mprintf("'%q'", osExcludedTable.c_str());
     740          57 :                 oExcludedTablesList += pszEscapedName;
     741          57 :                 sqlite3_free(pszEscapedName);
     742             :             }
     743             : 
     744          72 :             osSQL += "AND base_table_name NOT IN (" + oExcludedTablesList +
     745             :                      ")"
     746          72 :                      " AND m.name NOT IN (" +
     747          36 :                      oExcludedTablesList + ") ";
     748             :         }
     749         107 :         osSQL += "ORDER BY m.name";
     750             : 
     751         107 :         auto oResult = SQLQuery(hDB, osSQL.c_str());
     752             : 
     753         107 :         if (!oResult)
     754             :         {
     755           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Cannot load relationships");
     756           0 :             return;
     757             :         }
     758             : 
     759         129 :         for (int iRecord = 0; iRecord < oResult->RowCount(); iRecord++)
     760             :         {
     761          22 :             const char *pszRelatedTableName = oResult->GetValue(0, iRecord);
     762          22 :             if (!pszRelatedTableName)
     763           0 :                 continue;
     764             : 
     765          22 :             const char *pszBaseTableName = oResult->GetValue(3, iRecord);
     766          22 :             if (!pszBaseTableName)
     767           0 :                 continue;
     768             : 
     769          22 :             const char *pszRelatedFieldName = oResult->GetValue(4, iRecord);
     770          22 :             if (!pszRelatedFieldName)
     771           0 :                 continue;
     772             : 
     773          22 :             const char *pszBaseFieldName = oResult->GetValue(5, iRecord);
     774          22 :             if (!pszBaseFieldName)
     775           0 :                 continue;
     776             : 
     777          22 :             const int nId = oResult->GetValueAsInteger(1, iRecord);
     778             : 
     779             :             // form relationship name by appending foreign key id to base and
     780             :             // related table names
     781          44 :             std::ostringstream stream;
     782          22 :             stream << pszBaseTableName << '_' << pszRelatedTableName;
     783          22 :             if (nId > 0)
     784             :             {
     785             :                 // note we use nId + 1 here as the first id will be zero, and
     786             :                 // we'd like subsequent relations to have names starting with
     787             :                 // _2, _3 etc, not _1, _2 etc.
     788           2 :                 stream << '_' << (nId + 1);
     789             :             }
     790          44 :             const std::string osRelationName = stream.str();
     791             : 
     792          22 :             const auto it = m_osMapRelationships.find(osRelationName);
     793          22 :             if (it != m_osMapRelationships.end())
     794             :             {
     795             :                 // already have a relationship with this name -- that means that
     796             :                 // the base and related table name and id are the same, so we've
     797             :                 // found a multi-column relationship
     798          10 :                 auto osListLeftFields = it->second->GetLeftTableFields();
     799           5 :                 osListLeftFields.emplace_back(pszBaseFieldName);
     800           5 :                 it->second->SetLeftTableFields(osListLeftFields);
     801             : 
     802          10 :                 auto osListRightFields = it->second->GetRightTableFields();
     803           5 :                 osListRightFields.emplace_back(pszRelatedFieldName);
     804           5 :                 it->second->SetRightTableFields(osListRightFields);
     805             :             }
     806             :             else
     807             :             {
     808             :                 std::unique_ptr<GDALRelationship> poRelationship(
     809             :                     new GDALRelationship(osRelationName, pszBaseTableName,
     810          51 :                                          pszRelatedTableName, GRC_ONE_TO_MANY));
     811          34 :                 poRelationship->SetLeftTableFields({pszBaseFieldName});
     812          34 :                 poRelationship->SetRightTableFields({pszRelatedFieldName});
     813          17 :                 poRelationship->SetRelatedTableType("features");
     814             : 
     815          17 :                 if (const char *pszOnDeleteAction =
     816          17 :                         oResult->GetValue(6, iRecord))
     817             :                 {
     818          17 :                     if (EQUAL(pszOnDeleteAction, "CASCADE"))
     819             :                     {
     820           2 :                         poRelationship->SetType(GRT_COMPOSITE);
     821             :                     }
     822             :                 }
     823             : 
     824          17 :                 m_osMapRelationships[osRelationName] =
     825          34 :                     std::move(poRelationship);
     826             :             }
     827             :         }
     828             :     }
     829             : }
     830             : 
     831             : /************************************************************************/
     832             : /*                        GetRelationshipNames()                        */
     833             : /************************************************************************/
     834             : 
     835          89 : std::vector<std::string> OGRSQLiteBaseDataSource::GetRelationshipNames(
     836             :     CPL_UNUSED CSLConstList papszOptions) const
     837             : 
     838             : {
     839          89 :     if (!m_bHasPopulatedRelationships)
     840             :     {
     841          75 :         LoadRelationships();
     842             :     }
     843             : 
     844          89 :     std::vector<std::string> oasNames;
     845          89 :     oasNames.reserve(m_osMapRelationships.size());
     846         141 :     for (const auto &kv : m_osMapRelationships)
     847             :     {
     848          52 :         oasNames.emplace_back(kv.first);
     849             :     }
     850          89 :     return oasNames;
     851             : }
     852             : 
     853             : /************************************************************************/
     854             : /*                          GetRelationship()                           */
     855             : /************************************************************************/
     856             : 
     857             : const GDALRelationship *
     858          79 : OGRSQLiteBaseDataSource::GetRelationship(const std::string &name) const
     859             : 
     860             : {
     861          79 :     if (!m_bHasPopulatedRelationships)
     862             :     {
     863           9 :         LoadRelationships();
     864             :     }
     865             : 
     866          79 :     const auto it = m_osMapRelationships.find(name);
     867          79 :     if (it == m_osMapRelationships.end())
     868          37 :         return nullptr;
     869             : 
     870          42 :     return it->second.get();
     871             : }
     872             : 
     873             : /************************************************************************/
     874             : /*                             prepareSql()                             */
     875             : /************************************************************************/
     876             : 
     877       12196 : sqlite3_stmt *OGRSQLiteBaseDataSource::prepareSql(sqlite3 *db, const char *zSql,
     878             :                                                   int nByte)
     879             : {
     880       12196 :     sqlite3_stmt *stmt = nullptr;
     881       12196 :     const char *pszTail = nullptr;
     882       12196 :     const int rc = sqlite3_prepare_v2(db, zSql, nByte, &stmt, &pszTail);
     883       12196 :     if (rc != SQLITE_OK && pfnQueryLoggerFunc)
     884             :     {
     885           1 :         pfnQueryLoggerFunc(
     886             :             zSql,
     887           2 :             SQLFormatErrorMsgFailedPrepare(db, "Error preparing query: ", zSql)
     888             :                 .c_str(),
     889             :             -1, -1, poQueryLoggerArg);
     890             :     }
     891       12195 :     else if (strchr(zSql, ';') && pszTail && SQLHasRemainingContent(pszTail))
     892             :     {
     893           6 :         sqlite3_finalize(stmt);
     894           6 :         stmt = nullptr;
     895             :     }
     896       12196 :     return stmt;
     897             : }
     898             : 
     899             : /************************************************************************/
     900             : /*                        OGRSQLiteDataSource()                         */
     901             : /************************************************************************/
     902             : 
     903             : OGRSQLiteDataSource::OGRSQLiteDataSource() = default;
     904             : 
     905             : /************************************************************************/
     906             : /*                        ~OGRSQLiteDataSource()                        */
     907             : /************************************************************************/
     908             : 
     909        2654 : OGRSQLiteDataSource::~OGRSQLiteDataSource()
     910             : 
     911             : {
     912        1327 :     OGRSQLiteDataSource::Close();
     913        2654 : }
     914             : 
     915             : /************************************************************************/
     916             : /*                               Close()                                */
     917             : /************************************************************************/
     918             : 
     919        1886 : CPLErr OGRSQLiteDataSource::Close(GDALProgressFunc, void *)
     920             : {
     921        1886 :     CPLErr eErr = CE_None;
     922        1886 :     if (nOpenFlags != OPEN_FLAGS_CLOSED)
     923             :     {
     924        1327 :         if (OGRSQLiteDataSource::FlushCache(true) != CE_None)
     925           0 :             eErr = CE_Failure;
     926             : 
     927             : #ifdef HAVE_RASTERLITE2
     928             :         if (m_pRL2Coverage != nullptr)
     929             :         {
     930             :             rl2_destroy_coverage(m_pRL2Coverage);
     931             :         }
     932             : #endif
     933        1327 :         for (size_t i = 0; i < m_apoOverviewDS.size(); ++i)
     934             :         {
     935           0 :             delete m_apoOverviewDS[i];
     936             :         }
     937             : 
     938        1327 :         if (!m_apoLayers.empty() || !m_apoInvisibleLayers.empty())
     939             :         {
     940             :             // Close any remaining iterator
     941        2181 :             for (auto &poLayer : m_apoLayers)
     942        1369 :                 poLayer->ResetReading();
     943         814 :             for (auto &poLayer : m_apoInvisibleLayers)
     944           2 :                 poLayer->ResetReading();
     945             : 
     946             :             // Create spatial indices in a transaction for faster execution
     947         812 :             if (hDB)
     948         812 :                 SoftStartTransaction();
     949        2181 :             for (auto &poLayer : m_apoLayers)
     950             :             {
     951        1369 :                 if (poLayer->IsTableLayer())
     952             :                 {
     953             :                     OGRSQLiteTableLayer *poTableLayer =
     954        1364 :                         cpl::down_cast<OGRSQLiteTableLayer *>(poLayer.get());
     955        1364 :                     poTableLayer->RunDeferredCreationIfNecessary();
     956        1364 :                     poTableLayer->CreateSpatialIndexIfNecessary();
     957             :                 }
     958             :             }
     959         812 :             if (hDB)
     960         812 :                 SoftCommitTransaction();
     961             :         }
     962             : 
     963        1327 :         SaveStatistics();
     964             : 
     965        1327 :         m_apoLayers.clear();
     966        1327 :         m_apoInvisibleLayers.clear();
     967             : 
     968        1327 :         m_oSRSCache.clear();
     969             : 
     970        1327 :         if (!CloseDB())
     971           1 :             eErr = CE_Failure;
     972             : #ifdef HAVE_RASTERLITE2
     973             :         FinishRasterLite2();
     974             : #endif
     975             : 
     976        1327 :         if (GDALPamDataset::Close() != CE_None)
     977           0 :             eErr = CE_Failure;
     978             :     }
     979        1886 :     return eErr;
     980             : }
     981             : 
     982             : #ifdef HAVE_RASTERLITE2
     983             : 
     984             : /************************************************************************/
     985             : /*                          InitRasterLite2()                           */
     986             : /************************************************************************/
     987             : 
     988             : bool OGRSQLiteDataSource::InitRasterLite2()
     989             : {
     990             :     CPLAssert(m_hRL2Ctxt == nullptr);
     991             :     m_hRL2Ctxt = rl2_alloc_private();
     992             :     if (m_hRL2Ctxt != nullptr)
     993             :     {
     994             :         rl2_init(hDB, m_hRL2Ctxt, 0);
     995             :     }
     996             :     return m_hRL2Ctxt != nullptr;
     997             : }
     998             : 
     999             : /************************************************************************/
    1000             : /*                         FinishRasterLite2()                          */
    1001             : /************************************************************************/
    1002             : 
    1003             : void OGRSQLiteDataSource::FinishRasterLite2()
    1004             : {
    1005             :     if (m_hRL2Ctxt != nullptr)
    1006             :     {
    1007             :         rl2_cleanup_private(m_hRL2Ctxt);
    1008             :         m_hRL2Ctxt = nullptr;
    1009             :     }
    1010             : }
    1011             : 
    1012             : #endif  // HAVE_RASTERLITE2
    1013             : 
    1014             : /************************************************************************/
    1015             : /*                           SaveStatistics()                           */
    1016             : /************************************************************************/
    1017             : 
    1018        1327 : void OGRSQLiteDataSource::SaveStatistics()
    1019             : {
    1020         650 :     if (!m_bIsSpatiaLiteDB || !IsSpatialiteLoaded() ||
    1021        1977 :         m_bLastSQLCommandIsUpdateLayerStatistics || !GetUpdate())
    1022         720 :         return;
    1023             : 
    1024         607 :     int nSavedAllLayersCacheData = -1;
    1025             : 
    1026         946 :     for (auto &poLayer : m_apoLayers)
    1027             :     {
    1028         339 :         if (poLayer->IsTableLayer())
    1029             :         {
    1030             :             OGRSQLiteTableLayer *poTableLayer =
    1031         338 :                 cpl::down_cast<OGRSQLiteTableLayer *>(poLayer.get());
    1032         338 :             int nSaveRet = poTableLayer->SaveStatistics();
    1033         338 :             if (nSaveRet >= 0)
    1034             :             {
    1035         134 :                 if (nSavedAllLayersCacheData < 0)
    1036          39 :                     nSavedAllLayersCacheData = nSaveRet;
    1037             :                 else
    1038          95 :                     nSavedAllLayersCacheData &= nSaveRet;
    1039             :             }
    1040             :         }
    1041             :     }
    1042             : 
    1043         607 :     if (hDB && nSavedAllLayersCacheData == TRUE)
    1044             :     {
    1045          39 :         int nReplaceEventId = -1;
    1046             : 
    1047             :         auto oResult = SQLQuery(
    1048             :             hDB, "SELECT event_id, table_name, geometry_column, event "
    1049          78 :                  "FROM spatialite_history ORDER BY event_id DESC LIMIT 1");
    1050             : 
    1051          39 :         if (oResult && oResult->RowCount() == 1)
    1052             :         {
    1053          39 :             const char *pszEventId = oResult->GetValue(0, 0);
    1054          39 :             const char *pszTableName = oResult->GetValue(1, 0);
    1055          39 :             const char *pszGeomCol = oResult->GetValue(2, 0);
    1056          39 :             const char *pszEvent = oResult->GetValue(3, 0);
    1057             : 
    1058          39 :             if (pszEventId != nullptr && pszTableName != nullptr &&
    1059          39 :                 pszGeomCol != nullptr && pszEvent != nullptr &&
    1060          39 :                 strcmp(pszTableName, "ALL-TABLES") == 0 &&
    1061           3 :                 strcmp(pszGeomCol, "ALL-GEOMETRY-COLUMNS") == 0 &&
    1062           3 :                 strcmp(pszEvent, "UpdateLayerStatistics") == 0)
    1063             :             {
    1064           3 :                 nReplaceEventId = atoi(pszEventId);
    1065             :             }
    1066             :         }
    1067             : 
    1068          39 :         const char *pszNow = HasSpatialite4Layout()
    1069          39 :                                  ? "strftime('%Y-%m-%dT%H:%M:%fZ','now')"
    1070          39 :                                  : "DateTime('now')";
    1071             :         const char *pszSQL;
    1072          39 :         if (nReplaceEventId >= 0)
    1073             :         {
    1074           3 :             pszSQL = CPLSPrintf("UPDATE spatialite_history SET "
    1075             :                                 "timestamp = %s "
    1076             :                                 "WHERE event_id = %d",
    1077             :                                 pszNow, nReplaceEventId);
    1078             :         }
    1079             :         else
    1080             :         {
    1081          36 :             pszSQL = CPLSPrintf(
    1082             :                 "INSERT INTO spatialite_history (table_name, geometry_column, "
    1083             :                 "event, timestamp, ver_sqlite, ver_splite) VALUES ("
    1084             :                 "'ALL-TABLES', 'ALL-GEOMETRY-COLUMNS', "
    1085             :                 "'UpdateLayerStatistics', "
    1086             :                 "%s, sqlite_version(), spatialite_version())",
    1087             :                 pszNow);
    1088             :         }
    1089             : 
    1090          39 :         SQLCommand(hDB, pszSQL);
    1091             :     }
    1092             : }
    1093             : 
    1094             : /************************************************************************/
    1095             : /*                           SetSynchronous()                           */
    1096             : /************************************************************************/
    1097             : 
    1098        3674 : bool OGRSQLiteBaseDataSource::SetSynchronous()
    1099             : {
    1100             :     const char *pszSqliteSync =
    1101        3674 :         CPLGetConfigOption("OGR_SQLITE_SYNCHRONOUS", nullptr);
    1102        3674 :     if (pszSqliteSync != nullptr)
    1103             :     {
    1104        1578 :         const char *pszSQL = nullptr;
    1105        1578 :         if (EQUAL(pszSqliteSync, "OFF") || EQUAL(pszSqliteSync, "0") ||
    1106           0 :             EQUAL(pszSqliteSync, "FALSE"))
    1107        1578 :             pszSQL = "PRAGMA synchronous = OFF";
    1108           0 :         else if (EQUAL(pszSqliteSync, "NORMAL") || EQUAL(pszSqliteSync, "1"))
    1109           0 :             pszSQL = "PRAGMA synchronous = NORMAL";
    1110           0 :         else if (EQUAL(pszSqliteSync, "ON") || EQUAL(pszSqliteSync, "FULL") ||
    1111           0 :                  EQUAL(pszSqliteSync, "2") || EQUAL(pszSqliteSync, "TRUE"))
    1112           0 :             pszSQL = "PRAGMA synchronous = FULL";
    1113             :         else
    1114           0 :             CPLError(CE_Warning, CPLE_AppDefined,
    1115             :                      "Unrecognized value for OGR_SQLITE_SYNCHRONOUS : %s",
    1116             :                      pszSqliteSync);
    1117             : 
    1118        1578 :         return pszSQL != nullptr && SQLCommand(hDB, pszSQL) == OGRERR_NONE;
    1119             :     }
    1120        2096 :     return true;
    1121             : }
    1122             : 
    1123             : /************************************************************************/
    1124             : /*                           LoadExtensions()                           */
    1125             : /************************************************************************/
    1126             : 
    1127        3674 : void OGRSQLiteBaseDataSource::LoadExtensions()
    1128             : {
    1129             :     const char *pszExtensions =
    1130        3674 :         CPLGetConfigOption("OGR_SQLITE_LOAD_EXTENSIONS", nullptr);
    1131        3674 :     if (pszExtensions != nullptr)
    1132             :     {
    1133             : #ifdef OGR_SQLITE_ALLOW_LOAD_EXTENSIONS
    1134             :         // Allow sqlite3_load_extension() (C API only)
    1135             : #ifdef SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
    1136           4 :         int oldMode = 0;
    1137           4 :         if (sqlite3_db_config(hDB, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, -1,
    1138           4 :                               &oldMode) != SQLITE_OK)
    1139             :         {
    1140           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1141             :                      "Cannot get initial value for "
    1142             :                      "SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION");
    1143           0 :             return;
    1144             :         }
    1145           4 :         CPLDebugOnly(
    1146             :             "SQLite",
    1147             :             "Initial mode for SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION = %d",
    1148             :             oldMode);
    1149           4 :         int newMode = 0;
    1150           8 :         if (oldMode != 1 &&
    1151           4 :             (sqlite3_db_config(hDB, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1,
    1152           4 :                                &newMode) != SQLITE_OK ||
    1153           4 :              newMode != 1))
    1154             :         {
    1155           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1156             :                      "SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION failed");
    1157           0 :             return;
    1158             :         }
    1159             : #endif
    1160             :         const CPLStringList aosExtensions(
    1161           8 :             CSLTokenizeString2(pszExtensions, ",", 0));
    1162           4 :         bool bRestoreOldMode = true;
    1163           8 :         for (int i = 0; i < aosExtensions.size(); i++)
    1164             :         {
    1165           4 :             if (EQUAL(aosExtensions[i], "ENABLE_SQL_LOAD_EXTENSION"))
    1166             :             {
    1167           2 :                 if (sqlite3_enable_load_extension(hDB, 1) == SQLITE_OK)
    1168             :                 {
    1169           2 :                     bRestoreOldMode = false;
    1170             :                 }
    1171             :                 else
    1172             :                 {
    1173           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
    1174             :                              "sqlite3_enable_load_extension() failed");
    1175             :                 }
    1176             :             }
    1177             :             else
    1178             :             {
    1179           2 :                 char *pszErrMsg = nullptr;
    1180           2 :                 if (sqlite3_load_extension(hDB, aosExtensions[i], nullptr,
    1181           2 :                                            &pszErrMsg) != SQLITE_OK)
    1182             :                 {
    1183           1 :                     CPLError(CE_Failure, CPLE_AppDefined,
    1184             :                              "Cannot load extension %s: %s", aosExtensions[i],
    1185           1 :                              pszErrMsg ? pszErrMsg : "unknown reason");
    1186             :                 }
    1187           2 :                 sqlite3_free(pszErrMsg);
    1188             :             }
    1189             :         }
    1190           4 :         CPL_IGNORE_RET_VAL(bRestoreOldMode);
    1191             : #ifdef SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
    1192           4 :         if (bRestoreOldMode && oldMode != 1)
    1193             :         {
    1194           2 :             CPL_IGNORE_RET_VAL(sqlite3_db_config(
    1195             :                 hDB, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, oldMode, nullptr));
    1196             :         }
    1197             : #endif
    1198             : #else
    1199             :         CPLError(
    1200             :             CE_Failure, CPLE_NotSupported,
    1201             :             "The OGR_SQLITE_LOAD_EXTENSIONS was specified at run time, "
    1202             :             "but GDAL has been built without OGR_SQLITE_ALLOW_LOAD_EXTENSIONS. "
    1203             :             "So extensions won't be loaded");
    1204             : #endif
    1205             :     }
    1206             : }
    1207             : 
    1208             : /************************************************************************/
    1209             : /*                            SetCacheSize()                            */
    1210             : /************************************************************************/
    1211             : 
    1212        3674 : bool OGRSQLiteBaseDataSource::SetCacheSize()
    1213             : {
    1214             :     const char *pszSqliteCacheMB =
    1215        3674 :         CPLGetConfigOption("OGR_SQLITE_CACHE", nullptr);
    1216        3674 :     if (pszSqliteCacheMB != nullptr)
    1217             :     {
    1218           0 :         const GIntBig iSqliteCacheBytes =
    1219           0 :             static_cast<GIntBig>(atoi(pszSqliteCacheMB)) * 1024 * 1024;
    1220             : 
    1221             :         /* querying the current PageSize */
    1222           0 :         int iSqlitePageSize = SQLGetInteger(hDB, "PRAGMA page_size", nullptr);
    1223           0 :         if (iSqlitePageSize <= 0)
    1224           0 :             return false;
    1225             :         /* computing the CacheSize as #Pages */
    1226           0 :         const int iSqliteCachePages =
    1227           0 :             static_cast<int>(iSqliteCacheBytes / iSqlitePageSize);
    1228           0 :         if (iSqliteCachePages <= 0)
    1229           0 :             return false;
    1230             : 
    1231           0 :         return SQLCommand(hDB, CPLSPrintf("PRAGMA cache_size = %d",
    1232           0 :                                           iSqliteCachePages)) == OGRERR_NONE;
    1233             :     }
    1234        3674 :     return true;
    1235             : }
    1236             : 
    1237             : /************************************************************************/
    1238             : /*              OGRSQLiteBaseDataSourceNotifyFileOpened()               */
    1239             : /************************************************************************/
    1240             : 
    1241       23796 : static void OGRSQLiteBaseDataSourceNotifyFileOpened(void *pfnUserData,
    1242             :                                                     const char *pszFilename,
    1243             :                                                     VSILFILE *fp)
    1244             : {
    1245             :     static_cast<OGRSQLiteBaseDataSource *>(pfnUserData)
    1246       23796 :         ->NotifyFileOpened(pszFilename, fp);
    1247       23796 : }
    1248             : 
    1249             : /************************************************************************/
    1250             : /*                          NotifyFileOpened()                          */
    1251             : /************************************************************************/
    1252             : 
    1253       23796 : void OGRSQLiteBaseDataSource::NotifyFileOpened(const char *pszFilename,
    1254             :                                                VSILFILE *fp)
    1255             : {
    1256       23796 :     if (strcmp(pszFilename, m_pszFilename) == 0)
    1257             :     {
    1258        2969 :         fpMainFile = fp;
    1259             :     }
    1260       23796 : }
    1261             : 
    1262             : #ifdef USE_SQLITE_DEBUG_MEMALLOC
    1263             : 
    1264             : /* DMA9 */
    1265             : constexpr int DMA_SIGNATURE = 0x444D4139;
    1266             : 
    1267             : static void *OGRSQLiteDMA_Malloc(int size)
    1268             : {
    1269             :     int *ret = (int *)CPLMalloc(size + 8);
    1270             :     ret[0] = size;
    1271             :     ret[1] = DMA_SIGNATURE;
    1272             :     return ret + 2;
    1273             : }
    1274             : 
    1275             : static void *OGRSQLiteDMA_Realloc(void *old_ptr, int size)
    1276             : {
    1277             :     CPLAssert(((int *)old_ptr)[-1] == DMA_SIGNATURE);
    1278             :     int *ret = (int *)CPLRealloc(old_ptr ? (int *)old_ptr - 2 : NULL, size + 8);
    1279             :     ret[0] = size;
    1280             :     ret[1] = DMA_SIGNATURE;
    1281             :     return ret + 2;
    1282             : }
    1283             : 
    1284             : static void OGRSQLiteDMA_Free(void *ptr)
    1285             : {
    1286             :     if (ptr)
    1287             :     {
    1288             :         CPLAssert(((int *)ptr)[-1] == DMA_SIGNATURE);
    1289             :         ((int *)ptr)[-1] = 0;
    1290             :         CPLFree((int *)ptr - 2);
    1291             :     }
    1292             : }
    1293             : 
    1294             : static int OGRSQLiteDMA_Size(void *ptr)
    1295             : {
    1296             :     if (ptr)
    1297             :     {
    1298             :         CPLAssert(((int *)ptr)[-1] == DMA_SIGNATURE);
    1299             :         return ((int *)ptr)[-2];
    1300             :     }
    1301             :     else
    1302             :         return 0;
    1303             : }
    1304             : 
    1305             : static int OGRSQLiteDMA_Roundup(int size)
    1306             : {
    1307             :     return (size + 7) & (~7);
    1308             : }
    1309             : 
    1310             : static int OGRSQLiteDMA_Init(void *)
    1311             : {
    1312             :     return SQLITE_OK;
    1313             : }
    1314             : 
    1315             : static void OGRSQLiteDMA_Shutdown(void *)
    1316             : {
    1317             : }
    1318             : 
    1319             : const struct sqlite3_mem_methods sDebugMemAlloc = {
    1320             :     OGRSQLiteDMA_Malloc,   OGRSQLiteDMA_Free,
    1321             :     OGRSQLiteDMA_Realloc,  OGRSQLiteDMA_Size,
    1322             :     OGRSQLiteDMA_Roundup,  OGRSQLiteDMA_Init,
    1323             :     OGRSQLiteDMA_Shutdown, NULL};
    1324             : 
    1325             : #endif  // USE_SQLITE_DEBUG_MEMALLOC
    1326             : 
    1327             : /************************************************************************/
    1328             : /*                           OpenOrCreateDB()                           */
    1329             : /************************************************************************/
    1330             : 
    1331        3688 : bool OGRSQLiteBaseDataSource::OpenOrCreateDB(int flagsIn,
    1332             :                                              bool bRegisterOGR2SQLiteExtensions,
    1333             :                                              bool bLoadExtensions)
    1334             : {
    1335             : #ifdef USE_SQLITE_DEBUG_MEMALLOC
    1336             :     if (CPLTestBool(CPLGetConfigOption("USE_SQLITE_DEBUG_MEMALLOC", "NO")))
    1337             :         sqlite3_config(SQLITE_CONFIG_MALLOC, &sDebugMemAlloc);
    1338             : #endif
    1339             : 
    1340        3688 :     if (bRegisterOGR2SQLiteExtensions)
    1341        1326 :         OGR2SQLITE_Register();
    1342             : 
    1343             :     const bool bUseOGRVFS =
    1344        3688 :         CPLTestBool(CPLGetConfigOption("SQLITE_USE_OGR_VFS", "NO")) ||
    1345        4407 :         STARTS_WITH(m_pszFilename, "/vsi") ||
    1346             :         // https://sqlite.org/forum/forumpost/0b1b8b5116: MAX_PATHNAME=512
    1347         719 :         strlen(m_pszFilename) >= 512 - strlen(".journal");
    1348             : 
    1349             : #ifdef SQLITE_OPEN_URI
    1350             :     const bool bNoLock =
    1351        3688 :         CPLTestBool(CSLFetchNameValueDef(papszOpenOptions, "NOLOCK", "NO"));
    1352        3688 :     const char *pszImmutable = CSLFetchNameValue(papszOpenOptions, "IMMUTABLE");
    1353        3688 :     const bool bImmutable = pszImmutable && CPLTestBool(pszImmutable);
    1354        3688 :     if (m_osFilenameForSQLiteOpen.empty() &&
    1355        3677 :         (flagsIn & SQLITE_OPEN_READWRITE) == 0 &&
    1356        7365 :         !STARTS_WITH(m_pszFilename, "file:") && (bNoLock || bImmutable))
    1357             :     {
    1358           7 :         m_osFilenameForSQLiteOpen = "file:";
    1359             : 
    1360             :         // Apply rules from "3.1. The URI Path" of
    1361             :         // https://www.sqlite.org/uri.html
    1362          14 :         CPLString osFilenameForURI(m_pszFilename);
    1363           7 :         osFilenameForURI.replaceAll('?', "%3f");
    1364           7 :         osFilenameForURI.replaceAll('#', "%23");
    1365             : #ifdef _WIN32
    1366             :         osFilenameForURI.replaceAll('\\', '/');
    1367             : #endif
    1368           7 :         if (!STARTS_WITH(m_pszFilename, "/vsi"))
    1369             :         {
    1370           5 :             osFilenameForURI.replaceAll("//", '/');
    1371             :         }
    1372             : #ifdef _WIN32
    1373             :         if (osFilenameForURI.size() > 3 && osFilenameForURI[1] == ':' &&
    1374             :             osFilenameForURI[2] == '/')
    1375             :         {
    1376             :             osFilenameForURI = '/' + osFilenameForURI;
    1377             :         }
    1378             : #endif
    1379             : 
    1380           7 :         m_osFilenameForSQLiteOpen += osFilenameForURI;
    1381           7 :         m_osFilenameForSQLiteOpen += "?";
    1382           7 :         if (bNoLock)
    1383           5 :             m_osFilenameForSQLiteOpen += "nolock=1";
    1384           7 :         if (bImmutable)
    1385             :         {
    1386           2 :             if (m_osFilenameForSQLiteOpen.back() != '?')
    1387           0 :                 m_osFilenameForSQLiteOpen += '&';
    1388           2 :             m_osFilenameForSQLiteOpen += "immutable=1";
    1389             :         }
    1390             :     }
    1391             : #endif
    1392        3688 :     if (m_osFilenameForSQLiteOpen.empty())
    1393             :     {
    1394        3670 :         m_osFilenameForSQLiteOpen = m_pszFilename;
    1395             :     }
    1396             : 
    1397             :     // No mutex since OGR objects are not supposed to be used concurrently
    1398             :     // from multiple threads.
    1399        3688 :     int flags = flagsIn | SQLITE_OPEN_NOMUTEX;
    1400             : #ifdef SQLITE_OPEN_URI
    1401             :     // This code enables support for named memory databases in SQLite.
    1402             :     // SQLITE_USE_URI is checked only to enable backward compatibility, in
    1403             :     // case we accidentally hijacked some other format.
    1404        3696 :     if (STARTS_WITH(m_osFilenameForSQLiteOpen.c_str(), "file:") &&
    1405           8 :         CPLTestBool(CPLGetConfigOption("SQLITE_USE_URI", "YES")))
    1406             :     {
    1407           8 :         flags |= SQLITE_OPEN_URI;
    1408             :     }
    1409             : #endif
    1410             : 
    1411        3688 :     bool bPageSizeFound = false;
    1412        3688 :     bool bSecureDeleteFound = false;
    1413             : 
    1414             :     const char *pszSqlitePragma =
    1415        3688 :         CPLGetConfigOption("OGR_SQLITE_PRAGMA", nullptr);
    1416        7376 :     CPLString osJournalMode = CPLGetConfigOption("OGR_SQLITE_JOURNAL", "");
    1417             : 
    1418        3688 :     if (bUseOGRVFS)
    1419             :     {
    1420        2969 :         pMyVFS =
    1421        2969 :             OGRSQLiteCreateVFS(OGRSQLiteBaseDataSourceNotifyFileOpened, this);
    1422        2969 :         sqlite3_vfs_register(pMyVFS, 0);
    1423             :     }
    1424             : 
    1425        3689 :     for (int iterOpen = 0; iterOpen < 2; iterOpen++)
    1426             :     {
    1427        3689 :         CPLAssert(hDB == nullptr);
    1428        3689 :         int rc = sqlite3_open_v2(m_osFilenameForSQLiteOpen.c_str(), &hDB, flags,
    1429        3689 :                                  pMyVFS ? pMyVFS->zName : nullptr);
    1430        3689 :         if (rc != SQLITE_OK || !hDB)
    1431             :         {
    1432          10 :             CPLError(CE_Failure, CPLE_OpenFailed, "sqlite3_open(%s) failed: %s",
    1433             :                      m_pszFilename,
    1434          10 :                      hDB ? sqlite3_errmsg(hDB) : "(unknown error)");
    1435          10 :             sqlite3_close(hDB);
    1436          10 :             hDB = nullptr;
    1437          10 :             return false;
    1438             :         }
    1439             : 
    1440             : #ifdef SQLITE_DBCONFIG_DEFENSIVE
    1441             :         // SQLite builds on recent MacOS enable defensive mode by default, which
    1442             :         // causes issues in the VDV driver (when updating a deleted database),
    1443             :         // or in the GPKG driver (when modifying a CREATE TABLE DDL with
    1444             :         // writable_schema=ON) So disable it.
    1445        3679 :         int bDefensiveOldValue = 0;
    1446        3679 :         if (sqlite3_db_config(hDB, SQLITE_DBCONFIG_DEFENSIVE, -1,
    1447        7358 :                               &bDefensiveOldValue) == SQLITE_OK &&
    1448        3679 :             bDefensiveOldValue == 1)
    1449             :         {
    1450           0 :             if (sqlite3_db_config(hDB, SQLITE_DBCONFIG_DEFENSIVE, 0, nullptr) ==
    1451             :                 SQLITE_OK)
    1452             :             {
    1453           0 :                 CPLDebug("SQLITE", "Disabling defensive mode succeeded");
    1454             :             }
    1455             :             else
    1456             :             {
    1457           0 :                 CPLDebug("SQLITE", "Could not disable defensive mode");
    1458             :             }
    1459             :         }
    1460             : #endif
    1461             : 
    1462             : #ifdef SQLITE_FCNTL_PERSIST_WAL
    1463        3679 :         int nPersistentWAL = -1;
    1464        3679 :         sqlite3_file_control(hDB, "main", SQLITE_FCNTL_PERSIST_WAL,
    1465             :                              &nPersistentWAL);
    1466        3679 :         if (nPersistentWAL == 1)
    1467             :         {
    1468           0 :             nPersistentWAL = 0;
    1469           0 :             if (sqlite3_file_control(hDB, "main", SQLITE_FCNTL_PERSIST_WAL,
    1470           0 :                                      &nPersistentWAL) == SQLITE_OK)
    1471             :             {
    1472           0 :                 CPLDebug("SQLITE", "Disabling persistent WAL succeeded");
    1473             :             }
    1474             :             else
    1475             :             {
    1476           0 :                 CPLDebug("SQLITE", "Could not disable persistent WAL");
    1477             :             }
    1478             :         }
    1479             : #endif
    1480             : 
    1481        3679 :         if (pszSqlitePragma != nullptr)
    1482             :         {
    1483             :             char **papszTokens =
    1484           6 :                 CSLTokenizeString2(pszSqlitePragma, ",", CSLT_HONOURSTRINGS);
    1485          12 :             for (int i = 0; papszTokens[i] != nullptr; i++)
    1486             :             {
    1487           6 :                 if (STARTS_WITH_CI(papszTokens[i], "PAGE_SIZE"))
    1488           0 :                     bPageSizeFound = true;
    1489           6 :                 else if (STARTS_WITH_CI(papszTokens[i], "JOURNAL_MODE"))
    1490             :                 {
    1491           0 :                     const char *pszEqual = strchr(papszTokens[i], '=');
    1492           0 :                     if (pszEqual)
    1493             :                     {
    1494           0 :                         osJournalMode = pszEqual + 1;
    1495           0 :                         osJournalMode.Trim();
    1496             :                         // Only apply journal_mode after changing page_size
    1497           0 :                         continue;
    1498             :                     }
    1499             :                 }
    1500           6 :                 else if (STARTS_WITH_CI(papszTokens[i], "SECURE_DELETE"))
    1501           1 :                     bSecureDeleteFound = true;
    1502             : 
    1503           6 :                 const char *pszSQL = CPLSPrintf("PRAGMA %s", papszTokens[i]);
    1504             : 
    1505           6 :                 CPL_IGNORE_RET_VAL(
    1506           6 :                     sqlite3_exec(hDB, pszSQL, nullptr, nullptr, nullptr));
    1507             :             }
    1508           6 :             CSLDestroy(papszTokens);
    1509             :         }
    1510             : 
    1511        3679 :         const char *pszVal = CPLGetConfigOption("SQLITE_BUSY_TIMEOUT", "5000");
    1512        3679 :         if (pszVal != nullptr)
    1513             :         {
    1514        3679 :             sqlite3_busy_timeout(hDB, atoi(pszVal));
    1515             :         }
    1516             : 
    1517             : #ifdef SQLITE_OPEN_URI
    1518        3679 :         if (iterOpen == 0 && bNoLock && !bImmutable)
    1519             :         {
    1520           6 :             int nRowCount = 0, nColCount = 0;
    1521           6 :             char **papszResult = nullptr;
    1522           6 :             rc = sqlite3_get_table(hDB, "PRAGMA journal_mode", &papszResult,
    1523             :                                    &nRowCount, &nColCount, nullptr);
    1524           6 :             bool bWal = false;
    1525             :             // rc == SQLITE_CANTOPEN seems to be what we get when issuing the
    1526             :             // above in nolock mode on a wal enabled file
    1527           6 :             if (rc != SQLITE_OK ||
    1528           5 :                 (nRowCount == 1 && nColCount == 1 && papszResult[1] &&
    1529           5 :                  EQUAL(papszResult[1], "wal")))
    1530             :             {
    1531           1 :                 bWal = true;
    1532             :             }
    1533           6 :             sqlite3_free_table(papszResult);
    1534           6 :             if (bWal)
    1535             :             {
    1536           1 :                 flags &= ~SQLITE_OPEN_URI;
    1537           1 :                 sqlite3_close(hDB);
    1538           1 :                 hDB = nullptr;
    1539           1 :                 CPLDebug("SQLite",
    1540             :                          "Cannot open %s in nolock mode because it is "
    1541             :                          "presumably in -wal mode",
    1542             :                          m_pszFilename);
    1543           1 :                 m_osFilenameForSQLiteOpen = m_pszFilename;
    1544           1 :                 continue;
    1545             :             }
    1546             :         }
    1547             : #endif
    1548        3678 :         break;
    1549             :     }
    1550             : 
    1551        3678 :     if ((flagsIn & SQLITE_OPEN_CREATE) == 0)
    1552             :     {
    1553        2329 :         if (CPLTestBool(CPLGetConfigOption("OGR_VFK_DB_READ", "NO")))
    1554             :         {
    1555           1 :             if (SQLGetInteger(hDB,
    1556             :                               "SELECT 1 FROM sqlite_master "
    1557             :                               "WHERE type = 'table' AND name = 'vfk_tables'",
    1558           1 :                               nullptr))
    1559           4 :                 return false; /* DB is valid VFK datasource */
    1560             :         }
    1561             : 
    1562        2328 :         int nRowCount = 0, nColCount = 0;
    1563        2328 :         char **papszResult = nullptr;
    1564        2328 :         char *pszErrMsg = nullptr;
    1565             :         int rc =
    1566        2328 :             sqlite3_get_table(hDB,
    1567             :                               "SELECT 1 FROM sqlite_master "
    1568             :                               "WHERE (type = 'trigger' OR type = 'view') AND ("
    1569             :                               "sql LIKE '%%ogr_geocode%%' OR "
    1570             :                               "sql LIKE '%%ogr_datasource_load_layers%%' OR "
    1571             :                               "sql LIKE '%%ogr_GetConfigOption%%' OR "
    1572             :                               "sql LIKE '%%ogr_SetConfigOption%%' ) "
    1573             :                               "LIMIT 1",
    1574             :                               &papszResult, &nRowCount, &nColCount, &pszErrMsg);
    1575        2328 :         if (rc != SQLITE_OK)
    1576             :         {
    1577           3 :             bool bIsWAL = false;
    1578           3 :             VSILFILE *fp = VSIFOpenL(m_pszFilename, "rb");
    1579           3 :             if (fp != nullptr)
    1580             :             {
    1581           3 :                 GByte byVal = 0;
    1582           3 :                 VSIFSeekL(fp, 18, SEEK_SET);
    1583           3 :                 VSIFReadL(&byVal, 1, 1, fp);
    1584           3 :                 bIsWAL = byVal == 2;
    1585           3 :                 VSIFCloseL(fp);
    1586             :             }
    1587           3 :             if (bIsWAL)
    1588             :             {
    1589             : #ifdef SQLITE_OPEN_URI
    1590           5 :                 if (pszImmutable == nullptr &&
    1591           4 :                     (flags & SQLITE_OPEN_READONLY) != 0 &&
    1592           1 :                     m_osFilenameForSQLiteOpen == m_pszFilename)
    1593             :                 {
    1594           1 :                     CPLError(CE_Warning, CPLE_AppDefined,
    1595             :                              "%s: this file is a WAL-enabled database. "
    1596             :                              "It cannot be opened "
    1597             :                              "because it is presumably read-only or in a "
    1598             :                              "read-only directory. Retrying with IMMUTABLE=YES "
    1599             :                              "open option",
    1600             :                              pszErrMsg);
    1601           1 :                     sqlite3_free(pszErrMsg);
    1602           1 :                     CloseDB();
    1603           1 :                     m_osFilenameForSQLiteOpen.clear();
    1604           1 :                     papszOpenOptions =
    1605           1 :                         CSLSetNameValue(papszOpenOptions, "IMMUTABLE", "YES");
    1606           1 :                     return OpenOrCreateDB(flagsIn,
    1607             :                                           bRegisterOGR2SQLiteExtensions,
    1608           1 :                                           bLoadExtensions);
    1609             :                 }
    1610             : #endif
    1611             : 
    1612           2 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1613             :                          "%s: this file is a WAL-enabled database. "
    1614             :                          "It cannot be opened "
    1615             :                          "because it is presumably read-only or in a "
    1616             :                          "read-only directory.%s",
    1617             :                          pszErrMsg,
    1618             : #ifdef SQLITE_OPEN_URI
    1619             :                          pszImmutable != nullptr
    1620             :                              ? ""
    1621             :                              : " Try opening with IMMUTABLE=YES open option"
    1622             : #else
    1623             :                          ""
    1624             : #endif
    1625             :                 );
    1626             :             }
    1627             :             else
    1628             :             {
    1629           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "%s", pszErrMsg);
    1630             :             }
    1631           2 :             sqlite3_free(pszErrMsg);
    1632           2 :             return false;
    1633             :         }
    1634             : 
    1635        2325 :         sqlite3_free_table(papszResult);
    1636             : 
    1637        2325 :         if (nRowCount > 0)
    1638             :         {
    1639           0 :             if (!CPLTestBool(CPLGetConfigOption(
    1640             :                     "ALLOW_OGR_SQL_FUNCTIONS_FROM_TRIGGER_AND_VIEW", "NO")))
    1641             :             {
    1642           0 :                 CPLError(CE_Failure, CPLE_OpenFailed, "%s",
    1643             :                          "A trigger and/or view calls a OGR extension SQL "
    1644             :                          "function that could be used to "
    1645             :                          "steal data, or use network bandwidth, without your "
    1646             :                          "consent.\n"
    1647             :                          "The database will not be opened unless the "
    1648             :                          "ALLOW_OGR_SQL_FUNCTIONS_FROM_TRIGGER_AND_VIEW "
    1649             :                          "configuration option to YES.");
    1650           0 :                 return false;
    1651             :             }
    1652             :         }
    1653             :     }
    1654             : 
    1655        3682 :     if (m_osFilenameForSQLiteOpen != m_pszFilename &&
    1656           8 :         (m_osFilenameForSQLiteOpen.find("?nolock=1") != std::string::npos ||
    1657           2 :          m_osFilenameForSQLiteOpen.find("&nolock=1") != std::string::npos))
    1658             :     {
    1659           4 :         m_bNoLock = true;
    1660           4 :         CPLDebug("SQLite", "%s open in nolock mode", m_pszFilename);
    1661             :     }
    1662             : 
    1663        3674 :     if (!bPageSizeFound && (flagsIn & SQLITE_OPEN_CREATE) != 0)
    1664             :     {
    1665             :         // Since sqlite 3.12 the default page_size is now 4096. But we
    1666             :         // can use that even with older versions.
    1667        1349 :         CPL_IGNORE_RET_VAL(sqlite3_exec(hDB, "PRAGMA page_size = 4096", nullptr,
    1668             :                                         nullptr, nullptr));
    1669             :     }
    1670             : 
    1671             :     // journal_mode = WAL must be done *AFTER* changing page size.
    1672        3674 :     if (!osJournalMode.empty())
    1673             :     {
    1674             :         const char *pszSQL =
    1675           2 :             CPLSPrintf("PRAGMA journal_mode = %s", osJournalMode.c_str());
    1676             : 
    1677           2 :         CPL_IGNORE_RET_VAL(
    1678           2 :             sqlite3_exec(hDB, pszSQL, nullptr, nullptr, nullptr));
    1679             :     }
    1680             : 
    1681        3674 :     if (!bSecureDeleteFound)
    1682             :     {
    1683             :         // Turn on secure_delete by default (unless the user specifies a
    1684             :         // value of this pragma through OGR_SQLITE_PRAGMA)
    1685             :         // For example, Debian and Conda-Forge SQLite3 builds already turn on
    1686             :         // secure_delete.
    1687        3673 :         CPL_IGNORE_RET_VAL(sqlite3_exec(hDB, "PRAGMA secure_delete = 1",
    1688             :                                         nullptr, nullptr, nullptr));
    1689             :     }
    1690             : 
    1691        3674 :     SetCacheSize();
    1692        3674 :     SetSynchronous();
    1693        3674 :     if (bLoadExtensions)
    1694        2351 :         LoadExtensions();
    1695             : 
    1696        3674 :     return true;
    1697             : }
    1698             : 
    1699             : /************************************************************************/
    1700             : /*                           OpenOrCreateDB()                           */
    1701             : /************************************************************************/
    1702             : 
    1703        1326 : bool OGRSQLiteDataSource::OpenOrCreateDB(int flagsIn,
    1704             :                                          bool bRegisterOGR2SQLiteExtensions)
    1705             : {
    1706             :     {
    1707             :         // Make sure that OGR2SQLITE_static_register() doesn't instantiate
    1708             :         // its default OGR2SQLITEModule. Let's do it ourselves just afterwards
    1709             :         //
    1710             :         CPLConfigOptionSetter oSetter("OGR_SQLITE_STATIC_VIRTUAL_OGR", "NO",
    1711        1326 :                                       false);
    1712        1326 :         if (!OGRSQLiteBaseDataSource::OpenOrCreateDB(
    1713             :                 flagsIn, bRegisterOGR2SQLiteExtensions,
    1714             :                 /*bLoadExtensions=*/false))
    1715             :         {
    1716           3 :             return false;
    1717             :         }
    1718             :     }
    1719        2646 :     if (bRegisterOGR2SQLiteExtensions &&
    1720             :         // Do not run OGR2SQLITE_Setup() if called from ogrsqlitexecute.sql
    1721             :         // that will do it with other datasets.
    1722        1323 :         CPLTestBool(CPLGetConfigOption("OGR_SQLITE_STATIC_VIRTUAL_OGR", "YES")))
    1723             :     {
    1724             :         // Make sure this is done before registering our custom functions
    1725             :         // to allow overriding Spatialite.
    1726         664 :         InitSpatialite();
    1727             : 
    1728         664 :         m_poSQLiteModule = OGR2SQLITE_Setup(this, this);
    1729             :     }
    1730             :     // We need to do LoadExtensions() after OGR2SQLITE_Setup(), otherwise
    1731             :     // tests in ogr_virtualogr.py::test_ogr_sqlite_load_extensions_load_self()
    1732             :     // will crash when trying to load libgdal as an extension (which is an
    1733             :     // errour we catch, but only if OGR2SQLITEModule has been created by
    1734             :     // above OGR2SQLITE_Setup()
    1735        1323 :     LoadExtensions();
    1736             : 
    1737             :     const char *pszPreludeStatements =
    1738        1323 :         CSLFetchNameValue(papszOpenOptions, "PRELUDE_STATEMENTS");
    1739        1323 :     if (pszPreludeStatements)
    1740             :     {
    1741           1 :         if (SQLCommand(hDB, pszPreludeStatements) != OGRERR_NONE)
    1742           0 :             return false;
    1743             :     }
    1744             : 
    1745        1323 :     return true;
    1746             : }
    1747             : 
    1748             : /************************************************************************/
    1749             : /*                         PostInitSpatialite()                         */
    1750             : /************************************************************************/
    1751             : 
    1752        1014 : void OGRSQLiteDataSource::PostInitSpatialite()
    1753             : {
    1754             : #ifdef HAVE_SPATIALITE
    1755             :     const char *pszSqlitePragma =
    1756        1014 :         CPLGetConfigOption("OGR_SQLITE_PRAGMA", nullptr);
    1757        1014 :     OGRErr eErr = OGRERR_NONE;
    1758           0 :     if ((!pszSqlitePragma || !strstr(pszSqlitePragma, "trusted_schema")) &&
    1759             :         // Older sqlite versions don't have this pragma
    1760        2026 :         SQLGetInteger(hDB, "PRAGMA trusted_schema", &eErr) == 0 &&
    1761        1012 :         eErr == OGRERR_NONE)
    1762             :     {
    1763             :         // Spatialite <= 5.1.0 doesn't declare its functions as SQLITE_INNOCUOUS
    1764        2024 :         if (IsSpatialiteLoaded() && SpatialiteRequiresTrustedSchemaOn() &&
    1765        1012 :             AreSpatialiteTriggersSafe())
    1766             :         {
    1767        1012 :             CPLDebug("SQLITE", "Setting PRAGMA trusted_schema = 1");
    1768        1012 :             SQLCommand(hDB, "PRAGMA trusted_schema = 1");
    1769             :         }
    1770             :     }
    1771             : #endif
    1772        1014 : }
    1773             : 
    1774             : /************************************************************************/
    1775             : /*                 SpatialiteRequiresTrustedSchemaOn()                  */
    1776             : /************************************************************************/
    1777             : 
    1778        1013 : bool OGRSQLiteBaseDataSource::SpatialiteRequiresTrustedSchemaOn()
    1779             : {
    1780             : #ifdef HAVE_SPATIALITE
    1781             :     // Spatialite <= 5.1.0 doesn't declare its functions as SQLITE_INNOCUOUS
    1782        1013 :     if (GetSpatialiteVersionNumber() <= MakeSpatialiteVersionNumber(5, 1, 0))
    1783             :     {
    1784        1013 :         return true;
    1785             :     }
    1786             : #endif
    1787           0 :     return false;
    1788             : }
    1789             : 
    1790             : /************************************************************************/
    1791             : /*                     AreSpatialiteTriggersSafe()                      */
    1792             : /************************************************************************/
    1793             : 
    1794        1013 : bool OGRSQLiteBaseDataSource::AreSpatialiteTriggersSafe()
    1795             : {
    1796             : #ifdef HAVE_SPATIALITE
    1797             :     // Not totally sure about the minimum spatialite version, but 4.3a is fine
    1798        1013 :     return GetSpatialiteVersionNumber() >=
    1799        2026 :                MakeSpatialiteVersionNumber(4, 3, 0) &&
    1800        2026 :            SQLGetInteger(hDB, "SELECT CountUnsafeTriggers()", nullptr) == 0;
    1801             : #else
    1802             :     return true;
    1803             : #endif
    1804             : }
    1805             : 
    1806             : /************************************************************************/
    1807             : /*                         GetInternalHandle()                          */
    1808             : /************************************************************************/
    1809             : 
    1810             : /* Used by MBTILES driver */
    1811          61 : void *OGRSQLiteBaseDataSource::GetInternalHandle(const char *pszKey)
    1812             : {
    1813          61 :     if (pszKey != nullptr && EQUAL(pszKey, "SQLITE_HANDLE"))
    1814          61 :         return hDB;
    1815           0 :     return nullptr;
    1816             : }
    1817             : 
    1818             : /************************************************************************/
    1819             : /*                               Create()                               */
    1820             : /************************************************************************/
    1821             : 
    1822         366 : bool OGRSQLiteDataSource::Create(const char *pszNameIn,
    1823             :                                  CSLConstList papszOptions)
    1824             : {
    1825         732 :     CPLString osCommand;
    1826             : 
    1827             :     const bool bUseTempFile =
    1828         366 :         CPLTestBool(CPLGetConfigOption(
    1829         367 :             "CPL_VSIL_USE_TEMP_FILE_FOR_RANDOM_WRITE", "NO")) &&
    1830           1 :         (VSIHasOptimizedReadMultiRange(pszNameIn) != FALSE ||
    1831           1 :          EQUAL(
    1832             :              CPLGetConfigOption("CPL_VSIL_USE_TEMP_FILE_FOR_RANDOM_WRITE", ""),
    1833         366 :              "FORCED"));
    1834             : 
    1835         366 :     if (bUseTempFile)
    1836             :     {
    1837           1 :         m_osFinalFilename = pszNameIn;
    1838           1 :         m_pszFilename = CPLStrdup(
    1839           2 :             CPLGenerateTempFilenameSafe(CPLGetFilename(pszNameIn)).c_str());
    1840           1 :         CPLDebug("SQLITE", "Creating temporary file %s", m_pszFilename);
    1841             :     }
    1842             :     else
    1843             :     {
    1844         365 :         m_pszFilename = CPLStrdup(pszNameIn);
    1845             :     }
    1846             : 
    1847             :     /* -------------------------------------------------------------------- */
    1848             :     /*      Check that spatialite extensions are loaded if required to      */
    1849             :     /*      create a spatialite database                                    */
    1850             :     /* -------------------------------------------------------------------- */
    1851         366 :     const bool bSpatialite = CPLFetchBool(papszOptions, "SPATIALITE", false);
    1852         366 :     const bool bMetadata = CPLFetchBool(papszOptions, "METADATA", true);
    1853             : 
    1854             :     if (bSpatialite)
    1855             :     {
    1856             : #ifndef HAVE_SPATIALITE
    1857             :         CPLError(
    1858             :             CE_Failure, CPLE_NotSupported,
    1859             :             "OGR was built without libspatialite support\n"
    1860             :             "... sorry, creating/writing any SpatiaLite DB is unsupported");
    1861             : 
    1862             :         return false;
    1863             : #endif
    1864             :     }
    1865             : 
    1866         366 :     m_bIsSpatiaLiteDB = bSpatialite;
    1867             : 
    1868             :     /* -------------------------------------------------------------------- */
    1869             :     /*      Create the database file.                                       */
    1870             :     /* -------------------------------------------------------------------- */
    1871         366 :     if (!OpenOrCreateDB(SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, true))
    1872           2 :         return false;
    1873             : 
    1874             :     /* -------------------------------------------------------------------- */
    1875             :     /*      Create the SpatiaLite metadata tables.                          */
    1876             :     /* -------------------------------------------------------------------- */
    1877         364 :     if (bSpatialite)
    1878             :     {
    1879          51 :         if (!InitSpatialite())
    1880             :         {
    1881           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    1882             :                      "Creating a Spatialite database, but Spatialite "
    1883             :                      "extensions are not loaded.");
    1884           0 :             return false;
    1885             :         }
    1886             : 
    1887          51 :         PostInitSpatialite();
    1888             : 
    1889             : #ifdef HAVE_RASTERLITE2
    1890             :         InitRasterLite2();
    1891             : #endif
    1892             : 
    1893             :         /*
    1894             :         / SpatiaLite full support: calling InitSpatialMetadata()
    1895             :         /
    1896             :         / IMPORTANT NOTICE: on SpatiaLite any attempt aimed
    1897             :         / to directly CREATE "geometry_columns" and "spatial_ref_sys"
    1898             :         / [by-passing InitSpatialMetadata() as absolutely required]
    1899             :         / will severely [and irremediably] corrupt the DB !!!
    1900             :         */
    1901             : 
    1902          51 :         const char *pszVal = CSLFetchNameValue(papszOptions, "INIT_WITH_EPSG");
    1903          51 :         const int nSpatialiteVersionNumber = GetSpatialiteVersionNumber();
    1904          52 :         if (pszVal != nullptr && !CPLTestBool(pszVal) &&
    1905           1 :             nSpatialiteVersionNumber >= MakeSpatialiteVersionNumber(4, 0, 0))
    1906             :         {
    1907           1 :             if (nSpatialiteVersionNumber >=
    1908           1 :                 MakeSpatialiteVersionNumber(4, 1, 0))
    1909           1 :                 osCommand = "SELECT InitSpatialMetadata(1, 'NONE')";
    1910             :             else
    1911           0 :                 osCommand = "SELECT InitSpatialMetadata('NONE')";
    1912             :         }
    1913             :         else
    1914             :         {
    1915             :             /* Since spatialite 4.1, InitSpatialMetadata() is no longer run */
    1916             :             /* into a transaction, which makes population of spatial_ref_sys */
    1917             :             /* from EPSG awfully slow. We have to use InitSpatialMetadata(1) */
    1918             :             /* to run within a transaction */
    1919          50 :             if (nSpatialiteVersionNumber >= 41)
    1920          50 :                 osCommand = "SELECT InitSpatialMetadata(1)";
    1921             :             else
    1922           0 :                 osCommand = "SELECT InitSpatialMetadata()";
    1923             :         }
    1924          51 :         if (SQLCommand(hDB, osCommand) != OGRERR_NONE)
    1925             :         {
    1926           0 :             return false;
    1927             :         }
    1928             :     }
    1929             : 
    1930             :     /* -------------------------------------------------------------------- */
    1931             :     /*  Create the geometry_columns and spatial_ref_sys metadata tables.    */
    1932             :     /* -------------------------------------------------------------------- */
    1933         313 :     else if (bMetadata)
    1934             :     {
    1935         304 :         if (SQLCommand(hDB, "CREATE TABLE geometry_columns ("
    1936             :                             "     f_table_name VARCHAR, "
    1937             :                             "     f_geometry_column VARCHAR, "
    1938             :                             "     geometry_type INTEGER, "
    1939             :                             "     coord_dimension INTEGER, "
    1940             :                             "     srid INTEGER,"
    1941             :                             "     geometry_format VARCHAR )"
    1942             :                             ";"
    1943             :                             "CREATE TABLE spatial_ref_sys        ("
    1944             :                             "     srid INTEGER UNIQUE,"
    1945             :                             "     auth_name TEXT,"
    1946             :                             "     auth_srid TEXT,"
    1947         304 :                             "     srtext TEXT)") != OGRERR_NONE)
    1948             :         {
    1949           0 :             return false;
    1950             :         }
    1951             :     }
    1952             : 
    1953             :     /* -------------------------------------------------------------------- */
    1954             :     /*      Optionally initialize the content of the spatial_ref_sys table  */
    1955             :     /*      with the EPSG database                                          */
    1956             :     /* -------------------------------------------------------------------- */
    1957         719 :     if ((bSpatialite || bMetadata) &&
    1958         355 :         CPLFetchBool(papszOptions, "INIT_WITH_EPSG", false))
    1959             :     {
    1960           2 :         if (!InitWithEPSG())
    1961           0 :             return false;
    1962             :     }
    1963             : 
    1964         728 :     GDALOpenInfo oOpenInfo(m_pszFilename, GDAL_OF_VECTOR | GDAL_OF_UPDATE);
    1965         364 :     return Open(&oOpenInfo);
    1966             : }
    1967             : 
    1968             : /************************************************************************/
    1969             : /*                            InitWithEPSG()                            */
    1970             : /************************************************************************/
    1971             : 
    1972           2 : bool OGRSQLiteDataSource::InitWithEPSG()
    1973             : {
    1974           4 :     CPLString osCommand;
    1975             : 
    1976           2 :     if (m_bIsSpatiaLiteDB)
    1977             :     {
    1978             :         /*
    1979             :         / if v.2.4.0 (or any subsequent) InitWithEPSG make no sense at all
    1980             :         / because the EPSG dataset is already self-initialized at DB creation
    1981             :         */
    1982           1 :         int iSpatialiteVersion = GetSpatialiteVersionNumber();
    1983           1 :         if (iSpatialiteVersion >= MakeSpatialiteVersionNumber(2, 4, 0))
    1984           1 :             return true;
    1985             :     }
    1986             : 
    1987           1 :     if (SoftStartTransaction() != OGRERR_NONE)
    1988           0 :         return false;
    1989             : 
    1990           2 :     OGRSpatialReference oSRS;
    1991           1 :     int rc = SQLITE_OK;
    1992           3 :     for (int i = 0; i < 2 && rc == SQLITE_OK; i++)
    1993             :     {
    1994           2 :         PROJ_STRING_LIST crsCodeList = proj_get_codes_from_database(
    1995             :             OSRGetProjTLSContext(), "EPSG",
    1996             :             i == 0 ? PJ_TYPE_GEOGRAPHIC_2D_CRS : PJ_TYPE_PROJECTED_CRS, true);
    1997        5670 :         for (auto iterCode = crsCodeList; iterCode && *iterCode; ++iterCode)
    1998             :         {
    1999        5668 :             int nSRSId = atoi(*iterCode);
    2000             : 
    2001        5668 :             CPLPushErrorHandler(CPLQuietErrorHandler);
    2002        5668 :             oSRS.importFromEPSG(nSRSId);
    2003        5668 :             CPLPopErrorHandler();
    2004             : 
    2005        5668 :             if (m_bIsSpatiaLiteDB)
    2006             :             {
    2007           0 :                 char *pszProj4 = nullptr;
    2008             : 
    2009           0 :                 CPLPushErrorHandler(CPLQuietErrorHandler);
    2010           0 :                 OGRErr eErr = oSRS.exportToProj4(&pszProj4);
    2011             : 
    2012           0 :                 char *pszWKT = nullptr;
    2013           0 :                 if (eErr == OGRERR_NONE &&
    2014           0 :                     oSRS.exportToWkt(&pszWKT) != OGRERR_NONE)
    2015             :                 {
    2016           0 :                     CPLFree(pszWKT);
    2017           0 :                     pszWKT = nullptr;
    2018           0 :                     eErr = OGRERR_FAILURE;
    2019             :                 }
    2020           0 :                 CPLPopErrorHandler();
    2021             : 
    2022           0 :                 if (eErr == OGRERR_NONE)
    2023             :                 {
    2024           0 :                     const char *pszProjCS = oSRS.GetAttrValue("PROJCS");
    2025           0 :                     if (pszProjCS == nullptr)
    2026           0 :                         pszProjCS = oSRS.GetAttrValue("GEOGCS");
    2027             : 
    2028           0 :                     const char *pszSRTEXTColName = GetSRTEXTColName();
    2029           0 :                     if (pszSRTEXTColName != nullptr)
    2030             :                     {
    2031             :                         /* the SPATIAL_REF_SYS table supports a SRS_WKT column
    2032             :                          */
    2033           0 :                         if (pszProjCS)
    2034             :                             osCommand.Printf(
    2035             :                                 "INSERT INTO spatial_ref_sys "
    2036             :                                 "(srid, auth_name, auth_srid, ref_sys_name, "
    2037             :                                 "proj4text, %s) "
    2038             :                                 "VALUES (%d, 'EPSG', '%d', ?, ?, ?)",
    2039           0 :                                 pszSRTEXTColName, nSRSId, nSRSId);
    2040             :                         else
    2041             :                             osCommand.Printf(
    2042             :                                 "INSERT INTO spatial_ref_sys "
    2043             :                                 "(srid, auth_name, auth_srid, proj4text, %s) "
    2044             :                                 "VALUES (%d, 'EPSG', '%d', ?, ?)",
    2045           0 :                                 pszSRTEXTColName, nSRSId, nSRSId);
    2046             :                     }
    2047             :                     else
    2048             :                     {
    2049             :                         /* the SPATIAL_REF_SYS table does not support a SRS_WKT
    2050             :                          * column */
    2051           0 :                         if (pszProjCS)
    2052             :                             osCommand.Printf("INSERT INTO spatial_ref_sys "
    2053             :                                              "(srid, auth_name, auth_srid, "
    2054             :                                              "ref_sys_name, proj4text) "
    2055             :                                              "VALUES (%d, 'EPSG', '%d', ?, ?)",
    2056           0 :                                              nSRSId, nSRSId);
    2057             :                         else
    2058             :                             osCommand.Printf(
    2059             :                                 "INSERT INTO spatial_ref_sys "
    2060             :                                 "(srid, auth_name, auth_srid, proj4text) "
    2061             :                                 "VALUES (%d, 'EPSG', '%d', ?)",
    2062           0 :                                 nSRSId, nSRSId);
    2063             :                     }
    2064             : 
    2065           0 :                     sqlite3_stmt *hInsertStmt = prepareSql(hDB, osCommand, -1);
    2066             : 
    2067           0 :                     if (pszProjCS)
    2068             :                     {
    2069           0 :                         if (rc == SQLITE_OK)
    2070           0 :                             rc = sqlite3_bind_text(hInsertStmt, 1, pszProjCS,
    2071             :                                                    -1, SQLITE_STATIC);
    2072           0 :                         if (rc == SQLITE_OK)
    2073           0 :                             rc = sqlite3_bind_text(hInsertStmt, 2, pszProj4, -1,
    2074             :                                                    SQLITE_STATIC);
    2075           0 :                         if (pszSRTEXTColName != nullptr)
    2076             :                         {
    2077             :                             /* the SPATIAL_REF_SYS table supports a SRS_WKT
    2078             :                              * column */
    2079           0 :                             if (rc == SQLITE_OK && pszWKT != nullptr)
    2080           0 :                                 rc = sqlite3_bind_text(hInsertStmt, 3, pszWKT,
    2081             :                                                        -1, SQLITE_STATIC);
    2082             :                         }
    2083             :                     }
    2084             :                     else
    2085             :                     {
    2086           0 :                         if (rc == SQLITE_OK)
    2087           0 :                             rc = sqlite3_bind_text(hInsertStmt, 1, pszProj4, -1,
    2088             :                                                    SQLITE_STATIC);
    2089           0 :                         if (pszSRTEXTColName != nullptr)
    2090             :                         {
    2091             :                             /* the SPATIAL_REF_SYS table supports a SRS_WKT
    2092             :                              * column */
    2093           0 :                             if (rc == SQLITE_OK && pszWKT != nullptr)
    2094           0 :                                 rc = sqlite3_bind_text(hInsertStmt, 2, pszWKT,
    2095             :                                                        -1, SQLITE_STATIC);
    2096             :                         }
    2097             :                     }
    2098             : 
    2099           0 :                     if (rc == SQLITE_OK)
    2100           0 :                         rc = sqlite3_step(hInsertStmt);
    2101             : 
    2102           0 :                     if (rc != SQLITE_OK && rc != SQLITE_DONE)
    2103             :                     {
    2104           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
    2105             :                                  "Cannot insert %s into spatial_ref_sys : %s",
    2106             :                                  pszProj4, sqlite3_errmsg(hDB));
    2107             : 
    2108           0 :                         sqlite3_finalize(hInsertStmt);
    2109           0 :                         CPLFree(pszProj4);
    2110           0 :                         CPLFree(pszWKT);
    2111           0 :                         break;
    2112             :                     }
    2113           0 :                     rc = SQLITE_OK;
    2114             : 
    2115           0 :                     sqlite3_finalize(hInsertStmt);
    2116             :                 }
    2117             : 
    2118           0 :                 CPLFree(pszProj4);
    2119           0 :                 CPLFree(pszWKT);
    2120             :             }
    2121             :             else
    2122             :             {
    2123        5668 :                 char *pszWKT = nullptr;
    2124        5668 :                 CPLPushErrorHandler(CPLQuietErrorHandler);
    2125        5668 :                 bool bSuccess = (oSRS.exportToWkt(&pszWKT) == OGRERR_NONE);
    2126        5668 :                 CPLPopErrorHandler();
    2127        5668 :                 if (bSuccess)
    2128             :                 {
    2129             :                     osCommand.Printf("INSERT INTO spatial_ref_sys "
    2130             :                                      "(srid, auth_name, auth_srid, srtext) "
    2131             :                                      "VALUES (%d, 'EPSG', '%d', ?)",
    2132        5668 :                                      nSRSId, nSRSId);
    2133             : 
    2134             :                     sqlite3_stmt *hInsertStmt =
    2135        5668 :                         prepareSql(hDB, osCommand.c_str());
    2136             : 
    2137        5668 :                     if (hInsertStmt)
    2138        5668 :                         rc = sqlite3_bind_text(hInsertStmt, 1, pszWKT, -1,
    2139             :                                                SQLITE_STATIC);
    2140             :                     else
    2141           0 :                         rc = SQLITE_ERROR;
    2142             : 
    2143        5668 :                     if (rc == SQLITE_OK)
    2144        5668 :                         rc = sqlite3_step(hInsertStmt);
    2145             : 
    2146        5668 :                     if (rc != SQLITE_OK && rc != SQLITE_DONE)
    2147             :                     {
    2148           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
    2149             :                                  "Cannot insert %s into spatial_ref_sys : %s",
    2150             :                                  pszWKT, sqlite3_errmsg(hDB));
    2151             : 
    2152           0 :                         sqlite3_finalize(hInsertStmt);
    2153           0 :                         CPLFree(pszWKT);
    2154           0 :                         break;
    2155             :                     }
    2156        5668 :                     rc = SQLITE_OK;
    2157             : 
    2158        5668 :                     sqlite3_finalize(hInsertStmt);
    2159             :                 }
    2160             : 
    2161        5668 :                 CPLFree(pszWKT);
    2162             :             }
    2163             :         }
    2164             : 
    2165           2 :         proj_string_list_destroy(crsCodeList);
    2166             :     }
    2167             : 
    2168           1 :     if (rc == SQLITE_OK)
    2169             :     {
    2170           1 :         if (SoftCommitTransaction() != OGRERR_NONE)
    2171           0 :             return false;
    2172           1 :         return true;
    2173             :     }
    2174             :     else
    2175             :     {
    2176           0 :         SoftRollbackTransaction();
    2177           0 :         return false;
    2178             :     }
    2179             : }
    2180             : 
    2181             : /************************************************************************/
    2182             : /*                            ReloadLayers()                            */
    2183             : /************************************************************************/
    2184             : 
    2185         657 : void OGRSQLiteDataSource::ReloadLayers()
    2186             : {
    2187         657 :     m_apoLayers.clear();
    2188             : 
    2189         657 :     GDALOpenInfo oOpenInfo(m_pszFilename,
    2190        1314 :                            GDAL_OF_VECTOR | (GetUpdate() ? GDAL_OF_UPDATE : 0));
    2191         657 :     Open(&oOpenInfo);
    2192         657 : }
    2193             : 
    2194             : /************************************************************************/
    2195             : /*                                Open()                                */
    2196             : /************************************************************************/
    2197             : 
    2198        1983 : bool OGRSQLiteDataSource::Open(GDALOpenInfo *poOpenInfo)
    2199             : 
    2200             : {
    2201        1983 :     const char *pszNewName = poOpenInfo->pszFilename;
    2202        1983 :     CPLAssert(m_apoLayers.empty());
    2203        1983 :     eAccess = poOpenInfo->eAccess;
    2204        1983 :     nOpenFlags = poOpenInfo->nOpenFlags & ~GDAL_OF_THREAD_SAFE;
    2205        1983 :     SetDescription(pszNewName);
    2206             : 
    2207        1983 :     if (m_pszFilename == nullptr)
    2208             :     {
    2209             : #ifdef HAVE_RASTERLITE2
    2210             :         if (STARTS_WITH_CI(pszNewName, "RASTERLITE2:") &&
    2211             :             (nOpenFlags & GDAL_OF_RASTER) != 0)
    2212             :         {
    2213             :             char **papszTokens =
    2214             :                 CSLTokenizeString2(pszNewName, ":", CSLT_HONOURSTRINGS);
    2215             :             if (CSLCount(papszTokens) < 2)
    2216             :             {
    2217             :                 CSLDestroy(papszTokens);
    2218             :                 return false;
    2219             :             }
    2220             :             m_pszFilename = CPLStrdup(SQLUnescape(papszTokens[1]));
    2221             :             CSLDestroy(papszTokens);
    2222             :         }
    2223             :         else
    2224             : #endif
    2225         962 :             if (STARTS_WITH_CI(pszNewName, "SQLITE:"))
    2226             :         {
    2227          79 :             m_pszFilename = CPLStrdup(pszNewName + strlen("SQLITE:"));
    2228             :         }
    2229             :         else
    2230             :         {
    2231         883 :             m_pszFilename = CPLStrdup(pszNewName);
    2232         883 :             if (poOpenInfo->pabyHeader &&
    2233         833 :                 STARTS_WITH(
    2234             :                     reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
    2235             :                     "SQLite format 3"))
    2236             :             {
    2237         832 :                 m_bCallUndeclareFileNotToOpen = true;
    2238         832 :                 GDALOpenInfoDeclareFileNotToOpen(m_pszFilename,
    2239         832 :                                                  poOpenInfo->pabyHeader,
    2240             :                                                  poOpenInfo->nHeaderBytes);
    2241             :             }
    2242             :         }
    2243             :     }
    2244        1983 :     SetPhysicalFilename(m_pszFilename);
    2245             : 
    2246             :     VSIStatBufL sStat;
    2247        1983 :     if (VSIStatL(m_pszFilename, &sStat) == 0)
    2248             :     {
    2249        1914 :         m_nFileTimestamp = sStat.st_mtime;
    2250             :     }
    2251             : 
    2252        1983 :     if (poOpenInfo->papszOpenOptions)
    2253             :     {
    2254          11 :         CSLDestroy(papszOpenOptions);
    2255          11 :         papszOpenOptions = CSLDuplicate(poOpenInfo->papszOpenOptions);
    2256             :     }
    2257             : 
    2258        1983 :     const bool bListVectorLayers = (nOpenFlags & GDAL_OF_VECTOR) != 0;
    2259             : 
    2260             :     const bool bListAllTables =
    2261        3966 :         bListVectorLayers &&
    2262        3966 :         CPLTestBool(CSLFetchNameValueDef(
    2263        1983 :             papszOpenOptions, "LIST_ALL_TABLES",
    2264        1983 :             CPLGetConfigOption("SQLITE_LIST_ALL_TABLES", "NO")));
    2265             : 
    2266             :     // Don't list by default: there might be some security implications
    2267             :     // if a user is provided with a file and doesn't know that there are
    2268             :     // virtual OGR tables in it.
    2269             :     const bool bListVirtualOGRLayers =
    2270        3966 :         bListVectorLayers &&
    2271        3966 :         CPLTestBool(CSLFetchNameValueDef(
    2272        1983 :             papszOpenOptions, "LIST_VIRTUAL_OGR",
    2273        1983 :             CPLGetConfigOption("OGR_SQLITE_LIST_VIRTUAL_OGR", "NO")));
    2274             : 
    2275             :     /* -------------------------------------------------------------------- */
    2276             :     /*      Try to open the sqlite database properly now.                   */
    2277             :     /* -------------------------------------------------------------------- */
    2278        1983 :     if (hDB == nullptr)
    2279             :     {
    2280             : #ifdef ENABLE_SQL_SQLITE_FORMAT
    2281             :         // SQLite -wal locking appears to be extremely fragile. In particular
    2282             :         // if we have a file descriptor opened on the file while sqlite3_open
    2283             :         // is called, then it will mis-behave (a process opening in update mode
    2284             :         // the file and closing it will remove the -wal file !)
    2285             :         // So make sure that the GDALOpenInfo object goes out of scope before
    2286             :         // going on.
    2287             :         {
    2288         962 :             GDALOpenInfo oOpenInfo(m_pszFilename, GA_ReadOnly);
    2289         962 :             if (oOpenInfo.pabyHeader &&
    2290         912 :                 (STARTS_WITH(
    2291             :                      reinterpret_cast<const char *>(oOpenInfo.pabyHeader),
    2292         911 :                      "-- SQL SQLITE") ||
    2293         911 :                  STARTS_WITH(
    2294             :                      reinterpret_cast<const char *>(oOpenInfo.pabyHeader),
    2295         911 :                      "-- SQL RASTERLITE") ||
    2296         911 :                  STARTS_WITH(
    2297             :                      reinterpret_cast<const char *>(oOpenInfo.pabyHeader),
    2298           2 :                      "-- SQL MBTILES")) &&
    2299           2 :                 oOpenInfo.fpL != nullptr)
    2300             :             {
    2301           2 :                 if (sqlite3_open_v2(":memory:", &hDB, SQLITE_OPEN_READWRITE,
    2302           2 :                                     nullptr) != SQLITE_OK)
    2303             :                 {
    2304           0 :                     return false;
    2305             :                 }
    2306             : 
    2307             :                 // We need it here for ST_MinX() and the like
    2308           2 :                 InitSpatialite();
    2309             : 
    2310           2 :                 PostInitSpatialite();
    2311             : 
    2312             :                 // Ingest the lines of the dump
    2313           2 :                 VSIFSeekL(oOpenInfo.fpL, 0, SEEK_SET);
    2314             :                 const char *pszLine;
    2315          24 :                 while ((pszLine = CPLReadLineL(oOpenInfo.fpL)) != nullptr)
    2316             :                 {
    2317          22 :                     if (STARTS_WITH(pszLine, "--"))
    2318           2 :                         continue;
    2319             : 
    2320          20 :                     if (!SQLCheckLineIsSafe(pszLine))
    2321           0 :                         return false;
    2322             : 
    2323          20 :                     char *pszErrMsg = nullptr;
    2324          20 :                     if (sqlite3_exec(hDB, pszLine, nullptr, nullptr,
    2325          20 :                                      &pszErrMsg) != SQLITE_OK)
    2326             :                     {
    2327           0 :                         if (pszErrMsg)
    2328             :                         {
    2329           0 :                             CPLDebug("SQLITE", "Error %s at line %s", pszErrMsg,
    2330             :                                      pszLine);
    2331             :                         }
    2332             :                     }
    2333          20 :                     sqlite3_free(pszErrMsg);
    2334             :                 }
    2335             :             }
    2336             :         }
    2337         962 :         if (hDB == nullptr)
    2338             : #endif
    2339             :         {
    2340         960 :             if (poOpenInfo->fpL)
    2341             :             {
    2342             :                 // See above comment about -wal locking for the importance of
    2343             :                 // closing that file, prior to calling sqlite3_open()
    2344         808 :                 VSIFCloseL(poOpenInfo->fpL);
    2345         808 :                 poOpenInfo->fpL = nullptr;
    2346             :             }
    2347         960 :             if (!OpenOrCreateDB(GetUpdate() ? SQLITE_OPEN_READWRITE
    2348             :                                             : SQLITE_OPEN_READONLY,
    2349             :                                 true))
    2350             :             {
    2351           1 :                 poOpenInfo->fpL =
    2352           1 :                     VSIFOpenL(poOpenInfo->pszFilename,
    2353           1 :                               poOpenInfo->eAccess == GA_Update ? "rb+" : "rb");
    2354           1 :                 return false;
    2355             :             }
    2356             :         }
    2357             : 
    2358         961 :         InitSpatialite();
    2359             : 
    2360         961 :         PostInitSpatialite();
    2361             : 
    2362             : #ifdef HAVE_RASTERLITE2
    2363             :         InitRasterLite2();
    2364             : #endif
    2365             :     }
    2366             : 
    2367             : #ifdef HAVE_RASTERLITE2
    2368             :     if (STARTS_WITH_CI(pszNewName, "RASTERLITE2:") &&
    2369             :         (nOpenFlags & GDAL_OF_RASTER) != 0)
    2370             :     {
    2371             :         return OpenRasterSubDataset(pszNewName);
    2372             :     }
    2373             : #endif
    2374             : 
    2375             :     /* -------------------------------------------------------------------- */
    2376             :     /*      If we have a GEOMETRY_COLUMNS tables, initialize on the basis   */
    2377             :     /*      of that.                                                        */
    2378             :     /* -------------------------------------------------------------------- */
    2379             :     CPLHashSet *hSet =
    2380        1982 :         CPLHashSetNew(CPLHashSetHashStr, CPLHashSetEqualStr, CPLFree);
    2381             : 
    2382        1982 :     char **papszResult = nullptr;
    2383        1982 :     char *pszErrMsg = nullptr;
    2384        1982 :     int nRowCount = 0;
    2385        1982 :     int nColCount = 0;
    2386        1982 :     int rc = sqlite3_get_table(
    2387             :         hDB,
    2388             :         "SELECT f_table_name, f_geometry_column, geometry_type, "
    2389             :         "coord_dimension, geometry_format, srid"
    2390             :         " FROM geometry_columns "
    2391             :         "LIMIT 10000",
    2392             :         &papszResult, &nRowCount, &nColCount, &pszErrMsg);
    2393             : 
    2394        1982 :     if (rc == SQLITE_OK)
    2395             :     {
    2396         550 :         CPLDebug("SQLITE", "OGR style SQLite DB found !");
    2397             : 
    2398         550 :         m_bHaveGeometryColumns = true;
    2399             : 
    2400         798 :         for (int iRow = 0; bListVectorLayers && iRow < nRowCount; iRow++)
    2401             :         {
    2402         248 :             char **papszRow = papszResult + iRow * 6 + 6;
    2403         248 :             const char *pszTableName = papszRow[0];
    2404         248 :             const char *pszGeomCol = papszRow[1];
    2405             : 
    2406         248 :             if (pszTableName == nullptr || pszGeomCol == nullptr)
    2407           0 :                 continue;
    2408             : 
    2409         496 :             m_aoMapTableToSetOfGeomCols[pszTableName].insert(
    2410         248 :                 CPLString(pszGeomCol).tolower());
    2411             :         }
    2412             : 
    2413         795 :         for (int iRow = 0; bListVectorLayers && iRow < nRowCount; iRow++)
    2414             :         {
    2415         248 :             char **papszRow = papszResult + iRow * 6 + 6;
    2416         248 :             const char *pszTableName = papszRow[0];
    2417             : 
    2418         248 :             if (pszTableName == nullptr)
    2419           0 :                 continue;
    2420             : 
    2421         248 :             if (GDALDataset::GetLayerByName(pszTableName) == nullptr)
    2422             :             {
    2423         237 :                 const bool bRet = OpenTable(pszTableName, true, false,
    2424             :                                             /* bMayEmitError = */ true);
    2425         237 :                 if (!bRet)
    2426             :                 {
    2427           3 :                     CPLDebug("SQLITE", "Failed to open layer %s", pszTableName);
    2428           3 :                     sqlite3_free_table(papszResult);
    2429           3 :                     CPLHashSetDestroy(hSet);
    2430           3 :                     return false;
    2431             :                 }
    2432             :             }
    2433             : 
    2434         245 :             if (bListAllTables)
    2435           2 :                 CPLHashSetInsert(hSet, CPLStrdup(pszTableName));
    2436             :         }
    2437             : 
    2438         547 :         sqlite3_free_table(papszResult);
    2439             : 
    2440             :         /* --------------------------------------------------------------------
    2441             :          */
    2442             :         /*      Detect VirtualOGR layers */
    2443             :         /* --------------------------------------------------------------------
    2444             :          */
    2445         547 :         if (bListVirtualOGRLayers)
    2446             :         {
    2447           2 :             rc = sqlite3_get_table(hDB,
    2448             :                                    "SELECT name, sql FROM sqlite_master "
    2449             :                                    "WHERE sql LIKE 'CREATE VIRTUAL TABLE %' "
    2450             :                                    "LIMIT 10000",
    2451             :                                    &papszResult, &nRowCount, &nColCount,
    2452             :                                    &pszErrMsg);
    2453             : 
    2454           2 :             if (rc == SQLITE_OK)
    2455             :             {
    2456           4 :                 for (int iRow = 0; iRow < nRowCount; iRow++)
    2457             :                 {
    2458           2 :                     char **papszRow = papszResult + iRow * 2 + 2;
    2459           2 :                     const char *pszName = papszRow[0];
    2460           2 :                     const char *pszSQL = papszRow[1];
    2461           2 :                     if (pszName == nullptr || pszSQL == nullptr)
    2462           0 :                         continue;
    2463             : 
    2464           2 :                     if (strstr(pszSQL, "VirtualOGR"))
    2465             :                     {
    2466           2 :                         OpenVirtualTable(pszName, pszSQL);
    2467             : 
    2468           2 :                         if (bListAllTables)
    2469           0 :                             CPLHashSetInsert(hSet, CPLStrdup(pszName));
    2470             :                     }
    2471             :                 }
    2472             :             }
    2473             :             else
    2474             :             {
    2475           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    2476             :                          "Unable to fetch list of tables: %s", pszErrMsg);
    2477           0 :                 sqlite3_free(pszErrMsg);
    2478             :             }
    2479             : 
    2480           2 :             sqlite3_free_table(papszResult);
    2481             :         }
    2482             : 
    2483         547 :         if (bListAllTables)
    2484           1 :             goto all_tables;
    2485             : 
    2486         546 :         CPLHashSetDestroy(hSet);
    2487             : 
    2488         546 :         if (nOpenFlags & GDAL_OF_RASTER)
    2489             :         {
    2490           0 :             bool bRet = OpenRaster();
    2491           0 :             if (!bRet && !(nOpenFlags & GDAL_OF_VECTOR))
    2492           0 :                 return false;
    2493             :         }
    2494             : 
    2495         546 :         return true;
    2496             :     }
    2497             : 
    2498             :     /* -------------------------------------------------------------------- */
    2499             :     /*      Otherwise we can deal with SpatiaLite database.                 */
    2500             :     /* -------------------------------------------------------------------- */
    2501        1432 :     sqlite3_free(pszErrMsg);
    2502        1432 :     rc = sqlite3_get_table(hDB,
    2503             :                            "SELECT sm.name, gc.f_geometry_column, "
    2504             :                            "gc.type, gc.coord_dimension, gc.srid, "
    2505             :                            "gc.spatial_index_enabled FROM geometry_columns gc "
    2506             :                            "JOIN sqlite_master sm ON "
    2507             :                            "LOWER(gc.f_table_name)=LOWER(sm.name) "
    2508             :                            "LIMIT 10000",
    2509             :                            &papszResult, &nRowCount, &nColCount, &pszErrMsg);
    2510        1432 :     if (rc != SQLITE_OK)
    2511             :     {
    2512             :         /* Test with SpatiaLite 4.0 schema */
    2513        1426 :         sqlite3_free(pszErrMsg);
    2514        1426 :         rc = sqlite3_get_table(
    2515             :             hDB,
    2516             :             "SELECT sm.name, gc.f_geometry_column, "
    2517             :             "gc.geometry_type, gc.coord_dimension, gc.srid, "
    2518             :             "gc.spatial_index_enabled FROM geometry_columns gc "
    2519             :             "JOIN sqlite_master sm ON "
    2520             :             "LOWER(gc.f_table_name)=LOWER(sm.name) "
    2521             :             "LIMIT 10000",
    2522             :             &papszResult, &nRowCount, &nColCount, &pszErrMsg);
    2523        1426 :         if (rc == SQLITE_OK)
    2524             :         {
    2525        1191 :             m_bSpatialite4Layout = true;
    2526        1191 :             m_nUndefinedSRID = 0;
    2527             :         }
    2528             :     }
    2529             : 
    2530        1432 :     if (rc == SQLITE_OK)
    2531             :     {
    2532        1197 :         m_bIsSpatiaLiteDB = true;
    2533        1197 :         m_bHaveGeometryColumns = true;
    2534             : 
    2535        1197 :         int iSpatialiteVersion = -1;
    2536             : 
    2537             :         /* Only enables write-mode if linked against SpatiaLite */
    2538        1197 :         if (IsSpatialiteLoaded())
    2539             :         {
    2540        1197 :             iSpatialiteVersion = GetSpatialiteVersionNumber();
    2541             :         }
    2542           0 :         else if (GetUpdate())
    2543             :         {
    2544           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    2545             :                      "SpatiaLite%s DB found, "
    2546             :                      "but updating tables disabled because no linking against "
    2547             :                      "spatialite library !",
    2548           0 :                      (m_bSpatialite4Layout) ? " v4" : "");
    2549           0 :             sqlite3_free_table(papszResult);
    2550           0 :             CPLHashSetDestroy(hSet);
    2551        1197 :             return false;
    2552             :         }
    2553             : 
    2554        2351 :         if (m_bSpatialite4Layout && GetUpdate() && iSpatialiteVersion > 0 &&
    2555        1154 :             iSpatialiteVersion < MakeSpatialiteVersionNumber(4, 0, 0))
    2556             :         {
    2557           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    2558             :                      "SpatiaLite v4 DB found, "
    2559             :                      "but updating tables disabled because runtime spatialite "
    2560             :                      "library is v%d.%d.%d !",
    2561             :                      iSpatialiteVersion / 10000,
    2562           0 :                      (iSpatialiteVersion % 10000) / 100,
    2563             :                      (iSpatialiteVersion % 100));
    2564           0 :             sqlite3_free_table(papszResult);
    2565           0 :             CPLHashSetDestroy(hSet);
    2566           0 :             return false;
    2567             :         }
    2568             :         else
    2569             :         {
    2570        1197 :             CPLDebug("SQLITE", "SpatiaLite%s DB found !",
    2571        1197 :                      (m_bSpatialite4Layout) ? " v4" : "");
    2572             :         }
    2573             : 
    2574             :         // List RasterLite2 coverages, so as to avoid listing corresponding
    2575             :         // technical tables
    2576        1197 :         std::set<CPLString> aoSetTablesToIgnore;
    2577        1197 :         if (m_bSpatialite4Layout)
    2578             :         {
    2579        1191 :             char **papszResults2 = nullptr;
    2580        1191 :             int nRowCount2 = 0, nColCount2 = 0;
    2581        1191 :             rc = sqlite3_get_table(
    2582             :                 hDB,
    2583             :                 "SELECT name FROM sqlite_master WHERE "
    2584             :                 "type = 'table' AND name = 'raster_coverages'",
    2585             :                 &papszResults2, &nRowCount2, &nColCount2, nullptr);
    2586        1191 :             sqlite3_free_table(papszResults2);
    2587        1191 :             if (rc == SQLITE_OK && nRowCount2 == 1)
    2588             :             {
    2589           0 :                 papszResults2 = nullptr;
    2590           0 :                 nRowCount2 = 0;
    2591           0 :                 nColCount2 = 0;
    2592           0 :                 rc = sqlite3_get_table(
    2593             :                     hDB,
    2594             :                     "SELECT coverage_name FROM raster_coverages "
    2595             :                     "LIMIT 10000",
    2596             :                     &papszResults2, &nRowCount2, &nColCount2, nullptr);
    2597           0 :                 if (rc == SQLITE_OK)
    2598             :                 {
    2599           0 :                     for (int i = 0; i < nRowCount2; ++i)
    2600             :                     {
    2601           0 :                         const char *const *papszRow = papszResults2 + i * 1 + 1;
    2602           0 :                         if (papszRow[0] != nullptr)
    2603             :                         {
    2604           0 :                             aoSetTablesToIgnore.insert(CPLString(papszRow[0]) +
    2605           0 :                                                        "_sections");
    2606           0 :                             aoSetTablesToIgnore.insert(CPLString(papszRow[0]) +
    2607           0 :                                                        "_tiles");
    2608             :                         }
    2609             :                     }
    2610             :                 }
    2611           0 :                 sqlite3_free_table(papszResults2);
    2612             :             }
    2613             :         }
    2614             : 
    2615        1539 :         for (int iRow = 0; bListVectorLayers && iRow < nRowCount; iRow++)
    2616             :         {
    2617         342 :             char **papszRow = papszResult + iRow * 6 + 6;
    2618         342 :             const char *pszTableName = papszRow[0];
    2619         342 :             const char *pszGeomCol = papszRow[1];
    2620             : 
    2621         342 :             if (pszTableName == nullptr || pszGeomCol == nullptr)
    2622           0 :                 continue;
    2623         684 :             if (!bListAllTables &&
    2624         342 :                 cpl::contains(aoSetTablesToIgnore, pszTableName))
    2625             :             {
    2626           0 :                 continue;
    2627             :             }
    2628             : 
    2629         684 :             m_aoMapTableToSetOfGeomCols[pszTableName].insert(
    2630         342 :                 CPLString(pszGeomCol).tolower());
    2631             :         }
    2632             : 
    2633        1539 :         for (int iRow = 0; bListVectorLayers && iRow < nRowCount; iRow++)
    2634             :         {
    2635         342 :             char **papszRow = papszResult + iRow * 6 + 6;
    2636         342 :             const char *pszTableName = papszRow[0];
    2637             : 
    2638         342 :             if (pszTableName == nullptr)
    2639           0 :                 continue;
    2640         684 :             if (!bListAllTables &&
    2641         342 :                 cpl::contains(aoSetTablesToIgnore, pszTableName))
    2642             :             {
    2643           0 :                 continue;
    2644             :             }
    2645             : 
    2646         342 :             if (GDALDataset::GetLayerByName(pszTableName) == nullptr)
    2647         335 :                 OpenTable(pszTableName, true, false,
    2648             :                           /* bMayEmitError = */ true);
    2649         342 :             if (bListAllTables)
    2650           0 :                 CPLHashSetInsert(hSet, CPLStrdup(pszTableName));
    2651             :         }
    2652             : 
    2653        1197 :         sqlite3_free_table(papszResult);
    2654        1197 :         papszResult = nullptr;
    2655             : 
    2656             :         /* --------------------------------------------------------------------
    2657             :          */
    2658             :         /*      Detect VirtualShape, VirtualXL and VirtualOGR layers */
    2659             :         /* --------------------------------------------------------------------
    2660             :          */
    2661             :         rc =
    2662        1197 :             sqlite3_get_table(hDB,
    2663             :                               "SELECT name, sql FROM sqlite_master "
    2664             :                               "WHERE sql LIKE 'CREATE VIRTUAL TABLE %' "
    2665             :                               "LIMIT 10000",
    2666             :                               &papszResult, &nRowCount, &nColCount, &pszErrMsg);
    2667             : 
    2668        1197 :         if (rc == SQLITE_OK)
    2669             :         {
    2670        3983 :             for (int iRow = 0; bListVectorLayers && iRow < nRowCount; iRow++)
    2671             :             {
    2672        2786 :                 char **papszRow = papszResult + iRow * 2 + 2;
    2673        2786 :                 const char *pszName = papszRow[0];
    2674        2786 :                 const char *pszSQL = papszRow[1];
    2675        2786 :                 if (pszName == nullptr || pszSQL == nullptr)
    2676           0 :                     continue;
    2677             : 
    2678        5572 :                 if ((IsSpatialiteLoaded() && (strstr(pszSQL, "VirtualShape") ||
    2679        5572 :                                               strstr(pszSQL, "VirtualXL"))) ||
    2680           0 :                     (bListVirtualOGRLayers && strstr(pszSQL, "VirtualOGR")))
    2681             :                 {
    2682           1 :                     OpenVirtualTable(pszName, pszSQL);
    2683             : 
    2684           1 :                     if (bListAllTables)
    2685           0 :                         CPLHashSetInsert(hSet, CPLStrdup(pszName));
    2686             :                 }
    2687             :             }
    2688             :         }
    2689             :         else
    2690             :         {
    2691           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    2692             :                      "Unable to fetch list of tables: %s", pszErrMsg);
    2693           0 :             sqlite3_free(pszErrMsg);
    2694             :         }
    2695             : 
    2696        1197 :         sqlite3_free_table(papszResult);
    2697        1197 :         papszResult = nullptr;
    2698             : 
    2699             :         /* --------------------------------------------------------------------
    2700             :          */
    2701             :         /*      Detect spatial views */
    2702             :         /* --------------------------------------------------------------------
    2703             :          */
    2704             : 
    2705        1197 :         rc = sqlite3_get_table(hDB,
    2706             :                                "SELECT view_name, view_geometry, view_rowid, "
    2707             :                                "f_table_name, f_geometry_column "
    2708             :                                "FROM views_geometry_columns "
    2709             :                                "LIMIT 10000",
    2710             :                                &papszResult, &nRowCount, &nColCount, nullptr);
    2711        1197 :         if (rc == SQLITE_OK)
    2712             :         {
    2713        1200 :             for (int iRow = 0; bListVectorLayers && iRow < nRowCount; iRow++)
    2714             :             {
    2715           5 :                 char **papszRow = papszResult + iRow * 5 + 5;
    2716           5 :                 const char *pszViewName = papszRow[0];
    2717           5 :                 const char *pszViewGeometry = papszRow[1];
    2718           5 :                 const char *pszViewRowid = papszRow[2];
    2719           5 :                 const char *pszTableName = papszRow[3];
    2720           5 :                 const char *pszGeometryColumn = papszRow[4];
    2721             : 
    2722           5 :                 if (pszViewName == nullptr || pszViewGeometry == nullptr ||
    2723           5 :                     pszViewRowid == nullptr || pszTableName == nullptr ||
    2724             :                     pszGeometryColumn == nullptr)
    2725           0 :                     continue;
    2726             : 
    2727           5 :                 OpenView(pszViewName, pszViewGeometry, pszViewRowid,
    2728             :                          pszTableName, pszGeometryColumn);
    2729             : 
    2730           5 :                 if (bListAllTables)
    2731           0 :                     CPLHashSetInsert(hSet, CPLStrdup(pszViewName));
    2732             :             }
    2733        1195 :             sqlite3_free_table(papszResult);
    2734             :         }
    2735             : 
    2736        1197 :         if (bListAllTables)
    2737           0 :             goto all_tables;
    2738             : 
    2739        1197 :         CPLHashSetDestroy(hSet);
    2740             : 
    2741        1197 :         if (nOpenFlags & GDAL_OF_RASTER)
    2742             :         {
    2743           1 :             bool bRet = OpenRaster();
    2744           1 :             if (!bRet && !(nOpenFlags & GDAL_OF_VECTOR))
    2745           0 :                 return false;
    2746             :         }
    2747             : 
    2748        1197 :         return true;
    2749             :     }
    2750             : 
    2751             :     /* -------------------------------------------------------------------- */
    2752             :     /*      Otherwise our final resort is to return all tables and views    */
    2753             :     /*      as non-spatial tables.                                          */
    2754             :     /* -------------------------------------------------------------------- */
    2755         235 :     sqlite3_free(pszErrMsg);
    2756             : 
    2757         236 : all_tables:
    2758         236 :     rc = sqlite3_get_table(hDB,
    2759             :                            "SELECT name, type FROM sqlite_master "
    2760             :                            "WHERE type IN ('table','view') "
    2761             :                            "UNION ALL "
    2762             :                            "SELECT name, type FROM sqlite_temp_master "
    2763             :                            "WHERE type IN ('table','view') "
    2764             :                            "ORDER BY 1 "
    2765             :                            "LIMIT 10000",
    2766             :                            &papszResult, &nRowCount, &nColCount, &pszErrMsg);
    2767             : 
    2768         236 :     if (rc != SQLITE_OK)
    2769             :     {
    2770           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    2771             :                  "Unable to fetch list of tables: %s", pszErrMsg);
    2772           0 :         sqlite3_free(pszErrMsg);
    2773           0 :         CPLHashSetDestroy(hSet);
    2774           0 :         return false;
    2775             :     }
    2776             : 
    2777         600 :     for (int iRow = 0; iRow < nRowCount; iRow++)
    2778             :     {
    2779         364 :         const char *pszTableName = papszResult[2 * (iRow + 1) + 0];
    2780         364 :         const char *pszType = papszResult[2 * (iRow + 1) + 1];
    2781         728 :         if (pszTableName != nullptr &&
    2782         364 :             CPLHashSetLookup(hSet, pszTableName) == nullptr)
    2783             :         {
    2784         362 :             const bool bIsTable =
    2785         362 :                 pszType != nullptr && strcmp(pszType, "table") == 0;
    2786         362 :             OpenTable(pszTableName, bIsTable, false,
    2787             :                       /* bMayEmitError = */ true);
    2788             :         }
    2789             :     }
    2790             : 
    2791         236 :     sqlite3_free_table(papszResult);
    2792         236 :     CPLHashSetDestroy(hSet);
    2793             : 
    2794         236 :     if (nOpenFlags & GDAL_OF_RASTER)
    2795             :     {
    2796           2 :         bool bRet = OpenRaster();
    2797           2 :         if (!bRet && !(nOpenFlags & GDAL_OF_VECTOR))
    2798           0 :             return false;
    2799             :     }
    2800             : 
    2801         236 :     return true;
    2802             : }
    2803             : 
    2804             : /************************************************************************/
    2805             : /*                          OpenVirtualTable()                          */
    2806             : /************************************************************************/
    2807             : 
    2808          13 : bool OGRSQLiteDataSource::OpenVirtualTable(const char *pszName,
    2809             :                                            const char *pszSQL)
    2810             : {
    2811          13 :     int nSRID = m_nUndefinedSRID;
    2812          13 :     const char *pszVirtualShape = strstr(pszSQL, "VirtualShape");
    2813          13 :     if (pszVirtualShape != nullptr)
    2814             :     {
    2815           3 :         const char *pszParenthesis = strchr(pszVirtualShape, '(');
    2816           3 :         if (pszParenthesis)
    2817             :         {
    2818             :             /* CREATE VIRTUAL TABLE table_name VirtualShape(shapename, codepage,
    2819             :              * srid) */
    2820             :             /* Extract 3rd parameter */
    2821             :             char **papszTokens =
    2822           3 :                 CSLTokenizeString2(pszParenthesis + 1, ",", CSLT_HONOURSTRINGS);
    2823           3 :             if (CSLCount(papszTokens) == 3)
    2824             :             {
    2825           3 :                 nSRID = atoi(papszTokens[2]);
    2826             :             }
    2827           3 :             CSLDestroy(papszTokens);
    2828             :         }
    2829             :     }
    2830             : 
    2831          13 :     if (OpenTable(pszName, true, pszVirtualShape != nullptr,
    2832             :                   /* bMayEmitError = */ true))
    2833             :     {
    2834          13 :         OGRSQLiteLayer *poLayer = m_apoLayers.back().get();
    2835          13 :         if (poLayer->GetLayerDefn()->GetGeomFieldCount() == 1)
    2836             :         {
    2837             :             OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
    2838           3 :                 poLayer->myGetLayerDefn()->myGetGeomFieldDefn(0);
    2839           3 :             poGeomFieldDefn->m_eGeomFormat = OSGF_SpatiaLite;
    2840           3 :             if (nSRID > 0)
    2841             :             {
    2842           0 :                 poGeomFieldDefn->m_nSRSId = nSRID;
    2843           0 :                 poGeomFieldDefn->SetSpatialRef(FetchSRS(nSRID));
    2844             :             }
    2845             :         }
    2846             : 
    2847          13 :         OGRFeature *poFeature = poLayer->GetNextFeature();
    2848          13 :         if (poFeature)
    2849             :         {
    2850          12 :             OGRGeometry *poGeom = poFeature->GetGeometryRef();
    2851          12 :             if (poGeom)
    2852             :             {
    2853           6 :                 whileUnsealing(poLayer->GetLayerDefn())
    2854           3 :                     ->SetGeomType(poGeom->getGeometryType());
    2855             :             }
    2856          12 :             delete poFeature;
    2857             :         }
    2858          13 :         poLayer->ResetReading();
    2859          13 :         return true;
    2860             :     }
    2861             : 
    2862           0 :     return false;
    2863             : }
    2864             : 
    2865             : /************************************************************************/
    2866             : /*                             OpenTable()                              */
    2867             : /************************************************************************/
    2868             : 
    2869        1489 : bool OGRSQLiteDataSource::OpenTable(const char *pszTableName, bool bIsTable,
    2870             :                                     bool bIsVirtualShape, bool bMayEmitError)
    2871             : 
    2872             : {
    2873             :     /* -------------------------------------------------------------------- */
    2874             :     /*      Create the layer object.                                        */
    2875             :     /* -------------------------------------------------------------------- */
    2876        2978 :     auto poLayer = std::make_unique<OGRSQLiteTableLayer>(this);
    2877        1489 :     if (poLayer->Initialize(pszTableName, bIsTable, bIsVirtualShape, false,
    2878        1489 :                             bMayEmitError) != CE_None)
    2879             :     {
    2880         296 :         return false;
    2881             :     }
    2882             : 
    2883             :     /* -------------------------------------------------------------------- */
    2884             :     /*      Add layer to data source layer list.                            */
    2885             :     /* -------------------------------------------------------------------- */
    2886        1193 :     m_apoLayers.push_back(std::move(poLayer));
    2887             : 
    2888             :     // Remove in case of error in the schema processing
    2889        1193 :     if (!DealWithOgrSchemaOpenOption(papszOpenOptions))
    2890             :     {
    2891           4 :         m_apoLayers.pop_back();
    2892           4 :         return false;
    2893             :     }
    2894             : 
    2895        1189 :     return true;
    2896             : }
    2897             : 
    2898             : /************************************************************************/
    2899             : /*                              OpenView()                              */
    2900             : /************************************************************************/
    2901             : 
    2902           5 : bool OGRSQLiteDataSource::OpenView(const char *pszViewName,
    2903             :                                    const char *pszViewGeometry,
    2904             :                                    const char *pszViewRowid,
    2905             :                                    const char *pszTableName,
    2906             :                                    const char *pszGeometryColumn)
    2907             : 
    2908             : {
    2909             :     /* -------------------------------------------------------------------- */
    2910             :     /*      Create the layer object.                                        */
    2911             :     /* -------------------------------------------------------------------- */
    2912          10 :     auto poLayer = std::make_unique<OGRSQLiteViewLayer>(this);
    2913             : 
    2914           5 :     if (poLayer->Initialize(pszViewName, pszViewGeometry, pszViewRowid,
    2915           5 :                             pszTableName, pszGeometryColumn) != CE_None)
    2916             :     {
    2917           0 :         return false;
    2918             :     }
    2919             : 
    2920             :     /* -------------------------------------------------------------------- */
    2921             :     /*      Add layer to data source layer list.                            */
    2922             :     /* -------------------------------------------------------------------- */
    2923           5 :     m_apoLayers.push_back(std::move(poLayer));
    2924             : 
    2925           5 :     return true;
    2926             : }
    2927             : 
    2928             : /************************************************************************/
    2929             : /*                           TestCapability()                           */
    2930             : /************************************************************************/
    2931             : 
    2932        1377 : int OGRSQLiteDataSource::TestCapability(const char *pszCap) const
    2933             : 
    2934             : {
    2935        1377 :     if (EQUAL(pszCap, ODsCCreateLayer) || EQUAL(pszCap, ODsCDeleteLayer) ||
    2936        1164 :         EQUAL(pszCap, ODsCCreateGeomFieldAfterCreateLayer) ||
    2937        1056 :         EQUAL(pszCap, ODsCRandomLayerWrite) ||
    2938        1053 :         EQUAL(pszCap, GDsCAddRelationship))
    2939         324 :         return GetUpdate();
    2940        1053 :     else if (EQUAL(pszCap, ODsCCurveGeometries))
    2941         513 :         return !m_bIsSpatiaLiteDB;
    2942         540 :     else if (EQUAL(pszCap, ODsCMeasuredGeometries))
    2943         514 :         return TRUE;
    2944             :     else
    2945          26 :         return OGRSQLiteBaseDataSource::TestCapability(pszCap);
    2946             : }
    2947             : 
    2948             : /************************************************************************/
    2949             : /*                           TestCapability()                           */
    2950             : /************************************************************************/
    2951             : 
    2952         349 : int OGRSQLiteBaseDataSource::TestCapability(const char *pszCap) const
    2953             : {
    2954         349 :     if (EQUAL(pszCap, ODsCTransactions))
    2955         152 :         return true;
    2956         197 :     else if (EQUAL(pszCap, ODsCZGeometries))
    2957           8 :         return true;
    2958             :     else
    2959         189 :         return GDALPamDataset::TestCapability(pszCap);
    2960             : }
    2961             : 
    2962             : /************************************************************************/
    2963             : /*                              GetLayer()                              */
    2964             : /************************************************************************/
    2965             : 
    2966       17321 : const OGRLayer *OGRSQLiteDataSource::GetLayer(int iLayer) const
    2967             : 
    2968             : {
    2969       17321 :     if (iLayer < 0 || iLayer >= static_cast<int>(m_apoLayers.size()))
    2970          10 :         return nullptr;
    2971             :     else
    2972       17311 :         return m_apoLayers[iLayer].get();
    2973             : }
    2974             : 
    2975             : /************************************************************************/
    2976             : /*                           GetLayerByName()                           */
    2977             : /************************************************************************/
    2978             : 
    2979        1446 : OGRLayer *OGRSQLiteDataSource::GetLayerByName(const char *pszLayerName)
    2980             : 
    2981             : {
    2982        1446 :     OGRLayer *poLayer = GDALDataset::GetLayerByName(pszLayerName);
    2983        1446 :     if (poLayer != nullptr)
    2984         904 :         return poLayer;
    2985             : 
    2986         542 :     for (auto &poLayerIter : m_apoInvisibleLayers)
    2987             :     {
    2988           0 :         if (EQUAL(poLayerIter->GetName(), pszLayerName))
    2989           0 :             return poLayerIter.get();
    2990             :     }
    2991             : 
    2992        1084 :     std::string osName(pszLayerName);
    2993         542 :     bool bIsTable = true;
    2994         842 :     for (int i = 0; i < 2; i++)
    2995             :     {
    2996         842 :         char *pszSQL = sqlite3_mprintf("SELECT type FROM sqlite_master "
    2997             :                                        "WHERE type IN ('table', 'view') AND "
    2998             :                                        "lower(name) = lower('%q')",
    2999             :                                        osName.c_str());
    3000         842 :         int nRowCount = 0;
    3001         842 :         char **papszResult = nullptr;
    3002         842 :         CPL_IGNORE_RET_VAL(sqlite3_get_table(hDB, pszSQL, &papszResult,
    3003             :                                              &nRowCount, nullptr, nullptr));
    3004         842 :         if (papszResult && nRowCount == 1 && papszResult[1])
    3005         308 :             bIsTable = strcmp(papszResult[1], "table") == 0;
    3006         842 :         sqlite3_free_table(papszResult);
    3007         842 :         sqlite3_free(pszSQL);
    3008         842 :         if (i == 0 && nRowCount == 0)
    3009             :         {
    3010         531 :             const auto nParenthesis = osName.find('(');
    3011         531 :             if (nParenthesis != std::string::npos && osName.back() == ')')
    3012             :             {
    3013         300 :                 osName.resize(nParenthesis);
    3014         300 :                 continue;
    3015             :             }
    3016             :         }
    3017         542 :         break;
    3018             :     }
    3019             : 
    3020         542 :     if (!OpenTable(pszLayerName, bIsTable, /* bIsVirtualShape = */ false,
    3021             :                    /* bMayEmitError = */ false))
    3022         297 :         return nullptr;
    3023             : 
    3024         245 :     poLayer = m_apoLayers.back().get();
    3025         245 :     CPLErrorReset();
    3026         245 :     CPLPushErrorHandler(CPLQuietErrorHandler);
    3027         245 :     poLayer->GetLayerDefn();
    3028         245 :     CPLPopErrorHandler();
    3029         245 :     if (CPLGetLastErrorType() != 0)
    3030             :     {
    3031         230 :         CPLErrorReset();
    3032         230 :         m_apoLayers.pop_back();
    3033         230 :         return nullptr;
    3034             :     }
    3035             : 
    3036          15 :     return poLayer;
    3037             : }
    3038             : 
    3039             : /************************************************************************/
    3040             : /*                           IsLayerPrivate()                           */
    3041             : /************************************************************************/
    3042             : 
    3043           8 : bool OGRSQLiteDataSource::IsLayerPrivate(int iLayer) const
    3044             : {
    3045           8 :     if (iLayer < 0 || iLayer >= static_cast<int>(m_apoLayers.size()))
    3046           0 :         return false;
    3047             : 
    3048          16 :     const std::string osName(m_apoLayers[iLayer]->GetName());
    3049          16 :     const CPLString osLCName(CPLString(osName).tolower());
    3050         217 :     for (const char *systemTableName : {"spatialindex",
    3051             :                                         "geom_cols_ref_sys",
    3052             :                                         "geometry_columns",
    3053             :                                         "geometry_columns_auth",
    3054             :                                         "views_geometry_column",
    3055             :                                         "virts_geometry_column",
    3056             :                                         "spatial_ref_sys",
    3057             :                                         "spatial_ref_sys_all",
    3058             :                                         "spatial_ref_sys_aux",
    3059             :                                         "sqlite_sequence",
    3060             :                                         "tableprefix_metadata",
    3061             :                                         "tableprefix_rasters",
    3062             :                                         "layer_params",
    3063             :                                         "layer_statistics",
    3064             :                                         "layer_sub_classes",
    3065             :                                         "layer_table_layout",
    3066             :                                         "pattern_bitmaps",
    3067             :                                         "symbol_bitmaps",
    3068             :                                         "project_defs",
    3069             :                                         "raster_pyramids",
    3070             :                                         "sqlite_stat1",
    3071             :                                         "sqlite_stat2",
    3072             :                                         "spatialite_history",
    3073             :                                         "geometry_columns_field_infos",
    3074             :                                         "geometry_columns_statistics",
    3075             :                                         "geometry_columns_time",
    3076             :                                         "sql_statements_log",
    3077             :                                         "vector_layers",
    3078             :                                         "vector_layers_auth",
    3079             :                                         "vector_layers_field_infos",
    3080             :                                         "vector_layers_statistics",
    3081             :                                         "views_geometry_columns_auth",
    3082             :                                         "views_geometry_columns_field_infos",
    3083             :                                         "views_geometry_columns_statistics",
    3084             :                                         "virts_geometry_columns_auth",
    3085             :                                         "virts_geometry_columns_field_infos",
    3086             :                                         "virts_geometry_columns_statistics",
    3087             :                                         "virts_layer_statistics",
    3088             :                                         "views_layer_statistics",
    3089         225 :                                         "elementarygeometries"})
    3090             :     {
    3091         220 :         if (osLCName == systemTableName)
    3092           3 :             return true;
    3093             :     }
    3094             : 
    3095           5 :     return false;
    3096             : }
    3097             : 
    3098             : /************************************************************************/
    3099             : /*                      GetLayerByNameNotVisible()                      */
    3100             : /************************************************************************/
    3101             : 
    3102             : OGRLayer *
    3103           4 : OGRSQLiteDataSource::GetLayerByNameNotVisible(const char *pszLayerName)
    3104             : 
    3105             : {
    3106             :     {
    3107           4 :         OGRLayer *poLayer = GDALDataset::GetLayerByName(pszLayerName);
    3108           4 :         if (poLayer != nullptr)
    3109           2 :             return poLayer;
    3110             :     }
    3111             : 
    3112           2 :     for (auto &poLayerIter : m_apoInvisibleLayers)
    3113             :     {
    3114           0 :         if (EQUAL(poLayerIter->GetName(), pszLayerName))
    3115           0 :             return poLayerIter.get();
    3116             :     }
    3117             : 
    3118             :     /* -------------------------------------------------------------------- */
    3119             :     /*      Create the layer object.                                        */
    3120             :     /* -------------------------------------------------------------------- */
    3121           4 :     auto poLayer = std::make_unique<OGRSQLiteTableLayer>(this);
    3122           2 :     if (poLayer->Initialize(pszLayerName, true, false, false,
    3123           2 :                             /* bMayEmitError = */ true) != CE_None)
    3124             :     {
    3125           0 :         return nullptr;
    3126             :     }
    3127           2 :     CPLErrorReset();
    3128           2 :     CPLPushErrorHandler(CPLQuietErrorHandler);
    3129           2 :     poLayer->GetLayerDefn();
    3130           2 :     CPLPopErrorHandler();
    3131           2 :     if (CPLGetLastErrorType() != 0)
    3132             :     {
    3133           0 :         CPLErrorReset();
    3134           0 :         return nullptr;
    3135             :     }
    3136           2 :     m_apoInvisibleLayers.push_back(std::move(poLayer));
    3137             : 
    3138           2 :     return m_apoInvisibleLayers.back().get();
    3139             : }
    3140             : 
    3141             : /************************************************************************/
    3142             : /*                 GetLayerWithGetSpatialWhereByName()                  */
    3143             : /************************************************************************/
    3144             : 
    3145             : std::pair<OGRLayer *, IOGRSQLiteGetSpatialWhere *>
    3146         590 : OGRSQLiteDataSource::GetLayerWithGetSpatialWhereByName(const char *pszName)
    3147             : {
    3148             :     OGRSQLiteLayer *poRet =
    3149         590 :         cpl::down_cast<OGRSQLiteLayer *>(GetLayerByName(pszName));
    3150         590 :     return std::pair<OGRLayer *, IOGRSQLiteGetSpatialWhere *>(poRet, poRet);
    3151             : }
    3152             : 
    3153             : /************************************************************************/
    3154             : /*                             FlushCache()                             */
    3155             : /************************************************************************/
    3156             : 
    3157        1384 : CPLErr OGRSQLiteDataSource::FlushCache(bool bAtClosing)
    3158             : {
    3159        1384 :     CPLErr eErr = CE_None;
    3160        2994 :     for (auto &poLayer : m_apoLayers)
    3161             :     {
    3162        1610 :         if (poLayer->IsTableLayer())
    3163             :         {
    3164             :             OGRSQLiteTableLayer *poTableLayer =
    3165        1603 :                 cpl::down_cast<OGRSQLiteTableLayer *>(poLayer.get());
    3166        1603 :             if (poTableLayer->RunDeferredCreationIfNecessary() != OGRERR_NONE)
    3167           0 :                 eErr = CE_Failure;
    3168        1603 :             poTableLayer->CreateSpatialIndexIfNecessary();
    3169             :         }
    3170             :     }
    3171        1384 :     if (GDALDataset::FlushCache(bAtClosing) != CE_None)
    3172           0 :         eErr = CE_Failure;
    3173        1384 :     return eErr;
    3174             : }
    3175             : 
    3176             : /************************************************************************/
    3177             : /*                             ExecuteSQL()                             */
    3178             : /************************************************************************/
    3179             : 
    3180             : static const char *const apszFuncsWithSideEffects[] = {
    3181             :     "InitSpatialMetaData",       "AddGeometryColumn",
    3182             :     "RecoverGeometryColumn",     "DiscardGeometryColumn",
    3183             :     "CreateSpatialIndex",        "CreateMbrCache",
    3184             :     "DisableSpatialIndex",       "UpdateLayerStatistics",
    3185             : 
    3186             :     "ogr_datasource_load_layers"};
    3187             : 
    3188        1297 : OGRLayer *OGRSQLiteDataSource::ExecuteSQL(const char *pszSQLCommand,
    3189             :                                           OGRGeometry *poSpatialFilter,
    3190             :                                           const char *pszDialect)
    3191             : 
    3192             : {
    3193        5393 :     for (auto &poLayer : m_apoLayers)
    3194             :     {
    3195        4096 :         if (poLayer->IsTableLayer())
    3196             :         {
    3197             :             OGRSQLiteTableLayer *poTableLayer =
    3198        4092 :                 cpl::down_cast<OGRSQLiteTableLayer *>(poLayer.get());
    3199        4092 :             poTableLayer->RunDeferredCreationIfNecessary();
    3200        4092 :             poTableLayer->CreateSpatialIndexIfNecessary();
    3201             :         }
    3202             :     }
    3203             : 
    3204        1297 :     if (pszDialect != nullptr && EQUAL(pszDialect, "INDIRECT_SQLITE"))
    3205           0 :         return GDALDataset::ExecuteSQL(pszSQLCommand, poSpatialFilter,
    3206           0 :                                        "SQLITE");
    3207        1297 :     else if (pszDialect != nullptr && !EQUAL(pszDialect, "") &&
    3208           2 :              !EQUAL(pszDialect, "NATIVE") && !EQUAL(pszDialect, "SQLITE"))
    3209             : 
    3210           2 :         return GDALDataset::ExecuteSQL(pszSQLCommand, poSpatialFilter,
    3211           2 :                                        pszDialect);
    3212             : 
    3213        1295 :     if (EQUAL(pszSQLCommand, "PRAGMA case_sensitive_like = 0") ||
    3214        1294 :         EQUAL(pszSQLCommand, "PRAGMA case_sensitive_like=0") ||
    3215        1294 :         EQUAL(pszSQLCommand, "PRAGMA case_sensitive_like =0") ||
    3216        1294 :         EQUAL(pszSQLCommand, "PRAGMA case_sensitive_like= 0"))
    3217             :     {
    3218           1 :         if (m_poSQLiteModule)
    3219           1 :             OGR2SQLITE_SetCaseSensitiveLike(m_poSQLiteModule, false);
    3220             :     }
    3221        1294 :     else if (EQUAL(pszSQLCommand, "PRAGMA case_sensitive_like = 1") ||
    3222        1293 :              EQUAL(pszSQLCommand, "PRAGMA case_sensitive_like=1") ||
    3223        1293 :              EQUAL(pszSQLCommand, "PRAGMA case_sensitive_like =1") ||
    3224        1293 :              EQUAL(pszSQLCommand, "PRAGMA case_sensitive_like= 1"))
    3225             :     {
    3226           1 :         if (m_poSQLiteModule)
    3227           1 :             OGR2SQLITE_SetCaseSensitiveLike(m_poSQLiteModule, true);
    3228             :     }
    3229             : 
    3230             :     /* -------------------------------------------------------------------- */
    3231             :     /*      Special case DELLAYER: command.                                 */
    3232             :     /* -------------------------------------------------------------------- */
    3233        1295 :     if (STARTS_WITH_CI(pszSQLCommand, "DELLAYER:"))
    3234             :     {
    3235           1 :         const char *pszLayerName = pszSQLCommand + 9;
    3236             : 
    3237           1 :         while (*pszLayerName == ' ')
    3238           0 :             pszLayerName++;
    3239             : 
    3240           1 :         DeleteLayer(pszLayerName);
    3241           1 :         return nullptr;
    3242             :     }
    3243             : 
    3244             :     /* -------------------------------------------------------------------- */
    3245             :     /*      Special case for SQLITE_HAS_COLUMN_METADATA()                   */
    3246             :     /* -------------------------------------------------------------------- */
    3247        1294 :     if (strcmp(pszSQLCommand, "SQLITE_HAS_COLUMN_METADATA()") == 0)
    3248             :     {
    3249             : #ifdef SQLITE_HAS_COLUMN_METADATA
    3250             :         return new OGRSQLiteSingleFeatureLayer("SQLITE_HAS_COLUMN_METADATA",
    3251           2 :                                                TRUE);
    3252             : #else
    3253             :         return new OGRSQLiteSingleFeatureLayer("SQLITE_HAS_COLUMN_METADATA",
    3254             :                                                FALSE);
    3255             : #endif
    3256             :     }
    3257             : 
    3258             :     /* -------------------------------------------------------------------- */
    3259             :     /*      In case, this is not a SELECT, invalidate cached feature        */
    3260             :     /*      count and extent to be on the safe side.                        */
    3261             :     /* -------------------------------------------------------------------- */
    3262        1292 :     if (EQUAL(pszSQLCommand, "VACUUM"))
    3263             :     {
    3264           1 :         int nNeedRefresh = -1;
    3265           1 :         for (auto &poLayer : m_apoLayers)
    3266             :         {
    3267           1 :             if (poLayer->IsTableLayer())
    3268             :             {
    3269             :                 OGRSQLiteTableLayer *poTableLayer =
    3270           1 :                     cpl::down_cast<OGRSQLiteTableLayer *>(poLayer.get());
    3271           1 :                 if (!(poTableLayer->AreStatisticsValid()) ||
    3272           0 :                     poTableLayer->DoStatisticsNeedToBeFlushed())
    3273             :                 {
    3274           1 :                     nNeedRefresh = FALSE;
    3275           1 :                     break;
    3276             :                 }
    3277           0 :                 else if (nNeedRefresh < 0)
    3278           0 :                     nNeedRefresh = TRUE;
    3279             :             }
    3280             :         }
    3281           1 :         if (nNeedRefresh == TRUE)
    3282             :         {
    3283           0 :             for (auto &poLayer : m_apoLayers)
    3284             :             {
    3285           0 :                 if (poLayer->IsTableLayer())
    3286             :                 {
    3287             :                     OGRSQLiteTableLayer *poTableLayer =
    3288           0 :                         cpl::down_cast<OGRSQLiteTableLayer *>(poLayer.get());
    3289           0 :                     poTableLayer->ForceStatisticsToBeFlushed();
    3290             :                 }
    3291             :             }
    3292             :         }
    3293             :     }
    3294        1291 :     else if (ProcessTransactionSQL(pszSQLCommand))
    3295             :     {
    3296         251 :         return nullptr;
    3297             :     }
    3298        1040 :     else if (!STARTS_WITH_CI(pszSQLCommand, "SELECT ") &&
    3299         147 :              !STARTS_WITH_CI(pszSQLCommand, "CREATE TABLE ") &&
    3300         120 :              !STARTS_WITH_CI(pszSQLCommand, "PRAGMA "))
    3301             :     {
    3302         162 :         for (auto &poLayer : m_apoLayers)
    3303          52 :             poLayer->InvalidateCachedFeatureCountAndExtent();
    3304             :     }
    3305             : 
    3306        1041 :     m_bLastSQLCommandIsUpdateLayerStatistics =
    3307        1041 :         EQUAL(pszSQLCommand, "SELECT UpdateLayerStatistics()");
    3308             : 
    3309             :     /* -------------------------------------------------------------------- */
    3310             :     /*      Prepare statement.                                              */
    3311             :     /* -------------------------------------------------------------------- */
    3312        2082 :     CPLString osSQLCommand = pszSQLCommand;
    3313             : 
    3314             :     /* This will speed-up layer creation */
    3315             :     /* ORDER BY are costly to evaluate and are not necessary to establish */
    3316             :     /* the layer definition. */
    3317        1041 :     bool bUseStatementForGetNextFeature = true;
    3318        1041 :     bool bEmptyLayer = false;
    3319             : 
    3320        4909 :     if (osSQLCommand.ifind("SELECT ") == 0 &&
    3321        1934 :         CPLString(osSQLCommand.substr(1)).ifind("SELECT ") ==
    3322         808 :             std::string::npos &&
    3323         808 :         osSQLCommand.ifind(" UNION ") == std::string::npos &&
    3324        2742 :         osSQLCommand.ifind(" INTERSECT ") == std::string::npos &&
    3325         808 :         osSQLCommand.ifind(" EXCEPT ") == std::string::npos)
    3326             :     {
    3327         808 :         size_t nOrderByPos = osSQLCommand.ifind(" ORDER BY ");
    3328         808 :         if (nOrderByPos != std::string::npos)
    3329             :         {
    3330           8 :             osSQLCommand.resize(nOrderByPos);
    3331           8 :             bUseStatementForGetNextFeature = false;
    3332             :         }
    3333             :     }
    3334             : 
    3335        1041 :     const auto nErrorCount = CPLGetErrorCounter();
    3336        1041 :     sqlite3_stmt *hSQLStmt = prepareSql(GetDB(), osSQLCommand.c_str(),
    3337        1041 :                                         static_cast<int>(osSQLCommand.size()));
    3338             : 
    3339        1041 :     if (!hSQLStmt)
    3340             :     {
    3341          14 :         if (nErrorCount == CPLGetErrorCounter())
    3342             :         {
    3343          11 :             CPLError(CE_Failure, CPLE_AppDefined, "%s",
    3344          22 :                      SQLFormatErrorMsgFailedPrepare(
    3345             :                          GetDB(), "In ExecuteSQL(): sqlite3_prepare_v2(): ",
    3346             :                          osSQLCommand.c_str())
    3347             :                          .c_str());
    3348             :         }
    3349          14 :         return nullptr;
    3350             :     }
    3351             : 
    3352             :     /* -------------------------------------------------------------------- */
    3353             :     /*      Do we get a resultset?                                          */
    3354             :     /* -------------------------------------------------------------------- */
    3355        1027 :     int rc = sqlite3_step(hSQLStmt);
    3356        1027 :     if (rc != SQLITE_ROW)
    3357             :     {
    3358         302 :         if (rc != SQLITE_DONE)
    3359             :         {
    3360          17 :             CPLError(CE_Failure, CPLE_AppDefined,
    3361             :                      "In ExecuteSQL(): sqlite3_step(%s):\n  %s",
    3362             :                      osSQLCommand.c_str(), sqlite3_errmsg(GetDB()));
    3363             : 
    3364          17 :             sqlite3_finalize(hSQLStmt);
    3365          17 :             return nullptr;
    3366             :         }
    3367             : 
    3368         285 :         if (STARTS_WITH_CI(pszSQLCommand, "CREATE "))
    3369             :         {
    3370          56 :             char **papszTokens = CSLTokenizeString(pszSQLCommand);
    3371          56 :             if (CSLCount(papszTokens) >= 4 &&
    3372          66 :                 EQUAL(papszTokens[1], "VIRTUAL") &&
    3373          10 :                 EQUAL(papszTokens[2], "TABLE"))
    3374             :             {
    3375          10 :                 OpenVirtualTable(papszTokens[3], pszSQLCommand);
    3376             :             }
    3377          56 :             CSLDestroy(papszTokens);
    3378             : 
    3379          56 :             sqlite3_finalize(hSQLStmt);
    3380          56 :             return nullptr;
    3381             :         }
    3382             : 
    3383         229 :         if (!STARTS_WITH_CI(pszSQLCommand, "SELECT "))
    3384             :         {
    3385          62 :             sqlite3_finalize(hSQLStmt);
    3386          62 :             return nullptr;
    3387             :         }
    3388             : 
    3389         167 :         bUseStatementForGetNextFeature = false;
    3390         167 :         bEmptyLayer = true;
    3391             :     }
    3392             : 
    3393             :     /* -------------------------------------------------------------------- */
    3394             :     /*      Special case for some functions which must be run               */
    3395             :     /*      only once                                                       */
    3396             :     /* -------------------------------------------------------------------- */
    3397         892 :     if (STARTS_WITH_CI(pszSQLCommand, "SELECT "))
    3398             :     {
    3399        8766 :         for (unsigned int i = 0; i < sizeof(apszFuncsWithSideEffects) /
    3400             :                                          sizeof(apszFuncsWithSideEffects[0]);
    3401             :              i++)
    3402             :         {
    3403        7898 :             if (EQUALN(apszFuncsWithSideEffects[i], pszSQLCommand + 7,
    3404             :                        strlen(apszFuncsWithSideEffects[i])))
    3405             :             {
    3406          20 :                 if (sqlite3_column_count(hSQLStmt) == 1 &&
    3407          10 :                     sqlite3_column_type(hSQLStmt, 0) == SQLITE_INTEGER)
    3408             :                 {
    3409          10 :                     const int ret = sqlite3_column_int(hSQLStmt, 0);
    3410             : 
    3411          10 :                     sqlite3_finalize(hSQLStmt);
    3412             : 
    3413             :                     return new OGRSQLiteSingleFeatureLayer(
    3414          10 :                         apszFuncsWithSideEffects[i], ret);
    3415             :                 }
    3416             :             }
    3417             :         }
    3418             :     }
    3419             : 
    3420             :     /* -------------------------------------------------------------------- */
    3421             :     /*      Create layer.                                                   */
    3422             :     /* -------------------------------------------------------------------- */
    3423             : 
    3424             :     OGRSQLiteSelectLayer *poLayer = new OGRSQLiteSelectLayer(
    3425             :         this, pszSQLCommand, hSQLStmt, bUseStatementForGetNextFeature,
    3426         882 :         bEmptyLayer, true, /*bCanReopenBaseDS=*/true);
    3427             : 
    3428         885 :     if (poSpatialFilter != nullptr &&
    3429           3 :         poLayer->GetLayerDefn()->GetGeomFieldCount() > 0)
    3430           3 :         poLayer->SetSpatialFilter(0, poSpatialFilter);
    3431             : 
    3432         882 :     return poLayer;
    3433             : }
    3434             : 
    3435             : /************************************************************************/
    3436             : /*                          ReleaseResultSet()                          */
    3437             : /************************************************************************/
    3438             : 
    3439         896 : void OGRSQLiteDataSource::ReleaseResultSet(OGRLayer *poLayer)
    3440             : 
    3441             : {
    3442         896 :     delete poLayer;
    3443         896 : }
    3444             : 
    3445             : /************************************************************************/
    3446             : /*                            ICreateLayer()                            */
    3447             : /************************************************************************/
    3448             : 
    3449             : OGRLayer *
    3450         444 : OGRSQLiteDataSource::ICreateLayer(const char *pszLayerNameIn,
    3451             :                                   const OGRGeomFieldDefn *poGeomFieldDefn,
    3452             :                                   CSLConstList papszOptions)
    3453             : 
    3454             : {
    3455             :     /* -------------------------------------------------------------------- */
    3456             :     /*      Verify we are in update mode.                                   */
    3457             :     /* -------------------------------------------------------------------- */
    3458         444 :     char *pszLayerName = nullptr;
    3459         444 :     if (!GetUpdate())
    3460             :     {
    3461           1 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
    3462             :                  "Data source %s opened read-only.\n"
    3463             :                  "New layer %s cannot be created.\n",
    3464             :                  m_pszFilename, pszLayerNameIn);
    3465             : 
    3466           1 :         return nullptr;
    3467             :     }
    3468             : 
    3469         443 :     const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
    3470             :     const auto poSRS =
    3471         443 :         poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
    3472             : 
    3473         443 :     if (m_bIsSpatiaLiteDB && eType != wkbNone)
    3474             :     {
    3475             :         // We need to catch this right now as AddGeometryColumn does not
    3476             :         // return an error
    3477         146 :         OGRwkbGeometryType eFType = wkbFlatten(eType);
    3478         146 :         if (eFType > wkbGeometryCollection)
    3479             :         {
    3480           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    3481             :                      "Cannot create geometry field of type %s",
    3482             :                      OGRToOGCGeomType(eType));
    3483           0 :             return nullptr;
    3484             :         }
    3485             :     }
    3486             : 
    3487        4066 :     for (auto &poLayer : m_apoLayers)
    3488             :     {
    3489        3623 :         if (poLayer->IsTableLayer())
    3490             :         {
    3491             :             OGRSQLiteTableLayer *poTableLayer =
    3492        3623 :                 cpl::down_cast<OGRSQLiteTableLayer *>(poLayer.get());
    3493        3623 :             poTableLayer->RunDeferredCreationIfNecessary();
    3494             :         }
    3495             :     }
    3496             : 
    3497         886 :     CPLString osFIDColumnName;
    3498             :     const char *pszFIDColumnNameIn =
    3499         443 :         CSLFetchNameValueDef(papszOptions, "FID", "OGC_FID");
    3500         443 :     if (CPLFetchBool(papszOptions, "LAUNDER", true))
    3501             :     {
    3502         442 :         char *pszFIDColumnName = LaunderName(pszFIDColumnNameIn);
    3503         442 :         osFIDColumnName = pszFIDColumnName;
    3504         442 :         CPLFree(pszFIDColumnName);
    3505             :     }
    3506             :     else
    3507           1 :         osFIDColumnName = pszFIDColumnNameIn;
    3508             : 
    3509         443 :     if (CPLFetchBool(papszOptions, "LAUNDER", true))
    3510         442 :         pszLayerName = LaunderName(pszLayerNameIn);
    3511             :     else
    3512           1 :         pszLayerName = CPLStrdup(pszLayerNameIn);
    3513             : 
    3514         443 :     const char *pszGeomFormat = CSLFetchNameValue(papszOptions, "FORMAT");
    3515         443 :     if (pszGeomFormat == nullptr)
    3516             :     {
    3517         438 :         if (!m_bIsSpatiaLiteDB)
    3518         287 :             pszGeomFormat = "WKB";
    3519             :         else
    3520         151 :             pszGeomFormat = "SpatiaLite";
    3521             :     }
    3522             : 
    3523         443 :     if (!EQUAL(pszGeomFormat, "WKT") && !EQUAL(pszGeomFormat, "WKB") &&
    3524         153 :         !EQUAL(pszGeomFormat, "SpatiaLite"))
    3525             :     {
    3526           1 :         CPLError(CE_Failure, CPLE_NotSupported,
    3527             :                  "FORMAT=%s not recognised or supported.", pszGeomFormat);
    3528           1 :         CPLFree(pszLayerName);
    3529           1 :         return nullptr;
    3530             :     }
    3531             : 
    3532         884 :     CPLString osGeometryName;
    3533             :     const char *pszGeometryNameIn =
    3534         442 :         CSLFetchNameValue(papszOptions, "GEOMETRY_NAME");
    3535         442 :     if (pszGeometryNameIn == nullptr)
    3536             :     {
    3537             :         osGeometryName =
    3538         402 :             (EQUAL(pszGeomFormat, "WKT")) ? "WKT_GEOMETRY" : "GEOMETRY";
    3539             :     }
    3540             :     else
    3541             :     {
    3542          40 :         if (CPLFetchBool(papszOptions, "LAUNDER", true))
    3543             :         {
    3544          40 :             char *pszGeometryName = LaunderName(pszGeometryNameIn);
    3545          40 :             osGeometryName = pszGeometryName;
    3546          40 :             CPLFree(pszGeometryName);
    3547             :         }
    3548             :         else
    3549           0 :             osGeometryName = pszGeometryNameIn;
    3550             :     }
    3551             : 
    3552         442 :     if (m_bIsSpatiaLiteDB && !EQUAL(pszGeomFormat, "SpatiaLite"))
    3553             :     {
    3554           1 :         CPLError(CE_Failure, CPLE_NotSupported,
    3555             :                  "FORMAT=%s not supported on a SpatiaLite enabled database.",
    3556             :                  pszGeomFormat);
    3557           1 :         CPLFree(pszLayerName);
    3558           1 :         return nullptr;
    3559             :     }
    3560             : 
    3561             :     // Should not happen since a spatialite DB should be opened in
    3562             :     // read-only mode if libspatialite is not loaded.
    3563         441 :     if (m_bIsSpatiaLiteDB && !IsSpatialiteLoaded())
    3564             :     {
    3565           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    3566             :                  "Creating layers on a SpatiaLite enabled database, "
    3567             :                  "without Spatialite extensions loaded, is not supported.");
    3568           0 :         CPLFree(pszLayerName);
    3569           0 :         return nullptr;
    3570             :     }
    3571             : 
    3572             :     /* -------------------------------------------------------------------- */
    3573             :     /*      Do we already have this layer?  If so, should we blow it        */
    3574             :     /*      away?                                                           */
    3575             :     /* -------------------------------------------------------------------- */
    3576        4062 :     for (auto &poLayer : m_apoLayers)
    3577             :     {
    3578        3623 :         if (EQUAL(pszLayerName, poLayer->GetLayerDefn()->GetName()))
    3579             :         {
    3580           3 :             if (CSLFetchNameValue(papszOptions, "OVERWRITE") != nullptr &&
    3581           1 :                 !EQUAL(CSLFetchNameValue(papszOptions, "OVERWRITE"), "NO"))
    3582             :             {
    3583           1 :                 DeleteLayer(pszLayerName);
    3584           1 :                 break;
    3585             :             }
    3586             :             else
    3587             :             {
    3588           1 :                 CPLError(CE_Failure, CPLE_AppDefined,
    3589             :                          "Layer %s already exists, CreateLayer failed.\n"
    3590             :                          "Use the layer creation option OVERWRITE=YES to "
    3591             :                          "replace it.",
    3592             :                          pszLayerName);
    3593           1 :                 CPLFree(pszLayerName);
    3594           1 :                 return nullptr;
    3595             :             }
    3596             :         }
    3597             :     }
    3598             : 
    3599             :     /* -------------------------------------------------------------------- */
    3600             :     /*      Try to get the SRS Id of this spatial reference system,         */
    3601             :     /*      adding to the srs table if needed.                              */
    3602             :     /* -------------------------------------------------------------------- */
    3603         440 :     int nSRSId = m_nUndefinedSRID;
    3604         440 :     const char *pszSRID = CSLFetchNameValue(papszOptions, "SRID");
    3605             : 
    3606         440 :     if (pszSRID != nullptr && pszSRID[0] != '\0')
    3607             :     {
    3608           4 :         nSRSId = atoi(pszSRID);
    3609           4 :         if (nSRSId > 0)
    3610             :         {
    3611           4 :             OGRSpatialReference *poSRSFetched = FetchSRS(nSRSId);
    3612           4 :             if (poSRSFetched == nullptr)
    3613             :             {
    3614           2 :                 CPLError(CE_Warning, CPLE_AppDefined,
    3615             :                          "SRID %d will be used, but no matching SRS is defined "
    3616             :                          "in spatial_ref_sys",
    3617             :                          nSRSId);
    3618             :             }
    3619           4 :         }
    3620             :     }
    3621         436 :     else if (poSRS != nullptr)
    3622         113 :         nSRSId = FetchSRSId(poSRS);
    3623             : 
    3624         440 :     bool bImmediateSpatialIndexCreation = false;
    3625         440 :     bool bDeferredSpatialIndexCreation = false;
    3626             : 
    3627         440 :     const char *pszSI = CSLFetchNameValue(papszOptions, "SPATIAL_INDEX");
    3628         440 :     if (m_bHaveGeometryColumns && eType != wkbNone)
    3629             :     {
    3630           0 :         if (pszSI != nullptr && CPLTestBool(pszSI) &&
    3631         314 :             (m_bIsSpatiaLiteDB || EQUAL(pszGeomFormat, "SpatiaLite")) &&
    3632           0 :             !IsSpatialiteLoaded())
    3633             :         {
    3634           0 :             CPLError(CE_Warning, CPLE_OpenFailed,
    3635             :                      "Cannot create a spatial index when Spatialite extensions "
    3636             :                      "are not loaded.");
    3637             :         }
    3638             : 
    3639             : #ifdef HAVE_SPATIALITE
    3640             :         /* Only if linked against SpatiaLite and the datasource was created as a
    3641             :          * SpatiaLite DB */
    3642         314 :         if (m_bIsSpatiaLiteDB && IsSpatialiteLoaded())
    3643             :         {
    3644         145 :             if (pszSI != nullptr && EQUAL(pszSI, "IMMEDIATE"))
    3645             :             {
    3646           0 :                 bImmediateSpatialIndexCreation = true;
    3647             :             }
    3648         145 :             else if (pszSI == nullptr || CPLTestBool(pszSI))
    3649             :             {
    3650         145 :                 bDeferredSpatialIndexCreation = true;
    3651             :             }
    3652             :         }
    3653             : #endif
    3654             :     }
    3655         126 :     else if (m_bHaveGeometryColumns)
    3656             :     {
    3657             : #ifdef HAVE_SPATIALITE
    3658         117 :         if (m_bIsSpatiaLiteDB && IsSpatialiteLoaded() &&
    3659           0 :             (pszSI == nullptr || CPLTestBool(pszSI)))
    3660           6 :             bDeferredSpatialIndexCreation = true;
    3661             : #endif
    3662             :     }
    3663             : 
    3664             :     /* -------------------------------------------------------------------- */
    3665             :     /*      Create the layer object.                                        */
    3666             :     /* -------------------------------------------------------------------- */
    3667         880 :     auto poLayer = std::make_unique<OGRSQLiteTableLayer>(this);
    3668             : 
    3669         440 :     poLayer->Initialize(pszLayerName, true, false, true,
    3670             :                         /* bMayEmitError = */ false);
    3671         440 :     OGRSpatialReference *poSRSClone = nullptr;
    3672         440 :     if (poSRS)
    3673             :     {
    3674         113 :         poSRSClone = poSRS->Clone();
    3675         113 :         poSRSClone->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    3676             :     }
    3677         440 :     poLayer->SetCreationParameters(osFIDColumnName, eType, pszGeomFormat,
    3678             :                                    osGeometryName, poSRSClone, nSRSId);
    3679         440 :     if (poSRSClone)
    3680         113 :         poSRSClone->Release();
    3681             : 
    3682         440 :     poLayer->InitFeatureCount();
    3683         440 :     poLayer->SetLaunderFlag(CPLFetchBool(papszOptions, "LAUNDER", true));
    3684         440 :     if (CPLFetchBool(papszOptions, "COMPRESS_GEOM", false))
    3685          47 :         poLayer->SetUseCompressGeom(true);
    3686         440 :     if (bImmediateSpatialIndexCreation)
    3687           0 :         poLayer->CreateSpatialIndex(0);
    3688         440 :     else if (bDeferredSpatialIndexCreation)
    3689         151 :         poLayer->SetDeferredSpatialIndexCreation(true);
    3690         440 :     poLayer->SetCompressedColumns(
    3691             :         CSLFetchNameValue(papszOptions, "COMPRESS_COLUMNS"));
    3692         440 :     poLayer->SetStrictFlag(CPLFetchBool(papszOptions, "STRICT", false));
    3693             : 
    3694         440 :     CPLFree(pszLayerName);
    3695             : 
    3696             :     /* -------------------------------------------------------------------- */
    3697             :     /*      Add layer to data source layer list.                            */
    3698             :     /* -------------------------------------------------------------------- */
    3699         440 :     m_apoLayers.push_back(std::move(poLayer));
    3700             : 
    3701         440 :     return m_apoLayers.back().get();
    3702             : }
    3703             : 
    3704             : /************************************************************************/
    3705             : /*                            LaunderName()                             */
    3706             : /************************************************************************/
    3707             : 
    3708        2195 : char *OGRSQLiteDataSource::LaunderName(const char *pszSrcName)
    3709             : 
    3710             : {
    3711        2195 :     char *pszSafeName = CPLStrdup(pszSrcName);
    3712       22504 :     for (int i = 0; pszSafeName[i] != '\0'; i++)
    3713             :     {
    3714       20309 :         pszSafeName[i] = static_cast<char>(
    3715       20309 :             CPLTolower(static_cast<unsigned char>(pszSafeName[i])));
    3716       20309 :         if (pszSafeName[i] == '\'' || pszSafeName[i] == '-' ||
    3717       20309 :             pszSafeName[i] == '#')
    3718           0 :             pszSafeName[i] = '_';
    3719             :     }
    3720             : 
    3721        2195 :     return pszSafeName;
    3722             : }
    3723             : 
    3724             : /************************************************************************/
    3725             : /*                            DeleteLayer()                             */
    3726             : /************************************************************************/
    3727             : 
    3728           2 : void OGRSQLiteDataSource::DeleteLayer(const char *pszLayerName)
    3729             : 
    3730             : {
    3731             :     /* -------------------------------------------------------------------- */
    3732             :     /*      Verify we are in update mode.                                   */
    3733             :     /* -------------------------------------------------------------------- */
    3734           2 :     if (!GetUpdate())
    3735             :     {
    3736           0 :         CPLError(CE_Failure, CPLE_NoWriteAccess,
    3737             :                  "Data source %s opened read-only.\n"
    3738             :                  "Layer %s cannot be deleted.\n",
    3739             :                  m_pszFilename, pszLayerName);
    3740             : 
    3741           0 :         return;
    3742             :     }
    3743             : 
    3744             :     /* -------------------------------------------------------------------- */
    3745             :     /*      Try to find layer.                                              */
    3746             :     /* -------------------------------------------------------------------- */
    3747           2 :     int iLayer = 0;  // Used after for.
    3748             : 
    3749           2 :     for (; iLayer < static_cast<int>(m_apoLayers.size()); iLayer++)
    3750             :     {
    3751           2 :         if (EQUAL(pszLayerName, m_apoLayers[iLayer]->GetLayerDefn()->GetName()))
    3752           2 :             break;
    3753             :     }
    3754             : 
    3755           2 :     if (iLayer == static_cast<int>(m_apoLayers.size()))
    3756             :     {
    3757           0 :         CPLError(
    3758             :             CE_Failure, CPLE_AppDefined,
    3759             :             "Attempt to delete layer '%s', but this layer is not known to OGR.",
    3760             :             pszLayerName);
    3761           0 :         return;
    3762             :     }
    3763             : 
    3764           2 :     DeleteLayer(iLayer);
    3765             : }
    3766             : 
    3767             : /************************************************************************/
    3768             : /*                            DeleteLayer()                             */
    3769             : /************************************************************************/
    3770             : 
    3771          34 : OGRErr OGRSQLiteDataSource::DeleteLayer(int iLayer)
    3772             : {
    3773          34 :     if (iLayer < 0 || iLayer >= static_cast<int>(m_apoLayers.size()))
    3774             :     {
    3775           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    3776             :                  "Layer %d not in legal range of 0 to %d.", iLayer,
    3777           0 :                  static_cast<int>(m_apoLayers.size()) - 1);
    3778           0 :         return OGRERR_FAILURE;
    3779             :     }
    3780             : 
    3781          68 :     CPLString osLayerName = GetLayer(iLayer)->GetName();
    3782          68 :     CPLString osGeometryColumn = GetLayer(iLayer)->GetGeometryColumn();
    3783             : 
    3784             :     /* -------------------------------------------------------------------- */
    3785             :     /*      Blow away our OGR structures related to the layer.  This is     */
    3786             :     /*      pretty dangerous if anything has a reference to this layer!     */
    3787             :     /* -------------------------------------------------------------------- */
    3788          34 :     CPLDebug("OGR_SQLITE", "DeleteLayer(%s)", osLayerName.c_str());
    3789             : 
    3790          34 :     m_apoLayers.erase(m_apoLayers.begin() + iLayer);
    3791             : 
    3792             :     /* -------------------------------------------------------------------- */
    3793             :     /*      Remove from the database.                                       */
    3794             :     /* -------------------------------------------------------------------- */
    3795          68 :     CPLString osEscapedLayerName = SQLEscapeLiteral(osLayerName);
    3796          34 :     const char *pszEscapedLayerName = osEscapedLayerName.c_str();
    3797             :     const char *pszGeometryColumn =
    3798          34 :         osGeometryColumn.size() ? osGeometryColumn.c_str() : nullptr;
    3799             : 
    3800          34 :     if (SQLCommand(hDB, CPLSPrintf("DROP TABLE '%s'", pszEscapedLayerName)) !=
    3801             :         OGRERR_NONE)
    3802             :     {
    3803           0 :         return OGRERR_FAILURE;
    3804             :     }
    3805             : 
    3806             :     /* -------------------------------------------------------------------- */
    3807             :     /*      Drop from geometry_columns table.                               */
    3808             :     /* -------------------------------------------------------------------- */
    3809          34 :     if (m_bHaveGeometryColumns)
    3810             :     {
    3811          34 :         CPLString osCommand;
    3812             : 
    3813             :         osCommand.Printf(
    3814             :             "DELETE FROM geometry_columns WHERE f_table_name = '%s'",
    3815          34 :             pszEscapedLayerName);
    3816             : 
    3817          34 :         if (SQLCommand(hDB, osCommand) != OGRERR_NONE)
    3818             :         {
    3819           0 :             return OGRERR_FAILURE;
    3820             :         }
    3821             : 
    3822             :         /* --------------------------------------------------------------------
    3823             :          */
    3824             :         /*      Drop spatialite spatial index tables */
    3825             :         /* --------------------------------------------------------------------
    3826             :          */
    3827          34 :         if (m_bIsSpatiaLiteDB && pszGeometryColumn)
    3828             :         {
    3829             :             osCommand.Printf("DROP TABLE 'idx_%s_%s'", pszEscapedLayerName,
    3830          15 :                              SQLEscapeLiteral(pszGeometryColumn).c_str());
    3831          15 :             CPL_IGNORE_RET_VAL(
    3832          15 :                 sqlite3_exec(hDB, osCommand, nullptr, nullptr, nullptr));
    3833             : 
    3834             :             osCommand.Printf("DROP TABLE 'idx_%s_%s_node'", pszEscapedLayerName,
    3835          15 :                              SQLEscapeLiteral(pszGeometryColumn).c_str());
    3836          15 :             CPL_IGNORE_RET_VAL(
    3837          15 :                 sqlite3_exec(hDB, osCommand, nullptr, nullptr, nullptr));
    3838             : 
    3839             :             osCommand.Printf("DROP TABLE 'idx_%s_%s_parent'",
    3840             :                              pszEscapedLayerName,
    3841          15 :                              SQLEscapeLiteral(pszGeometryColumn).c_str());
    3842          15 :             CPL_IGNORE_RET_VAL(
    3843          15 :                 sqlite3_exec(hDB, osCommand, nullptr, nullptr, nullptr));
    3844             : 
    3845             :             osCommand.Printf("DROP TABLE 'idx_%s_%s_rowid'",
    3846             :                              pszEscapedLayerName,
    3847          15 :                              SQLEscapeLiteral(pszGeometryColumn).c_str());
    3848          15 :             CPL_IGNORE_RET_VAL(
    3849          15 :                 sqlite3_exec(hDB, osCommand, nullptr, nullptr, nullptr));
    3850             :         }
    3851             :     }
    3852          34 :     return OGRERR_NONE;
    3853             : }
    3854             : 
    3855             : /************************************************************************/
    3856             : /*                         StartTransaction()                           */
    3857             : /*                                                                      */
    3858             : /* Should only be called by user code. Not driver internals.            */
    3859             : /************************************************************************/
    3860             : 
    3861         504 : OGRErr OGRSQLiteBaseDataSource::StartTransaction(CPL_UNUSED int bForce)
    3862             : {
    3863         504 :     if (m_bUserTransactionActive || m_nSoftTransactionLevel != 0)
    3864             :     {
    3865          21 :         CPLError(CE_Failure, CPLE_AppDefined,
    3866             :                  "Transaction already established");
    3867          21 :         return OGRERR_FAILURE;
    3868             :     }
    3869             : 
    3870             :     // Check if we are in a SAVEPOINT transaction
    3871         483 :     if (m_aosSavepoints.size() > 0)
    3872             :     {
    3873           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    3874             :                  "Cannot start a transaction within a SAVEPOINT");
    3875           0 :         return OGRERR_FAILURE;
    3876             :     }
    3877             : 
    3878         483 :     OGRErr eErr = SoftStartTransaction();
    3879         483 :     if (eErr != OGRERR_NONE)
    3880           0 :         return eErr;
    3881             : 
    3882         483 :     m_bUserTransactionActive = true;
    3883         483 :     return OGRERR_NONE;
    3884             : }
    3885             : 
    3886          87 : OGRErr OGRSQLiteDataSource::StartTransaction(int bForce)
    3887             : {
    3888         162 :     for (auto &poLayer : m_apoLayers)
    3889             :     {
    3890          75 :         if (poLayer->IsTableLayer())
    3891             :         {
    3892             :             OGRSQLiteTableLayer *poTableLayer =
    3893          75 :                 cpl::down_cast<OGRSQLiteTableLayer *>(poLayer.get());
    3894          75 :             poTableLayer->RunDeferredCreationIfNecessary();
    3895             :         }
    3896             :     }
    3897             : 
    3898          87 :     return OGRSQLiteBaseDataSource::StartTransaction(bForce);
    3899             : }
    3900             : 
    3901             : /************************************************************************/
    3902             : /*                         CommitTransaction()                          */
    3903             : /*                                                                      */
    3904             : /* Should only be called by user code. Not driver internals.            */
    3905             : /************************************************************************/
    3906             : 
    3907         445 : OGRErr OGRSQLiteBaseDataSource::CommitTransaction()
    3908             : {
    3909         445 :     if (!m_bUserTransactionActive && !m_bImplicitTransactionOpened)
    3910             :     {
    3911           8 :         CPLError(CE_Failure, CPLE_AppDefined, "Transaction not established");
    3912           8 :         return OGRERR_FAILURE;
    3913             :     }
    3914             : 
    3915         437 :     m_bUserTransactionActive = false;
    3916         437 :     m_bImplicitTransactionOpened = false;
    3917         437 :     CPLAssert(m_nSoftTransactionLevel == 1);
    3918         437 :     return SoftCommitTransaction();
    3919             : }
    3920             : 
    3921          73 : OGRErr OGRSQLiteDataSource::CommitTransaction()
    3922             : 
    3923             : {
    3924          73 :     if (m_nSoftTransactionLevel == 1)
    3925             :     {
    3926         244 :         for (auto &poLayer : m_apoLayers)
    3927             :         {
    3928         173 :             if (poLayer->IsTableLayer())
    3929             :             {
    3930             :                 OGRSQLiteTableLayer *poTableLayer =
    3931         173 :                     cpl::down_cast<OGRSQLiteTableLayer *>(poLayer.get());
    3932         173 :                 poTableLayer->RunDeferredCreationIfNecessary();
    3933             :             }
    3934             :         }
    3935             :     }
    3936             : 
    3937          73 :     return OGRSQLiteBaseDataSource::CommitTransaction();
    3938             : }
    3939             : 
    3940             : /************************************************************************/
    3941             : /*                        RollbackTransaction()                         */
    3942             : /*                                                                      */
    3943             : /* Should only be called by user code. Not driver internals.            */
    3944             : /************************************************************************/
    3945             : 
    3946          58 : OGRErr OGRSQLiteBaseDataSource::RollbackTransaction()
    3947             : {
    3948          58 :     if (!m_bUserTransactionActive)
    3949             :     {
    3950           3 :         CPLError(CE_Failure, CPLE_AppDefined, "Transaction not established");
    3951           3 :         return OGRERR_FAILURE;
    3952             :     }
    3953             : 
    3954          55 :     m_bUserTransactionActive = false;
    3955          55 :     CPLAssert(m_nSoftTransactionLevel == 1);
    3956             : 
    3957          55 :     return SoftRollbackTransaction();
    3958             : }
    3959             : 
    3960          21 : OGRErr OGRSQLiteDataSource::RollbackTransaction()
    3961             : 
    3962             : {
    3963          21 :     if (m_nSoftTransactionLevel == 1)
    3964             :     {
    3965          38 :         for (auto &poLayer : m_apoLayers)
    3966             :         {
    3967          19 :             if (poLayer->IsTableLayer())
    3968             :             {
    3969             :                 OGRSQLiteTableLayer *poTableLayer =
    3970          19 :                     cpl::down_cast<OGRSQLiteTableLayer *>(poLayer.get());
    3971          19 :                 poTableLayer->RunDeferredCreationIfNecessary();
    3972             :             }
    3973             :         }
    3974             : 
    3975          38 :         for (auto &poLayer : m_apoLayers)
    3976             :         {
    3977          19 :             poLayer->InvalidateCachedFeatureCountAndExtent();
    3978          19 :             poLayer->ResetReading();
    3979             :         }
    3980             :     }
    3981             : 
    3982          21 :     return OGRSQLiteBaseDataSource::RollbackTransaction();
    3983             : }
    3984             : 
    3985        1737 : bool OGRSQLiteBaseDataSource::IsInTransaction() const
    3986             : {
    3987        1737 :     return m_nSoftTransactionLevel > 0;
    3988             : }
    3989             : 
    3990             : /************************************************************************/
    3991             : /*                        SoftStartTransaction()                        */
    3992             : /*                                                                      */
    3993             : /*      Create a transaction scope.  If we already have a               */
    3994             : /*      transaction active this isn't a real transaction, but just      */
    3995             : /*      an increment to the scope count.                                */
    3996             : /************************************************************************/
    3997             : 
    3998        3783 : OGRErr OGRSQLiteBaseDataSource::SoftStartTransaction()
    3999             : 
    4000             : {
    4001        3783 :     m_nSoftTransactionLevel++;
    4002             : 
    4003        3783 :     OGRErr eErr = OGRERR_NONE;
    4004        3783 :     if (m_nSoftTransactionLevel == 1)
    4005             :     {
    4006        6524 :         for (auto *poLayer : GetLayers())
    4007             :         {
    4008        2933 :             poLayer->PrepareStartTransaction();
    4009             :         }
    4010             : 
    4011        3591 :         eErr = DoTransactionCommand("BEGIN");
    4012             :     }
    4013             : 
    4014             :     // CPLDebug("SQLite", "%p->SoftStartTransaction() : %d",
    4015             :     //          this, nSoftTransactionLevel);
    4016             : 
    4017        3783 :     return eErr;
    4018             : }
    4019             : 
    4020             : /************************************************************************/
    4021             : /*                     SoftCommitTransaction()                          */
    4022             : /*                                                                      */
    4023             : /*      Commit the current transaction if we are at the outer           */
    4024             : /*      scope.                                                          */
    4025             : /************************************************************************/
    4026             : 
    4027        3726 : OGRErr OGRSQLiteBaseDataSource::SoftCommitTransaction()
    4028             : 
    4029             : {
    4030             :     // CPLDebug("SQLite", "%p->SoftCommitTransaction() : %d",
    4031             :     //          this, nSoftTransactionLevel);
    4032             : 
    4033        3726 :     if (m_nSoftTransactionLevel <= 0)
    4034             :     {
    4035           0 :         CPLAssert(false);
    4036             :         return OGRERR_FAILURE;
    4037             :     }
    4038             : 
    4039        3726 :     OGRErr eErr = OGRERR_NONE;
    4040        3726 :     m_nSoftTransactionLevel--;
    4041        3726 :     if (m_nSoftTransactionLevel == 0)
    4042             :     {
    4043        3534 :         eErr = DoTransactionCommand("COMMIT");
    4044             :     }
    4045             : 
    4046        3726 :     return eErr;
    4047             : }
    4048             : 
    4049             : /************************************************************************/
    4050             : /*                  SoftRollbackTransaction()                           */
    4051             : /*                                                                      */
    4052             : /*      Do a rollback of the current transaction if we are at the 1st   */
    4053             : /*      level                                                           */
    4054             : /************************************************************************/
    4055             : 
    4056         126 : OGRErr OGRSQLiteBaseDataSource::SoftRollbackTransaction()
    4057             : 
    4058             : {
    4059             :     // CPLDebug("SQLite", "%p->SoftRollbackTransaction() : %d",
    4060             :     //          this, nSoftTransactionLevel);
    4061             : 
    4062         126 :     while (!m_aosSavepoints.empty())
    4063             :     {
    4064          28 :         if (RollbackToSavepoint(m_aosSavepoints.back()) != OGRERR_NONE)
    4065             :         {
    4066           0 :             return OGRERR_FAILURE;
    4067             :         }
    4068          28 :         m_aosSavepoints.pop_back();
    4069             :     }
    4070             : 
    4071          98 :     if (m_nSoftTransactionLevel <= 0)
    4072             :     {
    4073           0 :         CPLAssert(false);
    4074             :         return OGRERR_FAILURE;
    4075             :     }
    4076             : 
    4077          98 :     OGRErr eErr = OGRERR_NONE;
    4078          98 :     m_nSoftTransactionLevel--;
    4079          98 :     if (m_nSoftTransactionLevel == 0)
    4080             :     {
    4081          98 :         eErr = DoTransactionCommand("ROLLBACK");
    4082          98 :         if (eErr == OGRERR_NONE)
    4083             :         {
    4084         190 :             for (auto *poLayer : GetLayers())
    4085             :             {
    4086          92 :                 poLayer->FinishRollbackTransaction("");
    4087             :             }
    4088             :         }
    4089             :     }
    4090             : 
    4091          98 :     return eErr;
    4092             : }
    4093             : 
    4094         293 : OGRErr OGRSQLiteBaseDataSource::StartSavepoint(const std::string &osName)
    4095             : {
    4096             : 
    4097             :     // A SAVEPOINT implicitly starts a transaction, let's fake one
    4098         293 :     if (!IsInTransaction())
    4099             :     {
    4100          52 :         m_bImplicitTransactionOpened = true;
    4101          52 :         m_nSoftTransactionLevel++;
    4102         104 :         for (auto *poLayer : GetLayers())
    4103             :         {
    4104          52 :             poLayer->PrepareStartTransaction();
    4105             :         }
    4106             :     }
    4107             : 
    4108         293 :     const std::string osCommand = "SAVEPOINT " + osName;
    4109         293 :     const auto eErr = DoTransactionCommand(osCommand.c_str());
    4110             : 
    4111         293 :     if (eErr == OGRERR_NONE)
    4112             :     {
    4113         293 :         m_aosSavepoints.push_back(osName);
    4114             :     }
    4115             : 
    4116         586 :     return eErr;
    4117             : }
    4118             : 
    4119          32 : OGRErr OGRSQLiteBaseDataSource::ReleaseSavepoint(const std::string &osName)
    4120             : {
    4121          64 :     if (m_aosSavepoints.empty() ||
    4122          32 :         std::find(m_aosSavepoints.cbegin(), m_aosSavepoints.cend(), osName) ==
    4123          64 :             m_aosSavepoints.cend())
    4124             :     {
    4125           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Savepoint %s not found",
    4126             :                  osName.c_str());
    4127           0 :         return OGRERR_FAILURE;
    4128             :     }
    4129             : 
    4130          32 :     const std::string osCommand = "RELEASE SAVEPOINT " + osName;
    4131          32 :     const auto eErr = DoTransactionCommand(osCommand.c_str());
    4132             : 
    4133          32 :     if (eErr == OGRERR_NONE)
    4134             :     {
    4135             :         // If the savepoint is the outer most, this is the same as COMMIT
    4136             :         // and the transaction is closed
    4137          48 :         if (m_bImplicitTransactionOpened &&
    4138          16 :             m_aosSavepoints.front().compare(osName) == 0)
    4139             :         {
    4140           4 :             m_bImplicitTransactionOpened = false;
    4141           4 :             m_bUserTransactionActive = false;
    4142           4 :             m_nSoftTransactionLevel = 0;
    4143           4 :             m_aosSavepoints.clear();
    4144             :         }
    4145             :         else
    4146             :         {
    4147             :             // Find all savepoints up to the target one and remove them
    4148          64 :             while (!m_aosSavepoints.empty() && m_aosSavepoints.back() != osName)
    4149             :             {
    4150          36 :                 m_aosSavepoints.pop_back();
    4151             :             }
    4152          28 :             if (!m_aosSavepoints.empty())  // should always be true
    4153             :             {
    4154          28 :                 m_aosSavepoints.pop_back();
    4155             :             }
    4156             :         }
    4157             :     }
    4158          32 :     return eErr;
    4159             : }
    4160             : 
    4161         117 : OGRErr OGRSQLiteBaseDataSource::RollbackToSavepoint(const std::string &osName)
    4162             : {
    4163         226 :     if (m_aosSavepoints.empty() ||
    4164         109 :         std::find(m_aosSavepoints.cbegin(), m_aosSavepoints.cend(), osName) ==
    4165         226 :             m_aosSavepoints.cend())
    4166             :     {
    4167          36 :         CPLError(CE_Failure, CPLE_AppDefined, "Savepoint %s not found",
    4168             :                  osName.c_str());
    4169          36 :         return OGRERR_FAILURE;
    4170             :     }
    4171             : 
    4172          81 :     const std::string osCommand = "ROLLBACK TO SAVEPOINT " + osName;
    4173          81 :     const auto eErr = DoTransactionCommand(osCommand.c_str());
    4174             : 
    4175          81 :     if (eErr == OGRERR_NONE)
    4176             :     {
    4177             : 
    4178             :         // The target savepoint should become the last one in the list
    4179             :         // and does not need to be removed because ROLLBACK TO SAVEPOINT
    4180         137 :         while (!m_aosSavepoints.empty() && m_aosSavepoints.back() != osName)
    4181             :         {
    4182          56 :             m_aosSavepoints.pop_back();
    4183             :         }
    4184             :     }
    4185             : 
    4186         162 :     for (int i = 0; i < GetLayerCount(); i++)
    4187             :     {
    4188          81 :         OGRLayer *poLayer = GetLayer(i);
    4189          81 :         poLayer->FinishRollbackTransaction(osName);
    4190             :     }
    4191             : 
    4192          81 :     return eErr;
    4193             : }
    4194             : 
    4195             : /************************************************************************/
    4196             : /*                       ProcessTransactionSQL()                        */
    4197             : /************************************************************************/
    4198        6985 : bool OGRSQLiteBaseDataSource::ProcessTransactionSQL(
    4199             :     const std::string &osSQLCommand)
    4200             : {
    4201        6985 :     bool retVal = true;
    4202             : 
    4203        6985 :     if (EQUAL(osSQLCommand.c_str(), "BEGIN"))
    4204             :     {
    4205          28 :         SoftStartTransaction();
    4206             :     }
    4207        6957 :     else if (EQUAL(osSQLCommand.c_str(), "COMMIT"))
    4208             :     {
    4209          30 :         SoftCommitTransaction();
    4210             :     }
    4211        6927 :     else if (EQUAL(osSQLCommand.c_str(), "ROLLBACK"))
    4212             :     {
    4213          32 :         SoftRollbackTransaction();
    4214             :     }
    4215        6895 :     else if (STARTS_WITH_CI(osSQLCommand.c_str(), "SAVEPOINT"))
    4216             :     {
    4217         586 :         const CPLStringList aosTokens(SQLTokenize(osSQLCommand.c_str()));
    4218         293 :         if (aosTokens.size() == 2)
    4219             :         {
    4220         293 :             const char *pszSavepointName = aosTokens[1];
    4221         293 :             StartSavepoint(pszSavepointName);
    4222             :         }
    4223             :         else
    4224             :         {
    4225           0 :             retVal = false;
    4226             :         }
    4227             :     }
    4228        6602 :     else if (STARTS_WITH_CI(osSQLCommand.c_str(), "RELEASE"))
    4229             :     {
    4230          64 :         const CPLStringList aosTokens(SQLTokenize(osSQLCommand.c_str()));
    4231          32 :         if (aosTokens.size() == 2)
    4232             :         {
    4233          32 :             const char *pszSavepointName = aosTokens[1];
    4234          32 :             ReleaseSavepoint(pszSavepointName);
    4235             :         }
    4236           0 :         else if (aosTokens.size() == 3 && EQUAL(aosTokens[1], "SAVEPOINT"))
    4237             :         {
    4238           0 :             const char *pszSavepointName = aosTokens[2];
    4239           0 :             ReleaseSavepoint(pszSavepointName);
    4240             :         }
    4241             :         else
    4242             :         {
    4243           0 :             retVal = false;
    4244             :         }
    4245             :     }
    4246        6570 :     else if (STARTS_WITH_CI(osSQLCommand.c_str(), "ROLLBACK"))
    4247             :     {
    4248         178 :         const CPLStringList aosTokens(SQLTokenize(osSQLCommand.c_str()));
    4249          89 :         if (aosTokens.size() == 2)
    4250             :         {
    4251          56 :             if (EQUAL(aosTokens[1], "TRANSACTION"))
    4252             :             {
    4253           0 :                 SoftRollbackTransaction();
    4254             :             }
    4255             :             else
    4256             :             {
    4257          56 :                 const char *pszSavepointName = aosTokens[1];
    4258          56 :                 RollbackToSavepoint(pszSavepointName);
    4259             :             }
    4260             :         }
    4261          33 :         else if (aosTokens.size() > 1)  // Savepoint name is last token
    4262             :         {
    4263          33 :             const char *pszSavepointName = aosTokens[aosTokens.size() - 1];
    4264          33 :             RollbackToSavepoint(pszSavepointName);
    4265             :         }
    4266             :     }
    4267             :     else
    4268             :     {
    4269        6481 :         retVal = false;
    4270             :     }
    4271             : 
    4272        6985 :     return retVal;
    4273             : }
    4274             : 
    4275             : /************************************************************************/
    4276             : /*                        DoTransactionCommand()                        */
    4277             : /************************************************************************/
    4278             : 
    4279        7629 : OGRErr OGRSQLiteBaseDataSource::DoTransactionCommand(const char *pszCommand)
    4280             : 
    4281             : {
    4282             : #ifdef DEBUG
    4283        7629 :     CPLDebug("OGR_SQLITE", "%s Transaction", pszCommand);
    4284             : #endif
    4285             : 
    4286        7629 :     return SQLCommand(hDB, pszCommand);
    4287             : }
    4288             : 
    4289             : /************************************************************************/
    4290             : /*                          GetSRTEXTColName()                          */
    4291             : /************************************************************************/
    4292             : 
    4293          36 : const char *OGRSQLiteDataSource::GetSRTEXTColName()
    4294             : {
    4295          36 :     if (!m_bIsSpatiaLiteDB || m_bSpatialite4Layout)
    4296          28 :         return "srtext";
    4297             : 
    4298             :     // Testing for SRS_WKT column presence.
    4299           8 :     bool bHasSrsWkt = false;
    4300           8 :     char **papszResult = nullptr;
    4301           8 :     int nRowCount = 0;
    4302           8 :     int nColCount = 0;
    4303           8 :     char *pszErrMsg = nullptr;
    4304             :     const int rc =
    4305           8 :         sqlite3_get_table(hDB, "PRAGMA table_info(spatial_ref_sys)",
    4306             :                           &papszResult, &nRowCount, &nColCount, &pszErrMsg);
    4307             : 
    4308           8 :     if (rc == SQLITE_OK)
    4309             :     {
    4310          56 :         for (int iRow = 1; iRow <= nRowCount; iRow++)
    4311             :         {
    4312          48 :             if (EQUAL("srs_wkt", papszResult[(iRow * nColCount) + 1]))
    4313           8 :                 bHasSrsWkt = true;
    4314             :         }
    4315           8 :         sqlite3_free_table(papszResult);
    4316             :     }
    4317             :     else
    4318             :     {
    4319           0 :         sqlite3_free(pszErrMsg);
    4320             :     }
    4321             : 
    4322           8 :     return bHasSrsWkt ? "srs_wkt" : nullptr;
    4323             : }
    4324             : 
    4325             : /************************************************************************/
    4326             : /*                         AddSRIDToCache()                             */
    4327             : /*                                                                      */
    4328             : /*      Note: this will not add a reference on the poSRS object. Make   */
    4329             : /*      sure it is freshly created, or add a reference yourself if not. */
    4330             : /************************************************************************/
    4331             : 
    4332         230 : OGRSpatialReference *OGRSQLiteDataSource::AddSRIDToCache(
    4333             :     int nId,
    4334             :     std::unique_ptr<OGRSpatialReference, OGRSpatialReferenceReleaser> &&poSRS)
    4335             : {
    4336             :     /* -------------------------------------------------------------------- */
    4337             :     /*      Add to the cache.                                               */
    4338             :     /* -------------------------------------------------------------------- */
    4339         230 :     auto oIter = m_oSRSCache.emplace(nId, std::move(poSRS)).first;
    4340         460 :     return oIter->second.get();
    4341             : }
    4342             : 
    4343             : /************************************************************************/
    4344             : /*                             FetchSRSId()                             */
    4345             : /*                                                                      */
    4346             : /*      Fetch the id corresponding to an SRS, and if not found, add     */
    4347             : /*      it to the table.                                                */
    4348             : /************************************************************************/
    4349             : 
    4350         279 : int OGRSQLiteDataSource::FetchSRSId(const OGRSpatialReference *poSRS)
    4351             : 
    4352             : {
    4353         279 :     int nSRSId = m_nUndefinedSRID;
    4354         279 :     if (poSRS == nullptr)
    4355           0 :         return nSRSId;
    4356             : 
    4357             :     /* -------------------------------------------------------------------- */
    4358             :     /*      First, we look through our SRID cache, is it there?             */
    4359             :     /* -------------------------------------------------------------------- */
    4360         486 :     for (const auto &pair : m_oSRSCache)
    4361             :     {
    4362         207 :         if (pair.second.get() == poSRS)
    4363           0 :             return pair.first;
    4364             :     }
    4365         379 :     for (const auto &pair : m_oSRSCache)
    4366             :     {
    4367         207 :         if (pair.second != nullptr && pair.second->IsSame(poSRS))
    4368         107 :             return pair.first;
    4369             :     }
    4370             : 
    4371             :     /* -------------------------------------------------------------------- */
    4372             :     /*      Build a copy since we may call AutoIdentifyEPSG()               */
    4373             :     /* -------------------------------------------------------------------- */
    4374         344 :     OGRSpatialReference oSRS(*poSRS);
    4375         172 :     poSRS = nullptr;
    4376             : 
    4377         172 :     const char *pszAuthorityName = oSRS.GetAuthorityName(nullptr);
    4378         172 :     const char *pszAuthorityCode = nullptr;
    4379             : 
    4380         172 :     if (pszAuthorityName == nullptr || strlen(pszAuthorityName) == 0)
    4381             :     {
    4382             :         /* --------------------------------------------------------------------
    4383             :          */
    4384             :         /*      Try to identify an EPSG code */
    4385             :         /* --------------------------------------------------------------------
    4386             :          */
    4387           3 :         oSRS.AutoIdentifyEPSG();
    4388             : 
    4389           3 :         pszAuthorityName = oSRS.GetAuthorityName(nullptr);
    4390           3 :         if (pszAuthorityName != nullptr && EQUAL(pszAuthorityName, "EPSG"))
    4391             :         {
    4392           0 :             pszAuthorityCode = oSRS.GetAuthorityCode(nullptr);
    4393           0 :             if (pszAuthorityCode != nullptr && strlen(pszAuthorityCode) > 0)
    4394             :             {
    4395             :                 /* Import 'clean' SRS */
    4396           0 :                 oSRS.importFromEPSG(atoi(pszAuthorityCode));
    4397             : 
    4398           0 :                 pszAuthorityName = oSRS.GetAuthorityName(nullptr);
    4399           0 :                 pszAuthorityCode = oSRS.GetAuthorityCode(nullptr);
    4400             :             }
    4401             :         }
    4402             :     }
    4403             : 
    4404             :     /* -------------------------------------------------------------------- */
    4405             :     /*      Check whether the EPSG authority code is already mapped to a    */
    4406             :     /*      SRS ID.                                                         */
    4407             :     /* -------------------------------------------------------------------- */
    4408         172 :     char *pszErrMsg = nullptr;
    4409         344 :     CPLString osCommand;
    4410         172 :     char **papszResult = nullptr;
    4411         172 :     int nRowCount = 0;
    4412         172 :     int nColCount = 0;
    4413             : 
    4414         172 :     if (pszAuthorityName != nullptr && strlen(pszAuthorityName) > 0)
    4415             :     {
    4416         169 :         pszAuthorityCode = oSRS.GetAuthorityCode(nullptr);
    4417             : 
    4418         169 :         if (pszAuthorityCode != nullptr && strlen(pszAuthorityCode) > 0)
    4419             :         {
    4420             :             // XXX: We are using case insensitive comparison for "auth_name"
    4421             :             // values, because there are variety of options exist. By default
    4422             :             // the driver uses 'EPSG' in upper case, but SpatiaLite extension
    4423             :             // uses 'epsg' in lower case.
    4424             :             osCommand.Printf(
    4425             :                 "SELECT srid FROM spatial_ref_sys WHERE "
    4426             :                 "auth_name = '%s' COLLATE NOCASE AND auth_srid = '%s' "
    4427             :                 "LIMIT 2",
    4428         169 :                 pszAuthorityName, pszAuthorityCode);
    4429             : 
    4430         169 :             int rc = sqlite3_get_table(hDB, osCommand, &papszResult, &nRowCount,
    4431             :                                        &nColCount, &pszErrMsg);
    4432         169 :             if (rc != SQLITE_OK)
    4433             :             {
    4434             :                 /* Retry without COLLATE NOCASE which may not be understood by
    4435             :                  * older sqlite3 */
    4436           0 :                 sqlite3_free(pszErrMsg);
    4437             : 
    4438             :                 osCommand.Printf("SELECT srid FROM spatial_ref_sys WHERE "
    4439             :                                  "auth_name = '%s' AND auth_srid = '%s'",
    4440           0 :                                  pszAuthorityName, pszAuthorityCode);
    4441             : 
    4442           0 :                 rc = sqlite3_get_table(hDB, osCommand, &papszResult, &nRowCount,
    4443             :                                        &nColCount, &pszErrMsg);
    4444             : 
    4445             :                 /* Retry in lower case for SpatiaLite */
    4446           0 :                 if (rc != SQLITE_OK)
    4447             :                 {
    4448           0 :                     sqlite3_free(pszErrMsg);
    4449             :                 }
    4450           0 :                 else if (nRowCount == 0 &&
    4451           0 :                          strcmp(pszAuthorityName, "EPSG") == 0)
    4452             :                 {
    4453             :                     /* If it is in upper case, look for lower case */
    4454           0 :                     sqlite3_free_table(papszResult);
    4455             : 
    4456             :                     osCommand.Printf("SELECT srid FROM spatial_ref_sys WHERE "
    4457             :                                      "auth_name = 'epsg' AND auth_srid = '%s' "
    4458             :                                      "LIMIT 2",
    4459           0 :                                      pszAuthorityCode);
    4460             : 
    4461           0 :                     rc = sqlite3_get_table(hDB, osCommand, &papszResult,
    4462             :                                            &nRowCount, &nColCount, &pszErrMsg);
    4463             : 
    4464           0 :                     if (rc != SQLITE_OK)
    4465             :                     {
    4466           0 :                         sqlite3_free(pszErrMsg);
    4467             :                     }
    4468             :                 }
    4469             :             }
    4470             : 
    4471         169 :             if (rc == SQLITE_OK && nRowCount == 1)
    4472             :             {
    4473         144 :                 nSRSId = (papszResult[1] != nullptr) ? atoi(papszResult[1])
    4474             :                                                      : m_nUndefinedSRID;
    4475         144 :                 sqlite3_free_table(papszResult);
    4476             : 
    4477         144 :                 if (nSRSId != m_nUndefinedSRID)
    4478             :                 {
    4479             :                     std::unique_ptr<OGRSpatialReference,
    4480             :                                     OGRSpatialReferenceReleaser>
    4481         144 :                         poCachedSRS;
    4482         144 :                     poCachedSRS.reset(oSRS.Clone());
    4483         144 :                     if (poCachedSRS)
    4484             :                     {
    4485         144 :                         poCachedSRS->SetAxisMappingStrategy(
    4486             :                             OAMS_TRADITIONAL_GIS_ORDER);
    4487             :                     }
    4488         144 :                     AddSRIDToCache(nSRSId, std::move(poCachedSRS));
    4489             :                 }
    4490             : 
    4491         144 :                 return nSRSId;
    4492             :             }
    4493          25 :             sqlite3_free_table(papszResult);
    4494             :         }
    4495             :     }
    4496             : 
    4497             :     /* -------------------------------------------------------------------- */
    4498             :     /*      Search for existing record using either WKT definition or       */
    4499             :     /*      PROJ.4 string (SpatiaLite variant).                             */
    4500             :     /* -------------------------------------------------------------------- */
    4501          56 :     CPLString osWKT;
    4502          56 :     CPLString osProj4;
    4503             : 
    4504             :     /* -------------------------------------------------------------------- */
    4505             :     /*      Translate SRS to WKT.                                           */
    4506             :     /* -------------------------------------------------------------------- */
    4507          28 :     char *pszWKT = nullptr;
    4508             : 
    4509          28 :     if (oSRS.exportToWkt(&pszWKT) != OGRERR_NONE)
    4510             :     {
    4511           0 :         CPLFree(pszWKT);
    4512           0 :         return m_nUndefinedSRID;
    4513             :     }
    4514             : 
    4515          28 :     osWKT = pszWKT;
    4516          28 :     CPLFree(pszWKT);
    4517          28 :     pszWKT = nullptr;
    4518             : 
    4519          28 :     const char *pszSRTEXTColName = GetSRTEXTColName();
    4520             : 
    4521          28 :     if (pszSRTEXTColName != nullptr)
    4522             :     {
    4523             :         /* --------------------------------------------------------------------
    4524             :          */
    4525             :         /*      Try to find based on the WKT match. */
    4526             :         /* --------------------------------------------------------------------
    4527             :          */
    4528             :         osCommand.Printf("SELECT srid FROM spatial_ref_sys WHERE \"%s\" = ? "
    4529             :                          "LIMIT 2",
    4530          28 :                          SQLEscapeName(pszSRTEXTColName).c_str());
    4531             :     }
    4532             : 
    4533             :     /* -------------------------------------------------------------------- */
    4534             :     /*      Handle SpatiaLite (< 4) flavor of the spatial_ref_sys.         */
    4535             :     /* -------------------------------------------------------------------- */
    4536             :     else
    4537             :     {
    4538             :         /* --------------------------------------------------------------------
    4539             :          */
    4540             :         /*      Translate SRS to PROJ.4 string. */
    4541             :         /* --------------------------------------------------------------------
    4542             :          */
    4543           0 :         char *pszProj4 = nullptr;
    4544             : 
    4545           0 :         if (oSRS.exportToProj4(&pszProj4) != OGRERR_NONE)
    4546             :         {
    4547           0 :             CPLFree(pszProj4);
    4548           0 :             return m_nUndefinedSRID;
    4549             :         }
    4550             : 
    4551           0 :         osProj4 = pszProj4;
    4552           0 :         CPLFree(pszProj4);
    4553           0 :         pszProj4 = nullptr;
    4554             : 
    4555             :         /* --------------------------------------------------------------------
    4556             :          */
    4557             :         /*      Try to find based on the PROJ.4 match. */
    4558             :         /* --------------------------------------------------------------------
    4559             :          */
    4560             :         osCommand.Printf(
    4561           0 :             "SELECT srid FROM spatial_ref_sys WHERE proj4text = ? LIMIT 2");
    4562             :     }
    4563             : 
    4564          28 :     sqlite3_stmt *hSelectStmt = prepareSql(hDB, osCommand.c_str());
    4565             : 
    4566          28 :     int rc = SQLITE_OK;
    4567          28 :     if (hSelectStmt)
    4568          56 :         rc = sqlite3_bind_text(hSelectStmt, 1,
    4569          28 :                                (pszSRTEXTColName != nullptr) ? osWKT.c_str()
    4570           0 :                                                              : osProj4.c_str(),
    4571             :                                -1, SQLITE_STATIC);
    4572             :     else
    4573           0 :         rc = SQLITE_ERROR;
    4574             : 
    4575          28 :     if (rc == SQLITE_OK)
    4576          28 :         rc = sqlite3_step(hSelectStmt);
    4577             : 
    4578          28 :     if (rc == SQLITE_ROW)
    4579             :     {
    4580           0 :         if (sqlite3_column_type(hSelectStmt, 0) == SQLITE_INTEGER)
    4581           0 :             nSRSId = sqlite3_column_int(hSelectStmt, 0);
    4582             :         else
    4583           0 :             nSRSId = m_nUndefinedSRID;
    4584             : 
    4585           0 :         sqlite3_finalize(hSelectStmt);
    4586             : 
    4587           0 :         if (nSRSId != m_nUndefinedSRID)
    4588             :         {
    4589             :             std::unique_ptr<OGRSpatialReference, OGRSpatialReferenceReleaser>
    4590           0 :                 poSRSClone;
    4591           0 :             poSRSClone.reset(oSRS.Clone());
    4592           0 :             AddSRIDToCache(nSRSId, std::move(poSRSClone));
    4593             :         }
    4594             : 
    4595           0 :         return nSRSId;
    4596             :     }
    4597             : 
    4598             :     /* -------------------------------------------------------------------- */
    4599             :     /*      If the command actually failed, then the metadata table is      */
    4600             :     /*      likely missing, so we give up.                                  */
    4601             :     /* -------------------------------------------------------------------- */
    4602          28 :     if (rc != SQLITE_DONE && rc != SQLITE_ROW)
    4603             :     {
    4604           0 :         sqlite3_finalize(hSelectStmt);
    4605           0 :         return m_nUndefinedSRID;
    4606             :     }
    4607             : 
    4608          28 :     sqlite3_finalize(hSelectStmt);
    4609             : 
    4610             :     /* -------------------------------------------------------------------- */
    4611             :     /*      Translate SRS to PROJ.4 string (if not already done)            */
    4612             :     /* -------------------------------------------------------------------- */
    4613          28 :     if (osProj4.empty())
    4614             :     {
    4615          28 :         char *pszProj4 = nullptr;
    4616          28 :         if (oSRS.exportToProj4(&pszProj4) == OGRERR_NONE)
    4617             :         {
    4618          26 :             osProj4 = pszProj4;
    4619             :         }
    4620          28 :         CPLFree(pszProj4);
    4621          28 :         pszProj4 = nullptr;
    4622             :     }
    4623             : 
    4624             :     /* -------------------------------------------------------------------- */
    4625             :     /*      If we have an authority code try to assign SRS ID the same      */
    4626             :     /*      as that code.                                                   */
    4627             :     /* -------------------------------------------------------------------- */
    4628          28 :     if (pszAuthorityCode != nullptr && strlen(pszAuthorityCode) > 0)
    4629             :     {
    4630             :         osCommand.Printf("SELECT * FROM spatial_ref_sys WHERE auth_srid='%s' "
    4631             :                          "LIMIT 2",
    4632          25 :                          SQLEscapeLiteral(pszAuthorityCode).c_str());
    4633          25 :         rc = sqlite3_get_table(hDB, osCommand, &papszResult, &nRowCount,
    4634             :                                &nColCount, &pszErrMsg);
    4635             : 
    4636          25 :         if (rc != SQLITE_OK)
    4637             :         {
    4638           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    4639             :                      "exec(SELECT '%s' FROM spatial_ref_sys) failed: %s",
    4640             :                      pszAuthorityCode, pszErrMsg);
    4641           0 :             sqlite3_free(pszErrMsg);
    4642             :         }
    4643             : 
    4644             :         /* --------------------------------------------------------------------
    4645             :          */
    4646             :         /*      If there is no SRS ID with such auth_srid, use it as SRS ID. */
    4647             :         /* --------------------------------------------------------------------
    4648             :          */
    4649          25 :         if (nRowCount < 1)
    4650             :         {
    4651          25 :             nSRSId = atoi(pszAuthorityCode);
    4652             :             /* The authority code might be non numeric, e.g. IGNF:LAMB93 */
    4653             :             /* in which case we might fallback to the fake OGR authority */
    4654             :             /* for spatialite, since its auth_srid is INTEGER */
    4655          25 :             if (nSRSId == 0)
    4656             :             {
    4657           0 :                 nSRSId = m_nUndefinedSRID;
    4658           0 :                 if (m_bIsSpatiaLiteDB)
    4659           0 :                     pszAuthorityName = nullptr;
    4660             :             }
    4661             :         }
    4662          25 :         sqlite3_free_table(papszResult);
    4663             :     }
    4664             : 
    4665             :     /* -------------------------------------------------------------------- */
    4666             :     /*      Otherwise get the current maximum srid in the srs table.        */
    4667             :     /* -------------------------------------------------------------------- */
    4668          28 :     if (nSRSId == m_nUndefinedSRID)
    4669             :     {
    4670             :         rc =
    4671           3 :             sqlite3_get_table(hDB, "SELECT MAX(srid) FROM spatial_ref_sys",
    4672             :                               &papszResult, &nRowCount, &nColCount, &pszErrMsg);
    4673             : 
    4674           3 :         if (rc != SQLITE_OK)
    4675             :         {
    4676           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    4677             :                      "SELECT of the maximum SRS ID failed: %s", pszErrMsg);
    4678           0 :             sqlite3_free(pszErrMsg);
    4679           0 :             return m_nUndefinedSRID;
    4680             :         }
    4681             : 
    4682           3 :         if (nRowCount < 1 || !papszResult[1])
    4683           1 :             nSRSId = 50000;
    4684             :         else
    4685           2 :             nSRSId = atoi(papszResult[1]) + 1;  // Insert as the next SRS ID
    4686           3 :         sqlite3_free_table(papszResult);
    4687             :     }
    4688             : 
    4689             :     /* -------------------------------------------------------------------- */
    4690             :     /*      Try adding the SRS to the SRS table.                            */
    4691             :     /* -------------------------------------------------------------------- */
    4692             : 
    4693          28 :     const char *apszToInsert[] = {nullptr, nullptr, nullptr,
    4694             :                                   nullptr, nullptr, nullptr};
    4695             : 
    4696          28 :     if (!m_bIsSpatiaLiteDB)
    4697             :     {
    4698          25 :         if (pszAuthorityName != nullptr)
    4699             :         {
    4700             :             osCommand.Printf(
    4701             :                 "INSERT INTO spatial_ref_sys (srid,srtext,auth_name,auth_srid) "
    4702             :                 "                     VALUES (%d, ?, ?, ?)",
    4703          24 :                 nSRSId);
    4704          24 :             apszToInsert[0] = osWKT.c_str();
    4705          24 :             apszToInsert[1] = pszAuthorityName;
    4706          24 :             apszToInsert[2] = pszAuthorityCode;
    4707             :         }
    4708             :         else
    4709             :         {
    4710             :             osCommand.Printf("INSERT INTO spatial_ref_sys (srid,srtext) "
    4711             :                              "                     VALUES (%d, ?)",
    4712           1 :                              nSRSId);
    4713           1 :             apszToInsert[0] = osWKT.c_str();
    4714             :         }
    4715             :     }
    4716             :     else
    4717             :     {
    4718           6 :         CPLString osSRTEXTColNameWithCommaBefore;
    4719           3 :         if (pszSRTEXTColName != nullptr)
    4720           3 :             osSRTEXTColNameWithCommaBefore.Printf(", %s", pszSRTEXTColName);
    4721             : 
    4722           3 :         const char *pszProjCS = oSRS.GetAttrValue("PROJCS");
    4723           3 :         if (pszProjCS == nullptr)
    4724           1 :             pszProjCS = oSRS.GetAttrValue("GEOGCS");
    4725             : 
    4726           3 :         if (pszAuthorityName != nullptr)
    4727             :         {
    4728           1 :             if (pszProjCS)
    4729             :             {
    4730             :                 osCommand.Printf(
    4731             :                     "INSERT INTO spatial_ref_sys "
    4732             :                     "(srid, auth_name, auth_srid, ref_sys_name, proj4text%s) "
    4733             :                     "VALUES (%d, ?, ?, ?, ?%s)",
    4734             :                     (pszSRTEXTColName != nullptr)
    4735           1 :                         ? osSRTEXTColNameWithCommaBefore.c_str()
    4736             :                         : "",
    4737           2 :                     nSRSId, (pszSRTEXTColName != nullptr) ? ", ?" : "");
    4738           1 :                 apszToInsert[0] = pszAuthorityName;
    4739           1 :                 apszToInsert[1] = pszAuthorityCode;
    4740           1 :                 apszToInsert[2] = pszProjCS;
    4741           1 :                 apszToInsert[3] = osProj4.c_str();
    4742           1 :                 apszToInsert[4] =
    4743           1 :                     (pszSRTEXTColName != nullptr) ? osWKT.c_str() : nullptr;
    4744             :             }
    4745             :             else
    4746             :             {
    4747             :                 osCommand.Printf("INSERT INTO spatial_ref_sys "
    4748             :                                  "(srid, auth_name, auth_srid, proj4text%s) "
    4749             :                                  "VALUES (%d, ?, ?, ?%s)",
    4750             :                                  (pszSRTEXTColName != nullptr)
    4751           0 :                                      ? osSRTEXTColNameWithCommaBefore.c_str()
    4752             :                                      : "",
    4753             :                                  nSRSId,
    4754           0 :                                  (pszSRTEXTColName != nullptr) ? ", ?" : "");
    4755           0 :                 apszToInsert[0] = pszAuthorityName;
    4756           0 :                 apszToInsert[1] = pszAuthorityCode;
    4757           0 :                 apszToInsert[2] = osProj4.c_str();
    4758           0 :                 apszToInsert[3] =
    4759           0 :                     (pszSRTEXTColName != nullptr) ? osWKT.c_str() : nullptr;
    4760             :             }
    4761             :         }
    4762             :         else
    4763             :         {
    4764             :             /* SpatiaLite spatial_ref_sys auth_name and auth_srid columns must
    4765             :              * be NOT NULL */
    4766             :             /* so insert within a fake OGR "authority" */
    4767           2 :             if (pszProjCS)
    4768             :             {
    4769             :                 osCommand.Printf("INSERT INTO spatial_ref_sys "
    4770             :                                  "(srid, auth_name, auth_srid, ref_sys_name, "
    4771             :                                  "proj4text%s) VALUES (%d, 'OGR', %d, ?, ?%s)",
    4772             :                                  (pszSRTEXTColName != nullptr)
    4773           1 :                                      ? osSRTEXTColNameWithCommaBefore.c_str()
    4774             :                                      : "",
    4775             :                                  nSRSId, nSRSId,
    4776           2 :                                  (pszSRTEXTColName != nullptr) ? ", ?" : "");
    4777           1 :                 apszToInsert[0] = pszProjCS;
    4778           1 :                 apszToInsert[1] = osProj4.c_str();
    4779           1 :                 apszToInsert[2] =
    4780           1 :                     (pszSRTEXTColName != nullptr) ? osWKT.c_str() : nullptr;
    4781             :             }
    4782             :             else
    4783             :             {
    4784             :                 osCommand.Printf("INSERT INTO spatial_ref_sys "
    4785             :                                  "(srid, auth_name, auth_srid, proj4text%s) "
    4786             :                                  "VALUES (%d, 'OGR', %d, ?%s)",
    4787             :                                  (pszSRTEXTColName != nullptr)
    4788           1 :                                      ? osSRTEXTColNameWithCommaBefore.c_str()
    4789             :                                      : "",
    4790             :                                  nSRSId, nSRSId,
    4791           2 :                                  (pszSRTEXTColName != nullptr) ? ", ?" : "");
    4792           1 :                 apszToInsert[0] = osProj4.c_str();
    4793           1 :                 apszToInsert[1] =
    4794           1 :                     (pszSRTEXTColName != nullptr) ? osWKT.c_str() : nullptr;
    4795             :             }
    4796             :         }
    4797             :     }
    4798             : 
    4799          28 :     sqlite3_stmt *hInsertStmt = prepareSql(hDB, osCommand.c_str());
    4800          28 :     if (!hInsertStmt)
    4801           0 :         rc = SQLITE_ERROR;
    4802             : 
    4803         111 :     for (int i = 0; rc == SQLITE_OK && apszToInsert[i] != nullptr; i++)
    4804             :     {
    4805          83 :         rc = sqlite3_bind_text(hInsertStmt, i + 1, apszToInsert[i], -1,
    4806             :                                SQLITE_STATIC);
    4807             :     }
    4808             : 
    4809          28 :     if (rc == SQLITE_OK)
    4810          28 :         rc = sqlite3_step(hInsertStmt);
    4811             : 
    4812          28 :     if (rc != SQLITE_OK && rc != SQLITE_DONE)
    4813             :     {
    4814           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Unable to insert SRID (%s): %s",
    4815             :                  osCommand.c_str(), sqlite3_errmsg(hDB));
    4816             : 
    4817           0 :         sqlite3_finalize(hInsertStmt);
    4818           0 :         return FALSE;
    4819             :     }
    4820             : 
    4821          28 :     sqlite3_finalize(hInsertStmt);
    4822             : 
    4823          28 :     if (nSRSId != m_nUndefinedSRID)
    4824             :     {
    4825             :         std::unique_ptr<OGRSpatialReference, OGRSpatialReferenceReleaser>
    4826          56 :             poCachedSRS(new OGRSpatialReference(std::move(oSRS)));
    4827          28 :         poCachedSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    4828          28 :         AddSRIDToCache(nSRSId, std::move(poCachedSRS));
    4829             :     }
    4830             : 
    4831          28 :     return nSRSId;
    4832             : }
    4833             : 
    4834             : /************************************************************************/
    4835             : /*                              FetchSRS()                              */
    4836             : /*                                                                      */
    4837             : /*      Return a SRS corresponding to a particular id.  Note that       */
    4838             : /*      reference counting should be honoured on the returned           */
    4839             : /*      OGRSpatialReference, as handles may be cached.                  */
    4840             : /************************************************************************/
    4841             : 
    4842         582 : OGRSpatialReference *OGRSQLiteDataSource::FetchSRS(int nId)
    4843             : 
    4844             : {
    4845         582 :     if (nId <= 0)
    4846         365 :         return nullptr;
    4847             : 
    4848             :     /* -------------------------------------------------------------------- */
    4849             :     /*      First, we look through our SRID cache, is it there?             */
    4850             :     /* -------------------------------------------------------------------- */
    4851         217 :     const auto oIter = m_oSRSCache.find(nId);
    4852         217 :     if (oIter != m_oSRSCache.end())
    4853             :     {
    4854         150 :         return oIter->second.get();
    4855             :     }
    4856             : 
    4857             :     /* -------------------------------------------------------------------- */
    4858             :     /*      Try looking up in spatial_ref_sys table.                        */
    4859             :     /* -------------------------------------------------------------------- */
    4860          67 :     char *pszErrMsg = nullptr;
    4861          67 :     char **papszResult = nullptr;
    4862          67 :     int nRowCount = 0;
    4863          67 :     int nColCount = 0;
    4864          67 :     std::unique_ptr<OGRSpatialReference, OGRSpatialReferenceReleaser> poSRS;
    4865             : 
    4866         134 :     CPLString osCommand;
    4867          67 :     osCommand.Printf("SELECT srtext FROM spatial_ref_sys WHERE srid = %d "
    4868             :                      "LIMIT 2",
    4869          67 :                      nId);
    4870          67 :     int rc = sqlite3_get_table(hDB, osCommand, &papszResult, &nRowCount,
    4871             :                                &nColCount, &pszErrMsg);
    4872             : 
    4873          67 :     if (rc == SQLITE_OK)
    4874             :     {
    4875          59 :         if (nRowCount < 1)
    4876             :         {
    4877           2 :             sqlite3_free_table(papszResult);
    4878           2 :             return nullptr;
    4879             :         }
    4880             : 
    4881          57 :         char **papszRow = papszResult + nColCount;
    4882          57 :         if (papszRow[0] != nullptr)
    4883             :         {
    4884         114 :             CPLString osWKT = papszRow[0];
    4885             : 
    4886             :             /* --------------------------------------------------------------------
    4887             :              */
    4888             :             /*      Translate into a spatial reference. */
    4889             :             /* --------------------------------------------------------------------
    4890             :              */
    4891          57 :             poSRS.reset(new OGRSpatialReference());
    4892          57 :             poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    4893          57 :             if (poSRS->importFromWkt(osWKT.c_str()) != OGRERR_NONE)
    4894             :             {
    4895           0 :                 poSRS.reset();
    4896             :             }
    4897             :         }
    4898             : 
    4899          57 :         sqlite3_free_table(papszResult);
    4900             :     }
    4901             : 
    4902             :     /* -------------------------------------------------------------------- */
    4903             :     /*      Next try SpatiaLite flavor. SpatiaLite uses PROJ.4 strings     */
    4904             :     /*      in 'proj4text' column instead of WKT in 'srtext'. Note: recent  */
    4905             :     /*      versions of spatialite have a srs_wkt column too                */
    4906             :     /* -------------------------------------------------------------------- */
    4907             :     else
    4908             :     {
    4909           8 :         sqlite3_free(pszErrMsg);
    4910           8 :         pszErrMsg = nullptr;
    4911             : 
    4912           8 :         const char *pszSRTEXTColName = GetSRTEXTColName();
    4913           8 :         CPLString osSRTEXTColNameWithCommaBefore;
    4914           8 :         if (pszSRTEXTColName != nullptr)
    4915           8 :             osSRTEXTColNameWithCommaBefore.Printf(", %s", pszSRTEXTColName);
    4916             : 
    4917           8 :         osCommand.Printf(
    4918             :             "SELECT proj4text, auth_name, auth_srid%s FROM spatial_ref_sys "
    4919             :             "WHERE srid = %d LIMIT 2",
    4920             :             (pszSRTEXTColName != nullptr)
    4921           8 :                 ? osSRTEXTColNameWithCommaBefore.c_str()
    4922             :                 : "",
    4923          16 :             nId);
    4924           8 :         rc = sqlite3_get_table(hDB, osCommand, &papszResult, &nRowCount,
    4925             :                                &nColCount, &pszErrMsg);
    4926           8 :         if (rc == SQLITE_OK)
    4927             :         {
    4928           8 :             if (nRowCount < 1)
    4929             :             {
    4930           7 :                 sqlite3_free_table(papszResult);
    4931           7 :                 return nullptr;
    4932             :             }
    4933             : 
    4934             :             /* --------------------------------------------------------------------
    4935             :              */
    4936             :             /*      Translate into a spatial reference. */
    4937             :             /* --------------------------------------------------------------------
    4938             :              */
    4939           1 :             char **papszRow = papszResult + nColCount;
    4940             : 
    4941           1 :             const char *pszProj4Text = papszRow[0];
    4942           1 :             const char *pszAuthName = papszRow[1];
    4943           1 :             int nAuthSRID = (papszRow[2] != nullptr) ? atoi(papszRow[2]) : 0;
    4944           1 :             const char *pszWKT =
    4945           1 :                 (pszSRTEXTColName != nullptr) ? papszRow[3] : nullptr;
    4946             : 
    4947           1 :             poSRS.reset(new OGRSpatialReference());
    4948           1 :             poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    4949             : 
    4950             :             /* Try first from EPSG code */
    4951           2 :             if (pszAuthName != nullptr && EQUAL(pszAuthName, "EPSG") &&
    4952           1 :                 poSRS->importFromEPSG(nAuthSRID) == OGRERR_NONE)
    4953             :             {
    4954             :                 /* Do nothing */
    4955             :             }
    4956             :             /* Then from WKT string */
    4957           0 :             else if (pszWKT != nullptr &&
    4958           0 :                      poSRS->importFromWkt(pszWKT) == OGRERR_NONE)
    4959             :             {
    4960             :                 /* Do nothing */
    4961             :             }
    4962             :             /* Finally from Proj4 string */
    4963           0 :             else if (pszProj4Text != nullptr &&
    4964           0 :                      poSRS->importFromProj4(pszProj4Text) == OGRERR_NONE)
    4965             :             {
    4966             :                 /* Do nothing */
    4967             :             }
    4968             :             else
    4969             :             {
    4970           0 :                 poSRS.reset();
    4971             :             }
    4972             : 
    4973           1 :             sqlite3_free_table(papszResult);
    4974             :         }
    4975             : 
    4976             :         /* --------------------------------------------------------------------
    4977             :          */
    4978             :         /*      No success, report an error. */
    4979             :         /* --------------------------------------------------------------------
    4980             :          */
    4981             :         else
    4982             :         {
    4983           0 :             CPLError(CE_Failure, CPLE_AppDefined, "%s: %s", osCommand.c_str(),
    4984             :                      pszErrMsg);
    4985           0 :             sqlite3_free(pszErrMsg);
    4986           0 :             return nullptr;
    4987             :         }
    4988             :     }
    4989             : 
    4990          58 :     if (poSRS)
    4991          58 :         poSRS->StripTOWGS84IfKnownDatumAndAllowed();
    4992             : 
    4993             :     /* -------------------------------------------------------------------- */
    4994             :     /*      Add to the cache.                                               */
    4995             :     /* -------------------------------------------------------------------- */
    4996          58 :     return AddSRIDToCache(nId, std::move(poSRS));
    4997             : }
    4998             : 
    4999             : /************************************************************************/
    5000             : /*                              SetName()                               */
    5001             : /************************************************************************/
    5002             : 
    5003           0 : void OGRSQLiteDataSource::SetName(const char *pszNameIn)
    5004             : {
    5005           0 :     CPLFree(m_pszFilename);
    5006           0 :     m_pszFilename = CPLStrdup(pszNameIn);
    5007           0 : }
    5008             : 
    5009             : /************************************************************************/
    5010             : /*                         GetEnvelopeFromSQL()                         */
    5011             : /************************************************************************/
    5012             : 
    5013             : const OGREnvelope *
    5014          16 : OGRSQLiteBaseDataSource::GetEnvelopeFromSQL(const CPLString &osSQL)
    5015             : {
    5016          16 :     const auto oIter = oMapSQLEnvelope.find(osSQL);
    5017          16 :     if (oIter != oMapSQLEnvelope.end())
    5018           5 :         return &oIter->second;
    5019             :     else
    5020          11 :         return nullptr;
    5021             : }
    5022             : 
    5023             : /************************************************************************/
    5024             : /*                         SetEnvelopeForSQL()                          */
    5025             : /************************************************************************/
    5026             : 
    5027           5 : void OGRSQLiteBaseDataSource::SetEnvelopeForSQL(const CPLString &osSQL,
    5028             :                                                 const OGREnvelope &oEnvelope)
    5029             : {
    5030           5 :     oMapSQLEnvelope[osSQL] = oEnvelope;
    5031           5 : }
    5032             : 
    5033             : /************************************************************************/
    5034             : /*                         SetQueryLoggerFunc()                         */
    5035             : /************************************************************************/
    5036             : 
    5037           1 : bool OGRSQLiteBaseDataSource::SetQueryLoggerFunc(
    5038             :     GDALQueryLoggerFunc pfnQueryLoggerFuncIn, void *poQueryLoggerArgIn)
    5039             : {
    5040           1 :     pfnQueryLoggerFunc = pfnQueryLoggerFuncIn;
    5041           1 :     poQueryLoggerArg = poQueryLoggerArgIn;
    5042             : 
    5043           1 :     if (pfnQueryLoggerFunc)
    5044             :     {
    5045           1 :         sqlite3_trace_v2(
    5046             :             hDB, SQLITE_TRACE_PROFILE,
    5047          17 :             [](unsigned int /* traceProfile */, void *context,
    5048             :                void *preparedStatement, void *executionTime) -> int
    5049             :             {
    5050          17 :                 if (context)
    5051             :                 {
    5052          17 :                     char *pzsSql{sqlite3_expanded_sql(
    5053             :                         reinterpret_cast<sqlite3_stmt *>(preparedStatement))};
    5054          17 :                     if (pzsSql)
    5055             :                     {
    5056          34 :                         const std::string sql{pzsSql};
    5057          17 :                         sqlite3_free(pzsSql);
    5058          17 :                         const uint64_t executionTimeMilliSeconds{
    5059             :                             static_cast<uint64_t>(
    5060          17 :                                 *reinterpret_cast<uint64_t *>(executionTime) /
    5061             :                                 1e+6)};
    5062          17 :                         OGRSQLiteBaseDataSource *source{
    5063             :                             reinterpret_cast<OGRSQLiteBaseDataSource *>(
    5064             :                                 context)};
    5065          17 :                         if (source->pfnQueryLoggerFunc)
    5066             :                         {
    5067          17 :                             source->pfnQueryLoggerFunc(
    5068             :                                 sql.c_str(), nullptr, -1,
    5069             :                                 executionTimeMilliSeconds,
    5070             :                                 source->poQueryLoggerArg);
    5071             :                         }
    5072             :                     }
    5073             :                 }
    5074          17 :                 return 0;
    5075             :             },
    5076             :             reinterpret_cast<void *>(this));
    5077           1 :         return true;
    5078             :     }
    5079           0 :     return false;
    5080             : }
    5081             : 
    5082             : /************************************************************************/
    5083             : /*                              AbortSQL()                              */
    5084             : /************************************************************************/
    5085             : 
    5086           2 : OGRErr OGRSQLiteBaseDataSource::AbortSQL()
    5087             : {
    5088           2 :     sqlite3_interrupt(hDB);
    5089           2 :     return OGRERR_NONE;
    5090             : }

Generated by: LCOV version 1.14