LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/sqlite - ogrsqlitedatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1543 1879 82.1 %
Date: 2024-11-25 13:07:18 Functions: 71 73 97.3 %

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

Generated by: LCOV version 1.14