LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/sqlite - ogrsqlitedatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1557 1898 82.0 %
Date: 2024-04-29 15:10:10 Functions: 70 72 97.2 %

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

Generated by: LCOV version 1.14