• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 15885686134

25 Jun 2025 07:44PM UTC coverage: 71.084%. Remained the same
15885686134

push

github

rouault
gdal_priv.h: fix C++11 compatibility

573814 of 807237 relevant lines covered (71.08%)

250621.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.53
/ogr/ogrsf_frmts/sqlite/ogrsqlitedatasource.cpp
1
/******************************************************************************
2
 *
3
 * Project:  OpenGIS Simple Features Reference Implementation
4
 * Purpose:  Implements OGRSQLiteDataSource class.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 *
9
 * Contributor: Alessandro Furieri, a.furieri@lqt.it
10
 * Portions of this module properly supporting SpatiaLite Table/Geom creation
11
 * Developed for Faunalia ( http://www.faunalia.it) with funding from
12
 * Regione Toscana - Settore SISTEMA INFORMATIVO TERRITORIALE ED AMBIENTALE
13
 *
14
 ******************************************************************************
15
 * Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.com>
16
 * Copyright (c) 2009-2013, Even Rouault <even dot rouault at spatialys.com>
17
 *
18
 * SPDX-License-Identifier: MIT
19
 ****************************************************************************/
20

21
#include "cpl_port.h"
22
#include "ogr_sqlite.h"
23
#include "ogrsqlitevirtualogr.h"
24
#include "ogrsqliteutility.h"
25
#include "ogrsqlitevfs.h"
26

27
#include <cctype>
28
#include <cstddef>
29
#include <cstdio>
30
#include <cstdlib>
31
#include <cstring>
32
#include <sys/stat.h>
33
#include <map>
34
#include <mutex>
35
#include <set>
36
#include <sstream>
37
#include <string>
38
#include <utility>
39
#include <vector>
40

41
#include "cpl_conv.h"
42
#include "cpl_error.h"
43
#include "cpl_hash_set.h"
44
#include "cpl_multiproc.h"
45
#include "cpl_string.h"
46
#include "cpl_vsi.h"
47
#include "gdal.h"
48
#include "gdal_pam.h"
49
#include "gdal_priv.h"
50
#include "ogr_core.h"
51
#include "ogr_feature.h"
52
#include "ogr_geometry.h"
53
#include "ogr_spatialref.h"
54
#include "ogr_schema_override.h"
55
#include "ogrsf_frmts.h"
56
#include "sqlite3.h"
57

58
#include "proj.h"
59
#include "ogr_proj_p.h"
60

61
#ifdef __clang__
62
#pragma clang diagnostic push
63
#pragma clang diagnostic ignored "-Wunknown-pragmas"
64
#pragma clang diagnostic ignored "-Wdocumentation"
65
#pragma clang diagnostic ignored "-Wdocumentation-unknown-command"
66
#endif
67

68
#if defined(HAVE_SPATIALITE) && !defined(SPATIALITE_DLOPEN)
69
#include "spatialite.h"
70
#endif
71

72
#ifdef __clang__
73
#pragma clang diagnostic pop
74
#endif
75

76
#undef SQLITE_STATIC
77
#define SQLITE_STATIC (static_cast<sqlite3_destructor_type>(nullptr))
78

79
// Keep in sync prototype of those 2 functions between gdalopeninfo.cpp,
80
// ogrsqlitedatasource.cpp and ogrgeopackagedatasource.cpp
81
void GDALOpenInfoDeclareFileNotToOpen(const char *pszFilename,
82
                                      const GByte *pabyHeader,
83
                                      int nHeaderBytes);
84
void GDALOpenInfoUnDeclareFileNotToOpen(const char *pszFilename);
85

86
#ifdef HAVE_SPATIALITE
87

88
#ifdef SPATIALITE_DLOPEN
89
static CPLMutex *hMutexLoadSpatialiteSymbols = nullptr;
90
static void *(*pfn_spatialite_alloc_connection)(void) = nullptr;
91
static void (*pfn_spatialite_shutdown)(void) = nullptr;
92
static void (*pfn_spatialite_init_ex)(sqlite3 *, const void *, int) = nullptr;
93
static void (*pfn_spatialite_cleanup_ex)(const void *) = nullptr;
94
static const char *(*pfn_spatialite_version)(void) = nullptr;
95
#else
96
static void *(*pfn_spatialite_alloc_connection)(void) =
97
    spatialite_alloc_connection;
98
static void (*pfn_spatialite_shutdown)(void) = spatialite_shutdown;
99
static void (*pfn_spatialite_init_ex)(sqlite3 *, const void *,
100
                                      int) = spatialite_init_ex;
101
static void (*pfn_spatialite_cleanup_ex)(const void *) = spatialite_cleanup_ex;
102
static const char *(*pfn_spatialite_version)(void) = spatialite_version;
103
#endif
104

105
#ifndef SPATIALITE_SONAME
106
#define SPATIALITE_SONAME "libspatialite.so"
107
#endif
108

109
#ifdef SPATIALITE_DLOPEN
110
static bool OGRSQLiteLoadSpatialiteSymbols()
111
{
112
    static bool bInitializationDone = false;
113
    CPLMutexHolderD(&hMutexLoadSpatialiteSymbols);
114
    if (bInitializationDone)
115
        return pfn_spatialite_alloc_connection != nullptr;
116
    bInitializationDone = true;
117

118
    const char *pszLibName =
119
        CPLGetConfigOption("SPATIALITESO", SPATIALITE_SONAME);
120
    CPLPushErrorHandler(CPLQuietErrorHandler);
121

122
    /* coverity[tainted_string] */
123
    pfn_spatialite_alloc_connection = (void *(*)(void))CPLGetSymbol(
124
        pszLibName, "spatialite_alloc_connection");
125
    CPLPopErrorHandler();
126

127
    if (pfn_spatialite_alloc_connection == nullptr)
128
    {
129
        CPLDebug("SQLITE", "Cannot find %s in %s",
130
                 "spatialite_alloc_connection", pszLibName);
131
        return false;
132
    }
133

134
    pfn_spatialite_shutdown =
135
        (void (*)(void))CPLGetSymbol(pszLibName, "spatialite_shutdown");
136
    pfn_spatialite_init_ex =
137
        (void (*)(sqlite3 *, const void *, int))CPLGetSymbol(
138
            pszLibName, "spatialite_init_ex");
139
    pfn_spatialite_cleanup_ex = (void (*)(const void *))CPLGetSymbol(
140
        pszLibName, "spatialite_cleanup_ex");
141
    pfn_spatialite_version =
142
        (const char *(*)(void))CPLGetSymbol(pszLibName, "spatialite_version");
143
    if (pfn_spatialite_shutdown == nullptr ||
144
        pfn_spatialite_init_ex == nullptr ||
145
        pfn_spatialite_cleanup_ex == nullptr ||
146
        pfn_spatialite_version == nullptr)
147
    {
148
        pfn_spatialite_shutdown = nullptr;
149
        pfn_spatialite_init_ex = nullptr;
150
        pfn_spatialite_cleanup_ex = nullptr;
151
        pfn_spatialite_version = nullptr;
152
        return false;
153
    }
154
    return true;
155
}
156
#endif
157

158
/************************************************************************/
159
/*                          InitSpatialite()                            */
160
/************************************************************************/
161

162
bool OGRSQLiteBaseDataSource::InitSpatialite()
3,670✔
163
{
164
    if (hSpatialiteCtxt == nullptr &&
6,906✔
165
        CPLTestBool(CPLGetConfigOption("SPATIALITE_LOAD", "TRUE")))
3,236✔
166
    {
167
#ifdef SPATIALITE_DLOPEN
168
        if (!OGRSQLiteLoadSpatialiteSymbols())
169
            return false;
170
#endif
171
        CPLAssert(hSpatialiteCtxt == nullptr);
3,236✔
172
        hSpatialiteCtxt = pfn_spatialite_alloc_connection();
3,236✔
173
        if (hSpatialiteCtxt != nullptr)
3,236✔
174
        {
175
            pfn_spatialite_init_ex(hDB, hSpatialiteCtxt,
6,472✔
176
                                   CPLTestBool(CPLGetConfigOption(
3,236✔
177
                                       "SPATIALITE_INIT_VERBOSE", "FALSE")));
178
        }
179
    }
180
    return hSpatialiteCtxt != nullptr;
3,670✔
181
}
182

183
/************************************************************************/
184
/*                         FinishSpatialite()                           */
185
/************************************************************************/
186

187
void OGRSQLiteBaseDataSource::FinishSpatialite()
3,714✔
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);
7,428✔
194

195
    if (hSpatialiteCtxt != nullptr)
3,714✔
196
    {
197
        pfn_spatialite_cleanup_ex(hSpatialiteCtxt);
3,236✔
198
        hSpatialiteCtxt = nullptr;
3,236✔
199
    }
200
}
3,714✔
201

202
/************************************************************************/
203
/*                          IsSpatialiteLoaded()                        */
204
/************************************************************************/
205

206
bool OGRSQLiteBaseDataSource::IsSpatialiteLoaded()
11,461✔
207
{
208
    return hSpatialiteCtxt != nullptr;
11,461✔
209
}
210

211
#else
212

213
bool OGRSQLiteBaseDataSource::InitSpatialite()
214
{
215
    return false;
216
}
217

218
void OGRSQLiteBaseDataSource::FinishSpatialite()
219
{
220
}
221

222
bool OGRSQLiteBaseDataSource::IsSpatialiteLoaded()
223
{
224
    return false;
225
}
226

227
#endif
228

229
/************************************************************************/
230
/*                          OGRSQLiteDriverUnload()                     */
231
/************************************************************************/
232

233
void OGRSQLiteDriverUnload(GDALDriver *)
1,113✔
234
{
235
#ifdef HAVE_SPATIALITE
236
    if (pfn_spatialite_shutdown != nullptr)
1,113✔
237
        pfn_spatialite_shutdown();
1,113✔
238
#ifdef SPATIALITE_DLOPEN
239
    if (hMutexLoadSpatialiteSymbols != nullptr)
240
    {
241
        CPLDestroyMutex(hMutexLoadSpatialiteSymbols);
242
        hMutexLoadSpatialiteSymbols = nullptr;
243
    }
244
#endif
245
#endif
246
}
1,113✔
247

248
/************************************************************************/
249
/*                      DealWithOgrSchemaOpenOption()                   */
250
/************************************************************************/
251
bool OGRSQLiteBaseDataSource::DealWithOgrSchemaOpenOption(
1,170✔
252
    CSLConstList papszOpenOptionsIn)
253
{
254
    std::string osFieldsSchemaOverrideParam =
255
        CSLFetchNameValueDef(papszOpenOptionsIn, "OGR_SCHEMA", "");
2,340✔
256

257
    if (!osFieldsSchemaOverrideParam.empty())
1,170✔
258
    {
259
        if (GetUpdate())
9✔
260
        {
261
            CPLError(CE_Failure, CPLE_NotSupported,
×
262
                     "OGR_SCHEMA open option is not supported in update mode.");
263
            return false;
4✔
264
        }
265

266
        OGRSchemaOverride osSchemaOverride;
9✔
267
        if (!osSchemaOverride.LoadFromJSON(osFieldsSchemaOverrideParam) ||
17✔
268
            !osSchemaOverride.IsValid())
8✔
269
        {
270
            return false;
1✔
271
        }
272

273
        const auto &oLayerOverrides = osSchemaOverride.GetLayerOverrides();
8✔
274
        for (const auto &oLayer : oLayerOverrides)
13✔
275
        {
276
            const auto &oLayerName = oLayer.first;
8✔
277
            const auto &oLayerFieldOverride = oLayer.second;
8✔
278
            const bool bIsFullOverride{oLayerFieldOverride.IsFullOverride()};
8✔
279
            auto oFieldOverrides = oLayerFieldOverride.GetFieldOverrides();
8✔
280
            std::vector<OGRFieldDefn *> aoFields;
8✔
281

282
            CPLDebug("SQLite", "Applying schema override for layer %s",
8✔
283
                     oLayerName.c_str());
284

285
            // Fail if the layer name does not exist
286
            auto poLayer = GetLayerByName(oLayerName.c_str());
8✔
287
            if (poLayer == nullptr)
8✔
288
            {
289
                CPLError(CE_Failure, CPLE_AppDefined,
1✔
290
                         "Layer %s not found in SQLite DB", oLayerName.c_str());
291
                return false;
1✔
292
            }
293

294
            // Patch field definitions
295
            auto poLayerDefn = poLayer->GetLayerDefn();
7✔
296
            for (int i = 0; i < poLayerDefn->GetFieldCount(); i++)
55✔
297
            {
298
                auto poFieldDefn = poLayerDefn->GetFieldDefn(i);
48✔
299
                auto oFieldOverride =
300
                    oFieldOverrides.find(poFieldDefn->GetNameRef());
48✔
301
                if (oFieldOverride != oFieldOverrides.cend())
48✔
302
                {
303
                    if (oFieldOverride->second.GetFieldType().has_value())
8✔
304
                        whileUnsealing(poFieldDefn)
8✔
305
                            ->SetType(
4✔
306
                                oFieldOverride->second.GetFieldType().value());
4✔
307
                    if (oFieldOverride->second.GetFieldWidth().has_value())
8✔
308
                        whileUnsealing(poFieldDefn)
2✔
309
                            ->SetWidth(
1✔
310
                                oFieldOverride->second.GetFieldWidth().value());
1✔
311
                    if (oFieldOverride->second.GetFieldPrecision().has_value())
8✔
312
                        whileUnsealing(poFieldDefn)
2✔
313
                            ->SetPrecision(
1✔
314
                                oFieldOverride->second.GetFieldPrecision()
2✔
315
                                    .value());
1✔
316
                    if (oFieldOverride->second.GetFieldSubType().has_value())
8✔
317
                        whileUnsealing(poFieldDefn)
8✔
318
                            ->SetSubType(
4✔
319
                                oFieldOverride->second.GetFieldSubType()
8✔
320
                                    .value());
4✔
321
                    if (oFieldOverride->second.GetFieldName().has_value())
8✔
322
                        whileUnsealing(poFieldDefn)
×
323
                            ->SetName(oFieldOverride->second.GetFieldName()
×
324
                                          .value()
×
325
                                          .c_str());
326

327
                    if (bIsFullOverride)
8✔
328
                    {
329
                        aoFields.push_back(poFieldDefn);
2✔
330
                    }
331
                    oFieldOverrides.erase(oFieldOverride);
8✔
332
                }
333
            }
334

335
            // Error if any field override is not found
336
            if (!oFieldOverrides.empty())
7✔
337
            {
338
                CPLError(CE_Failure, CPLE_AppDefined,
4✔
339
                         "Field %s not found in layer %s",
340
                         oFieldOverrides.cbegin()->first.c_str(),
2✔
341
                         oLayerName.c_str());
342
                return false;
2✔
343
            }
344

345
            // Remove fields not in the override
346
            if (bIsFullOverride)
5✔
347
            {
348
                for (int i = poLayerDefn->GetFieldCount() - 1; i >= 0; i--)
9✔
349
                {
350
                    auto poFieldDefn = poLayerDefn->GetFieldDefn(i);
8✔
351
                    if (std::find(aoFields.begin(), aoFields.end(),
8✔
352
                                  poFieldDefn) == aoFields.end())
8✔
353
                    {
354
                        whileUnsealing(poLayerDefn)->DeleteFieldDefn(i);
6✔
355
                    }
356
                }
357
            }
358
        }
359
    }
360
    return true;
1,166✔
361
}
362

363
/************************************************************************/
364
/*                     GetSpatialiteVersionNumber()                     */
365
/************************************************************************/
366

367
int OGRSQLiteBaseDataSource::GetSpatialiteVersionNumber()
5,316✔
368
{
369
    int v = 0;
5,316✔
370
#ifdef HAVE_SPATIALITE
371
    if (IsSpatialiteLoaded())
5,316✔
372
    {
373
        const CPLStringList aosTokens(
374
            CSLTokenizeString2(pfn_spatialite_version(), ".", 0));
10,516✔
375
        if (aosTokens.size() >= 2)
5,258✔
376
        {
377
            v = MakeSpatialiteVersionNumber(
5,258✔
378
                atoi(aosTokens[0]), atoi(aosTokens[1]),
379
                aosTokens.size() == 3 ? atoi(aosTokens[2]) : 0);
5,258✔
380
        }
381
    }
382
#endif
383
    return v;
5,316✔
384
}
385

386
/************************************************************************/
387
/*                          AddRelationship()                           */
388
/************************************************************************/
389

390
bool OGRSQLiteDataSource::AddRelationship(
15✔
391
    std::unique_ptr<GDALRelationship> &&relationship,
392
    std::string &failureReason)
393
{
394
    if (!GetUpdate())
15✔
395
    {
396
        CPLError(CE_Failure, CPLE_NotSupported,
×
397
                 "AddRelationship() not supported on read-only dataset");
398
        return false;
×
399
    }
400

401
    if (!ValidateRelationship(relationship.get(), failureReason))
15✔
402
    {
403
        return false;
12✔
404
    }
405

406
    const std::string &osLeftTableName = relationship->GetLeftTableName();
3✔
407
    const std::string &osRightTableName = relationship->GetRightTableName();
3✔
408
    const auto &aosLeftTableFields = relationship->GetLeftTableFields();
3✔
409
    const auto &aosRightTableFields = relationship->GetRightTableFields();
3✔
410

411
    bool bBaseKeyIsUnique = false;
3✔
412
    {
413
        const std::set<std::string> uniqueBaseFieldsUC =
414
            SQLGetUniqueFieldUCConstraints(GetDB(), osLeftTableName.c_str());
6✔
415
        if (cpl::contains(uniqueBaseFieldsUC,
9✔
416
                          CPLString(aosLeftTableFields[0]).toupper()))
3✔
417
        {
418
            bBaseKeyIsUnique = true;
2✔
419
        }
420
    }
421
    if (!bBaseKeyIsUnique)
3✔
422
    {
423
        failureReason = "Base table field must be a primary key field or have "
424
                        "a unique constraint set";
1✔
425
        return false;
1✔
426
    }
427

428
    OGRSQLiteTableLayer *poRightTable = dynamic_cast<OGRSQLiteTableLayer *>(
×
429
        GetLayerByName(osRightTableName.c_str()));
2✔
430
    if (!poRightTable)
2✔
431
    {
432
        failureReason = ("Right table " + osRightTableName +
×
433
                         " is not an existing layer in the dataset")
434
                            .c_str();
×
435
        return false;
×
436
    }
437

438
    char *pszForeignKeySQL = nullptr;
2✔
439
    if (relationship->GetType() == GDALRelationshipType::GRT_ASSOCIATION)
2✔
440
    {
441
        pszForeignKeySQL = sqlite3_mprintf(
2✔
442
            "FOREIGN KEY(\"%w\") REFERENCES \"%w\"(\"%w\") DEFERRABLE "
443
            "INITIALLY DEFERRED",
444
            aosRightTableFields[0].c_str(), osLeftTableName.c_str(),
1✔
445
            aosLeftTableFields[0].c_str());
1✔
446
    }
447
    else
448
    {
449
        pszForeignKeySQL = sqlite3_mprintf(
2✔
450
            "FOREIGN KEY(\"%w\") REFERENCES \"%w\"(\"%w\") ON DELETE CASCADE "
451
            "ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED",
452
            aosRightTableFields[0].c_str(), osLeftTableName.c_str(),
1✔
453
            aosLeftTableFields[0].c_str());
1✔
454
    }
455

456
    int eErr = poRightTable->AddForeignKeysToTable(pszForeignKeySQL);
2✔
457
    sqlite3_free(pszForeignKeySQL);
2✔
458
    if (eErr != OGRERR_NONE)
2✔
459
    {
460
        failureReason = "Could not add foreign keys to table";
×
461
        return false;
×
462
    }
463

464
    char *pszSQL = sqlite3_mprintf(
2✔
465
        "CREATE INDEX \"idx_%qw_related_id\" ON \"%w\" (\"%w\");",
466
        osRightTableName.c_str(), osRightTableName.c_str(),
467
        aosRightTableFields[0].c_str());
2✔
468
    eErr = SQLCommand(hDB, pszSQL);
2✔
469
    sqlite3_free(pszSQL);
2✔
470
    if (eErr != OGRERR_NONE)
2✔
471
    {
472
        failureReason = ("Could not create index for " + osRightTableName +
×
473
                         " " + aosRightTableFields[0])
×
474
                            .c_str();
×
475
        return false;
×
476
    }
477

478
    m_bHasPopulatedRelationships = false;
2✔
479
    m_osMapRelationships.clear();
2✔
480
    return true;
2✔
481
}
482

483
/************************************************************************/
484
/*                       ValidateRelationship()                         */
485
/************************************************************************/
486

487
bool OGRSQLiteDataSource::ValidateRelationship(
15✔
488
    const GDALRelationship *poRelationship, std::string &failureReason)
489
{
490

491
    if (poRelationship->GetCardinality() !=
15✔
492
        GDALRelationshipCardinality::GRC_ONE_TO_MANY)
493
    {
494
        failureReason = "Only one to many relationships are supported for "
495
                        "SQLITE datasources";
3✔
496
        return false;
3✔
497
    }
498

499
    if (poRelationship->GetType() != GDALRelationshipType::GRT_COMPOSITE &&
23✔
500
        poRelationship->GetType() != GDALRelationshipType::GRT_ASSOCIATION)
11✔
501
    {
502
        failureReason = "Only association and composite relationship types are "
503
                        "supported for SQLITE datasources";
×
504
        return false;
×
505
    }
506

507
    const std::string &osLeftTableName = poRelationship->GetLeftTableName();
12✔
508
    OGRLayer *poLeftTable = GetLayerByName(osLeftTableName.c_str());
12✔
509
    if (!poLeftTable)
12✔
510
    {
511
        failureReason = ("Left table " + osLeftTableName +
2✔
512
                         " is not an existing layer in the dataset")
513
                            .c_str();
1✔
514
        return false;
1✔
515
    }
516
    const std::string &osRightTableName = poRelationship->GetRightTableName();
11✔
517
    OGRLayer *poRightTable = GetLayerByName(osRightTableName.c_str());
11✔
518
    if (!poRightTable)
11✔
519
    {
520
        failureReason = ("Right table " + osRightTableName +
2✔
521
                         " is not an existing layer in the dataset")
522
                            .c_str();
1✔
523
        return false;
1✔
524
    }
525

526
    const auto &aosLeftTableFields = poRelationship->GetLeftTableFields();
10✔
527
    if (aosLeftTableFields.empty())
10✔
528
    {
529
        failureReason = "No left table fields were specified";
1✔
530
        return false;
1✔
531
    }
532
    else if (aosLeftTableFields.size() > 1)
9✔
533
    {
534
        failureReason = "Only a single left table field is permitted for the "
535
                        "SQLITE relationships";
1✔
536
        return false;
1✔
537
    }
538
    else
539
    {
540
        // validate left field exists
541
        if (poLeftTable->GetLayerDefn()->GetFieldIndex(
16✔
542
                aosLeftTableFields[0].c_str()) < 0 &&
17✔
543
            !EQUAL(poLeftTable->GetFIDColumn(), aosLeftTableFields[0].c_str()))
1✔
544
        {
545
            failureReason = ("Left table field " + aosLeftTableFields[0] +
2✔
546
                             " does not exist in " + osLeftTableName)
2✔
547
                                .c_str();
1✔
548
            return false;
1✔
549
        }
550
    }
551

552
    const auto &aosRightTableFields = poRelationship->GetRightTableFields();
7✔
553
    if (aosRightTableFields.empty())
7✔
554
    {
555
        failureReason = "No right table fields were specified";
1✔
556
        return false;
1✔
557
    }
558
    else if (aosRightTableFields.size() > 1)
6✔
559
    {
560
        failureReason = "Only a single right table field is permitted for the "
561
                        "SQLITE relationships";
1✔
562
        return false;
1✔
563
    }
564
    else
565
    {
566
        // validate right field exists
567
        if (poRightTable->GetLayerDefn()->GetFieldIndex(
10✔
568
                aosRightTableFields[0].c_str()) < 0 &&
11✔
569
            !EQUAL(poRightTable->GetFIDColumn(),
1✔
570
                   aosRightTableFields[0].c_str()))
571
        {
572
            failureReason = ("Right table field " + aosRightTableFields[0] +
2✔
573
                             " does not exist in " + osRightTableName)
2✔
574
                                .c_str();
1✔
575
            return false;
1✔
576
        }
577
    }
578

579
    // ensure relationship is different from existing relationships
580
    for (const auto &kv : m_osMapRelationships)
4✔
581
    {
582
        if (osLeftTableName == kv.second->GetLeftTableName() &&
2✔
583
            osRightTableName == kv.second->GetRightTableName() &&
1✔
584
            aosLeftTableFields == kv.second->GetLeftTableFields() &&
3✔
585
            aosRightTableFields == kv.second->GetRightTableFields())
1✔
586
        {
587
            failureReason =
588
                "A relationship between these tables and fields already exists";
1✔
589
            return false;
1✔
590
        }
591
    }
592

593
    return true;
3✔
594
}
595

596
/************************************************************************/
597
/*                       OGRSQLiteBaseDataSource()                      */
598
/************************************************************************/
599

600
OGRSQLiteBaseDataSource::OGRSQLiteBaseDataSource() = default;
601

602
/************************************************************************/
603
/*                      ~OGRSQLiteBaseDataSource()                      */
604
/************************************************************************/
605

606
OGRSQLiteBaseDataSource::~OGRSQLiteBaseDataSource()
3,703✔
607

608
{
609
    CloseDB();
3,703✔
610

611
    FinishSpatialite();
3,703✔
612

613
    if (m_bCallUndeclareFileNotToOpen)
3,703✔
614
    {
615
        GDALOpenInfoUnDeclareFileNotToOpen(m_pszFilename);
1,762✔
616
    }
617

618
    if (!m_osFinalFilename.empty())
3,703✔
619
    {
620
        if (!bSuppressOnClose)
4✔
621
        {
622
            CPLDebug("SQLITE", "Copying temporary file %s onto %s",
4✔
623
                     m_pszFilename, m_osFinalFilename.c_str());
624
            if (CPLCopyFile(m_osFinalFilename.c_str(), m_pszFilename) != 0)
4✔
625
            {
626
                CPLError(CE_Failure, CPLE_AppDefined,
×
627
                         "Copy temporary file %s onto %s failed", m_pszFilename,
628
                         m_osFinalFilename.c_str());
629
            }
630
        }
631
        CPLDebug("SQLITE", "Deleting temporary file %s", m_pszFilename);
4✔
632
        if (VSIUnlink(m_pszFilename) != 0)
4✔
633
        {
634
            CPLError(CE_Failure, CPLE_AppDefined,
×
635
                     "Deleting temporary file %s failed", m_pszFilename);
636
        }
637
    }
638

639
    CPLFree(m_pszFilename);
3,703✔
640
}
3,703✔
641

642
/************************************************************************/
643
/*                               CloseDB()                              */
644
/************************************************************************/
645

646
bool OGRSQLiteBaseDataSource::CloseDB()
7,418✔
647
{
648
    bool bOK = true;
7,418✔
649
    if (hDB != nullptr)
7,418✔
650
    {
651
        bOK = (sqlite3_close(hDB) == SQLITE_OK);
3,350✔
652
        hDB = nullptr;
3,350✔
653

654
        // If we opened the DB in read-only mode, there might be spurious
655
        // -wal and -shm files that we can make disappear by reopening in
656
        // read-write
657
        VSIStatBufL sStat;
658
        if (eAccess == GA_ReadOnly &&
7,931✔
659
            !(STARTS_WITH(m_pszFilename, "/vsicurl/") ||
1,231✔
660
              STARTS_WITH(m_pszFilename, "/vsitar/") ||
1,227✔
661
              STARTS_WITH(m_pszFilename, "/vsizip/")) &&
5,803✔
662
            VSIStatL(CPLSPrintf("%s-wal", m_pszFilename), &sStat) == 0)
1,222✔
663
        {
664
            if (sqlite3_open(m_pszFilename, &hDB) != SQLITE_OK)
4✔
665
            {
666
                sqlite3_close(hDB);
×
667
                hDB = nullptr;
×
668
            }
669
            else if (hDB != nullptr)
4✔
670
            {
671
#ifdef SQLITE_FCNTL_PERSIST_WAL
672
                int nPersistentWAL = -1;
4✔
673
                sqlite3_file_control(hDB, "main", SQLITE_FCNTL_PERSIST_WAL,
4✔
674
                                     &nPersistentWAL);
675
                if (nPersistentWAL == 1)
4✔
676
                {
677
                    nPersistentWAL = 0;
×
678
                    if (sqlite3_file_control(hDB, "main",
×
679
                                             SQLITE_FCNTL_PERSIST_WAL,
680
                                             &nPersistentWAL) == SQLITE_OK)
×
681
                    {
682
                        CPLDebug("SQLITE",
×
683
                                 "Disabling persistent WAL succeeded");
684
                    }
685
                    else
686
                    {
687
                        CPLDebug("SQLITE", "Could not disable persistent WAL");
×
688
                    }
689
                }
690
#endif
691

692
                // Dummy request
693
                int nRowCount = 0, nColCount = 0;
4✔
694
                char **papszResult = nullptr;
4✔
695
                sqlite3_get_table(hDB, "SELECT name FROM sqlite_master WHERE 0",
4✔
696
                                  &papszResult, &nRowCount, &nColCount,
697
                                  nullptr);
698
                sqlite3_free_table(papszResult);
4✔
699

700
                sqlite3_close(hDB);
4✔
701
                hDB = nullptr;
4✔
702
#ifdef DEBUG_VERBOSE
703
                if (VSIStatL(CPLSPrintf("%s-wal", m_pszFilename), &sStat) != 0)
704
                {
705
                    CPLDebug("SQLite", "%s-wal file has been removed",
706
                             m_pszFilename);
707
                }
708
#endif
709
            }
710
        }
711
    }
712

713
    if (pMyVFS)
7,418✔
714
    {
715
        sqlite3_vfs_unregister(pMyVFS);
2,697✔
716
        CPLFree(pMyVFS->pAppData);
2,697✔
717
        CPLFree(pMyVFS);
2,697✔
718
        pMyVFS = nullptr;
2,697✔
719
    }
720

721
    return bOK;
7,418✔
722
}
723

724
/* Returns the first row of first column of SQL as integer */
725
OGRErr OGRSQLiteBaseDataSource::PragmaCheck(const char *pszPragma,
73✔
726
                                            const char *pszExpected,
727
                                            int nRowsExpected)
728
{
729
    CPLAssert(pszPragma != nullptr);
73✔
730
    CPLAssert(pszExpected != nullptr);
73✔
731
    CPLAssert(nRowsExpected >= 0);
73✔
732

733
    char **papszResult = nullptr;
73✔
734
    int nRowCount = 0;
73✔
735
    int nColCount = 0;
73✔
736
    char *pszErrMsg = nullptr;
73✔
737

738
    int rc =
739
        sqlite3_get_table(hDB, CPLSPrintf("PRAGMA %s", pszPragma), &papszResult,
73✔
740
                          &nRowCount, &nColCount, &pszErrMsg);
741

742
    if (rc != SQLITE_OK)
73✔
743
    {
744
        CPLError(CE_Failure, CPLE_AppDefined, "Unable to execute PRAGMA %s: %s",
×
745
                 pszPragma, pszErrMsg ? pszErrMsg : "(null)");
×
746
        sqlite3_free(pszErrMsg);
×
747
        return OGRERR_FAILURE;
×
748
    }
749

750
    if (nRowCount != nRowsExpected)
73✔
751
    {
752
        CPLError(CE_Failure, CPLE_AppDefined,
×
753
                 "bad result for PRAGMA %s, got %d rows, expected %d",
754
                 pszPragma, nRowCount, nRowsExpected);
755
        sqlite3_free_table(papszResult);
×
756
        return OGRERR_FAILURE;
×
757
    }
758

759
    if (nRowCount > 0 && !EQUAL(papszResult[1], pszExpected))
73✔
760
    {
761
        CPLError(CE_Failure, CPLE_AppDefined,
×
762
                 "invalid %s (expected '%s', got '%s')", pszPragma, pszExpected,
763
                 papszResult[1]);
×
764
        sqlite3_free_table(papszResult);
×
765
        return OGRERR_FAILURE;
×
766
    }
767

768
    sqlite3_free_table(papszResult);
73✔
769

770
    return OGRERR_NONE;
73✔
771
}
772

773
/************************************************************************/
774
/*                     LoadRelationships()                              */
775
/************************************************************************/
776

777
void OGRSQLiteBaseDataSource::LoadRelationships() const
8✔
778

779
{
780
    m_osMapRelationships.clear();
8✔
781
    LoadRelationshipsFromForeignKeys({});
8✔
782
    m_bHasPopulatedRelationships = true;
8✔
783
}
8✔
784

785
/************************************************************************/
786
/*                LoadRelationshipsFromForeignKeys()                    */
787
/************************************************************************/
788

789
void OGRSQLiteBaseDataSource::LoadRelationshipsFromForeignKeys(
91✔
790
    const std::vector<std::string> &excludedTables) const
791

792
{
793
    if (hDB)
91✔
794
    {
795
        std::string osSQL =
796
            "SELECT m.name, p.id, p.seq, p.\"table\" AS base_table_name, "
797
            "p.\"from\", p.\"to\", "
798
            "p.on_delete FROM sqlite_master m "
799
            "JOIN pragma_foreign_key_list(m.name) p ON m.name != p.\"table\" "
800
            "WHERE m.type = 'table' "
801
            // skip over foreign keys which relate to private GPKG tables
802
            "AND base_table_name NOT LIKE 'gpkg_%' "
803
            // Same with NGA GeoInt system tables
804
            "AND base_table_name NOT LIKE 'nga_%' "
805
            // Same with Spatialite system tables
806
            "AND base_table_name NOT IN ('geometry_columns', "
807
            "'spatial_ref_sys', 'views_geometry_columns', "
808
            "'virts_geometry_columns') ";
91✔
809
        if (!excludedTables.empty())
91✔
810
        {
811
            std::string oExcludedTablesList;
32✔
812
            for (const auto &osExcludedTable : excludedTables)
84✔
813
            {
814
                oExcludedTablesList += !oExcludedTablesList.empty() ? "," : "";
52✔
815
                char *pszEscapedName =
816
                    sqlite3_mprintf("'%q'", osExcludedTable.c_str());
52✔
817
                oExcludedTablesList += pszEscapedName;
52✔
818
                sqlite3_free(pszEscapedName);
52✔
819
            }
820

821
            osSQL += "AND base_table_name NOT IN (" + oExcludedTablesList +
64✔
822
                     ")"
823
                     " AND m.name NOT IN (" +
64✔
824
                     oExcludedTablesList + ") ";
32✔
825
        }
826
        osSQL += "ORDER BY m.name";
91✔
827

828
        auto oResult = SQLQuery(hDB, osSQL.c_str());
91✔
829

830
        if (!oResult)
91✔
831
        {
832
            CPLError(CE_Failure, CPLE_AppDefined, "Cannot load relationships");
×
833
            return;
×
834
        }
835

836
        for (int iRecord = 0; iRecord < oResult->RowCount(); iRecord++)
113✔
837
        {
838
            const char *pszRelatedTableName = oResult->GetValue(0, iRecord);
22✔
839
            if (!pszRelatedTableName)
22✔
840
                continue;
×
841

842
            const char *pszBaseTableName = oResult->GetValue(3, iRecord);
22✔
843
            if (!pszBaseTableName)
22✔
844
                continue;
×
845

846
            const char *pszRelatedFieldName = oResult->GetValue(4, iRecord);
22✔
847
            if (!pszRelatedFieldName)
22✔
848
                continue;
×
849

850
            const char *pszBaseFieldName = oResult->GetValue(5, iRecord);
22✔
851
            if (!pszBaseFieldName)
22✔
852
                continue;
×
853

854
            const int nId = oResult->GetValueAsInteger(1, iRecord);
22✔
855

856
            // form relationship name by appending foreign key id to base and
857
            // related table names
858
            std::ostringstream stream;
44✔
859
            stream << pszBaseTableName << '_' << pszRelatedTableName;
22✔
860
            if (nId > 0)
22✔
861
            {
862
                // note we use nId + 1 here as the first id will be zero, and
863
                // we'd like subsequent relations to have names starting with
864
                // _2, _3 etc, not _1, _2 etc.
865
                stream << '_' << (nId + 1);
2✔
866
            }
867
            const std::string osRelationName = stream.str();
44✔
868

869
            const auto it = m_osMapRelationships.find(osRelationName);
22✔
870
            if (it != m_osMapRelationships.end())
22✔
871
            {
872
                // already have a relationship with this name -- that means that
873
                // the base and related table name and id are the same, so we've
874
                // found a multi-column relationship
875
                auto osListLeftFields = it->second->GetLeftTableFields();
10✔
876
                osListLeftFields.emplace_back(pszBaseFieldName);
5✔
877
                it->second->SetLeftTableFields(osListLeftFields);
5✔
878

879
                auto osListRightFields = it->second->GetRightTableFields();
10✔
880
                osListRightFields.emplace_back(pszRelatedFieldName);
5✔
881
                it->second->SetRightTableFields(osListRightFields);
5✔
882
            }
883
            else
884
            {
885
                std::unique_ptr<GDALRelationship> poRelationship(
886
                    new GDALRelationship(osRelationName, pszBaseTableName,
887
                                         pszRelatedTableName, GRC_ONE_TO_MANY));
51✔
888
                poRelationship->SetLeftTableFields({pszBaseFieldName});
34✔
889
                poRelationship->SetRightTableFields({pszRelatedFieldName});
34✔
890
                poRelationship->SetRelatedTableType("features");
17✔
891

892
                if (const char *pszOnDeleteAction =
17✔
893
                        oResult->GetValue(6, iRecord))
17✔
894
                {
895
                    if (EQUAL(pszOnDeleteAction, "CASCADE"))
17✔
896
                    {
897
                        poRelationship->SetType(GRT_COMPOSITE);
2✔
898
                    }
899
                }
900

901
                m_osMapRelationships[osRelationName] =
17✔
902
                    std::move(poRelationship);
34✔
903
            }
904
        }
905
    }
906
}
907

908
/************************************************************************/
909
/*                        GetRelationshipNames()                        */
910
/************************************************************************/
911

912
std::vector<std::string> OGRSQLiteBaseDataSource::GetRelationshipNames(
71✔
913
    CPL_UNUSED CSLConstList papszOptions) const
914

915
{
916
    if (!m_bHasPopulatedRelationships)
71✔
917
    {
918
        LoadRelationships();
62✔
919
    }
920

921
    std::vector<std::string> oasNames;
71✔
922
    oasNames.reserve(m_osMapRelationships.size());
71✔
923
    for (const auto &kv : m_osMapRelationships)
116✔
924
    {
925
        oasNames.emplace_back(kv.first);
45✔
926
    }
927
    return oasNames;
71✔
928
}
929

930
/************************************************************************/
931
/*                        GetRelationship()                             */
932
/************************************************************************/
933

934
const GDALRelationship *
935
OGRSQLiteBaseDataSource::GetRelationship(const std::string &name) const
71✔
936

937
{
938
    if (!m_bHasPopulatedRelationships)
71✔
939
    {
940
        LoadRelationships();
8✔
941
    }
942

943
    const auto it = m_osMapRelationships.find(name);
71✔
944
    if (it == m_osMapRelationships.end())
71✔
945
        return nullptr;
34✔
946

947
    return it->second.get();
37✔
948
}
949

950
/***********************************************************************/
951
/*                         prepareSql()                                */
952
/***********************************************************************/
953

954
int OGRSQLiteBaseDataSource::prepareSql(sqlite3 *db, const char *zSql,
12,083✔
955
                                        int nByte, sqlite3_stmt **ppStmt,
956
                                        const char **pzTail)
957
{
958
    const int rc{sqlite3_prepare_v2(db, zSql, nByte, ppStmt, pzTail)};
12,083✔
959
    if (rc != SQLITE_OK && pfnQueryLoggerFunc)
12,083✔
960
    {
961
        std::string error{"Error preparing query: "};
2✔
962
        error.append(sqlite3_errmsg(db));
1✔
963
        pfnQueryLoggerFunc(zSql, error.c_str(), -1, -1, poQueryLoggerArg);
1✔
964
    }
965
    return rc;
12,083✔
966
}
967

968
/************************************************************************/
969
/*                        OGRSQLiteDataSource()                         */
970
/************************************************************************/
971

972
OGRSQLiteDataSource::OGRSQLiteDataSource() = default;
973

974
/************************************************************************/
975
/*                        ~OGRSQLiteDataSource()                        */
976
/************************************************************************/
977

978
OGRSQLiteDataSource::~OGRSQLiteDataSource()
2,552✔
979

980
{
981
    OGRSQLiteDataSource::Close();
1,276✔
982
}
2,552✔
983

984
/************************************************************************/
985
/*                              Close()                                 */
986
/************************************************************************/
987

988
CPLErr OGRSQLiteDataSource::Close()
1,808✔
989
{
990
    CPLErr eErr = CE_None;
1,808✔
991
    if (nOpenFlags != OPEN_FLAGS_CLOSED)
1,808✔
992
    {
993
        if (OGRSQLiteDataSource::FlushCache(true) != CE_None)
1,276✔
994
            eErr = CE_Failure;
×
995

996
#ifdef HAVE_RASTERLITE2
997
        if (m_pRL2Coverage != nullptr)
998
        {
999
            rl2_destroy_coverage(m_pRL2Coverage);
1000
        }
1001
#endif
1002
        for (size_t i = 0; i < m_apoOverviewDS.size(); ++i)
1,276✔
1003
        {
1004
            delete m_apoOverviewDS[i];
×
1005
        }
1006

1007
        if (!m_apoLayers.empty() || !m_apoInvisibleLayers.empty())
1,276✔
1008
        {
1009
            // Close any remaining iterator
1010
            for (auto &poLayer : m_apoLayers)
2,128✔
1011
                poLayer->ResetReading();
1,342✔
1012
            for (auto &poLayer : m_apoInvisibleLayers)
788✔
1013
                poLayer->ResetReading();
2✔
1014

1015
            // Create spatial indices in a transaction for faster execution
1016
            if (hDB)
786✔
1017
                SoftStartTransaction();
786✔
1018
            for (auto &poLayer : m_apoLayers)
2,128✔
1019
            {
1020
                if (poLayer->IsTableLayer())
1,342✔
1021
                {
1022
                    OGRSQLiteTableLayer *poTableLayer =
1023
                        cpl::down_cast<OGRSQLiteTableLayer *>(poLayer.get());
1,337✔
1024
                    poTableLayer->RunDeferredCreationIfNecessary();
1,337✔
1025
                    poTableLayer->CreateSpatialIndexIfNecessary();
1,337✔
1026
                }
1027
            }
1028
            if (hDB)
786✔
1029
                SoftCommitTransaction();
786✔
1030
        }
1031

1032
        SaveStatistics();
1,276✔
1033

1034
        m_apoLayers.clear();
1,276✔
1035
        m_apoInvisibleLayers.clear();
1,276✔
1036

1037
        m_oSRSCache.clear();
1,276✔
1038

1039
        if (!CloseDB())
1,276✔
1040
            eErr = CE_Failure;
×
1041
#ifdef HAVE_RASTERLITE2
1042
        FinishRasterLite2();
1043
#endif
1044

1045
        if (GDALPamDataset::Close() != CE_None)
1,276✔
1046
            eErr = CE_Failure;
×
1047
    }
1048
    return eErr;
1,808✔
1049
}
1050

1051
#ifdef HAVE_RASTERLITE2
1052

1053
/************************************************************************/
1054
/*                          InitRasterLite2()                           */
1055
/************************************************************************/
1056

1057
bool OGRSQLiteDataSource::InitRasterLite2()
1058
{
1059
    CPLAssert(m_hRL2Ctxt == nullptr);
1060
    m_hRL2Ctxt = rl2_alloc_private();
1061
    if (m_hRL2Ctxt != nullptr)
1062
    {
1063
        rl2_init(hDB, m_hRL2Ctxt, 0);
1064
    }
1065
    return m_hRL2Ctxt != nullptr;
1066
}
1067

1068
/************************************************************************/
1069
/*                         FinishRasterLite2()                          */
1070
/************************************************************************/
1071

1072
void OGRSQLiteDataSource::FinishRasterLite2()
1073
{
1074
    if (m_hRL2Ctxt != nullptr)
1075
    {
1076
        rl2_cleanup_private(m_hRL2Ctxt);
1077
        m_hRL2Ctxt = nullptr;
1078
    }
1079
}
1080

1081
#endif  // HAVE_RASTERLITE2
1082

1083
/************************************************************************/
1084
/*                              SaveStatistics()                        */
1085
/************************************************************************/
1086

1087
void OGRSQLiteDataSource::SaveStatistics()
1,276✔
1088
{
1089
    if (!m_bIsSpatiaLiteDB || !IsSpatialiteLoaded() ||
625✔
1090
        m_bLastSQLCommandIsUpdateLayerStatistics || !GetUpdate())
1,901✔
1091
        return;
688✔
1092

1093
    int nSavedAllLayersCacheData = -1;
588✔
1094

1095
    for (auto &poLayer : m_apoLayers)
920✔
1096
    {
1097
        if (poLayer->IsTableLayer())
332✔
1098
        {
1099
            OGRSQLiteTableLayer *poTableLayer =
1100
                cpl::down_cast<OGRSQLiteTableLayer *>(poLayer.get());
331✔
1101
            int nSaveRet = poTableLayer->SaveStatistics();
331✔
1102
            if (nSaveRet >= 0)
331✔
1103
            {
1104
                if (nSavedAllLayersCacheData < 0)
132✔
1105
                    nSavedAllLayersCacheData = nSaveRet;
37✔
1106
                else
1107
                    nSavedAllLayersCacheData &= nSaveRet;
95✔
1108
            }
1109
        }
1110
    }
1111

1112
    if (hDB && nSavedAllLayersCacheData == TRUE)
588✔
1113
    {
1114
        int nReplaceEventId = -1;
37✔
1115

1116
        auto oResult = SQLQuery(
1117
            hDB, "SELECT event_id, table_name, geometry_column, event "
1118
                 "FROM spatialite_history ORDER BY event_id DESC LIMIT 1");
74✔
1119

1120
        if (oResult && oResult->RowCount() == 1)
37✔
1121
        {
1122
            const char *pszEventId = oResult->GetValue(0, 0);
37✔
1123
            const char *pszTableName = oResult->GetValue(1, 0);
37✔
1124
            const char *pszGeomCol = oResult->GetValue(2, 0);
37✔
1125
            const char *pszEvent = oResult->GetValue(3, 0);
37✔
1126

1127
            if (pszEventId != nullptr && pszTableName != nullptr &&
37✔
1128
                pszGeomCol != nullptr && pszEvent != nullptr &&
37✔
1129
                strcmp(pszTableName, "ALL-TABLES") == 0 &&
37✔
1130
                strcmp(pszGeomCol, "ALL-GEOMETRY-COLUMNS") == 0 &&
3✔
1131
                strcmp(pszEvent, "UpdateLayerStatistics") == 0)
3✔
1132
            {
1133
                nReplaceEventId = atoi(pszEventId);
3✔
1134
            }
1135
        }
1136

1137
        const char *pszNow = HasSpatialite4Layout()
37✔
1138
                                 ? "strftime('%Y-%m-%dT%H:%M:%fZ','now')"
37✔
1139
                                 : "DateTime('now')";
37✔
1140
        const char *pszSQL;
1141
        if (nReplaceEventId >= 0)
37✔
1142
        {
1143
            pszSQL = CPLSPrintf("UPDATE spatialite_history SET "
3✔
1144
                                "timestamp = %s "
1145
                                "WHERE event_id = %d",
1146
                                pszNow, nReplaceEventId);
1147
        }
1148
        else
1149
        {
1150
            pszSQL = CPLSPrintf(
34✔
1151
                "INSERT INTO spatialite_history (table_name, geometry_column, "
1152
                "event, timestamp, ver_sqlite, ver_splite) VALUES ("
1153
                "'ALL-TABLES', 'ALL-GEOMETRY-COLUMNS', "
1154
                "'UpdateLayerStatistics', "
1155
                "%s, sqlite_version(), spatialite_version())",
1156
                pszNow);
1157
        }
1158

1159
        SQLCommand(hDB, pszSQL);
37✔
1160
    }
1161
}
1162

1163
/************************************************************************/
1164
/*                              SetSynchronous()                        */
1165
/************************************************************************/
1166

1167
bool OGRSQLiteBaseDataSource::SetSynchronous()
3,339✔
1168
{
1169
    const char *pszSqliteSync =
1170
        CPLGetConfigOption("OGR_SQLITE_SYNCHRONOUS", nullptr);
3,339✔
1171
    if (pszSqliteSync != nullptr)
3,339✔
1172
    {
1173
        const char *pszSQL = nullptr;
1,516✔
1174
        if (EQUAL(pszSqliteSync, "OFF") || EQUAL(pszSqliteSync, "0") ||
1,516✔
1175
            EQUAL(pszSqliteSync, "FALSE"))
×
1176
            pszSQL = "PRAGMA synchronous = OFF";
1,516✔
1177
        else if (EQUAL(pszSqliteSync, "NORMAL") || EQUAL(pszSqliteSync, "1"))
×
1178
            pszSQL = "PRAGMA synchronous = NORMAL";
×
1179
        else if (EQUAL(pszSqliteSync, "ON") || EQUAL(pszSqliteSync, "FULL") ||
×
1180
                 EQUAL(pszSqliteSync, "2") || EQUAL(pszSqliteSync, "TRUE"))
×
1181
            pszSQL = "PRAGMA synchronous = FULL";
×
1182
        else
1183
            CPLError(CE_Warning, CPLE_AppDefined,
×
1184
                     "Unrecognized value for OGR_SQLITE_SYNCHRONOUS : %s",
1185
                     pszSqliteSync);
1186

1187
        return pszSQL != nullptr && SQLCommand(hDB, pszSQL) == OGRERR_NONE;
1,516✔
1188
    }
1189
    return true;
1,823✔
1190
}
1191

1192
/************************************************************************/
1193
/*                              LoadExtensions()                        */
1194
/************************************************************************/
1195

1196
void OGRSQLiteBaseDataSource::LoadExtensions()
3,339✔
1197
{
1198
    const char *pszExtensions =
1199
        CPLGetConfigOption("OGR_SQLITE_LOAD_EXTENSIONS", nullptr);
3,339✔
1200
    if (pszExtensions != nullptr)
3,339✔
1201
    {
1202
#ifdef OGR_SQLITE_ALLOW_LOAD_EXTENSIONS
1203
        // Allow sqlite3_load_extension() (C API only)
1204
#ifdef SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
1205
        int oldMode = 0;
4✔
1206
        if (sqlite3_db_config(hDB, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, -1,
4✔
1207
                              &oldMode) != SQLITE_OK)
4✔
1208
        {
1209
            CPLError(CE_Failure, CPLE_AppDefined,
×
1210
                     "Cannot get initial value for "
1211
                     "SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION");
1212
            return;
×
1213
        }
1214
        CPLDebugOnly(
4✔
1215
            "SQLite",
1216
            "Initial mode for SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION = %d",
1217
            oldMode);
1218
        int newMode = 0;
4✔
1219
        if (oldMode != 1 &&
8✔
1220
            (sqlite3_db_config(hDB, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1,
4✔
1221
                               &newMode) != SQLITE_OK ||
4✔
1222
             newMode != 1))
4✔
1223
        {
1224
            CPLError(CE_Failure, CPLE_AppDefined,
×
1225
                     "SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION failed");
1226
            return;
×
1227
        }
1228
#endif
1229
        const CPLStringList aosExtensions(
1230
            CSLTokenizeString2(pszExtensions, ",", 0));
8✔
1231
        bool bRestoreOldMode = true;
4✔
1232
        for (int i = 0; i < aosExtensions.size(); i++)
8✔
1233
        {
1234
            if (EQUAL(aosExtensions[i], "ENABLE_SQL_LOAD_EXTENSION"))
4✔
1235
            {
1236
                if (sqlite3_enable_load_extension(hDB, 1) == SQLITE_OK)
2✔
1237
                {
1238
                    bRestoreOldMode = false;
2✔
1239
                }
1240
                else
1241
                {
1242
                    CPLError(CE_Failure, CPLE_AppDefined,
×
1243
                             "sqlite3_enable_load_extension() failed");
1244
                }
1245
            }
1246
            else
1247
            {
1248
                char *pszErrMsg = nullptr;
2✔
1249
                if (sqlite3_load_extension(hDB, aosExtensions[i], nullptr,
2✔
1250
                                           &pszErrMsg) != SQLITE_OK)
2✔
1251
                {
1252
                    CPLError(CE_Failure, CPLE_AppDefined,
1✔
1253
                             "Cannot load extension %s: %s", aosExtensions[i],
1254
                             pszErrMsg ? pszErrMsg : "unknown reason");
1✔
1255
                }
1256
                sqlite3_free(pszErrMsg);
2✔
1257
            }
1258
        }
1259
        CPL_IGNORE_RET_VAL(bRestoreOldMode);
4✔
1260
#ifdef SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
1261
        if (bRestoreOldMode && oldMode != 1)
4✔
1262
        {
1263
            CPL_IGNORE_RET_VAL(sqlite3_db_config(
2✔
1264
                hDB, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, oldMode, nullptr));
1265
        }
1266
#endif
1267
#else
1268
        CPLError(
1269
            CE_Failure, CPLE_NotSupported,
1270
            "The OGR_SQLITE_LOAD_EXTENSIONS was specified at run time, "
1271
            "but GDAL has been built without OGR_SQLITE_ALLOW_LOAD_EXTENSIONS. "
1272
            "So extensions won't be loaded");
1273
#endif
1274
    }
1275
}
1276

1277
/************************************************************************/
1278
/*                              SetCacheSize()                          */
1279
/************************************************************************/
1280

1281
bool OGRSQLiteBaseDataSource::SetCacheSize()
3,339✔
1282
{
1283
    const char *pszSqliteCacheMB =
1284
        CPLGetConfigOption("OGR_SQLITE_CACHE", nullptr);
3,339✔
1285
    if (pszSqliteCacheMB != nullptr)
3,339✔
1286
    {
1287
        const GIntBig iSqliteCacheBytes =
×
1288
            static_cast<GIntBig>(atoi(pszSqliteCacheMB)) * 1024 * 1024;
×
1289

1290
        /* querying the current PageSize */
1291
        int iSqlitePageSize = SQLGetInteger(hDB, "PRAGMA page_size", nullptr);
×
1292
        if (iSqlitePageSize <= 0)
×
1293
            return false;
×
1294
        /* computing the CacheSize as #Pages */
1295
        const int iSqliteCachePages =
×
1296
            static_cast<int>(iSqliteCacheBytes / iSqlitePageSize);
×
1297
        if (iSqliteCachePages <= 0)
×
1298
            return false;
×
1299

1300
        return SQLCommand(hDB, CPLSPrintf("PRAGMA cache_size = %d",
×
1301
                                          iSqliteCachePages)) == OGRERR_NONE;
×
1302
    }
1303
    return true;
3,339✔
1304
}
1305

1306
/************************************************************************/
1307
/*               OGRSQLiteBaseDataSourceNotifyFileOpened()              */
1308
/************************************************************************/
1309

1310
static void OGRSQLiteBaseDataSourceNotifyFileOpened(void *pfnUserData,
21,958✔
1311
                                                    const char *pszFilename,
1312
                                                    VSILFILE *fp)
1313
{
1314
    static_cast<OGRSQLiteBaseDataSource *>(pfnUserData)
1315
        ->NotifyFileOpened(pszFilename, fp);
21,958✔
1316
}
21,958✔
1317

1318
/************************************************************************/
1319
/*                          NotifyFileOpened()                          */
1320
/************************************************************************/
1321

1322
void OGRSQLiteBaseDataSource::NotifyFileOpened(const char *pszFilename,
21,958✔
1323
                                               VSILFILE *fp)
1324
{
1325
    if (strcmp(pszFilename, m_pszFilename) == 0)
21,958✔
1326
    {
1327
        fpMainFile = fp;
2,697✔
1328
    }
1329
}
21,958✔
1330

1331
#ifdef USE_SQLITE_DEBUG_MEMALLOC
1332

1333
/* DMA9 */
1334
constexpr int DMA_SIGNATURE = 0x444D4139;
1335

1336
static void *OGRSQLiteDMA_Malloc(int size)
1337
{
1338
    int *ret = (int *)CPLMalloc(size + 8);
1339
    ret[0] = size;
1340
    ret[1] = DMA_SIGNATURE;
1341
    return ret + 2;
1342
}
1343

1344
static void *OGRSQLiteDMA_Realloc(void *old_ptr, int size)
1345
{
1346
    CPLAssert(((int *)old_ptr)[-1] == DMA_SIGNATURE);
1347
    int *ret = (int *)CPLRealloc(old_ptr ? (int *)old_ptr - 2 : NULL, size + 8);
1348
    ret[0] = size;
1349
    ret[1] = DMA_SIGNATURE;
1350
    return ret + 2;
1351
}
1352

1353
static void OGRSQLiteDMA_Free(void *ptr)
1354
{
1355
    if (ptr)
1356
    {
1357
        CPLAssert(((int *)ptr)[-1] == DMA_SIGNATURE);
1358
        ((int *)ptr)[-1] = 0;
1359
        CPLFree((int *)ptr - 2);
1360
    }
1361
}
1362

1363
static int OGRSQLiteDMA_Size(void *ptr)
1364
{
1365
    if (ptr)
1366
    {
1367
        CPLAssert(((int *)ptr)[-1] == DMA_SIGNATURE);
1368
        return ((int *)ptr)[-2];
1369
    }
1370
    else
1371
        return 0;
1372
}
1373

1374
static int OGRSQLiteDMA_Roundup(int size)
1375
{
1376
    return (size + 7) & (~7);
1377
}
1378

1379
static int OGRSQLiteDMA_Init(void *)
1380
{
1381
    return SQLITE_OK;
1382
}
1383

1384
static void OGRSQLiteDMA_Shutdown(void *)
1385
{
1386
}
1387

1388
const struct sqlite3_mem_methods sDebugMemAlloc = {
1389
    OGRSQLiteDMA_Malloc,   OGRSQLiteDMA_Free,
1390
    OGRSQLiteDMA_Realloc,  OGRSQLiteDMA_Size,
1391
    OGRSQLiteDMA_Roundup,  OGRSQLiteDMA_Init,
1392
    OGRSQLiteDMA_Shutdown, NULL};
1393

1394
#endif  // USE_SQLITE_DEBUG_MEMALLOC
1395

1396
/************************************************************************/
1397
/*                            OpenOrCreateDB()                          */
1398
/************************************************************************/
1399

1400
bool OGRSQLiteBaseDataSource::OpenOrCreateDB(int flagsIn,
3,352✔
1401
                                             bool bRegisterOGR2SQLiteExtensions,
1402
                                             bool bLoadExtensions)
1403
{
1404
#ifdef USE_SQLITE_DEBUG_MEMALLOC
1405
    if (CPLTestBool(CPLGetConfigOption("USE_SQLITE_DEBUG_MEMALLOC", "NO")))
1406
        sqlite3_config(SQLITE_CONFIG_MALLOC, &sDebugMemAlloc);
1407
#endif
1408

1409
    if (bRegisterOGR2SQLiteExtensions)
3,352✔
1410
        OGR2SQLITE_Register();
1,274✔
1411

1412
    const bool bUseOGRVFS =
1413
        CPLTestBool(CPLGetConfigOption("SQLITE_USE_OGR_VFS", "NO")) ||
3,352✔
1414
        STARTS_WITH(m_pszFilename, "/vsi") ||
4,007✔
1415
        // https://sqlite.org/forum/forumpost/0b1b8b5116: MAX_PATHNAME=512
1416
        strlen(m_pszFilename) >= 512 - strlen(".journal");
655✔
1417

1418
#ifdef SQLITE_OPEN_URI
1419
    const bool bNoLock =
1420
        CPLTestBool(CSLFetchNameValueDef(papszOpenOptions, "NOLOCK", "NO"));
3,352✔
1421
    const char *pszImmutable = CSLFetchNameValue(papszOpenOptions, "IMMUTABLE");
3,352✔
1422
    const bool bImmutable = pszImmutable && CPLTestBool(pszImmutable);
3,352✔
1423
    if (m_osFilenameForSQLiteOpen.empty() &&
3,352✔
1424
        (flagsIn & SQLITE_OPEN_READWRITE) == 0 &&
3,341✔
1425
        !STARTS_WITH(m_pszFilename, "file:") && (bNoLock || bImmutable))
6,693✔
1426
    {
1427
        m_osFilenameForSQLiteOpen = "file:";
7✔
1428

1429
        // Apply rules from "3.1. The URI Path" of
1430
        // https://www.sqlite.org/uri.html
1431
        CPLString osFilenameForURI(m_pszFilename);
14✔
1432
        osFilenameForURI.replaceAll('?', "%3f");
7✔
1433
        osFilenameForURI.replaceAll('#', "%23");
7✔
1434
#ifdef _WIN32
1435
        osFilenameForURI.replaceAll('\\', '/');
1436
#endif
1437
        if (!STARTS_WITH(m_pszFilename, "/vsi"))
7✔
1438
        {
1439
            osFilenameForURI.replaceAll("//", '/');
5✔
1440
        }
1441
#ifdef _WIN32
1442
        if (osFilenameForURI.size() > 3 && osFilenameForURI[1] == ':' &&
1443
            osFilenameForURI[2] == '/')
1444
        {
1445
            osFilenameForURI = '/' + osFilenameForURI;
1446
        }
1447
#endif
1448

1449
        m_osFilenameForSQLiteOpen += osFilenameForURI;
7✔
1450
        m_osFilenameForSQLiteOpen += "?";
7✔
1451
        if (bNoLock)
7✔
1452
            m_osFilenameForSQLiteOpen += "nolock=1";
5✔
1453
        if (bImmutable)
7✔
1454
        {
1455
            if (m_osFilenameForSQLiteOpen.back() != '?')
2✔
1456
                m_osFilenameForSQLiteOpen += '&';
×
1457
            m_osFilenameForSQLiteOpen += "immutable=1";
2✔
1458
        }
1459
    }
1460
#endif
1461
    if (m_osFilenameForSQLiteOpen.empty())
3,352✔
1462
    {
1463
        m_osFilenameForSQLiteOpen = m_pszFilename;
3,334✔
1464
    }
1465

1466
    // No mutex since OGR objects are not supposed to be used concurrently
1467
    // from multiple threads.
1468
    int flags = flagsIn | SQLITE_OPEN_NOMUTEX;
3,352✔
1469
#ifdef SQLITE_OPEN_URI
1470
    // This code enables support for named memory databases in SQLite.
1471
    // SQLITE_USE_URI is checked only to enable backward compatibility, in
1472
    // case we accidentally hijacked some other format.
1473
    if (STARTS_WITH(m_osFilenameForSQLiteOpen.c_str(), "file:") &&
3,360✔
1474
        CPLTestBool(CPLGetConfigOption("SQLITE_USE_URI", "YES")))
8✔
1475
    {
1476
        flags |= SQLITE_OPEN_URI;
8✔
1477
    }
1478
#endif
1479

1480
    bool bPageSizeFound = false;
3,352✔
1481
    bool bSecureDeleteFound = false;
3,352✔
1482

1483
    const char *pszSqlitePragma =
1484
        CPLGetConfigOption("OGR_SQLITE_PRAGMA", nullptr);
3,352✔
1485
    CPLString osJournalMode = CPLGetConfigOption("OGR_SQLITE_JOURNAL", "");
6,704✔
1486

1487
    if (bUseOGRVFS)
3,352✔
1488
    {
1489
        pMyVFS =
2,697✔
1490
            OGRSQLiteCreateVFS(OGRSQLiteBaseDataSourceNotifyFileOpened, this);
2,697✔
1491
        sqlite3_vfs_register(pMyVFS, 0);
2,697✔
1492
    }
1493

1494
    for (int iterOpen = 0; iterOpen < 2; iterOpen++)
3,353✔
1495
    {
1496
        CPLAssert(hDB == nullptr);
3,353✔
1497
        int rc = sqlite3_open_v2(m_osFilenameForSQLiteOpen.c_str(), &hDB, flags,
3,353✔
1498
                                 pMyVFS ? pMyVFS->zName : nullptr);
3,353✔
1499
        if (rc != SQLITE_OK || !hDB)
3,353✔
1500
        {
1501
            CPLError(CE_Failure, CPLE_OpenFailed, "sqlite3_open(%s) failed: %s",
9✔
1502
                     m_pszFilename,
1503
                     hDB ? sqlite3_errmsg(hDB) : "(unknown error)");
9✔
1504
            sqlite3_close(hDB);
9✔
1505
            hDB = nullptr;
9✔
1506
            return false;
9✔
1507
        }
1508

1509
#ifdef SQLITE_DBCONFIG_DEFENSIVE
1510
        // SQLite builds on recent MacOS enable defensive mode by default, which
1511
        // causes issues in the VDV driver (when updating a deleted database),
1512
        // or in the GPKG driver (when modifying a CREATE TABLE DDL with
1513
        // writable_schema=ON) So disable it.
1514
        int bDefensiveOldValue = 0;
3,344✔
1515
        if (sqlite3_db_config(hDB, SQLITE_DBCONFIG_DEFENSIVE, -1,
3,344✔
1516
                              &bDefensiveOldValue) == SQLITE_OK &&
6,688✔
1517
            bDefensiveOldValue == 1)
3,344✔
1518
        {
1519
            if (sqlite3_db_config(hDB, SQLITE_DBCONFIG_DEFENSIVE, 0, nullptr) ==
×
1520
                SQLITE_OK)
1521
            {
1522
                CPLDebug("SQLITE", "Disabling defensive mode succeeded");
×
1523
            }
1524
            else
1525
            {
1526
                CPLDebug("SQLITE", "Could not disable defensive mode");
×
1527
            }
1528
        }
1529
#endif
1530

1531
#ifdef SQLITE_FCNTL_PERSIST_WAL
1532
        int nPersistentWAL = -1;
3,344✔
1533
        sqlite3_file_control(hDB, "main", SQLITE_FCNTL_PERSIST_WAL,
3,344✔
1534
                             &nPersistentWAL);
1535
        if (nPersistentWAL == 1)
3,344✔
1536
        {
1537
            nPersistentWAL = 0;
×
1538
            if (sqlite3_file_control(hDB, "main", SQLITE_FCNTL_PERSIST_WAL,
×
1539
                                     &nPersistentWAL) == SQLITE_OK)
×
1540
            {
1541
                CPLDebug("SQLITE", "Disabling persistent WAL succeeded");
×
1542
            }
1543
            else
1544
            {
1545
                CPLDebug("SQLITE", "Could not disable persistent WAL");
×
1546
            }
1547
        }
1548
#endif
1549

1550
        if (pszSqlitePragma != nullptr)
3,344✔
1551
        {
1552
            char **papszTokens =
1553
                CSLTokenizeString2(pszSqlitePragma, ",", CSLT_HONOURSTRINGS);
6✔
1554
            for (int i = 0; papszTokens[i] != nullptr; i++)
12✔
1555
            {
1556
                if (STARTS_WITH_CI(papszTokens[i], "PAGE_SIZE"))
6✔
1557
                    bPageSizeFound = true;
×
1558
                else if (STARTS_WITH_CI(papszTokens[i], "JOURNAL_MODE"))
6✔
1559
                {
1560
                    const char *pszEqual = strchr(papszTokens[i], '=');
×
1561
                    if (pszEqual)
×
1562
                    {
1563
                        osJournalMode = pszEqual + 1;
×
1564
                        osJournalMode.Trim();
×
1565
                        // Only apply journal_mode after changing page_size
1566
                        continue;
×
1567
                    }
1568
                }
1569
                else if (STARTS_WITH_CI(papszTokens[i], "SECURE_DELETE"))
6✔
1570
                    bSecureDeleteFound = true;
1✔
1571

1572
                const char *pszSQL = CPLSPrintf("PRAGMA %s", papszTokens[i]);
6✔
1573

1574
                CPL_IGNORE_RET_VAL(
6✔
1575
                    sqlite3_exec(hDB, pszSQL, nullptr, nullptr, nullptr));
6✔
1576
            }
1577
            CSLDestroy(papszTokens);
6✔
1578
        }
1579

1580
        const char *pszVal = CPLGetConfigOption("SQLITE_BUSY_TIMEOUT", "5000");
3,344✔
1581
        if (pszVal != nullptr)
3,344✔
1582
        {
1583
            sqlite3_busy_timeout(hDB, atoi(pszVal));
3,344✔
1584
        }
1585

1586
#ifdef SQLITE_OPEN_URI
1587
        if (iterOpen == 0 && bNoLock && !bImmutable)
3,344✔
1588
        {
1589
            int nRowCount = 0, nColCount = 0;
6✔
1590
            char **papszResult = nullptr;
6✔
1591
            rc = sqlite3_get_table(hDB, "PRAGMA journal_mode", &papszResult,
6✔
1592
                                   &nRowCount, &nColCount, nullptr);
1593
            bool bWal = false;
6✔
1594
            // rc == SQLITE_CANTOPEN seems to be what we get when issuing the
1595
            // above in nolock mode on a wal enabled file
1596
            if (rc != SQLITE_OK ||
6✔
1597
                (nRowCount == 1 && nColCount == 1 && papszResult[1] &&
5✔
1598
                 EQUAL(papszResult[1], "wal")))
5✔
1599
            {
1600
                bWal = true;
1✔
1601
            }
1602
            sqlite3_free_table(papszResult);
6✔
1603
            if (bWal)
6✔
1604
            {
1605
                flags &= ~SQLITE_OPEN_URI;
1✔
1606
                sqlite3_close(hDB);
1✔
1607
                hDB = nullptr;
1✔
1608
                CPLDebug("SQLite",
1✔
1609
                         "Cannot open %s in nolock mode because it is "
1610
                         "presumably in -wal mode",
1611
                         m_pszFilename);
1612
                m_osFilenameForSQLiteOpen = m_pszFilename;
1✔
1613
                continue;
1✔
1614
            }
1615
        }
1616
#endif
1617
        break;
3,343✔
1618
    }
1619

1620
    if ((flagsIn & SQLITE_OPEN_CREATE) == 0)
3,343✔
1621
    {
1622
        if (CPLTestBool(CPLGetConfigOption("OGR_VFK_DB_READ", "NO")))
2,145✔
1623
        {
1624
            if (SQLGetInteger(hDB,
1✔
1625
                              "SELECT 1 FROM sqlite_master "
1626
                              "WHERE type = 'table' AND name = 'vfk_tables'",
1627
                              nullptr))
1✔
1628
                return false; /* DB is valid VFK datasource */
4✔
1629
        }
1630

1631
        int nRowCount = 0, nColCount = 0;
2,144✔
1632
        char **papszResult = nullptr;
2,144✔
1633
        char *pszErrMsg = nullptr;
2,144✔
1634
        int rc =
1635
            sqlite3_get_table(hDB,
2,144✔
1636
                              "SELECT 1 FROM sqlite_master "
1637
                              "WHERE (type = 'trigger' OR type = 'view') AND ("
1638
                              "sql LIKE '%%ogr_geocode%%' OR "
1639
                              "sql LIKE '%%ogr_datasource_load_layers%%' OR "
1640
                              "sql LIKE '%%ogr_GetConfigOption%%' OR "
1641
                              "sql LIKE '%%ogr_SetConfigOption%%' ) "
1642
                              "LIMIT 1",
1643
                              &papszResult, &nRowCount, &nColCount, &pszErrMsg);
1644
        if (rc != SQLITE_OK)
2,144✔
1645
        {
1646
            bool bIsWAL = false;
3✔
1647
            VSILFILE *fp = VSIFOpenL(m_pszFilename, "rb");
3✔
1648
            if (fp != nullptr)
3✔
1649
            {
1650
                GByte byVal = 0;
3✔
1651
                VSIFSeekL(fp, 18, SEEK_SET);
3✔
1652
                VSIFReadL(&byVal, 1, 1, fp);
3✔
1653
                bIsWAL = byVal == 2;
3✔
1654
                VSIFCloseL(fp);
3✔
1655
            }
1656
            if (bIsWAL)
3✔
1657
            {
1658
#ifdef SQLITE_OPEN_URI
1659
                if (pszImmutable == nullptr &&
5✔
1660
                    (flags & SQLITE_OPEN_READONLY) != 0 &&
4✔
1661
                    m_osFilenameForSQLiteOpen == m_pszFilename)
1✔
1662
                {
1663
                    CPLError(CE_Warning, CPLE_AppDefined,
1✔
1664
                             "%s: this file is a WAL-enabled database. "
1665
                             "It cannot be opened "
1666
                             "because it is presumably read-only or in a "
1667
                             "read-only directory. Retrying with IMMUTABLE=YES "
1668
                             "open option",
1669
                             pszErrMsg);
1670
                    sqlite3_free(pszErrMsg);
1✔
1671
                    CloseDB();
1✔
1672
                    m_osFilenameForSQLiteOpen.clear();
1✔
1673
                    papszOpenOptions =
1✔
1674
                        CSLSetNameValue(papszOpenOptions, "IMMUTABLE", "YES");
1✔
1675
                    return OpenOrCreateDB(flagsIn,
1✔
1676
                                          bRegisterOGR2SQLiteExtensions,
1677
                                          bLoadExtensions);
1✔
1678
                }
1679
#endif
1680

1681
                CPLError(CE_Failure, CPLE_AppDefined,
2✔
1682
                         "%s: this file is a WAL-enabled database. "
1683
                         "It cannot be opened "
1684
                         "because it is presumably read-only or in a "
1685
                         "read-only directory.%s",
1686
                         pszErrMsg,
1687
#ifdef SQLITE_OPEN_URI
1688
                         pszImmutable != nullptr
1689
                             ? ""
1690
                             : " Try opening with IMMUTABLE=YES open option"
1691
#else
1692
                         ""
1693
#endif
1694
                );
1695
            }
1696
            else
1697
            {
1698
                CPLError(CE_Failure, CPLE_AppDefined, "%s", pszErrMsg);
×
1699
            }
1700
            sqlite3_free(pszErrMsg);
2✔
1701
            return false;
2✔
1702
        }
1703

1704
        sqlite3_free_table(papszResult);
2,141✔
1705

1706
        if (nRowCount > 0)
2,141✔
1707
        {
1708
            if (!CPLTestBool(CPLGetConfigOption(
×
1709
                    "ALLOW_OGR_SQL_FUNCTIONS_FROM_TRIGGER_AND_VIEW", "NO")))
1710
            {
1711
                CPLError(CE_Failure, CPLE_OpenFailed, "%s",
×
1712
                         "A trigger and/or view calls a OGR extension SQL "
1713
                         "function that could be used to "
1714
                         "steal data, or use network bandwidth, without your "
1715
                         "consent.\n"
1716
                         "The database will not be opened unless the "
1717
                         "ALLOW_OGR_SQL_FUNCTIONS_FROM_TRIGGER_AND_VIEW "
1718
                         "configuration option to YES.");
1719
                return false;
×
1720
            }
1721
        }
1722
    }
1723

1724
    if (m_osFilenameForSQLiteOpen != m_pszFilename &&
3,347✔
1725
        (m_osFilenameForSQLiteOpen.find("?nolock=1") != std::string::npos ||
8✔
1726
         m_osFilenameForSQLiteOpen.find("&nolock=1") != std::string::npos))
2✔
1727
    {
1728
        m_bNoLock = true;
4✔
1729
        CPLDebug("SQLite", "%s open in nolock mode", m_pszFilename);
4✔
1730
    }
1731

1732
    if (!bPageSizeFound && (flagsIn & SQLITE_OPEN_CREATE) != 0)
3,339✔
1733
    {
1734
        // Since sqlite 3.12 the default page_size is now 4096. But we
1735
        // can use that even with older versions.
1736
        CPL_IGNORE_RET_VAL(sqlite3_exec(hDB, "PRAGMA page_size = 4096", nullptr,
1,198✔
1737
                                        nullptr, nullptr));
1738
    }
1739

1740
    // journal_mode = WAL must be done *AFTER* changing page size.
1741
    if (!osJournalMode.empty())
3,339✔
1742
    {
1743
        const char *pszSQL =
1744
            CPLSPrintf("PRAGMA journal_mode = %s", osJournalMode.c_str());
2✔
1745

1746
        CPL_IGNORE_RET_VAL(
2✔
1747
            sqlite3_exec(hDB, pszSQL, nullptr, nullptr, nullptr));
2✔
1748
    }
1749

1750
    if (!bSecureDeleteFound)
3,339✔
1751
    {
1752
        // Turn on secure_delete by default (unless the user specifies a
1753
        // value of this pragma through OGR_SQLITE_PRAGMA)
1754
        // For example, Debian and Conda-Forge SQLite3 builds already turn on
1755
        // secure_delete.
1756
        CPL_IGNORE_RET_VAL(sqlite3_exec(hDB, "PRAGMA secure_delete = 1",
3,338✔
1757
                                        nullptr, nullptr, nullptr));
1758
    }
1759

1760
    SetCacheSize();
3,339✔
1761
    SetSynchronous();
3,339✔
1762
    if (bLoadExtensions)
3,339✔
1763
        LoadExtensions();
2,068✔
1764

1765
    return true;
3,339✔
1766
}
1767

1768
/************************************************************************/
1769
/*                            OpenOrCreateDB()                          */
1770
/************************************************************************/
1771

1772
bool OGRSQLiteDataSource::OpenOrCreateDB(int flagsIn,
1,274✔
1773
                                         bool bRegisterOGR2SQLiteExtensions)
1774
{
1775
    {
1776
        // Make sure that OGR2SQLITE_static_register() doesn't instantiate
1777
        // its default OGR2SQLITEModule. Let's do it ourselves just afterwards
1778
        //
1779
        CPLConfigOptionSetter oSetter("OGR_SQLITE_STATIC_VIRTUAL_OGR", "NO",
1780
                                      false);
1,274✔
1781
        if (!OGRSQLiteBaseDataSource::OpenOrCreateDB(
1,274✔
1782
                flagsIn, bRegisterOGR2SQLiteExtensions,
1783
                /*bLoadExtensions=*/false))
1784
        {
1785
            return false;
3✔
1786
        }
1787
    }
1788
    if (bRegisterOGR2SQLiteExtensions &&
2,542✔
1789
        // Do not run OGR2SQLITE_Setup() if called from ogrsqlitexecute.sql
1790
        // that will do it with other datasets.
1791
        CPLTestBool(CPLGetConfigOption("OGR_SQLITE_STATIC_VIRTUAL_OGR", "YES")))
1,271✔
1792
    {
1793
        // Make sure this is done before registering our custom functions
1794
        // to allow overriding Spatialite.
1795
        InitSpatialite();
628✔
1796

1797
        m_poSQLiteModule = OGR2SQLITE_Setup(this, this);
628✔
1798
    }
1799
    // We need to do LoadExtensions() after OGR2SQLITE_Setup(), otherwise
1800
    // tests in ogr_virtualogr.py::test_ogr_sqlite_load_extensions_load_self()
1801
    // will crash when trying to load libgdal as an extension (which is an
1802
    // errour we catch, but only if OGR2SQLITEModule has been created by
1803
    // above OGR2SQLITE_Setup()
1804
    LoadExtensions();
1,271✔
1805

1806
    const char *pszPreludeStatements =
1807
        CSLFetchNameValue(papszOpenOptions, "PRELUDE_STATEMENTS");
1,271✔
1808
    if (pszPreludeStatements)
1,271✔
1809
    {
1810
        if (SQLCommand(hDB, pszPreludeStatements) != OGRERR_NONE)
1✔
1811
            return false;
×
1812
    }
1813

1814
    return true;
1,271✔
1815
}
1816

1817
/************************************************************************/
1818
/*                       PostInitSpatialite()                           */
1819
/************************************************************************/
1820

1821
void OGRSQLiteDataSource::PostInitSpatialite()
969✔
1822
{
1823
#ifdef HAVE_SPATIALITE
1824
    const char *pszSqlitePragma =
1825
        CPLGetConfigOption("OGR_SQLITE_PRAGMA", nullptr);
969✔
1826
    OGRErr eErr = OGRERR_NONE;
969✔
1827
    if ((!pszSqlitePragma || !strstr(pszSqlitePragma, "trusted_schema")) &&
×
1828
        // Older sqlite versions don't have this pragma
1829
        SQLGetInteger(hDB, "PRAGMA trusted_schema", &eErr) == 0 &&
1,936✔
1830
        eErr == OGRERR_NONE)
967✔
1831
    {
1832
        // Spatialite <= 5.1.0 doesn't declare its functions as SQLITE_INNOCUOUS
1833
        if (IsSpatialiteLoaded() && SpatialiteRequiresTrustedSchemaOn() &&
1,934✔
1834
            AreSpatialiteTriggersSafe())
967✔
1835
        {
1836
            CPLDebug("SQLITE", "Setting PRAGMA trusted_schema = 1");
967✔
1837
            SQLCommand(hDB, "PRAGMA trusted_schema = 1");
967✔
1838
        }
1839
    }
1840
#endif
1841
}
969✔
1842

1843
/************************************************************************/
1844
/*                 SpatialiteRequiresTrustedSchemaOn()                  */
1845
/************************************************************************/
1846

1847
bool OGRSQLiteBaseDataSource::SpatialiteRequiresTrustedSchemaOn()
968✔
1848
{
1849
#ifdef HAVE_SPATIALITE
1850
    // Spatialite <= 5.1.0 doesn't declare its functions as SQLITE_INNOCUOUS
1851
    if (GetSpatialiteVersionNumber() <= MakeSpatialiteVersionNumber(5, 1, 0))
968✔
1852
    {
1853
        return true;
968✔
1854
    }
1855
#endif
1856
    return false;
×
1857
}
1858

1859
/************************************************************************/
1860
/*                    AreSpatialiteTriggersSafe()                       */
1861
/************************************************************************/
1862

1863
bool OGRSQLiteBaseDataSource::AreSpatialiteTriggersSafe()
968✔
1864
{
1865
#ifdef HAVE_SPATIALITE
1866
    // Not totally sure about the minimum spatialite version, but 4.3a is fine
1867
    return GetSpatialiteVersionNumber() >=
968✔
1868
               MakeSpatialiteVersionNumber(4, 3, 0) &&
1,936✔
1869
           SQLGetInteger(hDB, "SELECT CountUnsafeTriggers()", nullptr) == 0;
1,936✔
1870
#else
1871
    return true;
1872
#endif
1873
}
1874

1875
/************************************************************************/
1876
/*                          GetInternalHandle()                         */
1877
/************************************************************************/
1878

1879
/* Used by MBTILES driver */
1880
void *OGRSQLiteBaseDataSource::GetInternalHandle(const char *pszKey)
60✔
1881
{
1882
    if (pszKey != nullptr && EQUAL(pszKey, "SQLITE_HANDLE"))
60✔
1883
        return hDB;
60✔
1884
    return nullptr;
×
1885
}
1886

1887
/************************************************************************/
1888
/*                               Create()                               */
1889
/************************************************************************/
1890

1891
bool OGRSQLiteDataSource::Create(const char *pszNameIn, char **papszOptions)
356✔
1892
{
1893
    CPLString osCommand;
712✔
1894

1895
    const bool bUseTempFile =
1896
        CPLTestBool(CPLGetConfigOption(
356✔
1897
            "CPL_VSIL_USE_TEMP_FILE_FOR_RANDOM_WRITE", "NO")) &&
357✔
1898
        (VSIHasOptimizedReadMultiRange(pszNameIn) != FALSE ||
1✔
1899
         EQUAL(
1✔
1900
             CPLGetConfigOption("CPL_VSIL_USE_TEMP_FILE_FOR_RANDOM_WRITE", ""),
1901
             "FORCED"));
356✔
1902

1903
    if (bUseTempFile)
356✔
1904
    {
1905
        m_osFinalFilename = pszNameIn;
1✔
1906
        m_pszFilename = CPLStrdup(
1✔
1907
            CPLGenerateTempFilenameSafe(CPLGetFilename(pszNameIn)).c_str());
2✔
1908
        CPLDebug("SQLITE", "Creating temporary file %s", m_pszFilename);
1✔
1909
    }
1910
    else
1911
    {
1912
        m_pszFilename = CPLStrdup(pszNameIn);
355✔
1913
    }
1914

1915
    /* -------------------------------------------------------------------- */
1916
    /*      Check that spatialite extensions are loaded if required to      */
1917
    /*      create a spatialite database                                    */
1918
    /* -------------------------------------------------------------------- */
1919
    const bool bSpatialite = CPLFetchBool(papszOptions, "SPATIALITE", false);
356✔
1920
    const bool bMetadata = CPLFetchBool(papszOptions, "METADATA", true);
356✔
1921

1922
    if (bSpatialite)
1923
    {
1924
#ifndef HAVE_SPATIALITE
1925
        CPLError(
1926
            CE_Failure, CPLE_NotSupported,
1927
            "OGR was built without libspatialite support\n"
1928
            "... sorry, creating/writing any SpatiaLite DB is unsupported\n");
1929

1930
        return false;
1931
#endif
1932
    }
1933

1934
    m_bIsSpatiaLiteDB = bSpatialite;
356✔
1935

1936
    /* -------------------------------------------------------------------- */
1937
    /*      Create the database file.                                       */
1938
    /* -------------------------------------------------------------------- */
1939
    if (!OpenOrCreateDB(SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, true))
356✔
1940
        return false;
2✔
1941

1942
    /* -------------------------------------------------------------------- */
1943
    /*      Create the SpatiaLite metadata tables.                          */
1944
    /* -------------------------------------------------------------------- */
1945
    if (bSpatialite)
354✔
1946
    {
1947
        if (!InitSpatialite())
48✔
1948
        {
1949
            CPLError(CE_Failure, CPLE_NotSupported,
×
1950
                     "Creating a Spatialite database, but Spatialite "
1951
                     "extensions are not loaded.");
1952
            return false;
×
1953
        }
1954

1955
        PostInitSpatialite();
48✔
1956

1957
#ifdef HAVE_RASTERLITE2
1958
        InitRasterLite2();
1959
#endif
1960

1961
        /*
1962
        / SpatiaLite full support: calling InitSpatialMetadata()
1963
        /
1964
        / IMPORTANT NOTICE: on SpatiaLite any attempt aimed
1965
        / to directly CREATE "geometry_columns" and "spatial_ref_sys"
1966
        / [by-passing InitSpatialMetadata() as absolutely required]
1967
        / will severely [and irremediably] corrupt the DB !!!
1968
        */
1969

1970
        const char *pszVal = CSLFetchNameValue(papszOptions, "INIT_WITH_EPSG");
48✔
1971
        const int nSpatialiteVersionNumber = GetSpatialiteVersionNumber();
48✔
1972
        if (pszVal != nullptr && !CPLTestBool(pszVal) &&
49✔
1973
            nSpatialiteVersionNumber >= MakeSpatialiteVersionNumber(4, 0, 0))
1✔
1974
        {
1975
            if (nSpatialiteVersionNumber >=
1✔
1976
                MakeSpatialiteVersionNumber(4, 1, 0))
1✔
1977
                osCommand = "SELECT InitSpatialMetadata(1, 'NONE')";
1✔
1978
            else
1979
                osCommand = "SELECT InitSpatialMetadata('NONE')";
×
1980
        }
1981
        else
1982
        {
1983
            /* Since spatialite 4.1, InitSpatialMetadata() is no longer run */
1984
            /* into a transaction, which makes population of spatial_ref_sys */
1985
            /* from EPSG awfully slow. We have to use InitSpatialMetadata(1) */
1986
            /* to run within a transaction */
1987
            if (nSpatialiteVersionNumber >= 41)
47✔
1988
                osCommand = "SELECT InitSpatialMetadata(1)";
47✔
1989
            else
1990
                osCommand = "SELECT InitSpatialMetadata()";
×
1991
        }
1992
        if (SQLCommand(hDB, osCommand) != OGRERR_NONE)
48✔
1993
        {
1994
            return false;
×
1995
        }
1996
    }
1997

1998
    /* -------------------------------------------------------------------- */
1999
    /*  Create the geometry_columns and spatial_ref_sys metadata tables.    */
2000
    /* -------------------------------------------------------------------- */
2001
    else if (bMetadata)
306✔
2002
    {
2003
        if (SQLCommand(hDB, "CREATE TABLE geometry_columns ("
297✔
2004
                            "     f_table_name VARCHAR, "
2005
                            "     f_geometry_column VARCHAR, "
2006
                            "     geometry_type INTEGER, "
2007
                            "     coord_dimension INTEGER, "
2008
                            "     srid INTEGER,"
2009
                            "     geometry_format VARCHAR )"
2010
                            ";"
2011
                            "CREATE TABLE spatial_ref_sys        ("
2012
                            "     srid INTEGER UNIQUE,"
2013
                            "     auth_name TEXT,"
2014
                            "     auth_srid TEXT,"
2015
                            "     srtext TEXT)") != OGRERR_NONE)
297✔
2016
        {
2017
            return false;
×
2018
        }
2019
    }
2020

2021
    /* -------------------------------------------------------------------- */
2022
    /*      Optionally initialize the content of the spatial_ref_sys table  */
2023
    /*      with the EPSG database                                          */
2024
    /* -------------------------------------------------------------------- */
2025
    if ((bSpatialite || bMetadata) &&
699✔
2026
        CPLFetchBool(papszOptions, "INIT_WITH_EPSG", false))
345✔
2027
    {
2028
        if (!InitWithEPSG())
2✔
2029
            return false;
×
2030
    }
2031

2032
    GDALOpenInfo oOpenInfo(m_pszFilename, GDAL_OF_VECTOR | GDAL_OF_UPDATE);
708✔
2033
    return Open(&oOpenInfo);
354✔
2034
}
2035

2036
/************************************************************************/
2037
/*                           InitWithEPSG()                             */
2038
/************************************************************************/
2039

2040
bool OGRSQLiteDataSource::InitWithEPSG()
2✔
2041
{
2042
    CPLString osCommand;
4✔
2043

2044
    if (m_bIsSpatiaLiteDB)
2✔
2045
    {
2046
        /*
2047
        / if v.2.4.0 (or any subsequent) InitWithEPSG make no sense at all
2048
        / because the EPSG dataset is already self-initialized at DB creation
2049
        */
2050
        int iSpatialiteVersion = GetSpatialiteVersionNumber();
1✔
2051
        if (iSpatialiteVersion >= MakeSpatialiteVersionNumber(2, 4, 0))
1✔
2052
            return true;
1✔
2053
    }
2054

2055
    if (SoftStartTransaction() != OGRERR_NONE)
1✔
2056
        return false;
×
2057

2058
    OGRSpatialReference oSRS;
2✔
2059
    int rc = SQLITE_OK;
1✔
2060
    for (int i = 0; i < 2 && rc == SQLITE_OK; i++)
3✔
2061
    {
2062
        PROJ_STRING_LIST crsCodeList = proj_get_codes_from_database(
2✔
2063
            OSRGetProjTLSContext(), "EPSG",
2064
            i == 0 ? PJ_TYPE_GEOGRAPHIC_2D_CRS : PJ_TYPE_PROJECTED_CRS, true);
2065
        for (auto iterCode = crsCodeList; iterCode && *iterCode; ++iterCode)
5,670✔
2066
        {
2067
            int nSRSId = atoi(*iterCode);
5,668✔
2068

2069
            CPLPushErrorHandler(CPLQuietErrorHandler);
5,668✔
2070
            oSRS.importFromEPSG(nSRSId);
5,668✔
2071
            CPLPopErrorHandler();
5,668✔
2072

2073
            if (m_bIsSpatiaLiteDB)
5,668✔
2074
            {
2075
                char *pszProj4 = nullptr;
×
2076

2077
                CPLPushErrorHandler(CPLQuietErrorHandler);
×
2078
                OGRErr eErr = oSRS.exportToProj4(&pszProj4);
×
2079

2080
                char *pszWKT = nullptr;
×
2081
                if (eErr == OGRERR_NONE &&
×
2082
                    oSRS.exportToWkt(&pszWKT) != OGRERR_NONE)
×
2083
                {
2084
                    CPLFree(pszWKT);
×
2085
                    pszWKT = nullptr;
×
2086
                    eErr = OGRERR_FAILURE;
×
2087
                }
2088
                CPLPopErrorHandler();
×
2089

2090
                if (eErr == OGRERR_NONE)
×
2091
                {
2092
                    const char *pszProjCS = oSRS.GetAttrValue("PROJCS");
×
2093
                    if (pszProjCS == nullptr)
×
2094
                        pszProjCS = oSRS.GetAttrValue("GEOGCS");
×
2095

2096
                    const char *pszSRTEXTColName = GetSRTEXTColName();
×
2097
                    if (pszSRTEXTColName != nullptr)
×
2098
                    {
2099
                        /* the SPATIAL_REF_SYS table supports a SRS_WKT column
2100
                         */
2101
                        if (pszProjCS)
×
2102
                            osCommand.Printf(
2103
                                "INSERT INTO spatial_ref_sys "
2104
                                "(srid, auth_name, auth_srid, ref_sys_name, "
2105
                                "proj4text, %s) "
2106
                                "VALUES (%d, 'EPSG', '%d', ?, ?, ?)",
2107
                                pszSRTEXTColName, nSRSId, nSRSId);
×
2108
                        else
2109
                            osCommand.Printf(
2110
                                "INSERT INTO spatial_ref_sys "
2111
                                "(srid, auth_name, auth_srid, proj4text, %s) "
2112
                                "VALUES (%d, 'EPSG', '%d', ?, ?)",
2113
                                pszSRTEXTColName, nSRSId, nSRSId);
×
2114
                    }
2115
                    else
2116
                    {
2117
                        /* the SPATIAL_REF_SYS table does not support a SRS_WKT
2118
                         * column */
2119
                        if (pszProjCS)
×
2120
                            osCommand.Printf("INSERT INTO spatial_ref_sys "
2121
                                             "(srid, auth_name, auth_srid, "
2122
                                             "ref_sys_name, proj4text) "
2123
                                             "VALUES (%d, 'EPSG', '%d', ?, ?)",
2124
                                             nSRSId, nSRSId);
×
2125
                        else
2126
                            osCommand.Printf(
2127
                                "INSERT INTO spatial_ref_sys "
2128
                                "(srid, auth_name, auth_srid, proj4text) "
2129
                                "VALUES (%d, 'EPSG', '%d', ?)",
2130
                                nSRSId, nSRSId);
×
2131
                    }
2132

2133
                    sqlite3_stmt *hInsertStmt = nullptr;
×
2134
                    rc = prepareSql(hDB, osCommand, -1, &hInsertStmt, nullptr);
×
2135

2136
                    if (pszProjCS)
×
2137
                    {
2138
                        if (rc == SQLITE_OK)
×
2139
                            rc = sqlite3_bind_text(hInsertStmt, 1, pszProjCS,
×
2140
                                                   -1, SQLITE_STATIC);
2141
                        if (rc == SQLITE_OK)
×
2142
                            rc = sqlite3_bind_text(hInsertStmt, 2, pszProj4, -1,
×
2143
                                                   SQLITE_STATIC);
2144
                        if (pszSRTEXTColName != nullptr)
×
2145
                        {
2146
                            /* the SPATIAL_REF_SYS table supports a SRS_WKT
2147
                             * column */
2148
                            if (rc == SQLITE_OK && pszWKT != nullptr)
×
2149
                                rc = sqlite3_bind_text(hInsertStmt, 3, pszWKT,
×
2150
                                                       -1, SQLITE_STATIC);
2151
                        }
2152
                    }
2153
                    else
2154
                    {
2155
                        if (rc == SQLITE_OK)
×
2156
                            rc = sqlite3_bind_text(hInsertStmt, 1, pszProj4, -1,
×
2157
                                                   SQLITE_STATIC);
2158
                        if (pszSRTEXTColName != nullptr)
×
2159
                        {
2160
                            /* the SPATIAL_REF_SYS table supports a SRS_WKT
2161
                             * column */
2162
                            if (rc == SQLITE_OK && pszWKT != nullptr)
×
2163
                                rc = sqlite3_bind_text(hInsertStmt, 2, pszWKT,
×
2164
                                                       -1, SQLITE_STATIC);
2165
                        }
2166
                    }
2167

2168
                    if (rc == SQLITE_OK)
×
2169
                        rc = sqlite3_step(hInsertStmt);
×
2170

2171
                    if (rc != SQLITE_OK && rc != SQLITE_DONE)
×
2172
                    {
2173
                        CPLError(CE_Failure, CPLE_AppDefined,
×
2174
                                 "Cannot insert %s into spatial_ref_sys : %s",
2175
                                 pszProj4, sqlite3_errmsg(hDB));
2176

2177
                        sqlite3_finalize(hInsertStmt);
×
2178
                        CPLFree(pszProj4);
×
2179
                        CPLFree(pszWKT);
×
2180
                        break;
×
2181
                    }
2182
                    rc = SQLITE_OK;
×
2183

2184
                    sqlite3_finalize(hInsertStmt);
×
2185
                }
2186

2187
                CPLFree(pszProj4);
×
2188
                CPLFree(pszWKT);
×
2189
            }
2190
            else
2191
            {
2192
                char *pszWKT = nullptr;
5,668✔
2193
                CPLPushErrorHandler(CPLQuietErrorHandler);
5,668✔
2194
                bool bSuccess = (oSRS.exportToWkt(&pszWKT) == OGRERR_NONE);
5,668✔
2195
                CPLPopErrorHandler();
5,668✔
2196
                if (bSuccess)
5,668✔
2197
                {
2198
                    osCommand.Printf("INSERT INTO spatial_ref_sys "
2199
                                     "(srid, auth_name, auth_srid, srtext) "
2200
                                     "VALUES (%d, 'EPSG', '%d', ?)",
2201
                                     nSRSId, nSRSId);
5,668✔
2202

2203
                    sqlite3_stmt *hInsertStmt = nullptr;
5,668✔
2204
                    rc = prepareSql(hDB, osCommand, -1, &hInsertStmt, nullptr);
5,668✔
2205

2206
                    if (rc == SQLITE_OK)
5,668✔
2207
                        rc = sqlite3_bind_text(hInsertStmt, 1, pszWKT, -1,
5,668✔
2208
                                               SQLITE_STATIC);
2209

2210
                    if (rc == SQLITE_OK)
5,668✔
2211
                        rc = sqlite3_step(hInsertStmt);
5,668✔
2212

2213
                    if (rc != SQLITE_OK && rc != SQLITE_DONE)
5,668✔
2214
                    {
2215
                        CPLError(CE_Failure, CPLE_AppDefined,
×
2216
                                 "Cannot insert %s into spatial_ref_sys : %s",
2217
                                 pszWKT, sqlite3_errmsg(hDB));
2218

2219
                        sqlite3_finalize(hInsertStmt);
×
2220
                        CPLFree(pszWKT);
×
2221
                        break;
×
2222
                    }
2223
                    rc = SQLITE_OK;
5,668✔
2224

2225
                    sqlite3_finalize(hInsertStmt);
5,668✔
2226
                }
2227

2228
                CPLFree(pszWKT);
5,668✔
2229
            }
2230
        }
2231

2232
        proj_string_list_destroy(crsCodeList);
2✔
2233
    }
2234

2235
    if (rc == SQLITE_OK)
1✔
2236
    {
2237
        if (SoftCommitTransaction() != OGRERR_NONE)
1✔
2238
            return false;
×
2239
        return true;
1✔
2240
    }
2241
    else
2242
    {
2243
        SoftRollbackTransaction();
×
2244
        return false;
×
2245
    }
2246
}
2247

2248
/************************************************************************/
2249
/*                        ReloadLayers()                                */
2250
/************************************************************************/
2251

2252
void OGRSQLiteDataSource::ReloadLayers()
641✔
2253
{
2254
    m_apoLayers.clear();
641✔
2255

2256
    GDALOpenInfo oOpenInfo(m_pszFilename,
641✔
2257
                           GDAL_OF_VECTOR | (GetUpdate() ? GDAL_OF_UPDATE : 0));
1,282✔
2258
    Open(&oOpenInfo);
641✔
2259
}
641✔
2260

2261
/************************************************************************/
2262
/*                                Open()                                */
2263
/************************************************************************/
2264

2265
bool OGRSQLiteDataSource::Open(GDALOpenInfo *poOpenInfo)
1,915✔
2266

2267
{
2268
    const char *pszNewName = poOpenInfo->pszFilename;
1,915✔
2269
    CPLAssert(m_apoLayers.empty());
1,915✔
2270
    eAccess = poOpenInfo->eAccess;
1,915✔
2271
    nOpenFlags = poOpenInfo->nOpenFlags & ~GDAL_OF_THREAD_SAFE;
1,915✔
2272
    SetDescription(pszNewName);
1,915✔
2273

2274
    if (m_pszFilename == nullptr)
1,915✔
2275
    {
2276
#ifdef HAVE_RASTERLITE2
2277
        if (STARTS_WITH_CI(pszNewName, "RASTERLITE2:") &&
2278
            (nOpenFlags & GDAL_OF_RASTER) != 0)
2279
        {
2280
            char **papszTokens =
2281
                CSLTokenizeString2(pszNewName, ":", CSLT_HONOURSTRINGS);
2282
            if (CSLCount(papszTokens) < 2)
2283
            {
2284
                CSLDestroy(papszTokens);
2285
                return false;
2286
            }
2287
            m_pszFilename = CPLStrdup(SQLUnescape(papszTokens[1]));
2288
            CSLDestroy(papszTokens);
2289
        }
2290
        else
2291
#endif
2292
            if (STARTS_WITH_CI(pszNewName, "SQLITE:"))
920✔
2293
        {
2294
            m_pszFilename = CPLStrdup(pszNewName + strlen("SQLITE:"));
78✔
2295
        }
2296
        else
2297
        {
2298
            m_pszFilename = CPLStrdup(pszNewName);
842✔
2299
            if (poOpenInfo->pabyHeader &&
842✔
2300
                STARTS_WITH(
805✔
2301
                    reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
2302
                    "SQLite format 3"))
2303
            {
2304
                m_bCallUndeclareFileNotToOpen = true;
804✔
2305
                GDALOpenInfoDeclareFileNotToOpen(m_pszFilename,
804✔
2306
                                                 poOpenInfo->pabyHeader,
804✔
2307
                                                 poOpenInfo->nHeaderBytes);
2308
            }
2309
        }
2310
    }
2311
    SetPhysicalFilename(m_pszFilename);
1,915✔
2312

2313
    VSIStatBufL sStat;
2314
    if (VSIStatL(m_pszFilename, &sStat) == 0)
1,915✔
2315
    {
2316
        m_nFileTimestamp = sStat.st_mtime;
1,859✔
2317
    }
2318

2319
    if (poOpenInfo->papszOpenOptions)
1,915✔
2320
    {
2321
        CSLDestroy(papszOpenOptions);
11✔
2322
        papszOpenOptions = CSLDuplicate(poOpenInfo->papszOpenOptions);
11✔
2323
    }
2324

2325
    const bool bListVectorLayers = (nOpenFlags & GDAL_OF_VECTOR) != 0;
1,915✔
2326

2327
    const bool bListAllTables =
2328
        bListVectorLayers &&
3,830✔
2329
        CPLTestBool(CSLFetchNameValueDef(
3,830✔
2330
            papszOpenOptions, "LIST_ALL_TABLES",
1,915✔
2331
            CPLGetConfigOption("SQLITE_LIST_ALL_TABLES", "NO")));
1,915✔
2332

2333
    // Don't list by default: there might be some security implications
2334
    // if a user is provided with a file and doesn't know that there are
2335
    // virtual OGR tables in it.
2336
    const bool bListVirtualOGRLayers =
2337
        bListVectorLayers &&
3,830✔
2338
        CPLTestBool(CSLFetchNameValueDef(
3,830✔
2339
            papszOpenOptions, "LIST_VIRTUAL_OGR",
1,915✔
2340
            CPLGetConfigOption("OGR_SQLITE_LIST_VIRTUAL_OGR", "NO")));
1,915✔
2341

2342
    /* -------------------------------------------------------------------- */
2343
    /*      Try to open the sqlite database properly now.                   */
2344
    /* -------------------------------------------------------------------- */
2345
    if (hDB == nullptr)
1,915✔
2346
    {
2347
#ifdef ENABLE_SQL_SQLITE_FORMAT
2348
        // SQLite -wal locking appears to be extremely fragile. In particular
2349
        // if we have a file descriptor opened on the file while sqlite3_open
2350
        // is called, then it will mis-behave (a process opening in update mode
2351
        // the file and closing it will remove the -wal file !)
2352
        // So make sure that the GDALOpenInfo object goes out of scope before
2353
        // going on.
2354
        {
2355
            GDALOpenInfo oOpenInfo(m_pszFilename, GA_ReadOnly);
920✔
2356
            if (oOpenInfo.pabyHeader &&
920✔
2357
                (STARTS_WITH(
883✔
2358
                     reinterpret_cast<const char *>(oOpenInfo.pabyHeader),
2359
                     "-- SQL SQLITE") ||
882✔
2360
                 STARTS_WITH(
882✔
2361
                     reinterpret_cast<const char *>(oOpenInfo.pabyHeader),
2362
                     "-- SQL RASTERLITE") ||
882✔
2363
                 STARTS_WITH(
882✔
2364
                     reinterpret_cast<const char *>(oOpenInfo.pabyHeader),
2365
                     "-- SQL MBTILES")) &&
2✔
2366
                oOpenInfo.fpL != nullptr)
2✔
2367
            {
2368
                if (sqlite3_open_v2(":memory:", &hDB, SQLITE_OPEN_READWRITE,
2✔
2369
                                    nullptr) != SQLITE_OK)
2✔
2370
                {
2371
                    return false;
×
2372
                }
2373

2374
                // We need it here for ST_MinX() and the like
2375
                InitSpatialite();
2✔
2376

2377
                PostInitSpatialite();
2✔
2378

2379
                // Ingest the lines of the dump
2380
                VSIFSeekL(oOpenInfo.fpL, 0, SEEK_SET);
2✔
2381
                const char *pszLine;
2382
                while ((pszLine = CPLReadLineL(oOpenInfo.fpL)) != nullptr)
24✔
2383
                {
2384
                    if (STARTS_WITH(pszLine, "--"))
22✔
2385
                        continue;
2✔
2386

2387
                    if (!SQLCheckLineIsSafe(pszLine))
20✔
2388
                        return false;
×
2389

2390
                    char *pszErrMsg = nullptr;
20✔
2391
                    if (sqlite3_exec(hDB, pszLine, nullptr, nullptr,
20✔
2392
                                     &pszErrMsg) != SQLITE_OK)
20✔
2393
                    {
2394
                        if (pszErrMsg)
×
2395
                        {
2396
                            CPLDebug("SQLITE", "Error %s at line %s", pszErrMsg,
×
2397
                                     pszLine);
2398
                        }
2399
                    }
2400
                    sqlite3_free(pszErrMsg);
20✔
2401
                }
2402
            }
2403
        }
2404
        if (hDB == nullptr)
920✔
2405
#endif
2406
        {
2407
            if (poOpenInfo->fpL)
918✔
2408
            {
2409
                // See above comment about -wal locking for the importance of
2410
                // closing that file, prior to calling sqlite3_open()
2411
                VSIFCloseL(poOpenInfo->fpL);
784✔
2412
                poOpenInfo->fpL = nullptr;
784✔
2413
            }
2414
            if (!OpenOrCreateDB(GetUpdate() ? SQLITE_OPEN_READWRITE
918✔
2415
                                            : SQLITE_OPEN_READONLY,
2416
                                true))
2417
            {
2418
                poOpenInfo->fpL =
1✔
2419
                    VSIFOpenL(poOpenInfo->pszFilename,
1✔
2420
                              poOpenInfo->eAccess == GA_Update ? "rb+" : "rb");
1✔
2421
                return false;
1✔
2422
            }
2423
        }
2424

2425
        InitSpatialite();
919✔
2426

2427
        PostInitSpatialite();
919✔
2428

2429
#ifdef HAVE_RASTERLITE2
2430
        InitRasterLite2();
2431
#endif
2432
    }
2433

2434
#ifdef HAVE_RASTERLITE2
2435
    if (STARTS_WITH_CI(pszNewName, "RASTERLITE2:") &&
2436
        (nOpenFlags & GDAL_OF_RASTER) != 0)
2437
    {
2438
        return OpenRasterSubDataset(pszNewName);
2439
    }
2440
#endif
2441

2442
    /* -------------------------------------------------------------------- */
2443
    /*      If we have a GEOMETRY_COLUMNS tables, initialize on the basis   */
2444
    /*      of that.                                                        */
2445
    /* -------------------------------------------------------------------- */
2446
    CPLHashSet *hSet =
2447
        CPLHashSetNew(CPLHashSetHashStr, CPLHashSetEqualStr, CPLFree);
1,914✔
2448

2449
    char **papszResult = nullptr;
1,914✔
2450
    char *pszErrMsg = nullptr;
1,914✔
2451
    int nRowCount = 0;
1,914✔
2452
    int nColCount = 0;
1,914✔
2453
    int rc = sqlite3_get_table(
1,914✔
2454
        hDB,
2455
        "SELECT f_table_name, f_geometry_column, geometry_type, "
2456
        "coord_dimension, geometry_format, srid"
2457
        " FROM geometry_columns "
2458
        "LIMIT 10000",
2459
        &papszResult, &nRowCount, &nColCount, &pszErrMsg);
2460

2461
    if (rc == SQLITE_OK)
1,914✔
2462
    {
2463
        CPLDebug("SQLITE", "OGR style SQLite DB found !");
537✔
2464

2465
        m_bHaveGeometryColumns = true;
537✔
2466

2467
        for (int iRow = 0; bListVectorLayers && iRow < nRowCount; iRow++)
777✔
2468
        {
2469
            char **papszRow = papszResult + iRow * 6 + 6;
240✔
2470
            const char *pszTableName = papszRow[0];
240✔
2471
            const char *pszGeomCol = papszRow[1];
240✔
2472

2473
            if (pszTableName == nullptr || pszGeomCol == nullptr)
240✔
2474
                continue;
×
2475

2476
            m_aoMapTableToSetOfGeomCols[pszTableName].insert(
480✔
2477
                CPLString(pszGeomCol).tolower());
240✔
2478
        }
2479

2480
        for (int iRow = 0; bListVectorLayers && iRow < nRowCount; iRow++)
774✔
2481
        {
2482
            char **papszRow = papszResult + iRow * 6 + 6;
240✔
2483
            const char *pszTableName = papszRow[0];
240✔
2484

2485
            if (pszTableName == nullptr)
240✔
2486
                continue;
×
2487

2488
            if (GDALDataset::GetLayerByName(pszTableName) == nullptr)
240✔
2489
            {
2490
                const bool bRet = OpenTable(pszTableName, true, false,
231✔
2491
                                            /* bMayEmitError = */ true);
2492
                if (!bRet)
231✔
2493
                {
2494
                    CPLDebug("SQLITE", "Failed to open layer %s", pszTableName);
3✔
2495
                    sqlite3_free_table(papszResult);
3✔
2496
                    CPLHashSetDestroy(hSet);
3✔
2497
                    return false;
3✔
2498
                }
2499
            }
2500

2501
            if (bListAllTables)
237✔
2502
                CPLHashSetInsert(hSet, CPLStrdup(pszTableName));
2✔
2503
        }
2504

2505
        sqlite3_free_table(papszResult);
534✔
2506

2507
        /* --------------------------------------------------------------------
2508
         */
2509
        /*      Detect VirtualOGR layers */
2510
        /* --------------------------------------------------------------------
2511
         */
2512
        if (bListVirtualOGRLayers)
534✔
2513
        {
2514
            rc = sqlite3_get_table(hDB,
2✔
2515
                                   "SELECT name, sql FROM sqlite_master "
2516
                                   "WHERE sql LIKE 'CREATE VIRTUAL TABLE %' "
2517
                                   "LIMIT 10000",
2518
                                   &papszResult, &nRowCount, &nColCount,
2519
                                   &pszErrMsg);
2520

2521
            if (rc == SQLITE_OK)
2✔
2522
            {
2523
                for (int iRow = 0; iRow < nRowCount; iRow++)
4✔
2524
                {
2525
                    char **papszRow = papszResult + iRow * 2 + 2;
2✔
2526
                    const char *pszName = papszRow[0];
2✔
2527
                    const char *pszSQL = papszRow[1];
2✔
2528
                    if (pszName == nullptr || pszSQL == nullptr)
2✔
2529
                        continue;
×
2530

2531
                    if (strstr(pszSQL, "VirtualOGR"))
2✔
2532
                    {
2533
                        OpenVirtualTable(pszName, pszSQL);
2✔
2534

2535
                        if (bListAllTables)
2✔
2536
                            CPLHashSetInsert(hSet, CPLStrdup(pszName));
×
2537
                    }
2538
                }
2539
            }
2540
            else
2541
            {
2542
                CPLError(CE_Failure, CPLE_AppDefined,
×
2543
                         "Unable to fetch list of tables: %s", pszErrMsg);
2544
                sqlite3_free(pszErrMsg);
×
2545
            }
2546

2547
            sqlite3_free_table(papszResult);
2✔
2548
        }
2549

2550
        if (bListAllTables)
534✔
2551
            goto all_tables;
1✔
2552

2553
        CPLHashSetDestroy(hSet);
533✔
2554

2555
        if (nOpenFlags & GDAL_OF_RASTER)
533✔
2556
        {
2557
            bool bRet = OpenRaster();
×
2558
            if (!bRet && !(nOpenFlags & GDAL_OF_VECTOR))
×
2559
                return false;
×
2560
        }
2561

2562
        return true;
533✔
2563
    }
2564

2565
    /* -------------------------------------------------------------------- */
2566
    /*      Otherwise we can deal with SpatiaLite database.                 */
2567
    /* -------------------------------------------------------------------- */
2568
    sqlite3_free(pszErrMsg);
1,377✔
2569
    rc = sqlite3_get_table(hDB,
1,377✔
2570
                           "SELECT sm.name, gc.f_geometry_column, "
2571
                           "gc.type, gc.coord_dimension, gc.srid, "
2572
                           "gc.spatial_index_enabled FROM geometry_columns gc "
2573
                           "JOIN sqlite_master sm ON "
2574
                           "LOWER(gc.f_table_name)=LOWER(sm.name) "
2575
                           "LIMIT 10000",
2576
                           &papszResult, &nRowCount, &nColCount, &pszErrMsg);
2577
    if (rc != SQLITE_OK)
1,377✔
2578
    {
2579
        /* Test with SpatiaLite 4.0 schema */
2580
        sqlite3_free(pszErrMsg);
1,371✔
2581
        rc = sqlite3_get_table(
1,371✔
2582
            hDB,
2583
            "SELECT sm.name, gc.f_geometry_column, "
2584
            "gc.geometry_type, gc.coord_dimension, gc.srid, "
2585
            "gc.spatial_index_enabled FROM geometry_columns gc "
2586
            "JOIN sqlite_master sm ON "
2587
            "LOWER(gc.f_table_name)=LOWER(sm.name) "
2588
            "LIMIT 10000",
2589
            &papszResult, &nRowCount, &nColCount, &pszErrMsg);
2590
        if (rc == SQLITE_OK)
1,371✔
2591
        {
2592
            m_bSpatialite4Layout = true;
1,150✔
2593
            m_nUndefinedSRID = 0;
1,150✔
2594
        }
2595
    }
2596

2597
    if (rc == SQLITE_OK)
1,377✔
2598
    {
2599
        m_bIsSpatiaLiteDB = true;
1,156✔
2600
        m_bHaveGeometryColumns = true;
1,156✔
2601

2602
        int iSpatialiteVersion = -1;
1,156✔
2603

2604
        /* Only enables write-mode if linked against SpatiaLite */
2605
        if (IsSpatialiteLoaded())
1,156✔
2606
        {
2607
            iSpatialiteVersion = GetSpatialiteVersionNumber();
1,156✔
2608
        }
2609
        else if (GetUpdate())
×
2610
        {
2611
            CPLError(CE_Failure, CPLE_AppDefined,
×
2612
                     "SpatiaLite%s DB found, "
2613
                     "but updating tables disabled because no linking against "
2614
                     "spatialite library !",
2615
                     (m_bSpatialite4Layout) ? " v4" : "");
×
2616
            sqlite3_free_table(papszResult);
×
2617
            CPLHashSetDestroy(hSet);
×
2618
            return false;
1,156✔
2619
        }
2620

2621
        if (m_bSpatialite4Layout && GetUpdate() && iSpatialiteVersion > 0 &&
2,275✔
2622
            iSpatialiteVersion < MakeSpatialiteVersionNumber(4, 0, 0))
1,119✔
2623
        {
2624
            CPLError(CE_Failure, CPLE_AppDefined,
×
2625
                     "SpatiaLite v4 DB found, "
2626
                     "but updating tables disabled because runtime spatialite "
2627
                     "library is v%d.%d.%d !",
2628
                     iSpatialiteVersion / 10000,
2629
                     (iSpatialiteVersion % 10000) / 100,
×
2630
                     (iSpatialiteVersion % 100));
2631
            sqlite3_free_table(papszResult);
×
2632
            CPLHashSetDestroy(hSet);
×
2633
            return false;
×
2634
        }
2635
        else
2636
        {
2637
            CPLDebug("SQLITE", "SpatiaLite%s DB found !",
1,156✔
2638
                     (m_bSpatialite4Layout) ? " v4" : "");
1,156✔
2639
        }
2640

2641
        // List RasterLite2 coverages, so as to avoid listing corresponding
2642
        // technical tables
2643
        std::set<CPLString> aoSetTablesToIgnore;
1,156✔
2644
        if (m_bSpatialite4Layout)
1,156✔
2645
        {
2646
            char **papszResults2 = nullptr;
1,150✔
2647
            int nRowCount2 = 0, nColCount2 = 0;
1,150✔
2648
            rc = sqlite3_get_table(
1,150✔
2649
                hDB,
2650
                "SELECT name FROM sqlite_master WHERE "
2651
                "type = 'table' AND name = 'raster_coverages'",
2652
                &papszResults2, &nRowCount2, &nColCount2, nullptr);
2653
            sqlite3_free_table(papszResults2);
1,150✔
2654
            if (rc == SQLITE_OK && nRowCount2 == 1)
1,150✔
2655
            {
2656
                papszResults2 = nullptr;
×
2657
                nRowCount2 = 0;
×
2658
                nColCount2 = 0;
×
2659
                rc = sqlite3_get_table(
×
2660
                    hDB,
2661
                    "SELECT coverage_name FROM raster_coverages "
2662
                    "LIMIT 10000",
2663
                    &papszResults2, &nRowCount2, &nColCount2, nullptr);
2664
                if (rc == SQLITE_OK)
×
2665
                {
2666
                    for (int i = 0; i < nRowCount2; ++i)
×
2667
                    {
2668
                        const char *const *papszRow = papszResults2 + i * 1 + 1;
×
2669
                        if (papszRow[0] != nullptr)
×
2670
                        {
2671
                            aoSetTablesToIgnore.insert(CPLString(papszRow[0]) +
×
2672
                                                       "_sections");
×
2673
                            aoSetTablesToIgnore.insert(CPLString(papszRow[0]) +
×
2674
                                                       "_tiles");
×
2675
                        }
2676
                    }
2677
                }
2678
                sqlite3_free_table(papszResults2);
×
2679
            }
2680
        }
2681

2682
        for (int iRow = 0; bListVectorLayers && iRow < nRowCount; iRow++)
1,488✔
2683
        {
2684
            char **papszRow = papszResult + iRow * 6 + 6;
332✔
2685
            const char *pszTableName = papszRow[0];
332✔
2686
            const char *pszGeomCol = papszRow[1];
332✔
2687

2688
            if (pszTableName == nullptr || pszGeomCol == nullptr)
332✔
2689
                continue;
×
2690
            if (!bListAllTables &&
664✔
2691
                cpl::contains(aoSetTablesToIgnore, pszTableName))
332✔
2692
            {
2693
                continue;
×
2694
            }
2695

2696
            m_aoMapTableToSetOfGeomCols[pszTableName].insert(
664✔
2697
                CPLString(pszGeomCol).tolower());
332✔
2698
        }
2699

2700
        for (int iRow = 0; bListVectorLayers && iRow < nRowCount; iRow++)
1,488✔
2701
        {
2702
            char **papszRow = papszResult + iRow * 6 + 6;
332✔
2703
            const char *pszTableName = papszRow[0];
332✔
2704

2705
            if (pszTableName == nullptr)
332✔
2706
                continue;
×
2707
            if (!bListAllTables &&
664✔
2708
                cpl::contains(aoSetTablesToIgnore, pszTableName))
332✔
2709
            {
2710
                continue;
×
2711
            }
2712

2713
            if (GDALDataset::GetLayerByName(pszTableName) == nullptr)
332✔
2714
                OpenTable(pszTableName, true, false,
325✔
2715
                          /* bMayEmitError = */ true);
2716
            if (bListAllTables)
332✔
2717
                CPLHashSetInsert(hSet, CPLStrdup(pszTableName));
×
2718
        }
2719

2720
        sqlite3_free_table(papszResult);
1,156✔
2721
        papszResult = nullptr;
1,156✔
2722

2723
        /* --------------------------------------------------------------------
2724
         */
2725
        /*      Detect VirtualShape, VirtualXL and VirtualOGR layers */
2726
        /* --------------------------------------------------------------------
2727
         */
2728
        rc =
2729
            sqlite3_get_table(hDB,
1,156✔
2730
                              "SELECT name, sql FROM sqlite_master "
2731
                              "WHERE sql LIKE 'CREATE VIRTUAL TABLE %' "
2732
                              "LIMIT 10000",
2733
                              &papszResult, &nRowCount, &nColCount, &pszErrMsg);
2734

2735
        if (rc == SQLITE_OK)
1,156✔
2736
        {
2737
            for (int iRow = 0; bListVectorLayers && iRow < nRowCount; iRow++)
3,850✔
2738
            {
2739
                char **papszRow = papszResult + iRow * 2 + 2;
2,694✔
2740
                const char *pszName = papszRow[0];
2,694✔
2741
                const char *pszSQL = papszRow[1];
2,694✔
2742
                if (pszName == nullptr || pszSQL == nullptr)
2,694✔
2743
                    continue;
×
2744

2745
                if ((IsSpatialiteLoaded() && (strstr(pszSQL, "VirtualShape") ||
5,388✔
2746
                                              strstr(pszSQL, "VirtualXL"))) ||
5,388✔
2747
                    (bListVirtualOGRLayers && strstr(pszSQL, "VirtualOGR")))
×
2748
                {
2749
                    OpenVirtualTable(pszName, pszSQL);
1✔
2750

2751
                    if (bListAllTables)
1✔
2752
                        CPLHashSetInsert(hSet, CPLStrdup(pszName));
×
2753
                }
2754
            }
2755
        }
2756
        else
2757
        {
2758
            CPLError(CE_Failure, CPLE_AppDefined,
×
2759
                     "Unable to fetch list of tables: %s", pszErrMsg);
2760
            sqlite3_free(pszErrMsg);
×
2761
        }
2762

2763
        sqlite3_free_table(papszResult);
1,156✔
2764
        papszResult = nullptr;
1,156✔
2765

2766
        /* --------------------------------------------------------------------
2767
         */
2768
        /*      Detect spatial views */
2769
        /* --------------------------------------------------------------------
2770
         */
2771

2772
        rc = sqlite3_get_table(hDB,
1,156✔
2773
                               "SELECT view_name, view_geometry, view_rowid, "
2774
                               "f_table_name, f_geometry_column "
2775
                               "FROM views_geometry_columns "
2776
                               "LIMIT 10000",
2777
                               &papszResult, &nRowCount, &nColCount, nullptr);
2778
        if (rc == SQLITE_OK)
1,156✔
2779
        {
2780
            for (int iRow = 0; bListVectorLayers && iRow < nRowCount; iRow++)
1,159✔
2781
            {
2782
                char **papszRow = papszResult + iRow * 5 + 5;
5✔
2783
                const char *pszViewName = papszRow[0];
5✔
2784
                const char *pszViewGeometry = papszRow[1];
5✔
2785
                const char *pszViewRowid = papszRow[2];
5✔
2786
                const char *pszTableName = papszRow[3];
5✔
2787
                const char *pszGeometryColumn = papszRow[4];
5✔
2788

2789
                if (pszViewName == nullptr || pszViewGeometry == nullptr ||
5✔
2790
                    pszViewRowid == nullptr || pszTableName == nullptr ||
5✔
2791
                    pszGeometryColumn == nullptr)
2792
                    continue;
×
2793

2794
                OpenView(pszViewName, pszViewGeometry, pszViewRowid,
5✔
2795
                         pszTableName, pszGeometryColumn);
2796

2797
                if (bListAllTables)
5✔
2798
                    CPLHashSetInsert(hSet, CPLStrdup(pszViewName));
×
2799
            }
2800
            sqlite3_free_table(papszResult);
1,154✔
2801
        }
2802

2803
        if (bListAllTables)
1,156✔
2804
            goto all_tables;
×
2805

2806
        CPLHashSetDestroy(hSet);
1,156✔
2807

2808
        if (nOpenFlags & GDAL_OF_RASTER)
1,156✔
2809
        {
2810
            bool bRet = OpenRaster();
1✔
2811
            if (!bRet && !(nOpenFlags & GDAL_OF_VECTOR))
1✔
2812
                return false;
×
2813
        }
2814

2815
        return true;
1,156✔
2816
    }
2817

2818
    /* -------------------------------------------------------------------- */
2819
    /*      Otherwise our final resort is to return all tables and views    */
2820
    /*      as non-spatial tables.                                          */
2821
    /* -------------------------------------------------------------------- */
2822
    sqlite3_free(pszErrMsg);
221✔
2823

2824
all_tables:
222✔
2825
    rc = sqlite3_get_table(hDB,
222✔
2826
                           "SELECT name, type FROM sqlite_master "
2827
                           "WHERE type IN ('table','view') "
2828
                           "UNION ALL "
2829
                           "SELECT name, type FROM sqlite_temp_master "
2830
                           "WHERE type IN ('table','view') "
2831
                           "ORDER BY 1 "
2832
                           "LIMIT 10000",
2833
                           &papszResult, &nRowCount, &nColCount, &pszErrMsg);
2834

2835
    if (rc != SQLITE_OK)
222✔
2836
    {
2837
        CPLError(CE_Failure, CPLE_AppDefined,
×
2838
                 "Unable to fetch list of tables: %s", pszErrMsg);
2839
        sqlite3_free(pszErrMsg);
×
2840
        CPLHashSetDestroy(hSet);
×
2841
        return false;
×
2842
    }
2843

2844
    for (int iRow = 0; iRow < nRowCount; iRow++)
584✔
2845
    {
2846
        const char *pszTableName = papszResult[2 * (iRow + 1) + 0];
362✔
2847
        const char *pszType = papszResult[2 * (iRow + 1) + 1];
362✔
2848
        if (pszTableName != nullptr &&
724✔
2849
            CPLHashSetLookup(hSet, pszTableName) == nullptr)
362✔
2850
        {
2851
            const bool bIsTable =
360✔
2852
                pszType != nullptr && strcmp(pszType, "table") == 0;
360✔
2853
            OpenTable(pszTableName, bIsTable, false,
360✔
2854
                      /* bMayEmitError = */ true);
2855
        }
2856
    }
2857

2858
    sqlite3_free_table(papszResult);
222✔
2859
    CPLHashSetDestroy(hSet);
222✔
2860

2861
    if (nOpenFlags & GDAL_OF_RASTER)
222✔
2862
    {
2863
        bool bRet = OpenRaster();
2✔
2864
        if (!bRet && !(nOpenFlags & GDAL_OF_VECTOR))
2✔
2865
            return false;
×
2866
    }
2867

2868
    return true;
222✔
2869
}
2870

2871
/************************************************************************/
2872
/*                          OpenVirtualTable()                          */
2873
/************************************************************************/
2874

2875
bool OGRSQLiteDataSource::OpenVirtualTable(const char *pszName,
13✔
2876
                                           const char *pszSQL)
2877
{
2878
    int nSRID = m_nUndefinedSRID;
13✔
2879
    const char *pszVirtualShape = strstr(pszSQL, "VirtualShape");
13✔
2880
    if (pszVirtualShape != nullptr)
13✔
2881
    {
2882
        const char *pszParenthesis = strchr(pszVirtualShape, '(');
3✔
2883
        if (pszParenthesis)
3✔
2884
        {
2885
            /* CREATE VIRTUAL TABLE table_name VirtualShape(shapename, codepage,
2886
             * srid) */
2887
            /* Extract 3rd parameter */
2888
            char **papszTokens =
2889
                CSLTokenizeString2(pszParenthesis + 1, ",", CSLT_HONOURSTRINGS);
3✔
2890
            if (CSLCount(papszTokens) == 3)
3✔
2891
            {
2892
                nSRID = atoi(papszTokens[2]);
3✔
2893
            }
2894
            CSLDestroy(papszTokens);
3✔
2895
        }
2896
    }
2897

2898
    if (OpenTable(pszName, true, pszVirtualShape != nullptr,
13✔
2899
                  /* bMayEmitError = */ true))
2900
    {
2901
        OGRSQLiteLayer *poLayer = m_apoLayers.back().get();
13✔
2902
        if (poLayer->GetLayerDefn()->GetGeomFieldCount() == 1)
13✔
2903
        {
2904
            OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
2905
                poLayer->myGetLayerDefn()->myGetGeomFieldDefn(0);
3✔
2906
            poGeomFieldDefn->m_eGeomFormat = OSGF_SpatiaLite;
3✔
2907
            if (nSRID > 0)
3✔
2908
            {
2909
                poGeomFieldDefn->m_nSRSId = nSRID;
×
2910
                poGeomFieldDefn->SetSpatialRef(FetchSRS(nSRID));
×
2911
            }
2912
        }
2913

2914
        OGRFeature *poFeature = poLayer->GetNextFeature();
13✔
2915
        if (poFeature)
13✔
2916
        {
2917
            OGRGeometry *poGeom = poFeature->GetGeometryRef();
12✔
2918
            if (poGeom)
12✔
2919
                whileUnsealing(poLayer->GetLayerDefn())
6✔
2920
                    ->SetGeomType(poGeom->getGeometryType());
3✔
2921
            delete poFeature;
12✔
2922
        }
2923
        poLayer->ResetReading();
13✔
2924
        return true;
13✔
2925
    }
2926

2927
    return false;
×
2928
}
2929

2930
/************************************************************************/
2931
/*                             OpenTable()                              */
2932
/************************************************************************/
2933

2934
bool OGRSQLiteDataSource::OpenTable(const char *pszTableName, bool bIsTable,
1,463✔
2935
                                    bool bIsVirtualShape, bool bMayEmitError)
2936

2937
{
2938
    /* -------------------------------------------------------------------- */
2939
    /*      Create the layer object.                                        */
2940
    /* -------------------------------------------------------------------- */
2941
    auto poLayer = std::make_unique<OGRSQLiteTableLayer>(this);
2,926✔
2942
    if (poLayer->Initialize(pszTableName, bIsTable, bIsVirtualShape, false,
1,463✔
2943
                            bMayEmitError) != CE_None)
1,463✔
2944
    {
2945
        return false;
293✔
2946
    }
2947

2948
    /* -------------------------------------------------------------------- */
2949
    /*      Add layer to data source layer list.                            */
2950
    /* -------------------------------------------------------------------- */
2951
    m_apoLayers.push_back(std::move(poLayer));
1,170✔
2952

2953
    // Remove in case of error in the schema processing
2954
    if (!DealWithOgrSchemaOpenOption(papszOpenOptions))
1,170✔
2955
    {
2956
        m_apoLayers.pop_back();
4✔
2957
        return false;
4✔
2958
    }
2959

2960
    return true;
1,166✔
2961
}
2962

2963
/************************************************************************/
2964
/*                             OpenView()                               */
2965
/************************************************************************/
2966

2967
bool OGRSQLiteDataSource::OpenView(const char *pszViewName,
5✔
2968
                                   const char *pszViewGeometry,
2969
                                   const char *pszViewRowid,
2970
                                   const char *pszTableName,
2971
                                   const char *pszGeometryColumn)
2972

2973
{
2974
    /* -------------------------------------------------------------------- */
2975
    /*      Create the layer object.                                        */
2976
    /* -------------------------------------------------------------------- */
2977
    auto poLayer = std::make_unique<OGRSQLiteViewLayer>(this);
10✔
2978

2979
    if (poLayer->Initialize(pszViewName, pszViewGeometry, pszViewRowid,
5✔
2980
                            pszTableName, pszGeometryColumn) != CE_None)
5✔
2981
    {
2982
        return false;
×
2983
    }
2984

2985
    /* -------------------------------------------------------------------- */
2986
    /*      Add layer to data source layer list.                            */
2987
    /* -------------------------------------------------------------------- */
2988
    m_apoLayers.push_back(std::move(poLayer));
5✔
2989

2990
    return true;
5✔
2991
}
2992

2993
/************************************************************************/
2994
/*                           TestCapability()                           */
2995
/************************************************************************/
2996

2997
int OGRSQLiteDataSource::TestCapability(const char *pszCap)
1,249✔
2998

2999
{
3000
    if (EQUAL(pszCap, ODsCCreateLayer) || EQUAL(pszCap, ODsCDeleteLayer) ||
1,249✔
3001
        EQUAL(pszCap, ODsCCreateGeomFieldAfterCreateLayer) ||
1,038✔
3002
        EQUAL(pszCap, ODsCRandomLayerWrite) ||
934✔
3003
        EQUAL(pszCap, GDsCAddRelationship))
931✔
3004
        return GetUpdate();
318✔
3005
    else if (EQUAL(pszCap, ODsCCurveGeometries))
931✔
3006
        return !m_bIsSpatiaLiteDB;
503✔
3007
    else if (EQUAL(pszCap, ODsCMeasuredGeometries))
428✔
3008
        return TRUE;
404✔
3009
    else
3010
        return OGRSQLiteBaseDataSource::TestCapability(pszCap);
24✔
3011
}
3012

3013
/************************************************************************/
3014
/*                           TestCapability()                           */
3015
/************************************************************************/
3016

3017
int OGRSQLiteBaseDataSource::TestCapability(const char *pszCap)
279✔
3018
{
3019
    if (EQUAL(pszCap, ODsCTransactions))
279✔
3020
        return true;
114✔
3021
    else if (EQUAL(pszCap, ODsCZGeometries))
165✔
3022
        return true;
8✔
3023
    else
3024
        return GDALPamDataset::TestCapability(pszCap);
157✔
3025
}
3026

3027
/************************************************************************/
3028
/*                              GetLayer()                              */
3029
/************************************************************************/
3030

3031
OGRLayer *OGRSQLiteDataSource::GetLayer(int iLayer)
17,220✔
3032

3033
{
3034
    if (iLayer < 0 || iLayer >= static_cast<int>(m_apoLayers.size()))
17,220✔
3035
        return nullptr;
10✔
3036
    else
3037
        return m_apoLayers[iLayer].get();
17,210✔
3038
}
3039

3040
/************************************************************************/
3041
/*                           GetLayerByName()                           */
3042
/************************************************************************/
3043

3044
OGRLayer *OGRSQLiteDataSource::GetLayerByName(const char *pszLayerName)
1,422✔
3045

3046
{
3047
    OGRLayer *poLayer = GDALDataset::GetLayerByName(pszLayerName);
1,422✔
3048
    if (poLayer != nullptr)
1,422✔
3049
        return poLayer;
888✔
3050

3051
    for (auto &poLayerIter : m_apoInvisibleLayers)
534✔
3052
    {
3053
        if (EQUAL(poLayerIter->GetName(), pszLayerName))
×
3054
            return poLayerIter.get();
×
3055
    }
3056

3057
    std::string osName(pszLayerName);
1,068✔
3058
    bool bIsTable = true;
534✔
3059
    for (int i = 0; i < 2; i++)
831✔
3060
    {
3061
        char *pszSQL = sqlite3_mprintf("SELECT type FROM sqlite_master "
831✔
3062
                                       "WHERE type IN ('table', 'view') AND "
3063
                                       "lower(name) = lower('%q')",
3064
                                       osName.c_str());
3065
        int nRowCount = 0;
831✔
3066
        char **papszResult = nullptr;
831✔
3067
        CPL_IGNORE_RET_VAL(sqlite3_get_table(hDB, pszSQL, &papszResult,
831✔
3068
                                             &nRowCount, nullptr, nullptr));
3069
        if (papszResult && nRowCount == 1 && papszResult[1])
831✔
3070
            bIsTable = strcmp(papszResult[1], "table") == 0;
305✔
3071
        sqlite3_free_table(papszResult);
831✔
3072
        sqlite3_free(pszSQL);
831✔
3073
        if (i == 0 && nRowCount == 0)
831✔
3074
        {
3075
            const auto nParenthesis = osName.find('(');
523✔
3076
            if (nParenthesis != std::string::npos && osName.back() == ')')
523✔
3077
            {
3078
                osName.resize(nParenthesis);
297✔
3079
                continue;
297✔
3080
            }
3081
        }
3082
        break;
534✔
3083
    }
3084

3085
    if (!OpenTable(pszLayerName, bIsTable, /* bIsVirtualShape = */ false,
534✔
3086
                   /* bMayEmitError = */ false))
3087
        return nullptr;
294✔
3088

3089
    poLayer = m_apoLayers.back().get();
240✔
3090
    CPLErrorReset();
240✔
3091
    CPLPushErrorHandler(CPLQuietErrorHandler);
240✔
3092
    poLayer->GetLayerDefn();
240✔
3093
    CPLPopErrorHandler();
240✔
3094
    if (CPLGetLastErrorType() != 0)
240✔
3095
    {
3096
        CPLErrorReset();
225✔
3097
        m_apoLayers.pop_back();
225✔
3098
        return nullptr;
225✔
3099
    }
3100

3101
    return poLayer;
15✔
3102
}
3103

3104
/************************************************************************/
3105
/*                    IsLayerPrivate()                                  */
3106
/************************************************************************/
3107

3108
bool OGRSQLiteDataSource::IsLayerPrivate(int iLayer) const
8✔
3109
{
3110
    if (iLayer < 0 || iLayer >= static_cast<int>(m_apoLayers.size()))
8✔
3111
        return false;
×
3112

3113
    const std::string osName(m_apoLayers[iLayer]->GetName());
16✔
3114
    const CPLString osLCName(CPLString(osName).tolower());
16✔
3115
    for (const char *systemTableName : {"spatialindex",
217✔
3116
                                        "geom_cols_ref_sys",
3117
                                        "geometry_columns",
3118
                                        "geometry_columns_auth",
3119
                                        "views_geometry_column",
3120
                                        "virts_geometry_column",
3121
                                        "spatial_ref_sys",
3122
                                        "spatial_ref_sys_all",
3123
                                        "spatial_ref_sys_aux",
3124
                                        "sqlite_sequence",
3125
                                        "tableprefix_metadata",
3126
                                        "tableprefix_rasters",
3127
                                        "layer_params",
3128
                                        "layer_statistics",
3129
                                        "layer_sub_classes",
3130
                                        "layer_table_layout",
3131
                                        "pattern_bitmaps",
3132
                                        "symbol_bitmaps",
3133
                                        "project_defs",
3134
                                        "raster_pyramids",
3135
                                        "sqlite_stat1",
3136
                                        "sqlite_stat2",
3137
                                        "spatialite_history",
3138
                                        "geometry_columns_field_infos",
3139
                                        "geometry_columns_statistics",
3140
                                        "geometry_columns_time",
3141
                                        "sql_statements_log",
3142
                                        "vector_layers",
3143
                                        "vector_layers_auth",
3144
                                        "vector_layers_field_infos",
3145
                                        "vector_layers_statistics",
3146
                                        "views_geometry_columns_auth",
3147
                                        "views_geometry_columns_field_infos",
3148
                                        "views_geometry_columns_statistics",
3149
                                        "virts_geometry_columns_auth",
3150
                                        "virts_geometry_columns_field_infos",
3151
                                        "virts_geometry_columns_statistics",
3152
                                        "virts_layer_statistics",
3153
                                        "views_layer_statistics",
3154
                                        "elementarygeometries"})
225✔
3155
    {
3156
        if (osLCName == systemTableName)
220✔
3157
            return true;
3✔
3158
    }
3159

3160
    return false;
5✔
3161
}
3162

3163
/************************************************************************/
3164
/*                    GetLayerByNameNotVisible()                        */
3165
/************************************************************************/
3166

3167
OGRLayer *
3168
OGRSQLiteDataSource::GetLayerByNameNotVisible(const char *pszLayerName)
4✔
3169

3170
{
3171
    {
3172
        OGRLayer *poLayer = GDALDataset::GetLayerByName(pszLayerName);
4✔
3173
        if (poLayer != nullptr)
4✔
3174
            return poLayer;
2✔
3175
    }
3176

3177
    for (auto &poLayerIter : m_apoInvisibleLayers)
2✔
3178
    {
3179
        if (EQUAL(poLayerIter->GetName(), pszLayerName))
×
3180
            return poLayerIter.get();
×
3181
    }
3182

3183
    /* -------------------------------------------------------------------- */
3184
    /*      Create the layer object.                                        */
3185
    /* -------------------------------------------------------------------- */
3186
    auto poLayer = std::make_unique<OGRSQLiteTableLayer>(this);
4✔
3187
    if (poLayer->Initialize(pszLayerName, true, false, false,
2✔
3188
                            /* bMayEmitError = */ true) != CE_None)
2✔
3189
    {
3190
        return nullptr;
×
3191
    }
3192
    CPLErrorReset();
2✔
3193
    CPLPushErrorHandler(CPLQuietErrorHandler);
2✔
3194
    poLayer->GetLayerDefn();
2✔
3195
    CPLPopErrorHandler();
2✔
3196
    if (CPLGetLastErrorType() != 0)
2✔
3197
    {
3198
        CPLErrorReset();
×
3199
        return nullptr;
×
3200
    }
3201
    m_apoInvisibleLayers.push_back(std::move(poLayer));
2✔
3202

3203
    return m_apoInvisibleLayers.back().get();
2✔
3204
}
3205

3206
/************************************************************************/
3207
/*                   GetLayerWithGetSpatialWhereByName()                */
3208
/************************************************************************/
3209

3210
std::pair<OGRLayer *, IOGRSQLiteGetSpatialWhere *>
3211
OGRSQLiteDataSource::GetLayerWithGetSpatialWhereByName(const char *pszName)
584✔
3212
{
3213
    OGRSQLiteLayer *poRet =
3214
        cpl::down_cast<OGRSQLiteLayer *>(GetLayerByName(pszName));
584✔
3215
    return std::pair<OGRLayer *, IOGRSQLiteGetSpatialWhere *>(poRet, poRet);
584✔
3216
}
3217

3218
/************************************************************************/
3219
/*                              FlushCache()                            */
3220
/************************************************************************/
3221

3222
CPLErr OGRSQLiteDataSource::FlushCache(bool bAtClosing)
1,329✔
3223
{
3224
    CPLErr eErr = CE_None;
1,329✔
3225
    for (auto &poLayer : m_apoLayers)
2,908✔
3226
    {
3227
        if (poLayer->IsTableLayer())
1,579✔
3228
        {
3229
            OGRSQLiteTableLayer *poTableLayer =
3230
                cpl::down_cast<OGRSQLiteTableLayer *>(poLayer.get());
1,572✔
3231
            if (poTableLayer->RunDeferredCreationIfNecessary() != OGRERR_NONE)
1,572✔
3232
                eErr = CE_Failure;
×
3233
            poTableLayer->CreateSpatialIndexIfNecessary();
1,572✔
3234
        }
3235
    }
3236
    if (GDALDataset::FlushCache(bAtClosing) != CE_None)
1,329✔
3237
        eErr = CE_Failure;
×
3238
    return eErr;
1,329✔
3239
}
3240

3241
/************************************************************************/
3242
/*                             ExecuteSQL()                             */
3243
/************************************************************************/
3244

3245
static const char *const apszFuncsWithSideEffects[] = {
3246
    "InitSpatialMetaData",       "AddGeometryColumn",
3247
    "RecoverGeometryColumn",     "DiscardGeometryColumn",
3248
    "CreateSpatialIndex",        "CreateMbrCache",
3249
    "DisableSpatialIndex",       "UpdateLayerStatistics",
3250

3251
    "ogr_datasource_load_layers"};
3252

3253
OGRLayer *OGRSQLiteDataSource::ExecuteSQL(const char *pszSQLCommand,
1,251✔
3254
                                          OGRGeometry *poSpatialFilter,
3255
                                          const char *pszDialect)
3256

3257
{
3258
    for (auto &poLayer : m_apoLayers)
5,604✔
3259
    {
3260
        if (poLayer->IsTableLayer())
4,353✔
3261
        {
3262
            OGRSQLiteTableLayer *poTableLayer =
3263
                cpl::down_cast<OGRSQLiteTableLayer *>(poLayer.get());
4,349✔
3264
            poTableLayer->RunDeferredCreationIfNecessary();
4,349✔
3265
            poTableLayer->CreateSpatialIndexIfNecessary();
4,349✔
3266
        }
3267
    }
3268

3269
    if (pszDialect != nullptr && EQUAL(pszDialect, "INDIRECT_SQLITE"))
1,251✔
3270
        return GDALDataset::ExecuteSQL(pszSQLCommand, poSpatialFilter,
×
3271
                                       "SQLITE");
×
3272
    else if (pszDialect != nullptr && !EQUAL(pszDialect, "") &&
1,251✔
3273
             !EQUAL(pszDialect, "NATIVE") && !EQUAL(pszDialect, "SQLITE"))
2✔
3274

3275
        return GDALDataset::ExecuteSQL(pszSQLCommand, poSpatialFilter,
2✔
3276
                                       pszDialect);
2✔
3277

3278
    if (EQUAL(pszSQLCommand, "PRAGMA case_sensitive_like = 0") ||
1,249✔
3279
        EQUAL(pszSQLCommand, "PRAGMA case_sensitive_like=0") ||
1,248✔
3280
        EQUAL(pszSQLCommand, "PRAGMA case_sensitive_like =0") ||
1,248✔
3281
        EQUAL(pszSQLCommand, "PRAGMA case_sensitive_like= 0"))
1,248✔
3282
    {
3283
        if (m_poSQLiteModule)
1✔
3284
            OGR2SQLITE_SetCaseSensitiveLike(m_poSQLiteModule, false);
1✔
3285
    }
3286
    else if (EQUAL(pszSQLCommand, "PRAGMA case_sensitive_like = 1") ||
1,248✔
3287
             EQUAL(pszSQLCommand, "PRAGMA case_sensitive_like=1") ||
1,247✔
3288
             EQUAL(pszSQLCommand, "PRAGMA case_sensitive_like =1") ||
1,247✔
3289
             EQUAL(pszSQLCommand, "PRAGMA case_sensitive_like= 1"))
1,247✔
3290
    {
3291
        if (m_poSQLiteModule)
1✔
3292
            OGR2SQLITE_SetCaseSensitiveLike(m_poSQLiteModule, true);
1✔
3293
    }
3294

3295
    /* -------------------------------------------------------------------- */
3296
    /*      Special case DELLAYER: command.                                 */
3297
    /* -------------------------------------------------------------------- */
3298
    if (STARTS_WITH_CI(pszSQLCommand, "DELLAYER:"))
1,249✔
3299
    {
3300
        const char *pszLayerName = pszSQLCommand + 9;
1✔
3301

3302
        while (*pszLayerName == ' ')
1✔
3303
            pszLayerName++;
×
3304

3305
        DeleteLayer(pszLayerName);
1✔
3306
        return nullptr;
1✔
3307
    }
3308

3309
    /* -------------------------------------------------------------------- */
3310
    /*      Special case for SQLITE_HAS_COLUMN_METADATA()                   */
3311
    /* -------------------------------------------------------------------- */
3312
    if (strcmp(pszSQLCommand, "SQLITE_HAS_COLUMN_METADATA()") == 0)
1,248✔
3313
    {
3314
#ifdef SQLITE_HAS_COLUMN_METADATA
3315
        return new OGRSQLiteSingleFeatureLayer("SQLITE_HAS_COLUMN_METADATA",
3316
                                               TRUE);
2✔
3317
#else
3318
        return new OGRSQLiteSingleFeatureLayer("SQLITE_HAS_COLUMN_METADATA",
3319
                                               FALSE);
3320
#endif
3321
    }
3322

3323
    /* -------------------------------------------------------------------- */
3324
    /*      In case, this is not a SELECT, invalidate cached feature        */
3325
    /*      count and extent to be on the safe side.                        */
3326
    /* -------------------------------------------------------------------- */
3327
    if (EQUAL(pszSQLCommand, "VACUUM"))
1,246✔
3328
    {
3329
        int nNeedRefresh = -1;
1✔
3330
        for (auto &poLayer : m_apoLayers)
1✔
3331
        {
3332
            if (poLayer->IsTableLayer())
1✔
3333
            {
3334
                OGRSQLiteTableLayer *poTableLayer =
3335
                    cpl::down_cast<OGRSQLiteTableLayer *>(poLayer.get());
1✔
3336
                if (!(poTableLayer->AreStatisticsValid()) ||
1✔
3337
                    poTableLayer->DoStatisticsNeedToBeFlushed())
×
3338
                {
3339
                    nNeedRefresh = FALSE;
1✔
3340
                    break;
1✔
3341
                }
3342
                else if (nNeedRefresh < 0)
×
3343
                    nNeedRefresh = TRUE;
×
3344
            }
3345
        }
3346
        if (nNeedRefresh == TRUE)
1✔
3347
        {
3348
            for (auto &poLayer : m_apoLayers)
×
3349
            {
3350
                if (poLayer->IsTableLayer())
×
3351
                {
3352
                    OGRSQLiteTableLayer *poTableLayer =
3353
                        cpl::down_cast<OGRSQLiteTableLayer *>(poLayer.get());
×
3354
                    poTableLayer->ForceStatisticsToBeFlushed();
×
3355
                }
3356
            }
3357
        }
3358
    }
3359
    else if (ProcessTransactionSQL(pszSQLCommand))
1,245✔
3360
    {
3361
        return nullptr;
251✔
3362
    }
3363
    else if (!STARTS_WITH_CI(pszSQLCommand, "SELECT ") &&
994✔
3364
             !STARTS_WITH_CI(pszSQLCommand, "CREATE TABLE ") &&
138✔
3365
             !STARTS_WITH_CI(pszSQLCommand, "PRAGMA "))
111✔
3366
    {
3367
        for (auto &poLayer : m_apoLayers)
144✔
3368
            poLayer->InvalidateCachedFeatureCountAndExtent();
43✔
3369
    }
3370

3371
    m_bLastSQLCommandIsUpdateLayerStatistics =
995✔
3372
        EQUAL(pszSQLCommand, "SELECT UpdateLayerStatistics()");
995✔
3373

3374
    /* -------------------------------------------------------------------- */
3375
    /*      Prepare statement.                                              */
3376
    /* -------------------------------------------------------------------- */
3377
    sqlite3_stmt *hSQLStmt = nullptr;
995✔
3378

3379
    CPLString osSQLCommand = pszSQLCommand;
1,990✔
3380

3381
    /* This will speed-up layer creation */
3382
    /* ORDER BY are costly to evaluate and are not necessary to establish */
3383
    /* the layer definition. */
3384
    bool bUseStatementForGetNextFeature = true;
995✔
3385
    bool bEmptyLayer = false;
995✔
3386

3387
    if (osSQLCommand.ifind("SELECT ") == 0 &&
4,697✔
3388
        CPLString(osSQLCommand.substr(1)).ifind("SELECT ") ==
1,851✔
3389
            std::string::npos &&
778✔
3390
        osSQLCommand.ifind(" UNION ") == std::string::npos &&
778✔
3391
        osSQLCommand.ifind(" INTERSECT ") == std::string::npos &&
2,629✔
3392
        osSQLCommand.ifind(" EXCEPT ") == std::string::npos)
778✔
3393
    {
3394
        size_t nOrderByPos = osSQLCommand.ifind(" ORDER BY ");
778✔
3395
        if (nOrderByPos != std::string::npos)
778✔
3396
        {
3397
            osSQLCommand.resize(nOrderByPos);
8✔
3398
            bUseStatementForGetNextFeature = false;
8✔
3399
        }
3400
    }
3401

3402
    int rc =
3403
        prepareSql(GetDB(), osSQLCommand.c_str(),
995✔
3404
                   static_cast<int>(osSQLCommand.size()), &hSQLStmt, nullptr);
995✔
3405

3406
    if (rc != SQLITE_OK)
995✔
3407
    {
3408
        CPLError(CE_Failure, CPLE_AppDefined,
7✔
3409
                 "In ExecuteSQL(): sqlite3_prepare_v2(%s):\n  %s",
3410
                 osSQLCommand.c_str(), sqlite3_errmsg(GetDB()));
3411

3412
        if (hSQLStmt != nullptr)
7✔
3413
        {
3414
            sqlite3_finalize(hSQLStmt);
×
3415
        }
3416

3417
        return nullptr;
7✔
3418
    }
3419

3420
    /* -------------------------------------------------------------------- */
3421
    /*      Do we get a resultset?                                          */
3422
    /* -------------------------------------------------------------------- */
3423
    rc = sqlite3_step(hSQLStmt);
988✔
3424
    if (rc != SQLITE_ROW)
988✔
3425
    {
3426
        if (rc != SQLITE_DONE)
301✔
3427
        {
3428
            CPLError(CE_Failure, CPLE_AppDefined,
18✔
3429
                     "In ExecuteSQL(): sqlite3_step(%s):\n  %s",
3430
                     osSQLCommand.c_str(), sqlite3_errmsg(GetDB()));
3431

3432
            sqlite3_finalize(hSQLStmt);
18✔
3433
            return nullptr;
18✔
3434
        }
3435

3436
        if (STARTS_WITH_CI(pszSQLCommand, "CREATE "))
283✔
3437
        {
3438
            char **papszTokens = CSLTokenizeString(pszSQLCommand);
56✔
3439
            if (CSLCount(papszTokens) >= 4 &&
56✔
3440
                EQUAL(papszTokens[1], "VIRTUAL") &&
66✔
3441
                EQUAL(papszTokens[2], "TABLE"))
10✔
3442
            {
3443
                OpenVirtualTable(papszTokens[3], pszSQLCommand);
10✔
3444
            }
3445
            CSLDestroy(papszTokens);
56✔
3446

3447
            sqlite3_finalize(hSQLStmt);
56✔
3448
            return nullptr;
56✔
3449
        }
3450

3451
        if (!STARTS_WITH_CI(pszSQLCommand, "SELECT "))
227✔
3452
        {
3453
            sqlite3_finalize(hSQLStmt);
62✔
3454
            return nullptr;
62✔
3455
        }
3456

3457
        bUseStatementForGetNextFeature = false;
165✔
3458
        bEmptyLayer = true;
165✔
3459
    }
3460

3461
    /* -------------------------------------------------------------------- */
3462
    /*      Special case for some functions which must be run               */
3463
    /*      only once                                                       */
3464
    /* -------------------------------------------------------------------- */
3465
    if (STARTS_WITH_CI(pszSQLCommand, "SELECT "))
852✔
3466
    {
3467
        for (unsigned int i = 0; i < sizeof(apszFuncsWithSideEffects) /
8,426✔
3468
                                         sizeof(apszFuncsWithSideEffects[0]);
3469
             i++)
3470
        {
3471
            if (EQUALN(apszFuncsWithSideEffects[i], pszSQLCommand + 7,
7,592✔
3472
                       strlen(apszFuncsWithSideEffects[i])))
3473
            {
3474
                if (sqlite3_column_count(hSQLStmt) == 1 &&
20✔
3475
                    sqlite3_column_type(hSQLStmt, 0) == SQLITE_INTEGER)
10✔
3476
                {
3477
                    const int ret = sqlite3_column_int(hSQLStmt, 0);
10✔
3478

3479
                    sqlite3_finalize(hSQLStmt);
10✔
3480

3481
                    return new OGRSQLiteSingleFeatureLayer(
3482
                        apszFuncsWithSideEffects[i], ret);
10✔
3483
                }
3484
            }
3485
        }
3486
    }
3487

3488
    /* -------------------------------------------------------------------- */
3489
    /*      Create layer.                                                   */
3490
    /* -------------------------------------------------------------------- */
3491

3492
    CPLString osSQL = pszSQLCommand;
842✔
3493
    OGRSQLiteSelectLayer *poLayer = new OGRSQLiteSelectLayer(
3494
        this, osSQL, hSQLStmt, bUseStatementForGetNextFeature, bEmptyLayer,
3495
        true, /*bCanReopenBaseDS=*/true);
842✔
3496

3497
    if (poSpatialFilter != nullptr &&
845✔
3498
        poLayer->GetLayerDefn()->GetGeomFieldCount() > 0)
3✔
3499
        poLayer->SetSpatialFilter(0, poSpatialFilter);
×
3500

3501
    return poLayer;
842✔
3502
}
3503

3504
/************************************************************************/
3505
/*                          ReleaseResultSet()                          */
3506
/************************************************************************/
3507

3508
void OGRSQLiteDataSource::ReleaseResultSet(OGRLayer *poLayer)
849✔
3509

3510
{
3511
    delete poLayer;
849✔
3512
}
849✔
3513

3514
/************************************************************************/
3515
/*                           ICreateLayer()                             */
3516
/************************************************************************/
3517

3518
OGRLayer *
3519
OGRSQLiteDataSource::ICreateLayer(const char *pszLayerNameIn,
434✔
3520
                                  const OGRGeomFieldDefn *poGeomFieldDefn,
3521
                                  CSLConstList papszOptions)
3522

3523
{
3524
    /* -------------------------------------------------------------------- */
3525
    /*      Verify we are in update mode.                                   */
3526
    /* -------------------------------------------------------------------- */
3527
    char *pszLayerName = nullptr;
434✔
3528
    if (!GetUpdate())
434✔
3529
    {
3530
        CPLError(CE_Failure, CPLE_NoWriteAccess,
1✔
3531
                 "Data source %s opened read-only.\n"
3532
                 "New layer %s cannot be created.\n",
3533
                 m_pszFilename, pszLayerNameIn);
3534

3535
        return nullptr;
1✔
3536
    }
3537

3538
    const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
433✔
3539
    const auto poSRS =
3540
        poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
433✔
3541

3542
    if (m_bIsSpatiaLiteDB && eType != wkbNone)
433✔
3543
    {
3544
        // We need to catch this right now as AddGeometryColumn does not
3545
        // return an error
3546
        OGRwkbGeometryType eFType = wkbFlatten(eType);
144✔
3547
        if (eFType > wkbGeometryCollection)
144✔
3548
        {
3549
            CPLError(CE_Failure, CPLE_NotSupported,
×
3550
                     "Cannot create geometry field of type %s",
3551
                     OGRToOGCGeomType(eType));
3552
            return nullptr;
×
3553
        }
3554
    }
3555

3556
    for (auto &poLayer : m_apoLayers)
4,056✔
3557
    {
3558
        if (poLayer->IsTableLayer())
3,623✔
3559
        {
3560
            OGRSQLiteTableLayer *poTableLayer =
3561
                cpl::down_cast<OGRSQLiteTableLayer *>(poLayer.get());
3,623✔
3562
            poTableLayer->RunDeferredCreationIfNecessary();
3,623✔
3563
        }
3564
    }
3565

3566
    CPLString osFIDColumnName;
866✔
3567
    const char *pszFIDColumnNameIn =
3568
        CSLFetchNameValueDef(papszOptions, "FID", "OGC_FID");
433✔
3569
    if (CPLFetchBool(papszOptions, "LAUNDER", true))
433✔
3570
    {
3571
        char *pszFIDColumnName = LaunderName(pszFIDColumnNameIn);
432✔
3572
        osFIDColumnName = pszFIDColumnName;
432✔
3573
        CPLFree(pszFIDColumnName);
432✔
3574
    }
3575
    else
3576
        osFIDColumnName = pszFIDColumnNameIn;
1✔
3577

3578
    if (CPLFetchBool(papszOptions, "LAUNDER", true))
433✔
3579
        pszLayerName = LaunderName(pszLayerNameIn);
432✔
3580
    else
3581
        pszLayerName = CPLStrdup(pszLayerNameIn);
1✔
3582

3583
    const char *pszGeomFormat = CSLFetchNameValue(papszOptions, "FORMAT");
433✔
3584
    if (pszGeomFormat == nullptr)
433✔
3585
    {
3586
        if (!m_bIsSpatiaLiteDB)
428✔
3587
            pszGeomFormat = "WKB";
280✔
3588
        else
3589
            pszGeomFormat = "SpatiaLite";
148✔
3590
    }
3591

3592
    if (!EQUAL(pszGeomFormat, "WKT") && !EQUAL(pszGeomFormat, "WKB") &&
433✔
3593
        !EQUAL(pszGeomFormat, "SpatiaLite"))
150✔
3594
    {
3595
        CPLError(CE_Failure, CPLE_NotSupported,
1✔
3596
                 "FORMAT=%s not recognised or supported.", pszGeomFormat);
3597
        CPLFree(pszLayerName);
1✔
3598
        return nullptr;
1✔
3599
    }
3600

3601
    CPLString osGeometryName;
864✔
3602
    const char *pszGeometryNameIn =
3603
        CSLFetchNameValue(papszOptions, "GEOMETRY_NAME");
432✔
3604
    if (pszGeometryNameIn == nullptr)
432✔
3605
    {
3606
        osGeometryName =
3607
            (EQUAL(pszGeomFormat, "WKT")) ? "WKT_GEOMETRY" : "GEOMETRY";
392✔
3608
    }
3609
    else
3610
    {
3611
        if (CPLFetchBool(papszOptions, "LAUNDER", true))
40✔
3612
        {
3613
            char *pszGeometryName = LaunderName(pszGeometryNameIn);
40✔
3614
            osGeometryName = pszGeometryName;
40✔
3615
            CPLFree(pszGeometryName);
40✔
3616
        }
3617
        else
3618
            osGeometryName = pszGeometryNameIn;
×
3619
    }
3620

3621
    if (m_bIsSpatiaLiteDB && !EQUAL(pszGeomFormat, "SpatiaLite"))
432✔
3622
    {
3623
        CPLError(CE_Failure, CPLE_NotSupported,
1✔
3624
                 "FORMAT=%s not supported on a SpatiaLite enabled database.",
3625
                 pszGeomFormat);
3626
        CPLFree(pszLayerName);
1✔
3627
        return nullptr;
1✔
3628
    }
3629

3630
    // Should not happen since a spatialite DB should be opened in
3631
    // read-only mode if libspatialite is not loaded.
3632
    if (m_bIsSpatiaLiteDB && !IsSpatialiteLoaded())
431✔
3633
    {
3634
        CPLError(CE_Failure, CPLE_NotSupported,
×
3635
                 "Creating layers on a SpatiaLite enabled database, "
3636
                 "without Spatialite extensions loaded, is not supported.");
3637
        CPLFree(pszLayerName);
×
3638
        return nullptr;
×
3639
    }
3640

3641
    /* -------------------------------------------------------------------- */
3642
    /*      Do we already have this layer?  If so, should we blow it        */
3643
    /*      away?                                                           */
3644
    /* -------------------------------------------------------------------- */
3645
    for (auto &poLayer : m_apoLayers)
4,052✔
3646
    {
3647
        if (EQUAL(pszLayerName, poLayer->GetLayerDefn()->GetName()))
3,623✔
3648
        {
3649
            if (CSLFetchNameValue(papszOptions, "OVERWRITE") != nullptr &&
3✔
3650
                !EQUAL(CSLFetchNameValue(papszOptions, "OVERWRITE"), "NO"))
1✔
3651
            {
3652
                DeleteLayer(pszLayerName);
1✔
3653
                break;
1✔
3654
            }
3655
            else
3656
            {
3657
                CPLError(CE_Failure, CPLE_AppDefined,
1✔
3658
                         "Layer %s already exists, CreateLayer failed.\n"
3659
                         "Use the layer creation option OVERWRITE=YES to "
3660
                         "replace it.",
3661
                         pszLayerName);
3662
                CPLFree(pszLayerName);
1✔
3663
                return nullptr;
1✔
3664
            }
3665
        }
3666
    }
3667

3668
    /* -------------------------------------------------------------------- */
3669
    /*      Try to get the SRS Id of this spatial reference system,         */
3670
    /*      adding to the srs table if needed.                              */
3671
    /* -------------------------------------------------------------------- */
3672
    int nSRSId = m_nUndefinedSRID;
430✔
3673
    const char *pszSRID = CSLFetchNameValue(papszOptions, "SRID");
430✔
3674

3675
    if (pszSRID != nullptr && pszSRID[0] != '\0')
430✔
3676
    {
3677
        nSRSId = atoi(pszSRID);
4✔
3678
        if (nSRSId > 0)
4✔
3679
        {
3680
            OGRSpatialReference *poSRSFetched = FetchSRS(nSRSId);
4✔
3681
            if (poSRSFetched == nullptr)
4✔
3682
            {
3683
                CPLError(CE_Warning, CPLE_AppDefined,
2✔
3684
                         "SRID %d will be used, but no matching SRS is defined "
3685
                         "in spatial_ref_sys",
3686
                         nSRSId);
3687
            }
3688
        }
4✔
3689
    }
3690
    else if (poSRS != nullptr)
426✔
3691
        nSRSId = FetchSRSId(poSRS);
113✔
3692

3693
    bool bImmediateSpatialIndexCreation = false;
430✔
3694
    bool bDeferredSpatialIndexCreation = false;
430✔
3695

3696
    const char *pszSI = CSLFetchNameValue(papszOptions, "SPATIAL_INDEX");
430✔
3697
    if (m_bHaveGeometryColumns && eType != wkbNone)
430✔
3698
    {
3699
        if (pszSI != nullptr && CPLTestBool(pszSI) &&
×
3700
            (m_bIsSpatiaLiteDB || EQUAL(pszGeomFormat, "SpatiaLite")) &&
305✔
3701
            !IsSpatialiteLoaded())
×
3702
        {
3703
            CPLError(CE_Warning, CPLE_OpenFailed,
×
3704
                     "Cannot create a spatial index when Spatialite extensions "
3705
                     "are not loaded.");
3706
        }
3707

3708
#ifdef HAVE_SPATIALITE
3709
        /* Only if linked against SpatiaLite and the datasource was created as a
3710
         * SpatiaLite DB */
3711
        if (m_bIsSpatiaLiteDB && IsSpatialiteLoaded())
305✔
3712
#else
3713
        if (0)
3714
#endif
3715
        {
3716
            if (pszSI != nullptr && EQUAL(pszSI, "IMMEDIATE"))
143✔
3717
            {
3718
                bImmediateSpatialIndexCreation = true;
×
3719
            }
3720
            else if (pszSI == nullptr || CPLTestBool(pszSI))
143✔
3721
            {
3722
                bDeferredSpatialIndexCreation = true;
143✔
3723
            }
3724
        }
3725
    }
3726
    else if (m_bHaveGeometryColumns)
125✔
3727
    {
3728
#ifdef HAVE_SPATIALITE
3729
        if (m_bIsSpatiaLiteDB && IsSpatialiteLoaded() &&
116✔
3730
            (pszSI == nullptr || CPLTestBool(pszSI)))
×
3731
            bDeferredSpatialIndexCreation = true;
5✔
3732
#endif
3733
    }
3734

3735
    /* -------------------------------------------------------------------- */
3736
    /*      Create the layer object.                                        */
3737
    /* -------------------------------------------------------------------- */
3738
    auto poLayer = std::make_unique<OGRSQLiteTableLayer>(this);
860✔
3739

3740
    poLayer->Initialize(pszLayerName, true, false, true,
430✔
3741
                        /* bMayEmitError = */ false);
3742
    OGRSpatialReference *poSRSClone = nullptr;
430✔
3743
    if (poSRS)
430✔
3744
    {
3745
        poSRSClone = poSRS->Clone();
113✔
3746
        poSRSClone->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
113✔
3747
    }
3748
    poLayer->SetCreationParameters(osFIDColumnName, eType, pszGeomFormat,
430✔
3749
                                   osGeometryName, poSRSClone, nSRSId);
3750
    if (poSRSClone)
430✔
3751
        poSRSClone->Release();
113✔
3752

3753
    poLayer->InitFeatureCount();
430✔
3754
    poLayer->SetLaunderFlag(CPLFetchBool(papszOptions, "LAUNDER", true));
430✔
3755
    if (CPLFetchBool(papszOptions, "COMPRESS_GEOM", false))
430✔
3756
        poLayer->SetUseCompressGeom(true);
47✔
3757
    if (bImmediateSpatialIndexCreation)
430✔
3758
        poLayer->CreateSpatialIndex(0);
×
3759
    else if (bDeferredSpatialIndexCreation)
430✔
3760
        poLayer->SetDeferredSpatialIndexCreation(true);
148✔
3761
    poLayer->SetCompressedColumns(
430✔
3762
        CSLFetchNameValue(papszOptions, "COMPRESS_COLUMNS"));
3763
    poLayer->SetStrictFlag(CPLFetchBool(papszOptions, "STRICT", false));
430✔
3764

3765
    CPLFree(pszLayerName);
430✔
3766

3767
    /* -------------------------------------------------------------------- */
3768
    /*      Add layer to data source layer list.                            */
3769
    /* -------------------------------------------------------------------- */
3770
    m_apoLayers.push_back(std::move(poLayer));
430✔
3771

3772
    return m_apoLayers.back().get();
430✔
3773
}
3774

3775
/************************************************************************/
3776
/*                            LaunderName()                             */
3777
/************************************************************************/
3778

3779
char *OGRSQLiteDataSource::LaunderName(const char *pszSrcName)
2,139✔
3780

3781
{
3782
    char *pszSafeName = CPLStrdup(pszSrcName);
2,139✔
3783
    for (int i = 0; pszSafeName[i] != '\0'; i++)
21,968✔
3784
    {
3785
        pszSafeName[i] = static_cast<char>(
19,829✔
3786
            CPLTolower(static_cast<unsigned char>(pszSafeName[i])));
19,829✔
3787
        if (pszSafeName[i] == '\'' || pszSafeName[i] == '-' ||
19,829✔
3788
            pszSafeName[i] == '#')
19,829✔
3789
            pszSafeName[i] = '_';
×
3790
    }
3791

3792
    return pszSafeName;
2,139✔
3793
}
3794

3795
/************************************************************************/
3796
/*                            DeleteLayer()                             */
3797
/************************************************************************/
3798

3799
void OGRSQLiteDataSource::DeleteLayer(const char *pszLayerName)
2✔
3800

3801
{
3802
    /* -------------------------------------------------------------------- */
3803
    /*      Verify we are in update mode.                                   */
3804
    /* -------------------------------------------------------------------- */
3805
    if (!GetUpdate())
2✔
3806
    {
3807
        CPLError(CE_Failure, CPLE_NoWriteAccess,
×
3808
                 "Data source %s opened read-only.\n"
3809
                 "Layer %s cannot be deleted.\n",
3810
                 m_pszFilename, pszLayerName);
3811

3812
        return;
×
3813
    }
3814

3815
    /* -------------------------------------------------------------------- */
3816
    /*      Try to find layer.                                              */
3817
    /* -------------------------------------------------------------------- */
3818
    int iLayer = 0;  // Used after for.
2✔
3819

3820
    for (; iLayer < static_cast<int>(m_apoLayers.size()); iLayer++)
2✔
3821
    {
3822
        if (EQUAL(pszLayerName, m_apoLayers[iLayer]->GetLayerDefn()->GetName()))
2✔
3823
            break;
2✔
3824
    }
3825

3826
    if (iLayer == static_cast<int>(m_apoLayers.size()))
2✔
3827
    {
3828
        CPLError(
×
3829
            CE_Failure, CPLE_AppDefined,
3830
            "Attempt to delete layer '%s', but this layer is not known to OGR.",
3831
            pszLayerName);
3832
        return;
×
3833
    }
3834

3835
    DeleteLayer(iLayer);
2✔
3836
}
3837

3838
/************************************************************************/
3839
/*                            DeleteLayer()                             */
3840
/************************************************************************/
3841

3842
OGRErr OGRSQLiteDataSource::DeleteLayer(int iLayer)
34✔
3843
{
3844
    if (iLayer < 0 || iLayer >= static_cast<int>(m_apoLayers.size()))
34✔
3845
    {
3846
        CPLError(CE_Failure, CPLE_AppDefined,
×
3847
                 "Layer %d not in legal range of 0 to %d.", iLayer,
3848
                 static_cast<int>(m_apoLayers.size()) - 1);
×
3849
        return OGRERR_FAILURE;
×
3850
    }
3851

3852
    CPLString osLayerName = GetLayer(iLayer)->GetName();
68✔
3853
    CPLString osGeometryColumn = GetLayer(iLayer)->GetGeometryColumn();
68✔
3854

3855
    /* -------------------------------------------------------------------- */
3856
    /*      Blow away our OGR structures related to the layer.  This is     */
3857
    /*      pretty dangerous if anything has a reference to this layer!     */
3858
    /* -------------------------------------------------------------------- */
3859
    CPLDebug("OGR_SQLITE", "DeleteLayer(%s)", osLayerName.c_str());
34✔
3860

3861
    m_apoLayers.erase(m_apoLayers.begin() + iLayer);
34✔
3862

3863
    /* -------------------------------------------------------------------- */
3864
    /*      Remove from the database.                                       */
3865
    /* -------------------------------------------------------------------- */
3866
    CPLString osEscapedLayerName = SQLEscapeLiteral(osLayerName);
68✔
3867
    const char *pszEscapedLayerName = osEscapedLayerName.c_str();
34✔
3868
    const char *pszGeometryColumn =
3869
        osGeometryColumn.size() ? osGeometryColumn.c_str() : nullptr;
34✔
3870

3871
    if (SQLCommand(hDB, CPLSPrintf("DROP TABLE '%s'", pszEscapedLayerName)) !=
34✔
3872
        OGRERR_NONE)
3873
    {
3874
        return OGRERR_FAILURE;
×
3875
    }
3876

3877
    /* -------------------------------------------------------------------- */
3878
    /*      Drop from geometry_columns table.                               */
3879
    /* -------------------------------------------------------------------- */
3880
    if (m_bHaveGeometryColumns)
34✔
3881
    {
3882
        CPLString osCommand;
34✔
3883

3884
        osCommand.Printf(
3885
            "DELETE FROM geometry_columns WHERE f_table_name = '%s'",
3886
            pszEscapedLayerName);
34✔
3887

3888
        if (SQLCommand(hDB, osCommand) != OGRERR_NONE)
34✔
3889
        {
3890
            return OGRERR_FAILURE;
×
3891
        }
3892

3893
        /* --------------------------------------------------------------------
3894
         */
3895
        /*      Drop spatialite spatial index tables */
3896
        /* --------------------------------------------------------------------
3897
         */
3898
        if (m_bIsSpatiaLiteDB && pszGeometryColumn)
34✔
3899
        {
3900
            osCommand.Printf("DROP TABLE 'idx_%s_%s'", pszEscapedLayerName,
3901
                             SQLEscapeLiteral(pszGeometryColumn).c_str());
15✔
3902
            CPL_IGNORE_RET_VAL(
15✔
3903
                sqlite3_exec(hDB, osCommand, nullptr, nullptr, nullptr));
15✔
3904

3905
            osCommand.Printf("DROP TABLE 'idx_%s_%s_node'", pszEscapedLayerName,
3906
                             SQLEscapeLiteral(pszGeometryColumn).c_str());
15✔
3907
            CPL_IGNORE_RET_VAL(
15✔
3908
                sqlite3_exec(hDB, osCommand, nullptr, nullptr, nullptr));
15✔
3909

3910
            osCommand.Printf("DROP TABLE 'idx_%s_%s_parent'",
3911
                             pszEscapedLayerName,
3912
                             SQLEscapeLiteral(pszGeometryColumn).c_str());
15✔
3913
            CPL_IGNORE_RET_VAL(
15✔
3914
                sqlite3_exec(hDB, osCommand, nullptr, nullptr, nullptr));
15✔
3915

3916
            osCommand.Printf("DROP TABLE 'idx_%s_%s_rowid'",
3917
                             pszEscapedLayerName,
3918
                             SQLEscapeLiteral(pszGeometryColumn).c_str());
15✔
3919
            CPL_IGNORE_RET_VAL(
15✔
3920
                sqlite3_exec(hDB, osCommand, nullptr, nullptr, nullptr));
15✔
3921
        }
3922
    }
3923
    return OGRERR_NONE;
34✔
3924
}
3925

3926
/************************************************************************/
3927
/*                         StartTransaction()                           */
3928
/*                                                                      */
3929
/* Should only be called by user code. Not driver internals.            */
3930
/************************************************************************/
3931

3932
OGRErr OGRSQLiteBaseDataSource::StartTransaction(CPL_UNUSED int bForce)
328✔
3933
{
3934
    if (m_bUserTransactionActive || m_nSoftTransactionLevel != 0)
328✔
3935
    {
3936
        CPLError(CE_Failure, CPLE_AppDefined,
13✔
3937
                 "Transaction already established");
3938
        return OGRERR_FAILURE;
13✔
3939
    }
3940

3941
    // Check if we are in a SAVEPOINT transaction
3942
    if (m_aosSavepoints.size() > 0)
315✔
3943
    {
3944
        CPLError(CE_Failure, CPLE_AppDefined,
×
3945
                 "Cannot start a transaction within a SAVEPOINT");
3946
        return OGRERR_FAILURE;
×
3947
    }
3948

3949
    OGRErr eErr = SoftStartTransaction();
315✔
3950
    if (eErr != OGRERR_NONE)
315✔
3951
        return eErr;
×
3952

3953
    m_bUserTransactionActive = true;
315✔
3954
    return OGRERR_NONE;
315✔
3955
}
3956

3957
OGRErr OGRSQLiteDataSource::StartTransaction(int bForce)
81✔
3958
{
3959
    for (auto &poLayer : m_apoLayers)
152✔
3960
    {
3961
        if (poLayer->IsTableLayer())
71✔
3962
        {
3963
            OGRSQLiteTableLayer *poTableLayer =
3964
                cpl::down_cast<OGRSQLiteTableLayer *>(poLayer.get());
71✔
3965
            poTableLayer->RunDeferredCreationIfNecessary();
71✔
3966
        }
3967
    }
3968

3969
    return OGRSQLiteBaseDataSource::StartTransaction(bForce);
81✔
3970
}
3971

3972
/************************************************************************/
3973
/*                         CommitTransaction()                          */
3974
/*                                                                      */
3975
/* Should only be called by user code. Not driver internals.            */
3976
/************************************************************************/
3977

3978
OGRErr OGRSQLiteBaseDataSource::CommitTransaction()
275✔
3979
{
3980
    if (!m_bUserTransactionActive && !m_bImplicitTransactionOpened)
275✔
3981
    {
3982
        CPLError(CE_Failure, CPLE_AppDefined, "Transaction not established");
3✔
3983
        return OGRERR_FAILURE;
3✔
3984
    }
3985

3986
    m_bUserTransactionActive = false;
272✔
3987
    m_bImplicitTransactionOpened = false;
272✔
3988
    CPLAssert(m_nSoftTransactionLevel == 1);
272✔
3989
    return SoftCommitTransaction();
272✔
3990
}
3991

3992
OGRErr OGRSQLiteDataSource::CommitTransaction()
67✔
3993

3994
{
3995
    if (m_nSoftTransactionLevel == 1)
67✔
3996
    {
3997
        for (auto &poLayer : m_apoLayers)
232✔
3998
        {
3999
            if (poLayer->IsTableLayer())
167✔
4000
            {
4001
                OGRSQLiteTableLayer *poTableLayer =
4002
                    cpl::down_cast<OGRSQLiteTableLayer *>(poLayer.get());
167✔
4003
                poTableLayer->RunDeferredCreationIfNecessary();
167✔
4004
            }
4005
        }
4006
    }
4007

4008
    return OGRSQLiteBaseDataSource::CommitTransaction();
67✔
4009
}
4010

4011
/************************************************************************/
4012
/*                        RollbackTransaction()                         */
4013
/*                                                                      */
4014
/* Should only be called by user code. Not driver internals.            */
4015
/************************************************************************/
4016

4017
OGRErr OGRSQLiteBaseDataSource::RollbackTransaction()
56✔
4018
{
4019
    if (!m_bUserTransactionActive)
56✔
4020
    {
4021
        CPLError(CE_Failure, CPLE_AppDefined, "Transaction not established");
3✔
4022
        return OGRERR_FAILURE;
3✔
4023
    }
4024

4025
    m_bUserTransactionActive = false;
53✔
4026
    CPLAssert(m_nSoftTransactionLevel == 1);
53✔
4027

4028
    return SoftRollbackTransaction();
53✔
4029
}
4030

4031
OGRErr OGRSQLiteDataSource::RollbackTransaction()
21✔
4032

4033
{
4034
    if (m_nSoftTransactionLevel == 1)
21✔
4035
    {
4036
        for (auto &poLayer : m_apoLayers)
38✔
4037
        {
4038
            if (poLayer->IsTableLayer())
19✔
4039
            {
4040
                OGRSQLiteTableLayer *poTableLayer =
4041
                    cpl::down_cast<OGRSQLiteTableLayer *>(poLayer.get());
19✔
4042
                poTableLayer->RunDeferredCreationIfNecessary();
19✔
4043
            }
4044
        }
4045

4046
        for (auto &poLayer : m_apoLayers)
38✔
4047
        {
4048
            poLayer->InvalidateCachedFeatureCountAndExtent();
19✔
4049
            poLayer->ResetReading();
19✔
4050
        }
4051
    }
4052

4053
    return OGRSQLiteBaseDataSource::RollbackTransaction();
21✔
4054
}
4055

4056
bool OGRSQLiteBaseDataSource::IsInTransaction() const
1,701✔
4057
{
4058
    return m_nSoftTransactionLevel > 0;
1,701✔
4059
}
4060

4061
/************************************************************************/
4062
/*                        SoftStartTransaction()                        */
4063
/*                                                                      */
4064
/*      Create a transaction scope.  If we already have a               */
4065
/*      transaction active this isn't a real transaction, but just      */
4066
/*      an increment to the scope count.                                */
4067
/************************************************************************/
4068

4069
OGRErr OGRSQLiteBaseDataSource::SoftStartTransaction()
3,316✔
4070

4071
{
4072
    m_nSoftTransactionLevel++;
3,316✔
4073

4074
    OGRErr eErr = OGRERR_NONE;
3,316✔
4075
    if (m_nSoftTransactionLevel == 1)
3,316✔
4076
    {
4077
        for (int i = 0; i < GetLayerCount(); i++)
5,747✔
4078
        {
4079
            OGRLayer *poLayer = GetLayer(i);
2,619✔
4080
            poLayer->PrepareStartTransaction();
2,619✔
4081
        }
4082

4083
        eErr = DoTransactionCommand("BEGIN");
3,128✔
4084
    }
4085

4086
    // CPLDebug("SQLite", "%p->SoftStartTransaction() : %d",
4087
    //          this, nSoftTransactionLevel);
4088

4089
    return eErr;
3,316✔
4090
}
4091

4092
/************************************************************************/
4093
/*                     SoftCommitTransaction()                          */
4094
/*                                                                      */
4095
/*      Commit the current transaction if we are at the outer           */
4096
/*      scope.                                                          */
4097
/************************************************************************/
4098

4099
OGRErr OGRSQLiteBaseDataSource::SoftCommitTransaction()
3,262✔
4100

4101
{
4102
    // CPLDebug("SQLite", "%p->SoftCommitTransaction() : %d",
4103
    //          this, nSoftTransactionLevel);
4104

4105
    if (m_nSoftTransactionLevel <= 0)
3,262✔
4106
    {
4107
        CPLAssert(false);
×
4108
        return OGRERR_FAILURE;
4109
    }
4110

4111
    OGRErr eErr = OGRERR_NONE;
3,262✔
4112
    m_nSoftTransactionLevel--;
3,262✔
4113
    if (m_nSoftTransactionLevel == 0)
3,262✔
4114
    {
4115
        eErr = DoTransactionCommand("COMMIT");
3,074✔
4116
    }
4117

4118
    return eErr;
3,262✔
4119
}
4120

4121
/************************************************************************/
4122
/*                  SoftRollbackTransaction()                           */
4123
/*                                                                      */
4124
/*      Do a rollback of the current transaction if we are at the 1st   */
4125
/*      level                                                           */
4126
/************************************************************************/
4127

4128
OGRErr OGRSQLiteBaseDataSource::SoftRollbackTransaction()
124✔
4129

4130
{
4131
    // CPLDebug("SQLite", "%p->SoftRollbackTransaction() : %d",
4132
    //          this, nSoftTransactionLevel);
4133

4134
    while (!m_aosSavepoints.empty())
124✔
4135
    {
4136
        if (RollbackToSavepoint(m_aosSavepoints.back()) != OGRERR_NONE)
28✔
4137
        {
4138
            return OGRERR_FAILURE;
×
4139
        }
4140
        m_aosSavepoints.pop_back();
28✔
4141
    }
4142

4143
    if (m_nSoftTransactionLevel <= 0)
96✔
4144
    {
4145
        CPLAssert(false);
×
4146
        return OGRERR_FAILURE;
4147
    }
4148

4149
    OGRErr eErr = OGRERR_NONE;
96✔
4150
    m_nSoftTransactionLevel--;
96✔
4151
    if (m_nSoftTransactionLevel == 0)
96✔
4152
    {
4153
        eErr = DoTransactionCommand("ROLLBACK");
96✔
4154
        if (eErr == OGRERR_NONE)
96✔
4155
        {
4156
            for (int i = 0; i < GetLayerCount(); i++)
186✔
4157
            {
4158
                OGRLayer *poLayer = GetLayer(i);
90✔
4159
                poLayer->FinishRollbackTransaction("");
90✔
4160
            }
4161
        }
4162
    }
4163

4164
    return eErr;
96✔
4165
}
4166

4167
OGRErr OGRSQLiteBaseDataSource::StartSavepoint(const std::string &osName)
293✔
4168
{
4169

4170
    // A SAVEPOINT implicitly starts a transaction, let's fake one
4171
    if (!IsInTransaction())
293✔
4172
    {
4173
        m_bImplicitTransactionOpened = true;
52✔
4174
        m_nSoftTransactionLevel++;
52✔
4175
        for (int i = 0; i < GetLayerCount(); i++)
104✔
4176
        {
4177
            OGRLayer *poLayer = GetLayer(i);
52✔
4178
            poLayer->PrepareStartTransaction();
52✔
4179
        }
4180
    }
4181

4182
    const std::string osCommand = "SAVEPOINT " + osName;
293✔
4183
    const auto eErr = DoTransactionCommand(osCommand.c_str());
293✔
4184

4185
    if (eErr == OGRERR_NONE)
293✔
4186
    {
4187
        m_aosSavepoints.push_back(osName);
293✔
4188
    }
4189

4190
    return eErr;
586✔
4191
}
4192

4193
OGRErr OGRSQLiteBaseDataSource::ReleaseSavepoint(const std::string &osName)
32✔
4194
{
4195
    if (m_aosSavepoints.empty() ||
64✔
4196
        std::find(m_aosSavepoints.cbegin(), m_aosSavepoints.cend(), osName) ==
32✔
4197
            m_aosSavepoints.cend())
64✔
4198
    {
4199
        CPLError(CE_Failure, CPLE_AppDefined, "Savepoint %s not found",
×
4200
                 osName.c_str());
4201
        return OGRERR_FAILURE;
×
4202
    }
4203

4204
    const std::string osCommand = "RELEASE SAVEPOINT " + osName;
32✔
4205
    const auto eErr = DoTransactionCommand(osCommand.c_str());
32✔
4206

4207
    if (eErr == OGRERR_NONE)
32✔
4208
    {
4209
        // If the savepoint is the outer most, this is the same as COMMIT
4210
        // and the transaction is closed
4211
        if (m_bImplicitTransactionOpened &&
48✔
4212
            m_aosSavepoints.front().compare(osName) == 0)
16✔
4213
        {
4214
            m_bImplicitTransactionOpened = false;
4✔
4215
            m_bUserTransactionActive = false;
4✔
4216
            m_nSoftTransactionLevel = 0;
4✔
4217
            m_aosSavepoints.clear();
4✔
4218
        }
4219
        else
4220
        {
4221
            // Find all savepoints up to the target one and remove them
4222
            while (!m_aosSavepoints.empty() && m_aosSavepoints.back() != osName)
64✔
4223
            {
4224
                m_aosSavepoints.pop_back();
36✔
4225
            }
4226
            if (!m_aosSavepoints.empty())  // should always be true
28✔
4227
            {
4228
                m_aosSavepoints.pop_back();
28✔
4229
            }
4230
        }
4231
    }
4232
    return eErr;
32✔
4233
}
4234

4235
OGRErr OGRSQLiteBaseDataSource::RollbackToSavepoint(const std::string &osName)
117✔
4236
{
4237
    if (m_aosSavepoints.empty() ||
226✔
4238
        std::find(m_aosSavepoints.cbegin(), m_aosSavepoints.cend(), osName) ==
109✔
4239
            m_aosSavepoints.cend())
226✔
4240
    {
4241
        CPLError(CE_Failure, CPLE_AppDefined, "Savepoint %s not found",
36✔
4242
                 osName.c_str());
4243
        return OGRERR_FAILURE;
36✔
4244
    }
4245

4246
    const std::string osCommand = "ROLLBACK TO SAVEPOINT " + osName;
81✔
4247
    const auto eErr = DoTransactionCommand(osCommand.c_str());
81✔
4248

4249
    if (eErr == OGRERR_NONE)
81✔
4250
    {
4251

4252
        // The target savepoint should become the last one in the list
4253
        // and does not need to be removed because ROLLBACK TO SAVEPOINT
4254
        while (!m_aosSavepoints.empty() && m_aosSavepoints.back() != osName)
137✔
4255
        {
4256
            m_aosSavepoints.pop_back();
56✔
4257
        }
4258
    }
4259

4260
    for (int i = 0; i < GetLayerCount(); i++)
162✔
4261
    {
4262
        OGRLayer *poLayer = GetLayer(i);
81✔
4263
        poLayer->FinishRollbackTransaction(osName);
81✔
4264
    }
4265

4266
    return eErr;
81✔
4267
}
4268

4269
/************************************************************************/
4270
/*                          ProcessTransactionSQL()                     */
4271
/************************************************************************/
4272
bool OGRSQLiteBaseDataSource::ProcessTransactionSQL(
6,872✔
4273
    const std::string &osSQLCommand)
4274
{
4275
    bool retVal = true;
6,872✔
4276

4277
    if (EQUAL(osSQLCommand.c_str(), "BEGIN"))
6,872✔
4278
    {
4279
        SoftStartTransaction();
28✔
4280
    }
4281
    else if (EQUAL(osSQLCommand.c_str(), "COMMIT"))
6,844✔
4282
    {
4283
        SoftCommitTransaction();
30✔
4284
    }
4285
    else if (EQUAL(osSQLCommand.c_str(), "ROLLBACK"))
6,814✔
4286
    {
4287
        SoftRollbackTransaction();
32✔
4288
    }
4289
    else if (STARTS_WITH_CI(osSQLCommand.c_str(), "SAVEPOINT"))
6,782✔
4290
    {
4291
        const CPLStringList aosTokens(SQLTokenize(osSQLCommand.c_str()));
586✔
4292
        if (aosTokens.size() == 2)
293✔
4293
        {
4294
            const char *pszSavepointName = aosTokens[1];
293✔
4295
            StartSavepoint(pszSavepointName);
293✔
4296
        }
4297
        else
4298
        {
4299
            retVal = false;
×
4300
        }
4301
    }
4302
    else if (STARTS_WITH_CI(osSQLCommand.c_str(), "RELEASE"))
6,489✔
4303
    {
4304
        const CPLStringList aosTokens(SQLTokenize(osSQLCommand.c_str()));
64✔
4305
        if (aosTokens.size() == 2)
32✔
4306
        {
4307
            const char *pszSavepointName = aosTokens[1];
32✔
4308
            ReleaseSavepoint(pszSavepointName);
32✔
4309
        }
4310
        else if (aosTokens.size() == 3 && EQUAL(aosTokens[1], "SAVEPOINT"))
×
4311
        {
4312
            const char *pszSavepointName = aosTokens[2];
×
4313
            ReleaseSavepoint(pszSavepointName);
×
4314
        }
4315
        else
4316
        {
4317
            retVal = false;
×
4318
        }
4319
    }
4320
    else if (STARTS_WITH_CI(osSQLCommand.c_str(), "ROLLBACK"))
6,457✔
4321
    {
4322
        const CPLStringList aosTokens(SQLTokenize(osSQLCommand.c_str()));
178✔
4323
        if (aosTokens.size() == 2)
89✔
4324
        {
4325
            if (EQUAL(aosTokens[1], "TRANSACTION"))
56✔
4326
            {
4327
                SoftRollbackTransaction();
×
4328
            }
4329
            else
4330
            {
4331
                const char *pszSavepointName = aosTokens[1];
56✔
4332
                RollbackToSavepoint(pszSavepointName);
56✔
4333
            }
4334
        }
4335
        else if (aosTokens.size() > 1)  // Savepoint name is last token
33✔
4336
        {
4337
            const char *pszSavepointName = aosTokens[aosTokens.size() - 1];
33✔
4338
            RollbackToSavepoint(pszSavepointName);
33✔
4339
        }
4340
    }
4341
    else
4342
    {
4343
        retVal = false;
6,368✔
4344
    }
4345

4346
    return retVal;
6,872✔
4347
}
4348

4349
/************************************************************************/
4350
/*                          DoTransactionCommand()                      */
4351
/************************************************************************/
4352

4353
OGRErr OGRSQLiteBaseDataSource::DoTransactionCommand(const char *pszCommand)
6,704✔
4354

4355
{
4356
#ifdef DEBUG
4357
    CPLDebug("OGR_SQLITE", "%s Transaction", pszCommand);
6,704✔
4358
#endif
4359

4360
    return SQLCommand(hDB, pszCommand);
6,704✔
4361
}
4362

4363
/************************************************************************/
4364
/*                          GetSRTEXTColName()                        */
4365
/************************************************************************/
4366

4367
const char *OGRSQLiteDataSource::GetSRTEXTColName()
36✔
4368
{
4369
    if (!m_bIsSpatiaLiteDB || m_bSpatialite4Layout)
36✔
4370
        return "srtext";
28✔
4371

4372
    // Testing for SRS_WKT column presence.
4373
    bool bHasSrsWkt = false;
8✔
4374
    char **papszResult = nullptr;
8✔
4375
    int nRowCount = 0;
8✔
4376
    int nColCount = 0;
8✔
4377
    char *pszErrMsg = nullptr;
8✔
4378
    const int rc =
4379
        sqlite3_get_table(hDB, "PRAGMA table_info(spatial_ref_sys)",
8✔
4380
                          &papszResult, &nRowCount, &nColCount, &pszErrMsg);
4381

4382
    if (rc == SQLITE_OK)
8✔
4383
    {
4384
        for (int iRow = 1; iRow <= nRowCount; iRow++)
56✔
4385
        {
4386
            if (EQUAL("srs_wkt", papszResult[(iRow * nColCount) + 1]))
48✔
4387
                bHasSrsWkt = true;
8✔
4388
        }
4389
        sqlite3_free_table(papszResult);
8✔
4390
    }
4391
    else
4392
    {
4393
        sqlite3_free(pszErrMsg);
×
4394
    }
4395

4396
    return bHasSrsWkt ? "srs_wkt" : nullptr;
8✔
4397
}
4398

4399
/************************************************************************/
4400
/*                         AddSRIDToCache()                             */
4401
/*                                                                      */
4402
/*      Note: this will not add a reference on the poSRS object. Make   */
4403
/*      sure it is freshly created, or add a reference yourself if not. */
4404
/************************************************************************/
4405

4406
OGRSpatialReference *OGRSQLiteDataSource::AddSRIDToCache(
226✔
4407
    int nId,
4408
    std::unique_ptr<OGRSpatialReference, OGRSpatialReferenceReleaser> &&poSRS)
4409
{
4410
    /* -------------------------------------------------------------------- */
4411
    /*      Add to the cache.                                               */
4412
    /* -------------------------------------------------------------------- */
4413
    auto oIter = m_oSRSCache.emplace(nId, std::move(poSRS)).first;
226✔
4414
    return oIter->second.get();
452✔
4415
}
4416

4417
/************************************************************************/
4418
/*                             FetchSRSId()                             */
4419
/*                                                                      */
4420
/*      Fetch the id corresponding to an SRS, and if not found, add     */
4421
/*      it to the table.                                                */
4422
/************************************************************************/
4423

4424
int OGRSQLiteDataSource::FetchSRSId(const OGRSpatialReference *poSRS)
271✔
4425

4426
{
4427
    int nSRSId = m_nUndefinedSRID;
271✔
4428
    if (poSRS == nullptr)
271✔
4429
        return nSRSId;
×
4430

4431
    /* -------------------------------------------------------------------- */
4432
    /*      First, we look through our SRID cache, is it there?             */
4433
    /* -------------------------------------------------------------------- */
4434
    for (const auto &pair : m_oSRSCache)
474✔
4435
    {
4436
        if (pair.second.get() == poSRS)
203✔
4437
            return pair.first;
×
4438
    }
4439
    for (const auto &pair : m_oSRSCache)
371✔
4440
    {
4441
        if (pair.second != nullptr && pair.second->IsSame(poSRS))
203✔
4442
            return pair.first;
103✔
4443
    }
4444

4445
    /* -------------------------------------------------------------------- */
4446
    /*      Build a copy since we may call AutoIdentifyEPSG()               */
4447
    /* -------------------------------------------------------------------- */
4448
    OGRSpatialReference oSRS(*poSRS);
336✔
4449
    poSRS = nullptr;
168✔
4450

4451
    const char *pszAuthorityName = oSRS.GetAuthorityName(nullptr);
168✔
4452
    const char *pszAuthorityCode = nullptr;
168✔
4453

4454
    if (pszAuthorityName == nullptr || strlen(pszAuthorityName) == 0)
168✔
4455
    {
4456
        /* --------------------------------------------------------------------
4457
         */
4458
        /*      Try to identify an EPSG code */
4459
        /* --------------------------------------------------------------------
4460
         */
4461
        oSRS.AutoIdentifyEPSG();
3✔
4462

4463
        pszAuthorityName = oSRS.GetAuthorityName(nullptr);
3✔
4464
        if (pszAuthorityName != nullptr && EQUAL(pszAuthorityName, "EPSG"))
3✔
4465
        {
4466
            pszAuthorityCode = oSRS.GetAuthorityCode(nullptr);
×
4467
            if (pszAuthorityCode != nullptr && strlen(pszAuthorityCode) > 0)
×
4468
            {
4469
                /* Import 'clean' SRS */
4470
                oSRS.importFromEPSG(atoi(pszAuthorityCode));
×
4471

4472
                pszAuthorityName = oSRS.GetAuthorityName(nullptr);
×
4473
                pszAuthorityCode = oSRS.GetAuthorityCode(nullptr);
×
4474
            }
4475
        }
4476
    }
4477

4478
    /* -------------------------------------------------------------------- */
4479
    /*      Check whether the EPSG authority code is already mapped to a    */
4480
    /*      SRS ID.                                                         */
4481
    /* -------------------------------------------------------------------- */
4482
    char *pszErrMsg = nullptr;
168✔
4483
    CPLString osCommand;
336✔
4484
    char **papszResult = nullptr;
168✔
4485
    int nRowCount = 0;
168✔
4486
    int nColCount = 0;
168✔
4487

4488
    if (pszAuthorityName != nullptr && strlen(pszAuthorityName) > 0)
168✔
4489
    {
4490
        pszAuthorityCode = oSRS.GetAuthorityCode(nullptr);
165✔
4491

4492
        if (pszAuthorityCode != nullptr && strlen(pszAuthorityCode) > 0)
165✔
4493
        {
4494
            // XXX: We are using case insensitive comparison for "auth_name"
4495
            // values, because there are variety of options exist. By default
4496
            // the driver uses 'EPSG' in upper case, but SpatiaLite extension
4497
            // uses 'epsg' in lower case.
4498
            osCommand.Printf(
4499
                "SELECT srid FROM spatial_ref_sys WHERE "
4500
                "auth_name = '%s' COLLATE NOCASE AND auth_srid = '%s' "
4501
                "LIMIT 2",
4502
                pszAuthorityName, pszAuthorityCode);
165✔
4503

4504
            int rc = sqlite3_get_table(hDB, osCommand, &papszResult, &nRowCount,
165✔
4505
                                       &nColCount, &pszErrMsg);
4506
            if (rc != SQLITE_OK)
165✔
4507
            {
4508
                /* Retry without COLLATE NOCASE which may not be understood by
4509
                 * older sqlite3 */
4510
                sqlite3_free(pszErrMsg);
×
4511

4512
                osCommand.Printf("SELECT srid FROM spatial_ref_sys WHERE "
4513
                                 "auth_name = '%s' AND auth_srid = '%s'",
4514
                                 pszAuthorityName, pszAuthorityCode);
×
4515

4516
                rc = sqlite3_get_table(hDB, osCommand, &papszResult, &nRowCount,
×
4517
                                       &nColCount, &pszErrMsg);
4518

4519
                /* Retry in lower case for SpatiaLite */
4520
                if (rc != SQLITE_OK)
×
4521
                {
4522
                    sqlite3_free(pszErrMsg);
×
4523
                }
4524
                else if (nRowCount == 0 &&
×
4525
                         strcmp(pszAuthorityName, "EPSG") == 0)
×
4526
                {
4527
                    /* If it is in upper case, look for lower case */
4528
                    sqlite3_free_table(papszResult);
×
4529

4530
                    osCommand.Printf("SELECT srid FROM spatial_ref_sys WHERE "
4531
                                     "auth_name = 'epsg' AND auth_srid = '%s' "
4532
                                     "LIMIT 2",
4533
                                     pszAuthorityCode);
×
4534

4535
                    rc = sqlite3_get_table(hDB, osCommand, &papszResult,
×
4536
                                           &nRowCount, &nColCount, &pszErrMsg);
4537

4538
                    if (rc != SQLITE_OK)
×
4539
                    {
4540
                        sqlite3_free(pszErrMsg);
×
4541
                    }
4542
                }
4543
            }
4544

4545
            if (rc == SQLITE_OK && nRowCount == 1)
165✔
4546
            {
4547
                nSRSId = (papszResult[1] != nullptr) ? atoi(papszResult[1])
140✔
4548
                                                     : m_nUndefinedSRID;
4549
                sqlite3_free_table(papszResult);
140✔
4550

4551
                if (nSRSId != m_nUndefinedSRID)
140✔
4552
                {
4553
                    std::unique_ptr<OGRSpatialReference,
4554
                                    OGRSpatialReferenceReleaser>
4555
                        poCachedSRS;
140✔
4556
                    poCachedSRS.reset(oSRS.Clone());
140✔
4557
                    if (poCachedSRS)
140✔
4558
                    {
4559
                        poCachedSRS->SetAxisMappingStrategy(
140✔
4560
                            OAMS_TRADITIONAL_GIS_ORDER);
4561
                    }
4562
                    AddSRIDToCache(nSRSId, std::move(poCachedSRS));
140✔
4563
                }
4564

4565
                return nSRSId;
140✔
4566
            }
4567
            sqlite3_free_table(papszResult);
25✔
4568
        }
4569
    }
4570

4571
    /* -------------------------------------------------------------------- */
4572
    /*      Search for existing record using either WKT definition or       */
4573
    /*      PROJ.4 string (SpatiaLite variant).                             */
4574
    /* -------------------------------------------------------------------- */
4575
    CPLString osWKT;
56✔
4576
    CPLString osProj4;
56✔
4577

4578
    /* -------------------------------------------------------------------- */
4579
    /*      Translate SRS to WKT.                                           */
4580
    /* -------------------------------------------------------------------- */
4581
    char *pszWKT = nullptr;
28✔
4582

4583
    if (oSRS.exportToWkt(&pszWKT) != OGRERR_NONE)
28✔
4584
    {
4585
        CPLFree(pszWKT);
×
4586
        return m_nUndefinedSRID;
×
4587
    }
4588

4589
    osWKT = pszWKT;
28✔
4590
    CPLFree(pszWKT);
28✔
4591
    pszWKT = nullptr;
28✔
4592

4593
    const char *pszSRTEXTColName = GetSRTEXTColName();
28✔
4594

4595
    if (pszSRTEXTColName != nullptr)
28✔
4596
    {
4597
        /* --------------------------------------------------------------------
4598
         */
4599
        /*      Try to find based on the WKT match. */
4600
        /* --------------------------------------------------------------------
4601
         */
4602
        osCommand.Printf("SELECT srid FROM spatial_ref_sys WHERE \"%s\" = ? "
4603
                         "LIMIT 2",
4604
                         SQLEscapeName(pszSRTEXTColName).c_str());
28✔
4605
    }
4606

4607
    /* -------------------------------------------------------------------- */
4608
    /*      Handle SpatiaLite (< 4) flavor of the spatial_ref_sys.         */
4609
    /* -------------------------------------------------------------------- */
4610
    else
4611
    {
4612
        /* --------------------------------------------------------------------
4613
         */
4614
        /*      Translate SRS to PROJ.4 string. */
4615
        /* --------------------------------------------------------------------
4616
         */
4617
        char *pszProj4 = nullptr;
×
4618

4619
        if (oSRS.exportToProj4(&pszProj4) != OGRERR_NONE)
×
4620
        {
4621
            CPLFree(pszProj4);
×
4622
            return m_nUndefinedSRID;
×
4623
        }
4624

4625
        osProj4 = pszProj4;
×
4626
        CPLFree(pszProj4);
×
4627
        pszProj4 = nullptr;
×
4628

4629
        /* --------------------------------------------------------------------
4630
         */
4631
        /*      Try to find based on the PROJ.4 match. */
4632
        /* --------------------------------------------------------------------
4633
         */
4634
        osCommand.Printf(
4635
            "SELECT srid FROM spatial_ref_sys WHERE proj4text = ? LIMIT 2");
×
4636
    }
4637

4638
    sqlite3_stmt *hSelectStmt = nullptr;
28✔
4639
    int rc = prepareSql(hDB, osCommand, -1, &hSelectStmt, nullptr);
28✔
4640

4641
    if (rc == SQLITE_OK)
28✔
4642
        rc = sqlite3_bind_text(hSelectStmt, 1,
56✔
4643
                               (pszSRTEXTColName != nullptr) ? osWKT.c_str()
28✔
4644
                                                             : osProj4.c_str(),
×
4645
                               -1, SQLITE_STATIC);
4646

4647
    if (rc == SQLITE_OK)
28✔
4648
        rc = sqlite3_step(hSelectStmt);
28✔
4649

4650
    if (rc == SQLITE_ROW)
28✔
4651
    {
4652
        if (sqlite3_column_type(hSelectStmt, 0) == SQLITE_INTEGER)
×
4653
            nSRSId = sqlite3_column_int(hSelectStmt, 0);
×
4654
        else
4655
            nSRSId = m_nUndefinedSRID;
×
4656

4657
        sqlite3_finalize(hSelectStmt);
×
4658

4659
        if (nSRSId != m_nUndefinedSRID)
×
4660
        {
4661
            std::unique_ptr<OGRSpatialReference, OGRSpatialReferenceReleaser>
4662
                poSRSClone;
×
4663
            poSRSClone.reset(oSRS.Clone());
×
4664
            AddSRIDToCache(nSRSId, std::move(poSRSClone));
×
4665
        }
4666

4667
        return nSRSId;
×
4668
    }
4669

4670
    /* -------------------------------------------------------------------- */
4671
    /*      If the command actually failed, then the metadata table is      */
4672
    /*      likely missing, so we give up.                                  */
4673
    /* -------------------------------------------------------------------- */
4674
    if (rc != SQLITE_DONE && rc != SQLITE_ROW)
28✔
4675
    {
4676
        sqlite3_finalize(hSelectStmt);
×
4677
        return m_nUndefinedSRID;
×
4678
    }
4679

4680
    sqlite3_finalize(hSelectStmt);
28✔
4681

4682
    /* -------------------------------------------------------------------- */
4683
    /*      Translate SRS to PROJ.4 string (if not already done)            */
4684
    /* -------------------------------------------------------------------- */
4685
    if (osProj4.empty())
28✔
4686
    {
4687
        char *pszProj4 = nullptr;
28✔
4688
        if (oSRS.exportToProj4(&pszProj4) == OGRERR_NONE)
28✔
4689
        {
4690
            osProj4 = pszProj4;
26✔
4691
        }
4692
        CPLFree(pszProj4);
28✔
4693
        pszProj4 = nullptr;
28✔
4694
    }
4695

4696
    /* -------------------------------------------------------------------- */
4697
    /*      If we have an authority code try to assign SRS ID the same      */
4698
    /*      as that code.                                                   */
4699
    /* -------------------------------------------------------------------- */
4700
    if (pszAuthorityCode != nullptr && strlen(pszAuthorityCode) > 0)
28✔
4701
    {
4702
        osCommand.Printf("SELECT * FROM spatial_ref_sys WHERE auth_srid='%s' "
4703
                         "LIMIT 2",
4704
                         SQLEscapeLiteral(pszAuthorityCode).c_str());
25✔
4705
        rc = sqlite3_get_table(hDB, osCommand, &papszResult, &nRowCount,
25✔
4706
                               &nColCount, &pszErrMsg);
4707

4708
        if (rc != SQLITE_OK)
25✔
4709
        {
4710
            CPLError(CE_Failure, CPLE_AppDefined,
×
4711
                     "exec(SELECT '%s' FROM spatial_ref_sys) failed: %s",
4712
                     pszAuthorityCode, pszErrMsg);
4713
            sqlite3_free(pszErrMsg);
×
4714
        }
4715

4716
        /* --------------------------------------------------------------------
4717
         */
4718
        /*      If there is no SRS ID with such auth_srid, use it as SRS ID. */
4719
        /* --------------------------------------------------------------------
4720
         */
4721
        if (nRowCount < 1)
25✔
4722
        {
4723
            nSRSId = atoi(pszAuthorityCode);
25✔
4724
            /* The authority code might be non numeric, e.g. IGNF:LAMB93 */
4725
            /* in which case we might fallback to the fake OGR authority */
4726
            /* for spatialite, since its auth_srid is INTEGER */
4727
            if (nSRSId == 0)
25✔
4728
            {
4729
                nSRSId = m_nUndefinedSRID;
×
4730
                if (m_bIsSpatiaLiteDB)
×
4731
                    pszAuthorityName = nullptr;
×
4732
            }
4733
        }
4734
        sqlite3_free_table(papszResult);
25✔
4735
    }
4736

4737
    /* -------------------------------------------------------------------- */
4738
    /*      Otherwise get the current maximum srid in the srs table.        */
4739
    /* -------------------------------------------------------------------- */
4740
    if (nSRSId == m_nUndefinedSRID)
28✔
4741
    {
4742
        rc =
4743
            sqlite3_get_table(hDB, "SELECT MAX(srid) FROM spatial_ref_sys",
3✔
4744
                              &papszResult, &nRowCount, &nColCount, &pszErrMsg);
4745

4746
        if (rc != SQLITE_OK)
3✔
4747
        {
4748
            CPLError(CE_Failure, CPLE_AppDefined,
×
4749
                     "SELECT of the maximum SRS ID failed: %s", pszErrMsg);
4750
            sqlite3_free(pszErrMsg);
×
4751
            return m_nUndefinedSRID;
×
4752
        }
4753

4754
        if (nRowCount < 1 || !papszResult[1])
3✔
4755
            nSRSId = 50000;
1✔
4756
        else
4757
            nSRSId = atoi(papszResult[1]) + 1;  // Insert as the next SRS ID
2✔
4758
        sqlite3_free_table(papszResult);
3✔
4759
    }
4760

4761
    /* -------------------------------------------------------------------- */
4762
    /*      Try adding the SRS to the SRS table.                            */
4763
    /* -------------------------------------------------------------------- */
4764

4765
    const char *apszToInsert[] = {nullptr, nullptr, nullptr,
28✔
4766
                                  nullptr, nullptr, nullptr};
4767

4768
    if (!m_bIsSpatiaLiteDB)
28✔
4769
    {
4770
        if (pszAuthorityName != nullptr)
25✔
4771
        {
4772
            osCommand.Printf(
4773
                "INSERT INTO spatial_ref_sys (srid,srtext,auth_name,auth_srid) "
4774
                "                     VALUES (%d, ?, ?, ?)",
4775
                nSRSId);
24✔
4776
            apszToInsert[0] = osWKT.c_str();
24✔
4777
            apszToInsert[1] = pszAuthorityName;
24✔
4778
            apszToInsert[2] = pszAuthorityCode;
24✔
4779
        }
4780
        else
4781
        {
4782
            osCommand.Printf("INSERT INTO spatial_ref_sys (srid,srtext) "
4783
                             "                     VALUES (%d, ?)",
4784
                             nSRSId);
1✔
4785
            apszToInsert[0] = osWKT.c_str();
1✔
4786
        }
4787
    }
4788
    else
4789
    {
4790
        CPLString osSRTEXTColNameWithCommaBefore;
6✔
4791
        if (pszSRTEXTColName != nullptr)
3✔
4792
            osSRTEXTColNameWithCommaBefore.Printf(", %s", pszSRTEXTColName);
3✔
4793

4794
        const char *pszProjCS = oSRS.GetAttrValue("PROJCS");
3✔
4795
        if (pszProjCS == nullptr)
3✔
4796
            pszProjCS = oSRS.GetAttrValue("GEOGCS");
1✔
4797

4798
        if (pszAuthorityName != nullptr)
3✔
4799
        {
4800
            if (pszProjCS)
1✔
4801
            {
4802
                osCommand.Printf(
4803
                    "INSERT INTO spatial_ref_sys "
4804
                    "(srid, auth_name, auth_srid, ref_sys_name, proj4text%s) "
4805
                    "VALUES (%d, ?, ?, ?, ?%s)",
4806
                    (pszSRTEXTColName != nullptr)
4807
                        ? osSRTEXTColNameWithCommaBefore.c_str()
1✔
4808
                        : "",
4809
                    nSRSId, (pszSRTEXTColName != nullptr) ? ", ?" : "");
2✔
4810
                apszToInsert[0] = pszAuthorityName;
1✔
4811
                apszToInsert[1] = pszAuthorityCode;
1✔
4812
                apszToInsert[2] = pszProjCS;
1✔
4813
                apszToInsert[3] = osProj4.c_str();
1✔
4814
                apszToInsert[4] =
1✔
4815
                    (pszSRTEXTColName != nullptr) ? osWKT.c_str() : nullptr;
1✔
4816
            }
4817
            else
4818
            {
4819
                osCommand.Printf("INSERT INTO spatial_ref_sys "
4820
                                 "(srid, auth_name, auth_srid, proj4text%s) "
4821
                                 "VALUES (%d, ?, ?, ?%s)",
4822
                                 (pszSRTEXTColName != nullptr)
4823
                                     ? osSRTEXTColNameWithCommaBefore.c_str()
×
4824
                                     : "",
4825
                                 nSRSId,
4826
                                 (pszSRTEXTColName != nullptr) ? ", ?" : "");
×
4827
                apszToInsert[0] = pszAuthorityName;
×
4828
                apszToInsert[1] = pszAuthorityCode;
×
4829
                apszToInsert[2] = osProj4.c_str();
×
4830
                apszToInsert[3] =
×
4831
                    (pszSRTEXTColName != nullptr) ? osWKT.c_str() : nullptr;
×
4832
            }
4833
        }
4834
        else
4835
        {
4836
            /* SpatiaLite spatial_ref_sys auth_name and auth_srid columns must
4837
             * be NOT NULL */
4838
            /* so insert within a fake OGR "authority" */
4839
            if (pszProjCS)
2✔
4840
            {
4841
                osCommand.Printf("INSERT INTO spatial_ref_sys "
4842
                                 "(srid, auth_name, auth_srid, ref_sys_name, "
4843
                                 "proj4text%s) VALUES (%d, 'OGR', %d, ?, ?%s)",
4844
                                 (pszSRTEXTColName != nullptr)
4845
                                     ? osSRTEXTColNameWithCommaBefore.c_str()
1✔
4846
                                     : "",
4847
                                 nSRSId, nSRSId,
4848
                                 (pszSRTEXTColName != nullptr) ? ", ?" : "");
2✔
4849
                apszToInsert[0] = pszProjCS;
1✔
4850
                apszToInsert[1] = osProj4.c_str();
1✔
4851
                apszToInsert[2] =
1✔
4852
                    (pszSRTEXTColName != nullptr) ? osWKT.c_str() : nullptr;
1✔
4853
            }
4854
            else
4855
            {
4856
                osCommand.Printf("INSERT INTO spatial_ref_sys "
4857
                                 "(srid, auth_name, auth_srid, proj4text%s) "
4858
                                 "VALUES (%d, 'OGR', %d, ?%s)",
4859
                                 (pszSRTEXTColName != nullptr)
4860
                                     ? osSRTEXTColNameWithCommaBefore.c_str()
1✔
4861
                                     : "",
4862
                                 nSRSId, nSRSId,
4863
                                 (pszSRTEXTColName != nullptr) ? ", ?" : "");
2✔
4864
                apszToInsert[0] = osProj4.c_str();
1✔
4865
                apszToInsert[1] =
1✔
4866
                    (pszSRTEXTColName != nullptr) ? osWKT.c_str() : nullptr;
1✔
4867
            }
4868
        }
4869
    }
4870

4871
    sqlite3_stmt *hInsertStmt = nullptr;
28✔
4872
    rc = prepareSql(hDB, osCommand, -1, &hInsertStmt, nullptr);
28✔
4873

4874
    for (int i = 0; apszToInsert[i] != nullptr; i++)
111✔
4875
    {
4876
        if (rc == SQLITE_OK)
83✔
4877
            rc = sqlite3_bind_text(hInsertStmt, i + 1, apszToInsert[i], -1,
83✔
4878
                                   SQLITE_STATIC);
4879
    }
4880

4881
    if (rc == SQLITE_OK)
28✔
4882
        rc = sqlite3_step(hInsertStmt);
28✔
4883

4884
    if (rc != SQLITE_OK && rc != SQLITE_DONE)
28✔
4885
    {
4886
        CPLError(CE_Failure, CPLE_AppDefined, "Unable to insert SRID (%s): %s",
×
4887
                 osCommand.c_str(), sqlite3_errmsg(hDB));
4888

4889
        sqlite3_finalize(hInsertStmt);
×
4890
        return FALSE;
×
4891
    }
4892

4893
    sqlite3_finalize(hInsertStmt);
28✔
4894

4895
    if (nSRSId != m_nUndefinedSRID)
28✔
4896
    {
4897
        std::unique_ptr<OGRSpatialReference, OGRSpatialReferenceReleaser>
4898
            poCachedSRS(new OGRSpatialReference(std::move(oSRS)));
56✔
4899
        poCachedSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
28✔
4900
        AddSRIDToCache(nSRSId, std::move(poCachedSRS));
28✔
4901
    }
4902

4903
    return nSRSId;
28✔
4904
}
4905

4906
/************************************************************************/
4907
/*                              FetchSRS()                              */
4908
/*                                                                      */
4909
/*      Return a SRS corresponding to a particular id.  Note that       */
4910
/*      reference counting should be honoured on the returned           */
4911
/*      OGRSpatialReference, as handles may be cached.                  */
4912
/************************************************************************/
4913

4914
OGRSpatialReference *OGRSQLiteDataSource::FetchSRS(int nId)
563✔
4915

4916
{
4917
    if (nId <= 0)
563✔
4918
        return nullptr;
346✔
4919

4920
    /* -------------------------------------------------------------------- */
4921
    /*      First, we look through our SRID cache, is it there?             */
4922
    /* -------------------------------------------------------------------- */
4923
    const auto oIter = m_oSRSCache.find(nId);
217✔
4924
    if (oIter != m_oSRSCache.end())
217✔
4925
    {
4926
        return oIter->second.get();
150✔
4927
    }
4928

4929
    /* -------------------------------------------------------------------- */
4930
    /*      Try looking up in spatial_ref_sys table.                        */
4931
    /* -------------------------------------------------------------------- */
4932
    char *pszErrMsg = nullptr;
67✔
4933
    char **papszResult = nullptr;
67✔
4934
    int nRowCount = 0;
67✔
4935
    int nColCount = 0;
67✔
4936
    std::unique_ptr<OGRSpatialReference, OGRSpatialReferenceReleaser> poSRS;
67✔
4937

4938
    CPLString osCommand;
134✔
4939
    osCommand.Printf("SELECT srtext FROM spatial_ref_sys WHERE srid = %d "
67✔
4940
                     "LIMIT 2",
4941
                     nId);
67✔
4942
    int rc = sqlite3_get_table(hDB, osCommand, &papszResult, &nRowCount,
67✔
4943
                               &nColCount, &pszErrMsg);
4944

4945
    if (rc == SQLITE_OK)
67✔
4946
    {
4947
        if (nRowCount < 1)
59✔
4948
        {
4949
            sqlite3_free_table(papszResult);
2✔
4950
            return nullptr;
2✔
4951
        }
4952

4953
        char **papszRow = papszResult + nColCount;
57✔
4954
        if (papszRow[0] != nullptr)
57✔
4955
        {
4956
            CPLString osWKT = papszRow[0];
114✔
4957

4958
            /* --------------------------------------------------------------------
4959
             */
4960
            /*      Translate into a spatial reference. */
4961
            /* --------------------------------------------------------------------
4962
             */
4963
            poSRS.reset(new OGRSpatialReference());
57✔
4964
            poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
57✔
4965
            if (poSRS->importFromWkt(osWKT.c_str()) != OGRERR_NONE)
57✔
4966
            {
4967
                poSRS.reset();
×
4968
            }
4969
        }
4970

4971
        sqlite3_free_table(papszResult);
57✔
4972
    }
4973

4974
    /* -------------------------------------------------------------------- */
4975
    /*      Next try SpatiaLite flavor. SpatiaLite uses PROJ.4 strings     */
4976
    /*      in 'proj4text' column instead of WKT in 'srtext'. Note: recent  */
4977
    /*      versions of spatialite have a srs_wkt column too                */
4978
    /* -------------------------------------------------------------------- */
4979
    else
4980
    {
4981
        sqlite3_free(pszErrMsg);
8✔
4982
        pszErrMsg = nullptr;
8✔
4983

4984
        const char *pszSRTEXTColName = GetSRTEXTColName();
8✔
4985
        CPLString osSRTEXTColNameWithCommaBefore;
8✔
4986
        if (pszSRTEXTColName != nullptr)
8✔
4987
            osSRTEXTColNameWithCommaBefore.Printf(", %s", pszSRTEXTColName);
8✔
4988

4989
        osCommand.Printf(
8✔
4990
            "SELECT proj4text, auth_name, auth_srid%s FROM spatial_ref_sys "
4991
            "WHERE srid = %d LIMIT 2",
4992
            (pszSRTEXTColName != nullptr)
4993
                ? osSRTEXTColNameWithCommaBefore.c_str()
8✔
4994
                : "",
4995
            nId);
16✔
4996
        rc = sqlite3_get_table(hDB, osCommand, &papszResult, &nRowCount,
8✔
4997
                               &nColCount, &pszErrMsg);
4998
        if (rc == SQLITE_OK)
8✔
4999
        {
5000
            if (nRowCount < 1)
8✔
5001
            {
5002
                sqlite3_free_table(papszResult);
7✔
5003
                return nullptr;
7✔
5004
            }
5005

5006
            /* --------------------------------------------------------------------
5007
             */
5008
            /*      Translate into a spatial reference. */
5009
            /* --------------------------------------------------------------------
5010
             */
5011
            char **papszRow = papszResult + nColCount;
1✔
5012

5013
            const char *pszProj4Text = papszRow[0];
1✔
5014
            const char *pszAuthName = papszRow[1];
1✔
5015
            int nAuthSRID = (papszRow[2] != nullptr) ? atoi(papszRow[2]) : 0;
1✔
5016
            const char *pszWKT =
1✔
5017
                (pszSRTEXTColName != nullptr) ? papszRow[3] : nullptr;
1✔
5018

5019
            poSRS.reset(new OGRSpatialReference());
1✔
5020
            poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1✔
5021

5022
            /* Try first from EPSG code */
5023
            if (pszAuthName != nullptr && EQUAL(pszAuthName, "EPSG") &&
2✔
5024
                poSRS->importFromEPSG(nAuthSRID) == OGRERR_NONE)
1✔
5025
            {
5026
                /* Do nothing */
5027
            }
5028
            /* Then from WKT string */
5029
            else if (pszWKT != nullptr &&
×
5030
                     poSRS->importFromWkt(pszWKT) == OGRERR_NONE)
×
5031
            {
5032
                /* Do nothing */
5033
            }
5034
            /* Finally from Proj4 string */
5035
            else if (pszProj4Text != nullptr &&
×
5036
                     poSRS->importFromProj4(pszProj4Text) == OGRERR_NONE)
×
5037
            {
5038
                /* Do nothing */
5039
            }
5040
            else
5041
            {
5042
                poSRS.reset();
×
5043
            }
5044

5045
            sqlite3_free_table(papszResult);
1✔
5046
        }
5047

5048
        /* --------------------------------------------------------------------
5049
         */
5050
        /*      No success, report an error. */
5051
        /* --------------------------------------------------------------------
5052
         */
5053
        else
5054
        {
5055
            CPLError(CE_Failure, CPLE_AppDefined, "%s: %s", osCommand.c_str(),
×
5056
                     pszErrMsg);
5057
            sqlite3_free(pszErrMsg);
×
5058
            return nullptr;
×
5059
        }
5060
    }
5061

5062
    if (poSRS)
58✔
5063
        poSRS->StripTOWGS84IfKnownDatumAndAllowed();
58✔
5064

5065
    /* -------------------------------------------------------------------- */
5066
    /*      Add to the cache.                                               */
5067
    /* -------------------------------------------------------------------- */
5068
    return AddSRIDToCache(nId, std::move(poSRS));
58✔
5069
}
5070

5071
/************************************************************************/
5072
/*                              SetName()                               */
5073
/************************************************************************/
5074

5075
void OGRSQLiteDataSource::SetName(const char *pszNameIn)
×
5076
{
5077
    CPLFree(m_pszFilename);
×
5078
    m_pszFilename = CPLStrdup(pszNameIn);
×
5079
}
×
5080

5081
/************************************************************************/
5082
/*                       GetEnvelopeFromSQL()                           */
5083
/************************************************************************/
5084

5085
const OGREnvelope *
5086
OGRSQLiteBaseDataSource::GetEnvelopeFromSQL(const CPLString &osSQL)
16✔
5087
{
5088
    const auto oIter = oMapSQLEnvelope.find(osSQL);
16✔
5089
    if (oIter != oMapSQLEnvelope.end())
16✔
5090
        return &oIter->second;
5✔
5091
    else
5092
        return nullptr;
11✔
5093
}
5094

5095
/************************************************************************/
5096
/*                         SetEnvelopeForSQL()                          */
5097
/************************************************************************/
5098

5099
void OGRSQLiteBaseDataSource::SetEnvelopeForSQL(const CPLString &osSQL,
5✔
5100
                                                const OGREnvelope &oEnvelope)
5101
{
5102
    oMapSQLEnvelope[osSQL] = oEnvelope;
5✔
5103
}
5✔
5104

5105
/***********************************************************************/
5106
/*                       SetQueryLoggerFunc()                          */
5107
/***********************************************************************/
5108

5109
bool OGRSQLiteBaseDataSource::SetQueryLoggerFunc(
1✔
5110
    GDALQueryLoggerFunc pfnQueryLoggerFuncIn, void *poQueryLoggerArgIn)
5111
{
5112
    pfnQueryLoggerFunc = pfnQueryLoggerFuncIn;
1✔
5113
    poQueryLoggerArg = poQueryLoggerArgIn;
1✔
5114

5115
    if (pfnQueryLoggerFunc)
1✔
5116
    {
5117
        sqlite3_trace_v2(
1✔
5118
            hDB, SQLITE_TRACE_PROFILE,
5119
            [](unsigned int /* traceProfile */, void *context,
17✔
5120
               void *preparedStatement, void *executionTime) -> int
5121
            {
5122
                if (context)
17✔
5123
                {
5124
                    char *pzsSql{sqlite3_expanded_sql(
17✔
5125
                        reinterpret_cast<sqlite3_stmt *>(preparedStatement))};
5126
                    if (pzsSql)
17✔
5127
                    {
5128
                        const std::string sql{pzsSql};
34✔
5129
                        sqlite3_free(pzsSql);
17✔
5130
                        const uint64_t executionTimeMilliSeconds{
17✔
5131
                            static_cast<uint64_t>(
5132
                                *reinterpret_cast<uint64_t *>(executionTime) /
17✔
5133
                                1e+6)};
5134
                        OGRSQLiteBaseDataSource *source{
17✔
5135
                            reinterpret_cast<OGRSQLiteBaseDataSource *>(
5136
                                context)};
5137
                        if (source->pfnQueryLoggerFunc)
17✔
5138
                        {
5139
                            source->pfnQueryLoggerFunc(
17✔
5140
                                sql.c_str(), nullptr, -1,
5141
                                executionTimeMilliSeconds,
5142
                                source->poQueryLoggerArg);
5143
                        }
5144
                    }
5145
                }
5146
                return 0;
17✔
5147
            },
5148
            reinterpret_cast<void *>(this));
5149
        return true;
1✔
5150
    }
5151
    return false;
×
5152
}
5153

5154
/************************************************************************/
5155
/*                         AbortSQL()                                   */
5156
/************************************************************************/
5157

5158
OGRErr OGRSQLiteBaseDataSource::AbortSQL()
2✔
5159
{
5160
    sqlite3_interrupt(hDB);
2✔
5161
    return OGRERR_NONE;
2✔
5162
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc