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