LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/sqlite - ogrsqlitedatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1699 2050 82.9 %
Date: 2025-02-20 10:14:44 Functions: 77 79 97.5 %

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

Generated by: LCOV version 1.14