Coverage Report

Created: 2026-08-14 09:29

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