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