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

Generated by: LCOV version 1.14