Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OpenGIS Simple Features Reference Implementation
4 : * Purpose: Implements OGRSQLiteTableLayer class, access to an existing table.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2004, Frank Warmerdam
9 : * Copyright (c) 2009-2013, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_port.h"
15 : #include "ogr_sqlite.h"
16 : #include "ogrsqliteutility.h"
17 :
18 : #include <json.h> // JSON-C
19 :
20 : #include <climits>
21 : #include <cstddef>
22 : #include <cstdio>
23 : #include <cstdlib>
24 : #include <cstring>
25 : #include <ctime>
26 : #include <limits>
27 : #include <memory>
28 : #include <set>
29 : #include <string>
30 : #include <utility>
31 : #include <vector>
32 :
33 : #include "cpl_conv.h"
34 : #include "cpl_error.h"
35 : #include "cpl_string.h"
36 : #include "cpl_time.h"
37 : #include "ogr_core.h"
38 : #include "ogrlibjsonutils.h"
39 : #include "ogr_feature.h"
40 : #include "ogr_geometry.h"
41 : #include "ogr_p.h"
42 : #include "ogr_spatialref.h"
43 : #include "ogrsf_frmts.h"
44 : #include "sqlite3.h"
45 :
46 : static const char UNSUPPORTED_OP_READ_ONLY[] =
47 : "%s : unsupported operation on a read-only datasource.";
48 :
49 : /************************************************************************/
50 : /* OGRSQLiteTableLayer() */
51 : /************************************************************************/
52 :
53 1978 : OGRSQLiteTableLayer::OGRSQLiteTableLayer(OGRSQLiteDataSource *poDSIn)
54 : : OGRSQLiteLayer(poDSIn),
55 : m_bSpatialite2D(
56 5934 : poDSIn->GetSpatialiteVersionNumber() <
57 1978 : OGRSQLiteDataSource::MakeSpatialiteVersionNumber(2, 4, 0)),
58 1978 : m_bHasCheckedTriggers(!CPLTestBool(
59 3956 : CPLGetConfigOption("OGR_SQLITE_DISABLE_INSERT_TRIGGERS", "YES")))
60 : {
61 1978 : }
62 :
63 : /************************************************************************/
64 : /* ~OGRSQLiteTableLayer() */
65 : /************************************************************************/
66 :
67 3954 : OGRSQLiteTableLayer::~OGRSQLiteTableLayer()
68 :
69 : {
70 1977 : ClearStatement();
71 1977 : ClearInsertStmt();
72 :
73 : const int nGeomFieldCount =
74 1977 : m_poFeatureDefn ? m_poFeatureDefn->GetGeomFieldCount() : 0;
75 2574 : for (int i = 0; i < nGeomFieldCount; i++)
76 : {
77 : OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
78 597 : m_poFeatureDefn->myGetGeomFieldDefn(i);
79 : // Restore temporarily disabled triggers.
80 1480 : for (int j = 0; j < static_cast<int>(
81 883 : poGeomFieldDefn->m_aosDisabledTriggers.size());
82 : j++)
83 : {
84 286 : CPLDebug("SQLite", "Restoring trigger %s",
85 286 : poGeomFieldDefn->m_aosDisabledTriggers[j].first.c_str());
86 : // This may fail since CreateSpatialIndex() reinstalls triggers, so
87 : // don't check result.
88 572 : CPL_IGNORE_RET_VAL(sqlite3_exec(
89 286 : m_poDS->GetDB(),
90 286 : poGeomFieldDefn->m_aosDisabledTriggers[j].second.c_str(),
91 : nullptr, nullptr, nullptr));
92 : }
93 : }
94 :
95 1977 : CPLFree(m_pszTableName);
96 1977 : CPLFree(m_pszEscapedTableName);
97 1977 : CPLFree(m_pszCreationGeomFormat);
98 3954 : }
99 :
100 : /************************************************************************/
101 : /* CreateSpatialIndexIfNecessary() */
102 : /************************************************************************/
103 :
104 7300 : void OGRSQLiteTableLayer::CreateSpatialIndexIfNecessary()
105 : {
106 7300 : if (m_bDeferredSpatialIndexCreation)
107 : {
108 274 : for (int iGeomCol = 0; iGeomCol < m_poFeatureDefn->GetGeomFieldCount();
109 : iGeomCol++)
110 137 : CreateSpatialIndex(iGeomCol);
111 137 : m_bDeferredSpatialIndexCreation = false;
112 : }
113 7300 : }
114 :
115 : /************************************************************************/
116 : /* ClearInsertStmt() */
117 : /************************************************************************/
118 :
119 13740 : void OGRSQLiteTableLayer::ClearInsertStmt()
120 : {
121 13740 : if (m_hInsertStmt != nullptr)
122 : {
123 5436 : sqlite3_finalize(m_hInsertStmt);
124 5436 : m_hInsertStmt = nullptr;
125 : }
126 13740 : m_osLastInsertStmt = "";
127 13740 : }
128 :
129 : /************************************************************************/
130 : /* Initialize() */
131 : /************************************************************************/
132 :
133 1978 : CPLErr OGRSQLiteTableLayer::Initialize(const char *m_pszTableNameIn,
134 : bool bIsTable, bool bIsVirtualShapeIn,
135 : bool bDeferredCreationIn,
136 : bool bMayEmitError)
137 : {
138 1978 : SetDescription(m_pszTableNameIn);
139 :
140 1978 : m_bIsTable = bIsTable;
141 1978 : m_bIsVirtualShape = bIsVirtualShapeIn;
142 1978 : m_pszTableName = CPLStrdup(m_pszTableNameIn);
143 1978 : m_bDeferredCreation = bDeferredCreationIn;
144 1978 : m_pszEscapedTableName = CPLStrdup(SQLEscapeLiteral(m_pszTableName));
145 :
146 1978 : if (!bDeferredCreationIn && strchr(m_pszTableName, '(') != nullptr &&
147 303 : m_pszTableName[strlen(m_pszTableName) - 1] == ')')
148 : {
149 303 : char *pszErrMsg = nullptr;
150 303 : int nRowCount = 0, nColCount = 0;
151 303 : char **papszResult = nullptr;
152 : const char *pszSQL =
153 303 : CPLSPrintf("SELECT * FROM sqlite_master WHERE name = '%s'",
154 : m_pszEscapedTableName);
155 303 : int rc = sqlite3_get_table(m_poDS->GetDB(), pszSQL, &papszResult,
156 : &nRowCount, &nColCount, &pszErrMsg);
157 303 : int bFound = (rc == SQLITE_OK && nRowCount == 1);
158 303 : sqlite3_free_table(papszResult);
159 303 : sqlite3_free(pszErrMsg);
160 :
161 303 : if (!bFound)
162 : {
163 302 : char *pszGeomCol = CPLStrdup(strchr(m_pszTableName, '(') + 1);
164 302 : pszGeomCol[strlen(pszGeomCol) - 1] = 0;
165 302 : *strchr(m_pszTableName, '(') = 0;
166 302 : CPLFree(m_pszEscapedTableName);
167 302 : m_pszEscapedTableName = CPLStrdup(SQLEscapeLiteral(m_pszTableName));
168 302 : EstablishFeatureDefn(pszGeomCol, bMayEmitError);
169 302 : CPLFree(pszGeomCol);
170 601 : if (m_poFeatureDefn == nullptr ||
171 299 : m_poFeatureDefn->GetGeomFieldCount() == 0)
172 296 : return CE_Failure;
173 : }
174 : }
175 :
176 1682 : return CE_None;
177 : }
178 :
179 : /************************************************************************/
180 : /* GetGeomFormat() */
181 : /************************************************************************/
182 :
183 447 : static OGRSQLiteGeomFormat GetGeomFormat(const char *pszGeomFormat)
184 : {
185 447 : OGRSQLiteGeomFormat eGeomFormat = OSGF_Unknown;
186 447 : if (pszGeomFormat)
187 : {
188 447 : if (EQUAL(pszGeomFormat, "WKT"))
189 2 : eGeomFormat = OSGF_WKT;
190 445 : else if (EQUAL(pszGeomFormat, "WKB"))
191 296 : eGeomFormat = OSGF_WKB;
192 149 : else if (EQUAL(pszGeomFormat, "FGF"))
193 1 : eGeomFormat = OSGF_FGF;
194 148 : else if (EQUAL(pszGeomFormat, "SpatiaLite"))
195 148 : eGeomFormat = OSGF_SpatiaLite;
196 : }
197 447 : return eGeomFormat;
198 : }
199 :
200 : /************************************************************************/
201 : /* SetCreationParameters() */
202 : /************************************************************************/
203 :
204 444 : void OGRSQLiteTableLayer::SetCreationParameters(const char *pszFIDColumnName,
205 : OGRwkbGeometryType eGeomType,
206 : const char *pszGeomFormat,
207 : const char *pszGeometryName,
208 : OGRSpatialReference *poSRS,
209 : int nSRSId)
210 :
211 : {
212 444 : m_pszFIDColumn = CPLStrdup(pszFIDColumnName);
213 444 : m_poFeatureDefn = new OGRSQLiteFeatureDefn(m_pszTableName);
214 444 : m_poFeatureDefn->SetGeomType(wkbNone);
215 444 : m_poFeatureDefn->Reference();
216 444 : m_pszCreationGeomFormat =
217 444 : (pszGeomFormat) ? CPLStrdup(pszGeomFormat) : nullptr;
218 444 : if (eGeomType != wkbNone)
219 : {
220 318 : if (nSRSId == UNINITIALIZED_SRID)
221 0 : nSRSId = m_poDS->GetUndefinedSRID();
222 318 : OGRSQLiteGeomFormat eGeomFormat = GetGeomFormat(pszGeomFormat);
223 : auto poGeomFieldDefn =
224 318 : std::make_unique<OGRSQLiteGeomFieldDefn>(pszGeometryName, -1);
225 318 : poGeomFieldDefn->SetType(eGeomType);
226 318 : poGeomFieldDefn->m_nSRSId = nSRSId;
227 318 : poGeomFieldDefn->m_eGeomFormat = eGeomFormat;
228 318 : poGeomFieldDefn->SetSpatialRef(poSRS);
229 318 : m_poFeatureDefn->AddGeomFieldDefn(std::move(poGeomFieldDefn));
230 : }
231 444 : m_poFeatureDefn->Seal(/* bSealFields */ true);
232 444 : }
233 :
234 : /************************************************************************/
235 : /* GetName() */
236 : /************************************************************************/
237 :
238 15074 : const char *OGRSQLiteTableLayer::GetName() const
239 : {
240 15074 : return GetDescription();
241 : }
242 :
243 : /************************************************************************/
244 : /* GetMetadata() */
245 : /************************************************************************/
246 :
247 16 : CSLConstList OGRSQLiteTableLayer::GetMetadata(const char *pszDomain)
248 :
249 : {
250 : // Update GetMetadataItem() optimization that skips calling GetMetadata()
251 : // when key != OLMD_FID64 if we add more metadata items.
252 :
253 16 : GetLayerDefn();
254 16 : if (!m_bHasTriedDetectingFID64 && m_pszFIDColumn != nullptr)
255 : {
256 9 : m_bHasTriedDetectingFID64 = true;
257 :
258 : /* --------------------------------------------------------------------
259 : */
260 : /* Find if the FID holds 64bit values */
261 : /* --------------------------------------------------------------------
262 : */
263 :
264 : // Normally the fid should be AUTOINCREMENT, so check sqlite_sequence
265 9 : OGRErr err = OGRERR_NONE;
266 : char *pszSQL =
267 9 : sqlite3_mprintf("SELECT seq FROM sqlite_sequence WHERE name = '%q'",
268 : m_pszTableName);
269 9 : CPLPushErrorHandler(CPLQuietErrorHandler);
270 9 : GIntBig nMaxId = SQLGetInteger64(m_poDS->GetDB(), pszSQL, &err);
271 9 : CPLPopErrorHandler();
272 9 : sqlite3_free(pszSQL);
273 9 : if (err != OGRERR_NONE)
274 : {
275 2 : CPLErrorReset();
276 :
277 : // In case of error, fallback to taking the MAX of the FID
278 2 : pszSQL = sqlite3_mprintf("SELECT MAX(\"%w\") FROM \"%w\"",
279 : m_pszFIDColumn, m_pszTableName);
280 :
281 2 : nMaxId = SQLGetInteger64(m_poDS->GetDB(), pszSQL, nullptr);
282 2 : sqlite3_free(pszSQL);
283 : }
284 9 : if (nMaxId > INT_MAX)
285 2 : OGRLayer::SetMetadataItem(OLMD_FID64, "YES");
286 : }
287 :
288 16 : return OGRSQLiteLayer::GetMetadata(pszDomain);
289 : }
290 :
291 : /************************************************************************/
292 : /* GetMetadataItem() */
293 : /************************************************************************/
294 :
295 15 : const char *OGRSQLiteTableLayer::GetMetadataItem(const char *pszName,
296 : const char *pszDomain)
297 : {
298 15 : if (!((pszDomain == nullptr || EQUAL(pszDomain, "")) &&
299 13 : EQUAL(pszName, OLMD_FID64)))
300 8 : return nullptr;
301 7 : return CSLFetchNameValue(GetMetadata(pszDomain), pszName);
302 : }
303 :
304 : /************************************************************************/
305 : /* EstablishFeatureDefn() */
306 : /************************************************************************/
307 :
308 1032 : CPLErr OGRSQLiteTableLayer::EstablishFeatureDefn(const char *pszGeomCol,
309 : bool bMayEmitError)
310 : {
311 1032 : sqlite3 *hDB = m_poDS->GetDB();
312 :
313 : /* -------------------------------------------------------------------- */
314 : /* Get the column definitions for this table. */
315 : /* -------------------------------------------------------------------- */
316 1032 : bool bHasRowId = m_bIsTable;
317 :
318 : // SELECT .. FROM ... LIMIT ... is broken on VirtualShape tables with
319 : // spatialite 5.0.1 and sqlite 3.38.0
320 : const char *pszSQLConst =
321 1032 : CPLSPrintf(m_bIsVirtualShape ? "SELECT %s* FROM '%s'"
322 : : "SELECT %s* FROM '%s' LIMIT 1",
323 1032 : m_bIsTable ? "_rowid_, " : "", m_pszEscapedTableName);
324 :
325 1032 : sqlite3_stmt *hColStmt = nullptr;
326 1032 : int rc = sqlite3_prepare_v2(hDB, pszSQLConst, -1, &hColStmt, nullptr);
327 1032 : if (rc != SQLITE_OK)
328 : {
329 242 : const char *pszErrMsg = sqlite3_errmsg(hDB);
330 242 : if (m_bIsTable && pszErrMsg && strstr(pszErrMsg, "_rowid_") != nullptr)
331 : {
332 : // This is likely a table WITHOUT ROWID
333 1 : bHasRowId = false;
334 1 : sqlite3_finalize(hColStmt);
335 1 : hColStmt = nullptr;
336 : pszSQLConst =
337 1 : CPLSPrintf("SELECT * FROM '%s' LIMIT 1", m_pszEscapedTableName);
338 1 : rc = sqlite3_prepare_v2(hDB, pszSQLConst, -1, &hColStmt, nullptr);
339 : }
340 242 : if (rc != SQLITE_OK)
341 : {
342 241 : if (bMayEmitError)
343 : {
344 238 : CPLError(
345 : CE_Failure, CPLE_AppDefined,
346 : "Unable to query table %s for column definitions : %s.",
347 : m_pszTableName, sqlite3_errmsg(hDB));
348 : }
349 241 : return CE_Failure;
350 : }
351 : }
352 :
353 791 : rc = sqlite3_step(hColStmt);
354 791 : if (rc != SQLITE_DONE && rc != SQLITE_ROW)
355 : {
356 102 : CPLError(CE_Failure, CPLE_AppDefined,
357 : "In Initialize(): sqlite3_step(%s):\n %s", pszSQLConst,
358 : sqlite3_errmsg(hDB));
359 102 : sqlite3_finalize(hColStmt);
360 102 : return CE_Failure;
361 : }
362 :
363 : /* -------------------------------------------------------------------- */
364 : /* What should we use as FID? If there is a primary key */
365 : /* integer field, then this will be used as the _rowid_, and we */
366 : /* will pick up the real column name here. */
367 : /* */
368 : /* Note that the select _rowid_ will return the real column */
369 : /* name if the rowid corresponds to another primary key */
370 : /* column. */
371 : /* -------------------------------------------------------------------- */
372 689 : if (bHasRowId)
373 : {
374 687 : CPLFree(m_pszFIDColumn);
375 687 : m_pszFIDColumn =
376 687 : CPLStrdup(SQLUnescape(sqlite3_column_name(hColStmt, 0)));
377 : }
378 :
379 : /* -------------------------------------------------------------------- */
380 : /* Collect the rest of the fields. */
381 : /* -------------------------------------------------------------------- */
382 689 : if (pszGeomCol)
383 : {
384 598 : std::set<CPLString> aosGeomCols;
385 299 : aosGeomCols.insert(pszGeomCol);
386 : std::set<CPLString> aosIgnoredCols(
387 598 : m_poDS->GetGeomColsForTable(m_pszTableName));
388 299 : aosIgnoredCols.erase(pszGeomCol);
389 299 : BuildFeatureDefn(GetDescription(), false, hColStmt, &aosGeomCols,
390 : aosIgnoredCols);
391 : }
392 : else
393 : {
394 780 : std::set<CPLString> aosIgnoredCols;
395 : const std::set<CPLString> &aosGeomCols(
396 390 : m_poDS->GetGeomColsForTable(m_pszTableName));
397 390 : BuildFeatureDefn(GetDescription(), false, hColStmt,
398 390 : (m_bIsVirtualShape) ? nullptr : &aosGeomCols,
399 : aosIgnoredCols);
400 : }
401 689 : sqlite3_finalize(hColStmt);
402 :
403 : /* -------------------------------------------------------------------- */
404 : /* Set the properties of the geometry column. */
405 : /* -------------------------------------------------------------------- */
406 689 : bool bHasSpatialiteCol = false;
407 950 : for (int i = 0; i < m_poFeatureDefn->GetGeomFieldCount(); i++)
408 : {
409 : OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
410 261 : m_poFeatureDefn->myGetGeomFieldDefn(i);
411 261 : poGeomFieldDefn->m_nSRSId = m_poDS->GetUndefinedSRID();
412 :
413 261 : if (m_poDS->IsSpatialiteDB())
414 : {
415 144 : if (m_poDS->HasSpatialite4Layout())
416 : {
417 141 : pszSQLConst = CPLSPrintf(
418 : "SELECT srid, geometry_type, coord_dimension, "
419 : "spatial_index_enabled FROM geometry_columns WHERE "
420 : "lower(f_table_name) = lower('%s') AND "
421 : "lower(f_geometry_column) = lower('%s')",
422 : m_pszEscapedTableName,
423 282 : SQLEscapeLiteral(poGeomFieldDefn->GetNameRef()).c_str());
424 : }
425 : else
426 : {
427 3 : pszSQLConst = CPLSPrintf(
428 : "SELECT srid, type, coord_dimension, spatial_index_enabled "
429 : "FROM geometry_columns WHERE lower(f_table_name) = "
430 : "lower('%s') AND lower(f_geometry_column) = lower('%s')",
431 : m_pszEscapedTableName,
432 6 : SQLEscapeLiteral(poGeomFieldDefn->GetNameRef()).c_str());
433 : }
434 : }
435 : else
436 : {
437 117 : pszSQLConst = CPLSPrintf(
438 : "SELECT srid, geometry_type, coord_dimension, geometry_format "
439 : "FROM geometry_columns WHERE lower(f_table_name) = lower('%s') "
440 : "AND lower(f_geometry_column) = lower('%s')",
441 : m_pszEscapedTableName,
442 234 : SQLEscapeLiteral(poGeomFieldDefn->GetNameRef()).c_str());
443 : }
444 261 : char *pszErrMsg = nullptr;
445 261 : int nRowCount = 0, nColCount = 0;
446 261 : char **papszResult = nullptr;
447 261 : rc = sqlite3_get_table(hDB, pszSQLConst, &papszResult, &nRowCount,
448 : &nColCount, &pszErrMsg);
449 261 : OGRwkbGeometryType eGeomType = wkbUnknown;
450 261 : OGRSQLiteGeomFormat eGeomFormat = OSGF_Unknown;
451 261 : if (rc == SQLITE_OK && nRowCount == 1)
452 : {
453 258 : char **papszRow = papszResult + nColCount;
454 258 : if (papszRow[1] == nullptr || papszRow[2] == nullptr)
455 : {
456 0 : CPLDebug("SQLite", "Did not get expected col value");
457 0 : sqlite3_free_table(papszResult);
458 0 : continue;
459 : }
460 258 : if (papszRow[0] != nullptr)
461 160 : poGeomFieldDefn->m_nSRSId = atoi(papszRow[0]);
462 258 : if (m_poDS->IsSpatialiteDB())
463 : {
464 141 : if (papszRow[3] != nullptr)
465 141 : poGeomFieldDefn->m_bHasSpatialIndex =
466 141 : atoi(papszRow[3]) != 0;
467 141 : if (m_poDS->HasSpatialite4Layout())
468 : {
469 138 : int nGeomType = atoi(papszRow[1]);
470 :
471 138 : if (nGeomType >= static_cast<int>(wkbPoint) &&
472 : nGeomType <=
473 : static_cast<int>(wkbGeometryCollection)) /* XY */
474 66 : eGeomType = static_cast<OGRwkbGeometryType>(nGeomType);
475 72 : else if (nGeomType >= 1000 && nGeomType <= 1007) /* XYZ */
476 29 : eGeomType = wkbSetZ(wkbFlatten(nGeomType));
477 43 : else if (nGeomType >= 2000 && nGeomType <= 2007) /* XYM */
478 16 : eGeomType = wkbSetM(wkbFlatten(nGeomType));
479 27 : else if (nGeomType >= 3000 && nGeomType <= 3007) /* XYZM */
480 16 : eGeomType = wkbSetM(wkbSetZ(wkbFlatten(nGeomType)));
481 : }
482 : else
483 : {
484 3 : eGeomType = OGRFromOGCGeomType(papszRow[1]);
485 :
486 3 : if (strcmp(papszRow[2], "XYZ") == 0 ||
487 3 : strcmp(papszRow[2], "3") ==
488 : 0) // SpatiaLite's own 3D geometries
489 0 : eGeomType = wkbSetZ(eGeomType);
490 3 : else if (strcmp(papszRow[2], "XYM") == 0)
491 0 : eGeomType = wkbSetM(eGeomType);
492 3 : else if (strcmp(papszRow[2], "XYZM") ==
493 : 0) // M coordinate declared
494 0 : eGeomType = wkbSetM(wkbSetZ(eGeomType));
495 : }
496 141 : eGeomFormat = OSGF_SpatiaLite;
497 : }
498 : else
499 : {
500 117 : eGeomType = static_cast<OGRwkbGeometryType>(atoi(papszRow[1]));
501 117 : if (atoi(papszRow[2]) > 2)
502 7 : eGeomType = wkbSetZ(eGeomType);
503 117 : eGeomFormat = GetGeomFormat(papszRow[3]);
504 : }
505 : }
506 261 : sqlite3_free_table(papszResult);
507 261 : sqlite3_free(pszErrMsg);
508 :
509 261 : poGeomFieldDefn->m_eGeomFormat = eGeomFormat;
510 261 : poGeomFieldDefn->SetType(eGeomType);
511 522 : poGeomFieldDefn->SetSpatialRef(
512 261 : m_poDS->FetchSRS(poGeomFieldDefn->m_nSRSId));
513 :
514 : // cppcheck-suppress knownConditionTrueFalse
515 261 : if (eGeomFormat == OSGF_SpatiaLite)
516 142 : bHasSpatialiteCol = true;
517 : }
518 :
519 280 : if (bHasSpatialiteCol && m_poDS->IsSpatialiteLoaded() &&
520 140 : m_poDS->GetSpatialiteVersionNumber() <
521 969 : OGRSQLiteDataSource::MakeSpatialiteVersionNumber(2, 4, 0) &&
522 0 : m_poDS->GetUpdate())
523 : {
524 : // we need to test version required by Spatialite TRIGGERs
525 : // hColStmt = NULL;
526 : pszSQLConst =
527 0 : CPLSPrintf("SELECT sql FROM sqlite_master WHERE type = 'trigger' "
528 : "AND tbl_name = '%s' AND sql LIKE '%%RTreeAlign%%'",
529 : m_pszEscapedTableName);
530 :
531 : int nRowTriggerCount, nColTriggerCount;
532 : char **papszTriggerResult, *pszErrMsg;
533 :
534 0 : /* rc = */ sqlite3_get_table(hDB, pszSQLConst, &papszTriggerResult,
535 : &nRowTriggerCount, &nColTriggerCount,
536 : &pszErrMsg);
537 0 : if (nRowTriggerCount >= 1)
538 : {
539 : // obsolete library version not supporting new triggers
540 : // enforcing ReadOnly mode
541 0 : CPLDebug("SQLITE", "Enforcing ReadOnly mode : obsolete library "
542 : "version not supporting new triggers");
543 0 : m_poDS->DisableUpdate();
544 : }
545 :
546 0 : sqlite3_free_table(papszTriggerResult);
547 : }
548 : /* -------------------------------------------------------------------- */
549 : /* Check if there are default values and nullable status */
550 : /* -------------------------------------------------------------------- */
551 :
552 689 : char **papszResult = nullptr;
553 689 : int nRowCount = 0;
554 689 : int nColCount = 0;
555 689 : char *pszErrMsg = nullptr;
556 : /* #|name|type|notnull|default|pk */
557 689 : char *pszSQL = sqlite3_mprintf("PRAGMA table_info('%q')", m_pszTableName);
558 689 : rc = sqlite3_get_table(hDB, pszSQL, &papszResult, &nRowCount, &nColCount,
559 : &pszErrMsg);
560 689 : sqlite3_free(pszSQL);
561 689 : if (rc != SQLITE_OK)
562 : {
563 0 : sqlite3_free(pszErrMsg);
564 : }
565 : else
566 : {
567 689 : if (nColCount == 6)
568 : {
569 : const std::set<std::string> uniqueFieldsUC(
570 1378 : SQLGetUniqueFieldUCConstraints(hDB, m_pszTableName));
571 :
572 689 : const int nFieldCount = m_poFeatureDefn->GetFieldCount();
573 1378 : std::map<std::string, int> oMapNametoIdx;
574 2122 : for (int i = 0; i < nFieldCount; ++i)
575 1433 : oMapNametoIdx[m_poFeatureDefn->GetFieldDefnUnsafe(i)
576 1433 : ->GetNameRef()] = i;
577 :
578 3063 : for (int i = 0; i < nRowCount; i++)
579 : {
580 2374 : const char *pszName = papszResult[(i + 1) * 6 + 1];
581 2374 : if (!pszName)
582 0 : continue; // should normally never happen
583 2374 : const char *pszNotNull = papszResult[(i + 1) * 6 + 3];
584 2374 : const char *pszDefault = papszResult[(i + 1) * 6 + 4];
585 2374 : int idx = -1;
586 2374 : const auto oIter = oMapNametoIdx.find(pszName);
587 2374 : if (oIter != oMapNametoIdx.end())
588 1433 : idx = oIter->second;
589 2374 : if (pszDefault != nullptr)
590 : {
591 18 : if (idx >= 0)
592 : {
593 : OGRFieldDefn *poFieldDefn =
594 17 : m_poFeatureDefn->GetFieldDefnUnsafe(idx);
595 17 : if (poFieldDefn->GetType() == OFTString &&
596 3 : !EQUAL(pszDefault, "NULL") &&
597 3 : !STARTS_WITH_CI(pszDefault, "CURRENT_") &&
598 20 : pszDefault[0] != '(' && pszDefault[0] != '\'' &&
599 0 : CPLGetValueType(pszDefault) == CPL_VALUE_STRING)
600 : {
601 0 : CPLString osDefault("'");
602 : char *pszTmp =
603 0 : CPLEscapeString(pszDefault, -1, CPLES_SQL);
604 0 : osDefault += pszTmp;
605 0 : CPLFree(pszTmp);
606 0 : osDefault += "'";
607 0 : poFieldDefn->SetDefault(osDefault);
608 : }
609 32 : else if ((poFieldDefn->GetType() == OFTDate ||
610 15 : poFieldDefn->GetType() == OFTDateTime) &&
611 9 : !EQUAL(pszDefault, "NULL") &&
612 9 : !STARTS_WITH_CI(pszDefault, "CURRENT_") &&
613 5 : pszDefault[0] != '(' &&
614 5 : pszDefault[0] != '\'' &&
615 1 : !(pszDefault[0] >= '0' &&
616 35 : pszDefault[0] <= '9') &&
617 1 : CPLGetValueType(pszDefault) ==
618 : CPL_VALUE_STRING)
619 : {
620 2 : CPLString osDefault("(");
621 1 : osDefault += pszDefault;
622 1 : osDefault += ")";
623 1 : poFieldDefn->SetDefault(osDefault);
624 : }
625 : else
626 16 : poFieldDefn->SetDefault(pszDefault);
627 : }
628 : }
629 2374 : if (pszNotNull != nullptr && EQUAL(pszNotNull, "1"))
630 : {
631 55 : if (idx >= 0)
632 51 : m_poFeatureDefn->GetFieldDefnUnsafe(idx)->SetNullable(
633 : 0);
634 : else
635 : {
636 : const int geomFieldIdx =
637 4 : m_poFeatureDefn->GetGeomFieldIndex(pszName);
638 4 : if (geomFieldIdx >= 0)
639 3 : m_poFeatureDefn->GetGeomFieldDefn(geomFieldIdx)
640 3 : ->SetNullable(0);
641 : }
642 : }
643 3807 : if (idx >= 0 &&
644 3807 : uniqueFieldsUC.find(CPLString(pszName).toupper()) !=
645 3807 : uniqueFieldsUC.end())
646 : {
647 9 : m_poFeatureDefn->GetFieldDefnUnsafe(idx)->SetUnique(TRUE);
648 : }
649 : }
650 : }
651 689 : sqlite3_free_table(papszResult);
652 : }
653 :
654 689 : nRowCount = 0;
655 689 : nColCount = 0;
656 689 : papszResult = nullptr;
657 :
658 689 : pszSQL = sqlite3_mprintf(
659 : "SELECT sql FROM sqlite_master WHERE type='table' AND name='%q'",
660 : m_pszTableName);
661 689 : rc = sqlite3_get_table(hDB, pszSQL, &papszResult, &nRowCount, &nColCount,
662 : nullptr);
663 689 : sqlite3_free(pszSQL);
664 689 : if (rc == SQLITE_OK && nRowCount == 1 && nColCount == 1)
665 : {
666 688 : const char *pszCreateTableSQL = papszResult[1];
667 688 : const char *pszLastParenthesis = strrchr(pszCreateTableSQL, ')');
668 688 : if (pszLastParenthesis)
669 : {
670 688 : m_bStrict = CPLString(pszLastParenthesis + 1).ifind("STRICT") !=
671 : std::string::npos;
672 : #ifdef DEBUG_VERBOSE
673 : if (m_bStrict)
674 : CPLDebug("SQLite", "Table %s has STRICT mode", m_pszTableName);
675 : #endif
676 : }
677 :
678 688 : const int nFieldCount = m_poFeatureDefn->GetFieldCount();
679 2120 : for (int i = 0; i < nFieldCount; ++i)
680 : {
681 1432 : auto poFieldDefn = m_poFeatureDefn->GetFieldDefn(i);
682 1432 : if (poFieldDefn->GetType() == OFTInteger)
683 : {
684 : // In strict mode, the number of allowed types is severely
685 : // restricted, so interpret INTEGER as Int64 by default, unless
686 : // a check constraint makes it clear it is Int32
687 178 : if (m_bStrict)
688 4 : poFieldDefn->SetType(OFTInteger64);
689 178 : if (strstr(pszCreateTableSQL,
690 0 : ("CHECK (\"" +
691 356 : CPLString(poFieldDefn->GetNameRef())
692 356 : .replaceAll('"', "\"\"") +
693 : "\" BETWEEN -2147483648 AND 2147483647)")
694 178 : .c_str()))
695 : {
696 2 : poFieldDefn->SetType(OFTInteger);
697 : }
698 176 : else if (strstr(pszCreateTableSQL,
699 0 : ("CHECK (\"" +
700 352 : CPLString(poFieldDefn->GetNameRef())
701 352 : .replaceAll('"', "\"\"") +
702 : "\" BETWEEN -9223372036854775808 AND "
703 : "9223372036854775807)")
704 176 : .c_str()))
705 : {
706 2 : poFieldDefn->SetType(OFTInteger64);
707 : }
708 : }
709 1254 : else if (poFieldDefn->GetType() == OFTString)
710 : {
711 757 : if (strstr(pszCreateTableSQL,
712 0 : ("CHECK (\"" +
713 1514 : CPLString(poFieldDefn->GetNameRef())
714 1514 : .replaceAll('"', "\"\"") +
715 : "\" LIKE "
716 : "'[0-9][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9]T[0-2]["
717 : "0-9]:[0-5][0-9]:[0-6][0-9]*')")
718 757 : .c_str()))
719 : {
720 1 : poFieldDefn->SetType(OFTDateTime);
721 : }
722 756 : else if (strstr(
723 : pszCreateTableSQL,
724 0 : ("CHECK (\"" +
725 1512 : CPLString(poFieldDefn->GetNameRef())
726 1512 : .replaceAll('"', "\"\"") +
727 : "\" LIKE "
728 : "'[0-9][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9]T')")
729 756 : .c_str()))
730 : {
731 1 : poFieldDefn->SetType(OFTDate);
732 : }
733 755 : else if (strstr(pszCreateTableSQL,
734 0 : ("CHECK (\"" +
735 1510 : CPLString(poFieldDefn->GetNameRef())
736 1510 : .replaceAll('"', "\"\"") +
737 : "\" LIKE '[0-2][0-9]:[0-5][0-9]:[0-6][0-9]*')")
738 755 : .c_str()))
739 : {
740 1 : poFieldDefn->SetType(OFTTime);
741 : }
742 : }
743 : }
744 : }
745 689 : sqlite3_free_table(papszResult);
746 :
747 689 : return CE_None;
748 : }
749 :
750 : /************************************************************************/
751 : /* RecomputeOrdinals() */
752 : /************************************************************************/
753 :
754 636 : OGRErr OGRSQLiteTableLayer::RecomputeOrdinals()
755 : {
756 636 : sqlite3 *hDB = m_poDS->GetDB();
757 636 : sqlite3_stmt *hColStmt = nullptr;
758 : /* -------------------------------------------------------------------- */
759 : /* Get the column definitions for this table. */
760 : /* -------------------------------------------------------------------- */
761 :
762 636 : const char *pszSQL = CPLSPrintf(
763 : "SELECT %s* FROM '%s' LIMIT 1",
764 636 : m_pszFIDColumn != nullptr ? "_rowid_, " : "", m_pszEscapedTableName);
765 :
766 636 : int rc = sqlite3_prepare_v2(hDB, pszSQL, -1, &hColStmt, nullptr);
767 636 : if (rc != SQLITE_OK)
768 : {
769 0 : CPLError(CE_Failure, CPLE_AppDefined,
770 : "Unable to query table %s for column definitions : %s.",
771 : m_pszTableName, sqlite3_errmsg(hDB));
772 :
773 0 : return OGRERR_FAILURE;
774 : }
775 :
776 636 : rc = sqlite3_step(hColStmt);
777 636 : if (rc != SQLITE_DONE && rc != SQLITE_ROW)
778 : {
779 0 : CPLError(CE_Failure, CPLE_AppDefined,
780 : "In Initialize(): sqlite3_step(%s):\n %s", pszSQL,
781 : sqlite3_errmsg(hDB));
782 0 : sqlite3_finalize(hColStmt);
783 0 : return OGRERR_FAILURE;
784 : }
785 :
786 636 : int nRawColumns = sqlite3_column_count(hColStmt);
787 :
788 636 : CPLFree(m_panFieldOrdinals);
789 636 : m_panFieldOrdinals = static_cast<int *>(
790 636 : CPLMalloc(sizeof(int) * m_poFeatureDefn->GetFieldCount()));
791 636 : int nCountFieldOrdinals = 0;
792 636 : int nCountGeomFieldOrdinals = 0;
793 636 : m_iFIDCol = -1;
794 :
795 4144 : for (int iCol = 0; iCol < nRawColumns; iCol++)
796 : {
797 3508 : CPLString osName = SQLUnescape(sqlite3_column_name(hColStmt, iCol));
798 3508 : int nIdx = m_poFeatureDefn->GetFieldIndex(osName);
799 3508 : if (m_pszFIDColumn != nullptr && strcmp(osName, m_pszFIDColumn) == 0)
800 : {
801 1272 : if (m_iFIDCol < 0)
802 : {
803 636 : m_iFIDCol = iCol;
804 636 : if (nIdx >=
805 : 0) /* in case it has also been created as a regular field */
806 1 : nCountFieldOrdinals++;
807 : }
808 1272 : continue;
809 : }
810 2236 : if (nIdx >= 0)
811 : {
812 1708 : m_panFieldOrdinals[nIdx] = iCol;
813 1708 : nCountFieldOrdinals++;
814 : }
815 : else
816 : {
817 528 : nIdx = m_poFeatureDefn->GetGeomFieldIndex(osName);
818 528 : if (nIdx >= 0)
819 : {
820 : OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
821 528 : m_poFeatureDefn->myGetGeomFieldDefn(nIdx);
822 528 : poGeomFieldDefn->m_iCol = iCol;
823 528 : nCountGeomFieldOrdinals++;
824 : }
825 : }
826 : }
827 : (void)nCountFieldOrdinals;
828 636 : CPLAssert(nCountFieldOrdinals == m_poFeatureDefn->GetFieldCount());
829 : (void)nCountGeomFieldOrdinals;
830 636 : CPLAssert(nCountGeomFieldOrdinals == m_poFeatureDefn->GetGeomFieldCount());
831 636 : CPLAssert(m_pszFIDColumn == nullptr || m_iFIDCol >= 0);
832 :
833 636 : sqlite3_finalize(hColStmt);
834 :
835 636 : return OGRERR_NONE;
836 : }
837 :
838 : /************************************************************************/
839 : /* GetLayerDefn() */
840 : /************************************************************************/
841 :
842 27806 : const OGRFeatureDefn *OGRSQLiteTableLayer::GetLayerDefn() const
843 : {
844 27806 : if (!m_poFeatureDefn)
845 : {
846 730 : const_cast<OGRSQLiteTableLayer *>(this)->BuildLayerDefn();
847 : }
848 27806 : return m_poFeatureDefn;
849 : }
850 :
851 : /************************************************************************/
852 : /* BuildLayerDefn() */
853 : /************************************************************************/
854 :
855 730 : void OGRSQLiteTableLayer::BuildLayerDefn()
856 : {
857 730 : EstablishFeatureDefn(nullptr, /* bMayEmitError = */ true);
858 :
859 730 : if (m_poFeatureDefn == nullptr)
860 : {
861 340 : m_bLayerDefnError = true;
862 :
863 340 : m_poFeatureDefn = new OGRSQLiteFeatureDefn(GetDescription());
864 340 : m_poFeatureDefn->Reference();
865 : }
866 : else
867 390 : LoadStatistics();
868 :
869 730 : m_poFeatureDefn->Seal(/* bSealFields */ true);
870 730 : }
871 :
872 : /************************************************************************/
873 : /* ResetStatement() */
874 : /************************************************************************/
875 :
876 886 : OGRErr OGRSQLiteTableLayer::ResetStatement()
877 :
878 : {
879 1772 : CPLString osSQL;
880 :
881 886 : if (m_bDeferredCreation)
882 0 : RunDeferredCreationIfNecessary();
883 :
884 886 : ClearStatement();
885 :
886 886 : m_iNextShapeId = 0;
887 :
888 : osSQL.Printf("SELECT %s* FROM '%s' %s",
889 886 : m_pszFIDColumn != nullptr ? "_rowid_, " : "",
890 886 : m_pszEscapedTableName, m_osWHERE.c_str());
891 : #ifdef DEBUG_VERBOSE
892 : CPLDebug("SQLite", "%s", osSQL.c_str());
893 : #endif
894 :
895 : const int rc =
896 886 : sqlite3_prepare_v2(m_poDS->GetDB(), osSQL, -1, &m_hStmt, nullptr);
897 886 : if (rc == SQLITE_OK)
898 : {
899 885 : return OGRERR_NONE;
900 : }
901 :
902 1 : CPLError(CE_Failure, CPLE_AppDefined,
903 : "In ResetStatement(): sqlite3_prepare_v2(%s):\n %s",
904 1 : osSQL.c_str(), sqlite3_errmsg(m_poDS->GetDB()));
905 1 : m_hStmt = nullptr;
906 1 : return OGRERR_FAILURE;
907 : }
908 :
909 : /************************************************************************/
910 : /* GetNextFeature() */
911 : /************************************************************************/
912 :
913 3477 : OGRFeature *OGRSQLiteTableLayer::GetNextFeature()
914 :
915 : {
916 3477 : if (m_bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE)
917 0 : return nullptr;
918 :
919 3477 : if (HasLayerDefnError())
920 1 : return nullptr;
921 :
922 3476 : OGRFeature *poFeature = OGRSQLiteLayer::GetNextFeature();
923 3476 : if (poFeature && m_iFIDAsRegularColumnIndex >= 0)
924 : {
925 1 : poFeature->SetField(m_iFIDAsRegularColumnIndex, poFeature->GetFID());
926 : }
927 3476 : return poFeature;
928 : }
929 :
930 : /************************************************************************/
931 : /* GetFeature() */
932 : /************************************************************************/
933 :
934 66 : OGRFeature *OGRSQLiteTableLayer::GetFeature(GIntBig nFeatureId)
935 :
936 : {
937 66 : if (m_bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE)
938 0 : return nullptr;
939 :
940 66 : if (HasLayerDefnError())
941 0 : return nullptr;
942 :
943 : /* -------------------------------------------------------------------- */
944 : /* If we don't have an explicit FID column, just read through */
945 : /* the result set iteratively to find our target. */
946 : /* -------------------------------------------------------------------- */
947 66 : if (m_pszFIDColumn == nullptr)
948 1 : return OGRSQLiteLayer::GetFeature(nFeatureId);
949 :
950 : /* -------------------------------------------------------------------- */
951 : /* Setup explicit query statement to fetch the record we want. */
952 : /* -------------------------------------------------------------------- */
953 130 : CPLString osSQL;
954 :
955 65 : ClearStatement();
956 :
957 65 : m_iNextShapeId = nFeatureId;
958 :
959 : osSQL.Printf("SELECT _rowid_, * FROM '%s' WHERE \"%s\" = " CPL_FRMT_GIB,
960 : m_pszEscapedTableName,
961 65 : SQLEscapeLiteral(m_pszFIDColumn).c_str(), nFeatureId);
962 :
963 65 : CPLDebug("OGR_SQLITE", "exec(%s)", osSQL.c_str());
964 :
965 : const int rc =
966 65 : sqlite3_prepare_v2(m_poDS->GetDB(), osSQL,
967 65 : static_cast<int>(osSQL.size()), &m_hStmt, nullptr);
968 65 : if (rc != SQLITE_OK)
969 : {
970 0 : CPLError(CE_Failure, CPLE_AppDefined,
971 : "In GetFeature(): sqlite3_prepare_v2(%s):\n %s",
972 0 : osSQL.c_str(), sqlite3_errmsg(m_poDS->GetDB()));
973 :
974 0 : return nullptr;
975 : }
976 : /* -------------------------------------------------------------------- */
977 : /* Get the feature if possible. */
978 : /* -------------------------------------------------------------------- */
979 65 : OGRFeature *poFeature = GetNextRawFeature();
980 :
981 65 : ResetReading();
982 :
983 65 : return poFeature;
984 : }
985 :
986 : /************************************************************************/
987 : /* SetAttributeFilter() */
988 : /************************************************************************/
989 :
990 523 : OGRErr OGRSQLiteTableLayer::SetAttributeFilter(const char *pszQuery)
991 :
992 : {
993 523 : CPLFree(m_pszAttrQueryString);
994 523 : m_pszAttrQueryString = (pszQuery) ? CPLStrdup(pszQuery) : nullptr;
995 :
996 523 : if (pszQuery == nullptr)
997 60 : m_osQuery = "";
998 : else
999 463 : m_osQuery = pszQuery;
1000 :
1001 523 : BuildWhere();
1002 :
1003 523 : ResetReading();
1004 :
1005 523 : return OGRERR_NONE;
1006 : }
1007 :
1008 : /************************************************************************/
1009 : /* ISetSpatialFilter() */
1010 : /************************************************************************/
1011 :
1012 62 : OGRErr OGRSQLiteTableLayer::ISetSpatialFilter(int iGeomField,
1013 : const OGRGeometry *poGeomIn)
1014 :
1015 : {
1016 62 : m_iGeomFieldFilter = iGeomField;
1017 62 : if (InstallFilter(poGeomIn))
1018 : {
1019 31 : BuildWhere();
1020 :
1021 31 : ResetReading();
1022 : }
1023 62 : return OGRERR_NONE;
1024 : }
1025 :
1026 : /************************************************************************/
1027 : /* CheckSpatialIndexTable() */
1028 : /************************************************************************/
1029 :
1030 104 : bool OGRSQLiteTableLayer::CheckSpatialIndexTable(int iGeomCol)
1031 : {
1032 104 : GetLayerDefn();
1033 104 : if (iGeomCol < 0 || iGeomCol >= m_poFeatureDefn->GetGeomFieldCount())
1034 0 : return false;
1035 : OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
1036 104 : m_poFeatureDefn->myGetGeomFieldDefn(iGeomCol);
1037 203 : if (HasSpatialIndex(iGeomCol) &&
1038 99 : !poGeomFieldDefn->m_bHasCheckedSpatialIndexTable)
1039 : {
1040 10 : poGeomFieldDefn->m_bHasCheckedSpatialIndexTable = true;
1041 10 : char **papszResult = nullptr;
1042 10 : int nRowCount = 0;
1043 10 : int nColCount = 0;
1044 10 : char *pszErrMsg = nullptr;
1045 :
1046 20 : CPLString osSQL;
1047 :
1048 : /* This will ensure that RTree support is available */
1049 : osSQL.Printf("SELECT pkid FROM 'idx_%s_%s' WHERE xmax > 0 AND xmin < 0 "
1050 : "AND ymax > 0 AND ymin < 0",
1051 : m_pszEscapedTableName,
1052 10 : SQLEscapeLiteral(poGeomFieldDefn->GetNameRef()).c_str());
1053 :
1054 10 : int rc = sqlite3_get_table(m_poDS->GetDB(), osSQL.c_str(), &papszResult,
1055 : &nRowCount, &nColCount, &pszErrMsg);
1056 :
1057 10 : if (rc != SQLITE_OK)
1058 : {
1059 0 : CPLDebug("SQLITE",
1060 : "Count not find or use idx_%s_%s layer (%s). Disabling "
1061 : "spatial index",
1062 : m_pszEscapedTableName, poGeomFieldDefn->GetNameRef(),
1063 : pszErrMsg);
1064 0 : sqlite3_free(pszErrMsg);
1065 0 : poGeomFieldDefn->m_bHasSpatialIndex = false;
1066 : }
1067 : else
1068 : {
1069 10 : sqlite3_free_table(papszResult);
1070 : }
1071 : }
1072 :
1073 104 : return poGeomFieldDefn->m_bHasSpatialIndex;
1074 : }
1075 :
1076 : /************************************************************************/
1077 : /* HasFastSpatialFilter() */
1078 : /************************************************************************/
1079 :
1080 8 : bool OGRSQLiteTableLayer::HasFastSpatialFilter(int iGeomCol)
1081 : {
1082 16 : OGRPolygon oFakePoly;
1083 8 : const char *pszWKT = "POLYGON((0 0,0 1,1 1,1 0,0 0))";
1084 8 : oFakePoly.importFromWkt(&pszWKT);
1085 8 : CPLString osSpatialWhere = GetSpatialWhere(iGeomCol, &oFakePoly);
1086 16 : return osSpatialWhere.find("ROWID") == 0;
1087 : }
1088 :
1089 : /************************************************************************/
1090 : /* GetSpatialWhere() */
1091 : /************************************************************************/
1092 :
1093 672 : CPLString OGRSQLiteTableLayer::GetSpatialWhere(int iGeomCol,
1094 : OGRGeometry *poFilterGeom)
1095 : {
1096 795 : if (!m_poDS->IsSpatialiteDB() || iGeomCol < 0 ||
1097 123 : iGeomCol >= GetLayerDefn()->GetGeomFieldCount())
1098 549 : return "";
1099 :
1100 : OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
1101 123 : m_poFeatureDefn->myGetGeomFieldDefn(iGeomCol);
1102 123 : if (poFilterGeom != nullptr && CheckSpatialIndexTable(iGeomCol))
1103 : {
1104 : return FormatSpatialFilterFromRTree(
1105 87 : poFilterGeom, "ROWID", m_pszEscapedTableName,
1106 174 : SQLEscapeLiteral(poGeomFieldDefn->GetNameRef()).c_str());
1107 : }
1108 :
1109 40 : if (poFilterGeom != nullptr && m_poDS->IsSpatialiteLoaded() &&
1110 4 : !poGeomFieldDefn->m_bHasSpatialIndex)
1111 : {
1112 : return FormatSpatialFilterFromMBR(
1113 8 : poFilterGeom, SQLEscapeName(poGeomFieldDefn->GetNameRef()).c_str());
1114 : }
1115 :
1116 32 : return "";
1117 : }
1118 :
1119 : /************************************************************************/
1120 : /* BuildWhere() */
1121 : /* */
1122 : /* Build the WHERE statement appropriate to the current set of */
1123 : /* criteria (spatial and attribute queries). */
1124 : /************************************************************************/
1125 :
1126 554 : void OGRSQLiteTableLayer::BuildWhere()
1127 :
1128 : {
1129 554 : m_osWHERE = "";
1130 :
1131 : CPLString osSpatialWHERE =
1132 1108 : GetSpatialWhere(m_iGeomFieldFilter, m_poFilterGeom);
1133 554 : if (!osSpatialWHERE.empty())
1134 : {
1135 22 : m_osWHERE = "WHERE ";
1136 22 : m_osWHERE += osSpatialWHERE;
1137 : }
1138 :
1139 554 : if (!m_osQuery.empty())
1140 : {
1141 461 : if (m_osWHERE.empty())
1142 : {
1143 457 : m_osWHERE = "WHERE ";
1144 457 : m_osWHERE += m_osQuery;
1145 : }
1146 : else
1147 : {
1148 4 : m_osWHERE += " AND (";
1149 4 : m_osWHERE += m_osQuery;
1150 4 : m_osWHERE += ")";
1151 : }
1152 : }
1153 554 : }
1154 :
1155 : /************************************************************************/
1156 : /* TestCapability() */
1157 : /************************************************************************/
1158 :
1159 1388 : bool OGRSQLiteTableLayer::TestCapability(const char *pszCap) const
1160 :
1161 : {
1162 1388 : if (EQUAL(pszCap, OLCFastFeatureCount))
1163 101 : return m_poFilterGeom == nullptr || HasSpatialIndex(0);
1164 :
1165 1287 : else if (EQUAL(pszCap, OLCFastSpatialFilter))
1166 2 : return HasSpatialIndex(0);
1167 :
1168 1285 : else if (EQUAL(pszCap, OLCFastGetExtent))
1169 : {
1170 12 : return GetLayerDefn()->GetGeomFieldCount() >= 1 &&
1171 12 : myGetLayerDefn()->myGetGeomFieldDefn(0)->m_bCachedExtentIsValid;
1172 : }
1173 :
1174 1279 : else if (EQUAL(pszCap, OLCRandomRead))
1175 6 : return m_pszFIDColumn != nullptr;
1176 :
1177 1273 : else if (EQUAL(pszCap, OLCSequentialWrite) || EQUAL(pszCap, OLCRandomWrite))
1178 : {
1179 44 : return m_poDS->GetUpdate();
1180 : }
1181 :
1182 1229 : else if (EQUAL(pszCap, OLCDeleteFeature))
1183 : {
1184 6 : return m_poDS->GetUpdate() && m_pszFIDColumn != nullptr;
1185 : }
1186 :
1187 1223 : else if (EQUAL(pszCap, OLCCreateField) || EQUAL(pszCap, OLCCreateGeomField))
1188 38 : return m_poDS->GetUpdate();
1189 :
1190 1185 : else if (EQUAL(pszCap, OLCDeleteField))
1191 7 : return m_poDS->GetUpdate();
1192 :
1193 1178 : else if (EQUAL(pszCap, OLCAlterFieldDefn))
1194 7 : return m_poDS->GetUpdate();
1195 :
1196 1171 : else if (EQUAL(pszCap, OLCReorderFields))
1197 7 : return m_poDS->GetUpdate();
1198 :
1199 1164 : else if (EQUAL(pszCap, OLCCurveGeometries))
1200 513 : return m_poDS->TestCapability(ODsCCurveGeometries);
1201 :
1202 651 : else if (EQUAL(pszCap, OLCMeasuredGeometries))
1203 513 : return m_poDS->TestCapability(ODsCMeasuredGeometries);
1204 :
1205 138 : else if (EQUAL(pszCap, OLCZGeometries))
1206 114 : return true;
1207 :
1208 : else
1209 24 : return OGRSQLiteLayer::TestCapability(pszCap);
1210 : }
1211 :
1212 : /************************************************************************/
1213 : /* GetFeatureCount() */
1214 : /************************************************************************/
1215 :
1216 96 : GIntBig OGRSQLiteTableLayer::GetFeatureCount(int bForce)
1217 :
1218 : {
1219 96 : if (HasLayerDefnError())
1220 0 : return 0;
1221 :
1222 96 : if (!TestCapability(OLCFastFeatureCount))
1223 7 : return OGRSQLiteLayer::GetFeatureCount(bForce);
1224 :
1225 89 : if (m_nFeatureCount >= 0 && m_poFilterGeom == nullptr && m_osQuery.empty())
1226 : {
1227 45 : return m_nFeatureCount;
1228 : }
1229 :
1230 : /* -------------------------------------------------------------------- */
1231 : /* Form count SQL. */
1232 : /* -------------------------------------------------------------------- */
1233 44 : const char *pszSQL = nullptr;
1234 :
1235 97 : if (m_poFilterGeom != nullptr &&
1236 44 : CheckSpatialIndexTable(m_iGeomFieldFilter) && m_osQuery.empty())
1237 : {
1238 5 : OGREnvelope sEnvelope;
1239 :
1240 5 : m_poFilterGeom->getEnvelope(&sEnvelope);
1241 : const char *pszGeomCol =
1242 5 : m_poFeatureDefn->GetGeomFieldDefn(m_iGeomFieldFilter)->GetNameRef();
1243 5 : pszSQL = CPLSPrintf("SELECT count(*) FROM 'idx_%s_%s' WHERE "
1244 : "xmax >= %.12f AND xmin <= %.12f AND ymax >= %.12f "
1245 : "AND ymin <= %.12f",
1246 : m_pszEscapedTableName,
1247 5 : SQLEscapeLiteral(pszGeomCol).c_str(),
1248 5 : sEnvelope.MinX - 1e-11, sEnvelope.MaxX + 1e-11,
1249 5 : sEnvelope.MinY - 1e-11, sEnvelope.MaxY + 1e-11);
1250 : }
1251 : else
1252 : {
1253 39 : pszSQL = CPLSPrintf("SELECT count(*) FROM '%s' %s",
1254 : m_pszEscapedTableName, m_osWHERE.c_str());
1255 : }
1256 :
1257 44 : CPLDebug("SQLITE", "Running %s", pszSQL);
1258 :
1259 : /* -------------------------------------------------------------------- */
1260 : /* Execute. */
1261 : /* -------------------------------------------------------------------- */
1262 44 : OGRErr eErr = OGRERR_NONE;
1263 44 : GIntBig nResult = SQLGetInteger64(m_poDS->GetDB(), pszSQL, &eErr);
1264 44 : if (eErr == OGRERR_FAILURE)
1265 : {
1266 0 : nResult = -1;
1267 : }
1268 : else
1269 : {
1270 44 : if (m_poFilterGeom == nullptr && m_osQuery.empty())
1271 : {
1272 28 : m_nFeatureCount = nResult;
1273 28 : if (m_poDS->GetUpdate())
1274 12 : ForceStatisticsToBeFlushed();
1275 : }
1276 : }
1277 :
1278 44 : return nResult;
1279 : }
1280 :
1281 : /************************************************************************/
1282 : /* IGetExtent() */
1283 : /************************************************************************/
1284 :
1285 20 : OGRErr OGRSQLiteTableLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent,
1286 : bool bForce)
1287 : {
1288 20 : if (HasLayerDefnError())
1289 0 : return OGRERR_FAILURE;
1290 :
1291 : OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
1292 20 : m_poFeatureDefn->myGetGeomFieldDefn(iGeomField);
1293 20 : if (poGeomFieldDefn->m_bCachedExtentIsValid)
1294 : {
1295 16 : *psExtent = poGeomFieldDefn->m_oCachedExtent;
1296 16 : return OGRERR_NONE;
1297 : }
1298 :
1299 7 : if (CheckSpatialIndexTable(iGeomField) &&
1300 3 : !CPLTestBool(CPLGetConfigOption("OGR_SQLITE_EXACT_EXTENT", "NO")))
1301 : {
1302 : const char *pszSQL =
1303 3 : CPLSPrintf("SELECT MIN(xmin), MIN(ymin), "
1304 : "MAX(xmax), MAX(ymax) FROM 'idx_%s_%s'",
1305 : m_pszEscapedTableName,
1306 6 : SQLEscapeLiteral(poGeomFieldDefn->GetNameRef()).c_str());
1307 :
1308 3 : CPLDebug("SQLITE", "Running %s", pszSQL);
1309 :
1310 : /* --------------------------------------------------------------------
1311 : */
1312 : /* Execute. */
1313 : /* --------------------------------------------------------------------
1314 : */
1315 3 : char **papszResult = nullptr;
1316 : char *pszErrMsg;
1317 3 : int nRowCount = 0;
1318 3 : int nColCount = 0;
1319 :
1320 3 : if (sqlite3_get_table(m_poDS->GetDB(), pszSQL, &papszResult, &nRowCount,
1321 3 : &nColCount, &pszErrMsg) != SQLITE_OK)
1322 3 : return OGRSQLiteLayer::IGetExtent(iGeomField, psExtent, bForce);
1323 :
1324 3 : OGRErr eErr = OGRERR_FAILURE;
1325 :
1326 3 : if (nRowCount == 1 && nColCount == 4 && papszResult[4 + 0] != nullptr &&
1327 3 : papszResult[4 + 1] != nullptr && papszResult[4 + 2] != nullptr &&
1328 3 : papszResult[4 + 3] != nullptr)
1329 : {
1330 3 : psExtent->MinX = CPLAtof(papszResult[4 + 0]);
1331 3 : psExtent->MinY = CPLAtof(papszResult[4 + 1]);
1332 3 : psExtent->MaxX = CPLAtof(papszResult[4 + 2]);
1333 3 : psExtent->MaxY = CPLAtof(papszResult[4 + 3]);
1334 3 : eErr = OGRERR_NONE;
1335 :
1336 3 : if (m_poFilterGeom == nullptr && m_osQuery.empty())
1337 : {
1338 3 : poGeomFieldDefn->m_bCachedExtentIsValid = true;
1339 3 : if (m_poDS->GetUpdate())
1340 1 : ForceStatisticsToBeFlushed();
1341 3 : poGeomFieldDefn->m_oCachedExtent = *psExtent;
1342 : }
1343 : }
1344 :
1345 3 : sqlite3_free_table(papszResult);
1346 :
1347 3 : if (eErr == OGRERR_NONE)
1348 3 : return eErr;
1349 : }
1350 :
1351 1 : OGRErr eErr = OGRSQLiteLayer::IGetExtent(iGeomField, psExtent, bForce);
1352 1 : if (eErr == OGRERR_NONE && m_poFilterGeom == nullptr && m_osQuery.empty())
1353 : {
1354 1 : poGeomFieldDefn->m_bCachedExtentIsValid = true;
1355 1 : ForceStatisticsToBeFlushed();
1356 1 : poGeomFieldDefn->m_oCachedExtent = *psExtent;
1357 : }
1358 1 : return eErr;
1359 : }
1360 :
1361 : /************************************************************************/
1362 : /* OGRSQLiteFieldDefnToSQliteFieldDefn() */
1363 : /************************************************************************/
1364 :
1365 5421 : CPLString OGRSQLiteFieldDefnToSQliteFieldDefn(const OGRFieldDefn *poFieldDefn,
1366 : bool bSQLiteDialectInternalUse,
1367 : bool bStrict)
1368 : {
1369 5421 : if (bStrict)
1370 : {
1371 8 : switch (poFieldDefn->GetType())
1372 : {
1373 1 : case OFTInteger:
1374 0 : return "INTEGER CHECK (\"" +
1375 2 : CPLString(poFieldDefn->GetNameRef())
1376 2 : .replaceAll('"', "\"\"") +
1377 1 : "\" BETWEEN -2147483648 AND 2147483647)";
1378 1 : case OFTInteger64:
1379 0 : return "INTEGER CHECK (\"" +
1380 2 : CPLString(poFieldDefn->GetNameRef())
1381 2 : .replaceAll('"', "\"\"") +
1382 : "\" BETWEEN -9223372036854775808 AND "
1383 1 : "9223372036854775807)";
1384 1 : case OFTReal:
1385 1 : return "REAL";
1386 1 : case OFTBinary:
1387 1 : return "BLOB";
1388 1 : case OFTDateTime:
1389 0 : return "TEXT CHECK (\"" +
1390 2 : CPLString(poFieldDefn->GetNameRef())
1391 2 : .replaceAll('"', "\"\"") +
1392 : "\" LIKE "
1393 : "'[0-9][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9]T[0-2][0-9]:"
1394 1 : "[0-5][0-9]:[0-6][0-9]*')";
1395 1 : case OFTDate:
1396 0 : return "TEXT CHECK (\"" +
1397 2 : CPLString(poFieldDefn->GetNameRef())
1398 2 : .replaceAll('"', "\"\"") +
1399 1 : "\" LIKE '[0-9][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9]T')";
1400 1 : case OFTTime:
1401 0 : return "TEXT CHECK (\"" +
1402 2 : CPLString(poFieldDefn->GetNameRef())
1403 2 : .replaceAll('"', "\"\"") +
1404 1 : "\" LIKE '[0-2][0-9]:[0-5][0-9]:[0-6][0-9]*')";
1405 1 : default:
1406 1 : return "TEXT";
1407 : }
1408 : }
1409 :
1410 5413 : switch (poFieldDefn->GetType())
1411 : {
1412 1159 : case OFTInteger:
1413 : {
1414 1159 : if (poFieldDefn->GetSubType() == OFSTBoolean)
1415 245 : return "INTEGER_BOOLEAN";
1416 914 : else if (poFieldDefn->GetSubType() == OFSTInt16)
1417 213 : return "INTEGER_INT16";
1418 701 : return "INTEGER";
1419 : }
1420 275 : case OFTInteger64:
1421 275 : return "BIGINT";
1422 609 : case OFTReal:
1423 : {
1424 1120 : if (bSQLiteDialectInternalUse &&
1425 511 : poFieldDefn->GetSubType() == OFSTFloat32)
1426 210 : return "FLOAT_FLOAT32";
1427 399 : return "FLOAT";
1428 : }
1429 237 : case OFTBinary:
1430 237 : return "BLOB";
1431 :
1432 1407 : case OFTString:
1433 : {
1434 1407 : if (poFieldDefn->GetWidth() > 0)
1435 73 : return CPLSPrintf("VARCHAR(%d)", poFieldDefn->GetWidth());
1436 1334 : return "VARCHAR";
1437 : }
1438 352 : case OFTDateTime:
1439 352 : return "TIMESTAMP";
1440 :
1441 251 : case OFTDate:
1442 251 : return "DATE";
1443 :
1444 219 : case OFTTime:
1445 219 : return "TIME";
1446 :
1447 231 : case OFTIntegerList:
1448 231 : return "JSONINTEGERLIST";
1449 :
1450 219 : case OFTInteger64List:
1451 219 : return "JSONINTEGER64LIST";
1452 :
1453 222 : case OFTRealList:
1454 222 : return "JSONREALLIST";
1455 :
1456 232 : case OFTStringList:
1457 232 : return "JSONSTRINGLIST";
1458 :
1459 0 : default:
1460 0 : break;
1461 : }
1462 0 : return "VARCHAR";
1463 : }
1464 :
1465 : /************************************************************************/
1466 : /* FieldDefnToSQliteFieldDefn() */
1467 : /************************************************************************/
1468 :
1469 : CPLString
1470 1359 : OGRSQLiteTableLayer::FieldDefnToSQliteFieldDefn(OGRFieldDefn *poFieldDefn)
1471 : {
1472 : CPLString osRet =
1473 1359 : OGRSQLiteFieldDefnToSQliteFieldDefn(poFieldDefn, false, m_bStrict);
1474 2175 : if (!m_bStrict && poFieldDefn->GetType() == OFTString &&
1475 816 : CSLFindString(m_papszCompressedColumns, poFieldDefn->GetNameRef()) >= 0)
1476 8 : osRet += "_deflate";
1477 :
1478 1359 : return osRet;
1479 : }
1480 :
1481 : /************************************************************************/
1482 : /* CreateField() */
1483 : /************************************************************************/
1484 :
1485 1260 : OGRErr OGRSQLiteTableLayer::CreateField(const OGRFieldDefn *poFieldIn,
1486 : CPL_UNUSED int bApproxOK)
1487 : {
1488 2520 : OGRFieldDefn oField(poFieldIn);
1489 :
1490 1260 : if (HasLayerDefnError())
1491 0 : return OGRERR_FAILURE;
1492 :
1493 1260 : if (!m_poDS->GetUpdate())
1494 : {
1495 0 : CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
1496 : "CreateField");
1497 0 : return OGRERR_FAILURE;
1498 : }
1499 :
1500 3780 : if (m_pszFIDColumn != nullptr &&
1501 1262 : EQUAL(oField.GetNameRef(), m_pszFIDColumn) &&
1502 2522 : oField.GetType() != OFTInteger && oField.GetType() != OFTInteger64)
1503 : {
1504 1 : CPLError(CE_Failure, CPLE_AppDefined, "Wrong field type for %s",
1505 : oField.GetNameRef());
1506 1 : return OGRERR_FAILURE;
1507 : }
1508 :
1509 1259 : ClearInsertStmt();
1510 :
1511 1259 : if (m_poDS->IsSpatialiteDB() && EQUAL(oField.GetNameRef(), "ROWID") &&
1512 0 : !(m_pszFIDColumn != nullptr &&
1513 0 : EQUAL(oField.GetNameRef(), m_pszFIDColumn)))
1514 : {
1515 0 : CPLError(CE_Warning, CPLE_AppDefined,
1516 : "In a Spatialite DB, a 'ROWID' column that is not the integer "
1517 : "primary key can corrupt spatial index. "
1518 : "See "
1519 : "https://www.gaia-gis.it/fossil/libspatialite/"
1520 : "wiki?name=Shadowed+ROWID+issues");
1521 : }
1522 :
1523 : /* -------------------------------------------------------------------- */
1524 : /* Do we want to "launder" the column names into SQLite */
1525 : /* friendly format? */
1526 : /* -------------------------------------------------------------------- */
1527 1259 : if (m_bLaunderColumnNames)
1528 : {
1529 1257 : char *pszSafeName = m_poDS->LaunderName(oField.GetNameRef());
1530 :
1531 1257 : oField.SetName(pszSafeName);
1532 1257 : CPLFree(pszSafeName);
1533 : }
1534 :
1535 3721 : if ((oField.GetType() == OFTTime || oField.GetType() == OFTDate ||
1536 3729 : oField.GetType() == OFTDateTime) &&
1537 109 : !(CPLTestBool(CPLGetConfigOption("OGR_SQLITE_ENABLE_DATETIME", "YES"))))
1538 : {
1539 0 : oField.SetType(OFTString);
1540 : }
1541 :
1542 1259 : if (!m_bDeferredCreation)
1543 : {
1544 25 : CPLString osCommand;
1545 :
1546 25 : CPLString osFieldType(FieldDefnToSQliteFieldDefn(&oField));
1547 : osCommand.Printf(
1548 : "ALTER TABLE '%s' ADD COLUMN '%s' %s", m_pszEscapedTableName,
1549 25 : SQLEscapeLiteral(oField.GetNameRef()).c_str(), osFieldType.c_str());
1550 25 : if (!oField.IsNullable())
1551 : {
1552 0 : osCommand += " NOT NULL";
1553 : }
1554 25 : if (oField.IsUnique())
1555 : {
1556 0 : osCommand += " UNIQUE";
1557 : }
1558 25 : if (oField.GetDefault() != nullptr && !oField.IsDefaultDriverSpecific())
1559 : {
1560 0 : osCommand += " DEFAULT ";
1561 0 : osCommand += oField.GetDefault();
1562 : }
1563 25 : else if (!oField.IsNullable())
1564 : {
1565 : // This is kind of dumb, but SQLite mandates a DEFAULT value
1566 : // when adding a NOT NULL column in an ALTER TABLE ADD COLUMN
1567 : // statement, which defeats the purpose of NOT NULL,
1568 : // whereas it doesn't in CREATE TABLE
1569 0 : osCommand += " DEFAULT ''";
1570 : }
1571 :
1572 : #ifdef DEBUG
1573 25 : CPLDebug("OGR_SQLITE", "exec(%s)", osCommand.c_str());
1574 : #endif
1575 :
1576 25 : if (SQLCommand(m_poDS->GetDB(), osCommand) != OGRERR_NONE)
1577 0 : return OGRERR_FAILURE;
1578 : }
1579 :
1580 : /* -------------------------------------------------------------------- */
1581 : /* Add the field to the OGRFeatureDefn. */
1582 : /* -------------------------------------------------------------------- */
1583 1259 : whileUnsealing(m_poFeatureDefn)->AddFieldDefn(&oField);
1584 :
1585 1259 : if (m_poDS->IsInTransaction())
1586 : {
1587 : m_apoFieldDefnChanges.emplace_back(
1588 597 : std::make_unique<OGRFieldDefn>(oField),
1589 597 : m_poFeatureDefn->GetFieldCount() - 1, FieldChangeType::ADD_FIELD,
1590 1791 : m_poDS->GetCurrentSavepoint());
1591 : }
1592 :
1593 1259 : if (m_pszFIDColumn != nullptr && EQUAL(oField.GetNameRef(), m_pszFIDColumn))
1594 : {
1595 1 : m_iFIDAsRegularColumnIndex = m_poFeatureDefn->GetFieldCount() - 1;
1596 : }
1597 :
1598 1259 : if (!m_bDeferredCreation)
1599 25 : RecomputeOrdinals();
1600 :
1601 1259 : return OGRERR_NONE;
1602 : }
1603 :
1604 : /************************************************************************/
1605 : /* CreateGeomField() */
1606 : /************************************************************************/
1607 :
1608 : OGRErr
1609 19 : OGRSQLiteTableLayer::CreateGeomField(const OGRGeomFieldDefn *poGeomFieldIn,
1610 : CPL_UNUSED int bApproxOK)
1611 : {
1612 19 : OGRwkbGeometryType eType = poGeomFieldIn->GetType();
1613 19 : if (eType == wkbNone)
1614 : {
1615 0 : CPLError(CE_Failure, CPLE_AppDefined,
1616 : "Cannot create geometry field of type wkbNone");
1617 0 : return OGRERR_FAILURE;
1618 : }
1619 19 : if (m_poDS->IsSpatialiteDB())
1620 : {
1621 : // We need to catch this right now as AddGeometryColumn does not
1622 : // return an error
1623 7 : OGRwkbGeometryType eFType = wkbFlatten(eType);
1624 7 : if (eFType > wkbGeometryCollection)
1625 : {
1626 1 : CPLError(CE_Failure, CPLE_NotSupported,
1627 : "Cannot create geometry field of type %s",
1628 : OGRToOGCGeomType(eType));
1629 1 : return OGRERR_FAILURE;
1630 : }
1631 : }
1632 :
1633 : auto poGeomField = std::make_unique<OGRSQLiteGeomFieldDefn>(
1634 36 : poGeomFieldIn->GetNameRef(), -1);
1635 18 : if (EQUAL(poGeomField->GetNameRef(), ""))
1636 : {
1637 0 : if (m_poFeatureDefn->GetGeomFieldCount() == 0)
1638 0 : poGeomField->SetName("GEOMETRY");
1639 : else
1640 0 : poGeomField->SetName(CPLSPrintf(
1641 0 : "GEOMETRY%d", m_poFeatureDefn->GetGeomFieldCount() + 1));
1642 : }
1643 18 : auto poSRSIn = poGeomFieldIn->GetSpatialRef();
1644 18 : if (poSRSIn)
1645 : {
1646 18 : auto l_poSRS = OGRSpatialReferenceRefCountedPtr::makeClone(poSRSIn);
1647 9 : l_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1648 9 : poGeomField->SetSpatialRef(l_poSRS.get());
1649 : }
1650 :
1651 : /* -------------------------------------------------------------------- */
1652 : /* Do we want to "launder" the column names into Postgres */
1653 : /* friendly format? */
1654 : /* -------------------------------------------------------------------- */
1655 18 : if (m_bLaunderColumnNames)
1656 : {
1657 18 : char *pszSafeName = m_poDS->LaunderName(poGeomField->GetNameRef());
1658 :
1659 18 : poGeomField->SetName(pszSafeName);
1660 18 : CPLFree(pszSafeName);
1661 : }
1662 :
1663 18 : const OGRSpatialReference *poSRS = poGeomField->GetSpatialRef();
1664 18 : int nSRSId = -1;
1665 18 : if (poSRS != nullptr)
1666 9 : nSRSId = m_poDS->FetchSRSId(poSRS);
1667 :
1668 18 : poGeomField->SetType(eType);
1669 18 : poGeomField->SetNullable(poGeomFieldIn->IsNullable());
1670 18 : poGeomField->m_nSRSId = nSRSId;
1671 18 : if (m_poDS->IsSpatialiteDB())
1672 6 : poGeomField->m_eGeomFormat = OSGF_SpatiaLite;
1673 12 : else if (m_pszCreationGeomFormat)
1674 12 : poGeomField->m_eGeomFormat = GetGeomFormat(m_pszCreationGeomFormat);
1675 : else
1676 0 : poGeomField->m_eGeomFormat = OSGF_WKB;
1677 :
1678 : /* -------------------------------------------------------------------- */
1679 : /* Create the new field. */
1680 : /* -------------------------------------------------------------------- */
1681 18 : if (!m_bDeferredCreation)
1682 : {
1683 0 : if (RunAddGeometryColumn(poGeomField.get(), true) != OGRERR_NONE)
1684 : {
1685 0 : return OGRERR_FAILURE;
1686 : }
1687 : }
1688 :
1689 : // Add to the list of changes BEFORE adding it to the feature definition
1690 : // because poGeomField is a unique ptr.
1691 18 : if (m_poDS->IsInTransaction())
1692 : {
1693 : m_apoGeomFieldDefnChanges.emplace_back(
1694 16 : std::make_unique<OGRGeomFieldDefn>(*poGeomField),
1695 24 : m_poFeatureDefn->GetGeomFieldCount(), FieldChangeType::ADD_FIELD);
1696 : }
1697 :
1698 18 : m_poFeatureDefn->AddGeomFieldDefn(std::move(poGeomField));
1699 :
1700 18 : if (!m_bDeferredCreation)
1701 0 : RecomputeOrdinals();
1702 :
1703 18 : return OGRERR_NONE;
1704 : }
1705 :
1706 : /************************************************************************/
1707 : /* RunAddGeometryColumn() */
1708 : /************************************************************************/
1709 :
1710 335 : OGRErr OGRSQLiteTableLayer::RunAddGeometryColumn(
1711 : const OGRSQLiteGeomFieldDefn *poGeomFieldDefn,
1712 : bool bAddColumnsForNonSpatialite)
1713 : {
1714 335 : OGRwkbGeometryType eType = poGeomFieldDefn->GetType();
1715 335 : const char *pszGeomCol = poGeomFieldDefn->GetNameRef();
1716 335 : int nSRSId = poGeomFieldDefn->m_nSRSId;
1717 :
1718 335 : const int nCoordDim = eType == wkbFlatten(eType) ? 2 : 3;
1719 :
1720 335 : if (bAddColumnsForNonSpatialite && !m_poDS->IsSpatialiteDB())
1721 : {
1722 : CPLString osCommand =
1723 0 : CPLSPrintf("ALTER TABLE '%s' ADD COLUMN ", m_pszEscapedTableName);
1724 0 : if (poGeomFieldDefn->m_eGeomFormat == OSGF_WKT)
1725 : {
1726 : osCommand += CPLSPrintf(
1727 : " '%s' VARCHAR",
1728 0 : SQLEscapeLiteral(poGeomFieldDefn->GetNameRef()).c_str());
1729 : }
1730 : else
1731 : {
1732 : osCommand += CPLSPrintf(
1733 : " '%s' BLOB",
1734 0 : SQLEscapeLiteral(poGeomFieldDefn->GetNameRef()).c_str());
1735 : }
1736 0 : if (!poGeomFieldDefn->IsNullable())
1737 0 : osCommand += " NOT NULL DEFAULT ''";
1738 :
1739 : #ifdef DEBUG
1740 0 : CPLDebug("OGR_SQLITE", "exec(%s)", osCommand.c_str());
1741 : #endif
1742 :
1743 0 : if (SQLCommand(m_poDS->GetDB(), osCommand) != OGRERR_NONE)
1744 0 : return OGRERR_FAILURE;
1745 : }
1746 :
1747 670 : CPLString osCommand;
1748 :
1749 335 : if (m_poDS->IsSpatialiteDB())
1750 : {
1751 : /*
1752 : / SpatiaLite full support: calling AddGeometryColumn()
1753 : /
1754 : / IMPORTANT NOTICE: on SpatiaLite any attempt aimed
1755 : / to directly INSERT a row into GEOMETRY_COLUMNS
1756 : / [by-passing AddGeometryColumn() as absolutely required]
1757 : / will severely [and irremediably] corrupt the DB !!!
1758 : */
1759 152 : const char *pszType = OGRToOGCGeomType(eType);
1760 152 : if (pszType[0] == '\0')
1761 0 : pszType = "GEOMETRY";
1762 :
1763 : /*
1764 : / SpatiaLite v.2.4.0 (or any subsequent) is required
1765 : / to support 2.5D: if an obsolete version of the library
1766 : / is found we'll unconditionally activate 2D casting mode
1767 : */
1768 152 : int iSpatialiteVersion = m_poDS->GetSpatialiteVersionNumber();
1769 152 : const char *pszCoordDim = "2";
1770 152 : if (iSpatialiteVersion <
1771 152 : OGRSQLiteDataSource::MakeSpatialiteVersionNumber(2, 4, 0) &&
1772 : nCoordDim == 3)
1773 : {
1774 0 : CPLDebug("SQLITE", "Spatialite < 2.4.0 --> 2.5D geometry not "
1775 : "supported. Casting to 2D");
1776 : }
1777 152 : else if (OGR_GT_HasM(eType))
1778 : {
1779 32 : pszCoordDim = (OGR_GT_HasZ(eType)) ? "'XYZM'" : "'XYM'";
1780 : }
1781 120 : else if (OGR_GT_HasZ(eType))
1782 : {
1783 36 : pszCoordDim = "3";
1784 : }
1785 : osCommand.Printf("SELECT AddGeometryColumn("
1786 : "'%s', '%s', %d, '%s', %s",
1787 : m_pszEscapedTableName,
1788 304 : SQLEscapeLiteral(pszGeomCol).c_str(), nSRSId, pszType,
1789 152 : pszCoordDim);
1790 152 : if (iSpatialiteVersion >=
1791 304 : OGRSQLiteDataSource::MakeSpatialiteVersionNumber(3, 0, 0) &&
1792 152 : !poGeomFieldDefn->IsNullable())
1793 1 : osCommand += ", 1";
1794 152 : osCommand += ")";
1795 : }
1796 : else
1797 : {
1798 183 : const char *pszGeomFormat =
1799 365 : (poGeomFieldDefn->m_eGeomFormat == OSGF_WKT) ? "WKT"
1800 183 : : (poGeomFieldDefn->m_eGeomFormat == OSGF_WKB) ? "WKB"
1801 1 : : (poGeomFieldDefn->m_eGeomFormat == OSGF_FGF) ? "FGF"
1802 : : "Spatialite";
1803 183 : if (nSRSId > 0)
1804 : {
1805 : osCommand.Printf(
1806 : "INSERT INTO geometry_columns "
1807 : "(f_table_name, f_geometry_column, geometry_format, "
1808 : "geometry_type, coord_dimension, srid) VALUES "
1809 : "('%s','%s','%s', %d, %d, %d)",
1810 19 : m_pszEscapedTableName, SQLEscapeLiteral(pszGeomCol).c_str(),
1811 19 : pszGeomFormat, static_cast<int>(wkbFlatten(eType)), nCoordDim,
1812 19 : nSRSId);
1813 : }
1814 : else
1815 : {
1816 : osCommand.Printf(
1817 : "INSERT INTO geometry_columns "
1818 : "(f_table_name, f_geometry_column, geometry_format, "
1819 : "geometry_type, coord_dimension) VALUES "
1820 : "('%s','%s','%s', %d, %d)",
1821 164 : m_pszEscapedTableName, SQLEscapeLiteral(pszGeomCol).c_str(),
1822 164 : pszGeomFormat, static_cast<int>(wkbFlatten(eType)), nCoordDim);
1823 : }
1824 : }
1825 :
1826 : #ifdef DEBUG
1827 335 : CPLDebug("OGR_SQLITE", "exec(%s)", osCommand.c_str());
1828 : #endif
1829 :
1830 335 : return SQLCommand(m_poDS->GetDB(), osCommand);
1831 : }
1832 :
1833 : /************************************************************************/
1834 : /* InitFieldListForRecrerate() */
1835 : /************************************************************************/
1836 :
1837 25 : void OGRSQLiteTableLayer::InitFieldListForRecrerate(
1838 : char *&pszNewFieldList, char *&pszFieldListForSelect, size_t &nBufLenOut,
1839 : int nExtraSpace)
1840 : {
1841 25 : size_t nFieldListLen = 100 + 2 * nExtraSpace;
1842 :
1843 126 : for (int iField = 0; iField < m_poFeatureDefn->GetFieldCount(); iField++)
1844 : {
1845 101 : OGRFieldDefn *poFieldDefn = m_poFeatureDefn->GetFieldDefn(iField);
1846 101 : nFieldListLen += 2 * strlen(poFieldDefn->GetNameRef()) + 70;
1847 101 : nFieldListLen += strlen(" UNIQUE");
1848 101 : if (poFieldDefn->GetDefault() != nullptr)
1849 18 : nFieldListLen += 10 + strlen(poFieldDefn->GetDefault());
1850 : }
1851 :
1852 25 : nFieldListLen +=
1853 25 : 50 + (m_pszFIDColumn ? 2 * strlen(m_pszFIDColumn) : strlen("OGC_FID"));
1854 48 : for (int iField = 0; iField < m_poFeatureDefn->GetGeomFieldCount();
1855 : iField++)
1856 : {
1857 23 : nFieldListLen +=
1858 23 : 70 +
1859 23 : 2 * strlen(m_poFeatureDefn->GetGeomFieldDefn(iField)->GetNameRef());
1860 : }
1861 :
1862 25 : nBufLenOut = nFieldListLen;
1863 25 : pszFieldListForSelect = static_cast<char *>(CPLCalloc(1, nFieldListLen));
1864 25 : pszNewFieldList = static_cast<char *>(CPLCalloc(1, nFieldListLen));
1865 :
1866 : /* -------------------------------------------------------------------- */
1867 : /* Build list of old fields, and the list of new fields. */
1868 : /* -------------------------------------------------------------------- */
1869 0 : snprintf(pszFieldListForSelect, nFieldListLen, "\"%s\"",
1870 25 : m_pszFIDColumn ? SQLEscapeName(m_pszFIDColumn).c_str()
1871 : : "OGC_FID");
1872 0 : snprintf(pszNewFieldList, nFieldListLen, "\"%s\" INTEGER PRIMARY KEY",
1873 25 : m_pszFIDColumn ? SQLEscapeName(m_pszFIDColumn).c_str()
1874 : : "OGC_FID");
1875 :
1876 48 : for (int iField = 0; iField < m_poFeatureDefn->GetGeomFieldCount();
1877 : iField++)
1878 : {
1879 : OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
1880 23 : m_poFeatureDefn->myGetGeomFieldDefn(iField);
1881 23 : strcat(pszFieldListForSelect, ",");
1882 23 : strcat(pszNewFieldList, ",");
1883 :
1884 23 : strcat(pszFieldListForSelect, "\"");
1885 23 : strcat(pszFieldListForSelect,
1886 46 : SQLEscapeName(poGeomFieldDefn->GetNameRef()));
1887 23 : strcat(pszFieldListForSelect, "\"");
1888 :
1889 23 : strcat(pszNewFieldList, "\"");
1890 23 : strcat(pszNewFieldList, SQLEscapeName(poGeomFieldDefn->GetNameRef()));
1891 23 : strcat(pszNewFieldList, "\"");
1892 :
1893 23 : if (poGeomFieldDefn->m_eGeomFormat == OSGF_WKT)
1894 0 : strcat(pszNewFieldList, " VARCHAR");
1895 : else
1896 23 : strcat(pszNewFieldList, " BLOB");
1897 23 : if (!poGeomFieldDefn->IsNullable())
1898 2 : strcat(pszNewFieldList, " NOT NULL");
1899 : }
1900 25 : }
1901 :
1902 : /************************************************************************/
1903 : /* AddColumnDef() */
1904 : /************************************************************************/
1905 :
1906 88 : void OGRSQLiteTableLayer::AddColumnDef(char *pszNewFieldList, size_t nBufLen,
1907 : OGRFieldDefn *poFldDefn)
1908 : {
1909 176 : snprintf(pszNewFieldList + strlen(pszNewFieldList),
1910 88 : nBufLen - strlen(pszNewFieldList), ", '%s' %s",
1911 176 : SQLEscapeLiteral(poFldDefn->GetNameRef()).c_str(),
1912 176 : FieldDefnToSQliteFieldDefn(poFldDefn).c_str());
1913 88 : if (!poFldDefn->IsNullable())
1914 0 : snprintf(pszNewFieldList + strlen(pszNewFieldList),
1915 0 : nBufLen - strlen(pszNewFieldList), " NOT NULL");
1916 88 : if (poFldDefn->IsUnique())
1917 0 : snprintf(pszNewFieldList + strlen(pszNewFieldList),
1918 0 : nBufLen - strlen(pszNewFieldList), " UNIQUE");
1919 104 : if (poFldDefn->GetDefault() != nullptr &&
1920 16 : !poFldDefn->IsDefaultDriverSpecific())
1921 : {
1922 14 : snprintf(pszNewFieldList + strlen(pszNewFieldList),
1923 14 : nBufLen - strlen(pszNewFieldList), " DEFAULT %s",
1924 : poFldDefn->GetDefault());
1925 : }
1926 88 : }
1927 :
1928 : /************************************************************************/
1929 : /* RecreateTable() */
1930 : /************************************************************************/
1931 :
1932 25 : OGRErr OGRSQLiteTableLayer::RecreateTable(const char *pszFieldListForSelect,
1933 : const char *pszNewFieldList,
1934 : const char *pszGenericErrorMessage,
1935 : const char *pszAdditionalDef)
1936 : {
1937 : /* -------------------------------------------------------------------- */
1938 : /* Do this all in a transaction. */
1939 : /* -------------------------------------------------------------------- */
1940 25 : m_poDS->SoftStartTransaction();
1941 :
1942 : /* -------------------------------------------------------------------- */
1943 : /* Save existing related triggers and index */
1944 : /* -------------------------------------------------------------------- */
1945 25 : char *pszErrMsg = nullptr;
1946 25 : sqlite3 *hDB = m_poDS->GetDB();
1947 50 : CPLString osSQL;
1948 :
1949 : osSQL.Printf("SELECT sql FROM sqlite_master WHERE type IN "
1950 : "('trigger','index') AND tbl_name='%s'",
1951 25 : m_pszEscapedTableName);
1952 :
1953 : int nRowTriggerIndexCount, nColTriggerIndexCount;
1954 25 : char **papszTriggerIndexResult = nullptr;
1955 25 : int rc = sqlite3_get_table(hDB, osSQL.c_str(), &papszTriggerIndexResult,
1956 : &nRowTriggerIndexCount, &nColTriggerIndexCount,
1957 : &pszErrMsg);
1958 :
1959 : /* -------------------------------------------------------------------- */
1960 : /* Make a backup of the table. */
1961 : /* -------------------------------------------------------------------- */
1962 :
1963 25 : if (rc == SQLITE_OK)
1964 27 : rc = sqlite3_exec(
1965 : hDB,
1966 : CPLSPrintf("CREATE TABLE t1_back(%s %s)%s", pszNewFieldList,
1967 : pszAdditionalDef
1968 27 : ? (std::string(", ") + pszAdditionalDef).c_str()
1969 : : "",
1970 25 : m_bStrict ? " STRICT" : ""),
1971 : nullptr, nullptr, &pszErrMsg);
1972 :
1973 25 : if (rc == SQLITE_OK)
1974 25 : rc = sqlite3_exec(hDB,
1975 : CPLSPrintf("INSERT INTO t1_back SELECT %s FROM '%s'",
1976 : pszFieldListForSelect,
1977 : m_pszEscapedTableName),
1978 : nullptr, nullptr, &pszErrMsg);
1979 :
1980 : /* -------------------------------------------------------------------- */
1981 : /* Drop the original table */
1982 : /* -------------------------------------------------------------------- */
1983 25 : if (rc == SQLITE_OK)
1984 25 : rc = sqlite3_exec(hDB,
1985 : CPLSPrintf("DROP TABLE '%s'", m_pszEscapedTableName),
1986 : nullptr, nullptr, &pszErrMsg);
1987 :
1988 : /* -------------------------------------------------------------------- */
1989 : /* Rename backup table as new table */
1990 : /* -------------------------------------------------------------------- */
1991 25 : if (rc == SQLITE_OK)
1992 : {
1993 25 : const char *pszCmd = CPLSPrintf("ALTER TABLE t1_back RENAME TO '%s'",
1994 : m_pszEscapedTableName);
1995 25 : rc = sqlite3_exec(hDB, pszCmd, nullptr, nullptr, &pszErrMsg);
1996 : }
1997 :
1998 : /* -------------------------------------------------------------------- */
1999 : /* Recreate existing related tables, triggers and index */
2000 : /* -------------------------------------------------------------------- */
2001 :
2002 25 : if (rc == SQLITE_OK)
2003 : {
2004 25 : for (int i = 1; i <= nRowTriggerIndexCount &&
2005 25 : nColTriggerIndexCount == 1 && rc == SQLITE_OK;
2006 : i++)
2007 : {
2008 0 : if (papszTriggerIndexResult[i] != nullptr &&
2009 0 : papszTriggerIndexResult[i][0] != '\0')
2010 0 : rc = sqlite3_exec(hDB, papszTriggerIndexResult[i], nullptr,
2011 : nullptr, &pszErrMsg);
2012 : }
2013 : }
2014 :
2015 : /* -------------------------------------------------------------------- */
2016 : /* COMMIT on success or ROLLBACK on failure. */
2017 : /* -------------------------------------------------------------------- */
2018 :
2019 25 : sqlite3_free_table(papszTriggerIndexResult);
2020 :
2021 25 : if (rc == SQLITE_OK)
2022 : {
2023 25 : m_poDS->SoftCommitTransaction();
2024 :
2025 25 : return OGRERR_NONE;
2026 : }
2027 : else
2028 : {
2029 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s:\n %s",
2030 : pszGenericErrorMessage, pszErrMsg);
2031 0 : sqlite3_free(pszErrMsg);
2032 :
2033 0 : m_poDS->SoftRollbackTransaction();
2034 :
2035 0 : return OGRERR_FAILURE;
2036 : }
2037 : }
2038 :
2039 : /************************************************************************/
2040 : /* DeleteField() */
2041 : /************************************************************************/
2042 :
2043 159 : OGRErr OGRSQLiteTableLayer::DeleteField(int iFieldToDelete)
2044 : {
2045 159 : if (HasLayerDefnError())
2046 0 : return OGRERR_FAILURE;
2047 :
2048 159 : if (!m_poDS->GetUpdate())
2049 : {
2050 0 : CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
2051 : "DeleteField");
2052 0 : return OGRERR_FAILURE;
2053 : }
2054 :
2055 317 : if (iFieldToDelete < 0 ||
2056 158 : iFieldToDelete >= m_poFeatureDefn->GetFieldCount())
2057 : {
2058 2 : CPLError(CE_Failure, CPLE_NotSupported, "Invalid field index");
2059 2 : return OGRERR_FAILURE;
2060 : }
2061 :
2062 157 : ResetReading();
2063 :
2064 157 : if (m_poDS->SoftStartTransaction() != OGRERR_NONE)
2065 0 : return OGRERR_FAILURE;
2066 :
2067 : // ALTER TABLE ... DROP COLUMN ... was first implemented in 3.35.0 but
2068 : // there was bug fixes related to it until 3.35.5
2069 : #if SQLITE_VERSION_NUMBER >= 3035005L
2070 : const char *pszFieldName =
2071 157 : m_poFeatureDefn->GetFieldDefn(iFieldToDelete)->GetNameRef();
2072 157 : OGRErr eErr = SQLCommand(
2073 314 : m_poDS->GetDB(), CPLString()
2074 : .Printf("ALTER TABLE \"%s\" DROP COLUMN \"%s\"",
2075 314 : SQLEscapeName(m_pszTableName).c_str(),
2076 471 : SQLEscapeName(pszFieldName).c_str())
2077 : .c_str());
2078 : #else
2079 : /* -------------------------------------------------------------------- */
2080 : /* Build list of old fields, and the list of new fields. */
2081 : /* -------------------------------------------------------------------- */
2082 : char *pszNewFieldList = nullptr;
2083 : char *pszFieldListForSelect = nullptr;
2084 : size_t nBufLen = 0;
2085 :
2086 : InitFieldListForRecrerate(pszNewFieldList, pszFieldListForSelect, nBufLen);
2087 :
2088 : for (int iField = 0; iField < m_poFeatureDefn->GetFieldCount(); iField++)
2089 : {
2090 : OGRFieldDefn *poFldDefn = m_poFeatureDefn->GetFieldDefn(iField);
2091 :
2092 : if (iField == iFieldToDelete)
2093 : continue;
2094 :
2095 : snprintf(pszFieldListForSelect + strlen(pszFieldListForSelect),
2096 : nBufLen - strlen(pszFieldListForSelect), ", \"%s\"",
2097 : SQLEscapeName(poFldDefn->GetNameRef()).c_str());
2098 :
2099 : AddColumnDef(pszNewFieldList, nBufLen, poFldDefn);
2100 : }
2101 :
2102 : /* -------------------------------------------------------------------- */
2103 : /* Recreate table. */
2104 : /* -------------------------------------------------------------------- */
2105 : CPLString osErrorMsg;
2106 : osErrorMsg.Printf(
2107 : "Failed to remove field %s from table %s",
2108 : m_poFeatureDefn->GetFieldDefn(iFieldToDelete)->GetNameRef(),
2109 : m_poFeatureDefn->GetName());
2110 :
2111 : OGRErr eErr = RecreateTable(pszFieldListForSelect, pszNewFieldList,
2112 : osErrorMsg.c_str());
2113 :
2114 : CPLFree(pszFieldListForSelect);
2115 : CPLFree(pszNewFieldList);
2116 : #endif
2117 :
2118 : /* -------------------------------------------------------------------- */
2119 : /* Check foreign key integrity if enforcement of foreign keys */
2120 : /* constraint is enabled. */
2121 : /* -------------------------------------------------------------------- */
2122 314 : if (eErr == OGRERR_NONE &&
2123 157 : SQLGetInteger(m_poDS->GetDB(), "PRAGMA foreign_keys", nullptr))
2124 : {
2125 0 : CPLDebug("SQLite", "Running PRAGMA foreign_key_check");
2126 0 : eErr = m_poDS->PragmaCheck("foreign_key_check", "", 0);
2127 : }
2128 :
2129 : /* -------------------------------------------------------------------- */
2130 : /* Finish */
2131 : /* -------------------------------------------------------------------- */
2132 :
2133 157 : if (eErr == OGRERR_NONE)
2134 : {
2135 157 : eErr = m_poDS->SoftCommitTransaction();
2136 157 : if (eErr == OGRERR_NONE)
2137 : {
2138 :
2139 : // Keep the field definition alive until a new transaction is started
2140 : // or the layer is destroyed.
2141 157 : if (m_poDS->IsInTransaction())
2142 : {
2143 152 : std::unique_ptr<OGRFieldDefn> poFieldDefn;
2144 152 : poFieldDefn = whileUnsealing(m_poFeatureDefn)
2145 152 : ->StealFieldDefn(iFieldToDelete);
2146 152 : if (poFieldDefn)
2147 : {
2148 : m_apoFieldDefnChanges.emplace_back(
2149 152 : std::move(poFieldDefn), iFieldToDelete,
2150 152 : FieldChangeType::DELETE_FIELD,
2151 304 : m_poDS->GetCurrentSavepoint());
2152 : }
2153 : else
2154 : {
2155 0 : eErr = OGRERR_FAILURE;
2156 : }
2157 : }
2158 : else
2159 : {
2160 10 : eErr = whileUnsealing(m_poFeatureDefn)
2161 5 : ->DeleteFieldDefn(iFieldToDelete);
2162 : }
2163 :
2164 157 : RecomputeOrdinals();
2165 :
2166 157 : ResetReading();
2167 : }
2168 : }
2169 : else
2170 : {
2171 0 : m_poDS->SoftRollbackTransaction();
2172 : }
2173 :
2174 157 : return eErr;
2175 : }
2176 :
2177 : /************************************************************************/
2178 : /* AlterFieldDefn() */
2179 : /************************************************************************/
2180 :
2181 16 : OGRErr OGRSQLiteTableLayer::AlterFieldDefn(int iFieldToAlter,
2182 : OGRFieldDefn *poNewFieldDefn,
2183 : int nFlagsIn)
2184 : {
2185 16 : if (HasLayerDefnError())
2186 0 : return OGRERR_FAILURE;
2187 :
2188 16 : if (!m_poDS->GetUpdate())
2189 : {
2190 0 : CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
2191 : "AlterFieldDefn");
2192 0 : return OGRERR_FAILURE;
2193 : }
2194 :
2195 16 : if (iFieldToAlter < 0 || iFieldToAlter >= m_poFeatureDefn->GetFieldCount())
2196 : {
2197 2 : CPLError(CE_Failure, CPLE_NotSupported, "Invalid field index");
2198 2 : return OGRERR_FAILURE;
2199 : }
2200 :
2201 14 : ClearInsertStmt();
2202 14 : ResetReading();
2203 :
2204 : /* -------------------------------------------------------------------- */
2205 : /* Check that the new column name is not a duplicate. */
2206 : /* -------------------------------------------------------------------- */
2207 :
2208 : OGRFieldDefn *poFieldDefnToAlter =
2209 14 : m_poFeatureDefn->GetFieldDefn(iFieldToAlter);
2210 28 : const CPLString osOldColName(poFieldDefnToAlter->GetNameRef());
2211 14 : const CPLString osNewColName((nFlagsIn & ALTER_NAME_FLAG)
2212 : ? CPLString(poNewFieldDefn->GetNameRef())
2213 28 : : osOldColName);
2214 :
2215 14 : const bool bRenameCol = osOldColName != osNewColName;
2216 14 : if (bRenameCol)
2217 : {
2218 33 : if ((m_pszFIDColumn &&
2219 11 : strcmp(poNewFieldDefn->GetNameRef(), m_pszFIDColumn) == 0) ||
2220 11 : (GetGeomType() != wkbNone &&
2221 11 : strcmp(poNewFieldDefn->GetNameRef(),
2222 33 : m_poFeatureDefn->GetGeomFieldDefn(0)->GetNameRef()) == 0) ||
2223 11 : m_poFeatureDefn->GetFieldIndex(poNewFieldDefn->GetNameRef()) >= 0)
2224 : {
2225 0 : CPLError(CE_Failure, CPLE_AppDefined,
2226 : "Field name %s is already used for another field",
2227 : poNewFieldDefn->GetNameRef());
2228 0 : return OGRERR_FAILURE;
2229 : }
2230 : }
2231 :
2232 : /* -------------------------------------------------------------------- */
2233 : /* Build the modified field definition from the flags. */
2234 : /* -------------------------------------------------------------------- */
2235 28 : OGRFieldDefn oTmpFieldDefn(poFieldDefnToAlter);
2236 14 : int nActualFlags = 0;
2237 14 : if (bRenameCol)
2238 : {
2239 11 : nActualFlags |= ALTER_NAME_FLAG;
2240 11 : oTmpFieldDefn.SetName(poNewFieldDefn->GetNameRef());
2241 : }
2242 26 : if ((nFlagsIn & ALTER_TYPE_FLAG) != 0 &&
2243 12 : (poFieldDefnToAlter->GetType() != poNewFieldDefn->GetType() ||
2244 6 : poFieldDefnToAlter->GetSubType() != poNewFieldDefn->GetSubType()))
2245 : {
2246 6 : nActualFlags |= ALTER_TYPE_FLAG;
2247 6 : oTmpFieldDefn.SetSubType(OFSTNone);
2248 6 : oTmpFieldDefn.SetType(poNewFieldDefn->GetType());
2249 6 : oTmpFieldDefn.SetSubType(poNewFieldDefn->GetSubType());
2250 : }
2251 33 : if ((nFlagsIn & ALTER_WIDTH_PRECISION_FLAG) != 0 &&
2252 19 : (poFieldDefnToAlter->GetWidth() != poNewFieldDefn->GetWidth() ||
2253 7 : poFieldDefnToAlter->GetPrecision() != poNewFieldDefn->GetPrecision()))
2254 : {
2255 5 : nActualFlags |= ALTER_WIDTH_PRECISION_FLAG;
2256 5 : oTmpFieldDefn.SetWidth(poNewFieldDefn->GetWidth());
2257 5 : oTmpFieldDefn.SetPrecision(poNewFieldDefn->GetPrecision());
2258 : }
2259 26 : if ((nFlagsIn & ALTER_NULLABLE_FLAG) != 0 &&
2260 12 : poFieldDefnToAlter->IsNullable() != poNewFieldDefn->IsNullable())
2261 : {
2262 2 : nActualFlags |= ALTER_NULLABLE_FLAG;
2263 2 : oTmpFieldDefn.SetNullable(poNewFieldDefn->IsNullable());
2264 : }
2265 28 : if ((nFlagsIn & ALTER_DEFAULT_FLAG) != 0 &&
2266 14 : !((poFieldDefnToAlter->GetDefault() == nullptr &&
2267 12 : poNewFieldDefn->GetDefault() == nullptr) ||
2268 2 : (poFieldDefnToAlter->GetDefault() != nullptr &&
2269 2 : poNewFieldDefn->GetDefault() != nullptr &&
2270 1 : strcmp(poFieldDefnToAlter->GetDefault(),
2271 : poNewFieldDefn->GetDefault()) == 0)))
2272 : {
2273 2 : nActualFlags |= ALTER_DEFAULT_FLAG;
2274 2 : oTmpFieldDefn.SetDefault(poNewFieldDefn->GetDefault());
2275 : }
2276 26 : if ((nFlagsIn & ALTER_UNIQUE_FLAG) != 0 &&
2277 12 : poFieldDefnToAlter->IsUnique() != poNewFieldDefn->IsUnique())
2278 : {
2279 0 : nActualFlags |= ALTER_UNIQUE_FLAG;
2280 0 : oTmpFieldDefn.SetUnique(poNewFieldDefn->IsUnique());
2281 : }
2282 :
2283 14 : int nActualFlagsToApplyWithSQL = nActualFlags;
2284 :
2285 : #if SQLITE_VERSION_NUMBER >= 3053000L
2286 : if ((nActualFlagsToApplyWithSQL & ALTER_NULLABLE_FLAG) != 0)
2287 : {
2288 : OGRErr eErr =
2289 : SQLCommand(m_poDS->GetDB(),
2290 : CPLString().Printf(
2291 : "ALTER TABLE \"%s\" ALTER COLUMN \"%s\" %s NOT NULL",
2292 : SQLEscapeName(m_pszTableName).c_str(),
2293 : SQLEscapeName(osOldColName).c_str(),
2294 : poNewFieldDefn->IsNullable() ? "DROP" : "SET"));
2295 :
2296 : if (eErr != OGRERR_NONE)
2297 : return eErr;
2298 :
2299 : nActualFlagsToApplyWithSQL &= ~ALTER_NULLABLE_FLAG;
2300 : }
2301 : #endif
2302 :
2303 14 : if (nActualFlagsToApplyWithSQL == ALTER_NAME_FLAG)
2304 : {
2305 1 : CPLDebug("SQLite", "Running ALTER TABLE RENAME COLUMN");
2306 1 : OGRErr eErr = SQLCommand(
2307 1 : m_poDS->GetDB(),
2308 1 : CPLString()
2309 : .Printf("ALTER TABLE \"%s\" RENAME COLUMN \"%s\" TO \"%s\"",
2310 2 : SQLEscapeName(m_pszTableName).c_str(),
2311 2 : SQLEscapeName(osOldColName).c_str(),
2312 4 : SQLEscapeName(osNewColName).c_str())
2313 : .c_str());
2314 :
2315 1 : if (eErr != OGRERR_NONE)
2316 0 : return eErr;
2317 : }
2318 13 : else if (nActualFlagsToApplyWithSQL != 0)
2319 : {
2320 : /* --------------------------------------------------------------------
2321 : */
2322 : /* Build list of old fields, and the list of new fields. */
2323 : /* --------------------------------------------------------------------
2324 : */
2325 13 : char *pszNewFieldList = nullptr;
2326 13 : char *pszFieldListForSelect = nullptr;
2327 13 : size_t nBufLen = 0;
2328 :
2329 13 : InitFieldListForRecrerate(
2330 : pszNewFieldList, pszFieldListForSelect, nBufLen,
2331 13 : static_cast<int>(strlen(poNewFieldDefn->GetNameRef())) + 50 +
2332 13 : (poNewFieldDefn->GetDefault()
2333 13 : ? static_cast<int>(strlen(poNewFieldDefn->GetDefault()))
2334 : : 0));
2335 :
2336 68 : for (int iField = 0; iField < m_poFeatureDefn->GetFieldCount();
2337 : iField++)
2338 : {
2339 55 : OGRFieldDefn *poFldDefn = m_poFeatureDefn->GetFieldDefn(iField);
2340 :
2341 55 : snprintf(pszFieldListForSelect + strlen(pszFieldListForSelect),
2342 55 : nBufLen - strlen(pszFieldListForSelect), ", \"%s\"",
2343 110 : SQLEscapeName(poFldDefn->GetNameRef()).c_str());
2344 :
2345 55 : if (iField == iFieldToAlter)
2346 : {
2347 26 : snprintf(pszNewFieldList + strlen(pszNewFieldList),
2348 13 : nBufLen - strlen(pszNewFieldList), ", '%s' %s",
2349 26 : SQLEscapeLiteral(oTmpFieldDefn.GetNameRef()).c_str(),
2350 26 : FieldDefnToSQliteFieldDefn(&oTmpFieldDefn).c_str());
2351 11 : if ((nFlagsIn & ALTER_NAME_FLAG) &&
2352 24 : oTmpFieldDefn.GetType() == OFTString &&
2353 6 : CSLFindString(m_papszCompressedColumns,
2354 : poFldDefn->GetNameRef()) >= 0)
2355 : {
2356 0 : snprintf(pszNewFieldList + strlen(pszNewFieldList),
2357 0 : nBufLen - strlen(pszNewFieldList), "_deflate");
2358 : }
2359 13 : if (!oTmpFieldDefn.IsNullable())
2360 1 : snprintf(pszNewFieldList + strlen(pszNewFieldList),
2361 1 : nBufLen - strlen(pszNewFieldList), " NOT NULL");
2362 13 : if (oTmpFieldDefn.IsUnique())
2363 0 : snprintf(pszNewFieldList + strlen(pszNewFieldList),
2364 0 : nBufLen - strlen(pszNewFieldList), " UNIQUE");
2365 13 : if (oTmpFieldDefn.GetDefault())
2366 : {
2367 1 : snprintf(pszNewFieldList + strlen(pszNewFieldList),
2368 1 : nBufLen - strlen(pszNewFieldList), " DEFAULT %s",
2369 : oTmpFieldDefn.GetDefault());
2370 : }
2371 : }
2372 : else
2373 : {
2374 42 : AddColumnDef(pszNewFieldList, nBufLen, poFldDefn);
2375 : }
2376 : }
2377 :
2378 : /* --------------------------------------------------------------------
2379 : */
2380 : /* Recreate table. */
2381 : /* --------------------------------------------------------------------
2382 : */
2383 13 : CPLString osErrorMsg;
2384 : osErrorMsg.Printf(
2385 : "Failed to alter field %s from table %s",
2386 13 : m_poFeatureDefn->GetFieldDefn(iFieldToAlter)->GetNameRef(),
2387 13 : m_poFeatureDefn->GetName());
2388 :
2389 13 : OGRErr eErr = RecreateTable(pszFieldListForSelect, pszNewFieldList,
2390 : osErrorMsg.c_str());
2391 :
2392 13 : CPLFree(pszFieldListForSelect);
2393 13 : CPLFree(pszNewFieldList);
2394 :
2395 13 : if (eErr != OGRERR_NONE)
2396 0 : return eErr;
2397 : }
2398 :
2399 : /* -------------------------------------------------------------------- */
2400 : /* Finish */
2401 : /* -------------------------------------------------------------------- */
2402 :
2403 14 : auto oTemporaryUnsealer(m_poFeatureDefn->GetTemporaryUnsealer());
2404 14 : OGRFieldDefn *poFieldDefn = m_poFeatureDefn->GetFieldDefn(iFieldToAlter);
2405 :
2406 14 : if (m_poDS->IsInTransaction())
2407 : {
2408 : m_apoFieldDefnChanges.emplace_back(
2409 4 : std::make_unique<OGRFieldDefn>(poFieldDefn), iFieldToAlter,
2410 8 : FieldChangeType::ALTER_FIELD, m_poDS->GetCurrentSavepoint());
2411 : }
2412 :
2413 14 : if (nActualFlags & ALTER_TYPE_FLAG)
2414 : {
2415 6 : int iIdx = 0;
2416 10 : if (poNewFieldDefn->GetType() != OFTString &&
2417 4 : (iIdx = CSLFindString(m_papszCompressedColumns,
2418 : poFieldDefn->GetNameRef())) >= 0)
2419 : {
2420 0 : m_papszCompressedColumns =
2421 0 : CSLRemoveStrings(m_papszCompressedColumns, iIdx, 1, nullptr);
2422 : }
2423 6 : poFieldDefn->SetSubType(OFSTNone);
2424 6 : poFieldDefn->SetType(poNewFieldDefn->GetType());
2425 6 : poFieldDefn->SetSubType(poNewFieldDefn->GetSubType());
2426 : }
2427 14 : if (nActualFlags & ALTER_NAME_FLAG)
2428 : {
2429 : const int iIdx =
2430 11 : CSLFindString(m_papszCompressedColumns, poFieldDefn->GetNameRef());
2431 11 : if (iIdx >= 0)
2432 : {
2433 0 : CPLFree(m_papszCompressedColumns[iIdx]);
2434 0 : m_papszCompressedColumns[iIdx] =
2435 0 : CPLStrdup(poNewFieldDefn->GetNameRef());
2436 : }
2437 11 : poFieldDefn->SetName(poNewFieldDefn->GetNameRef());
2438 : }
2439 14 : if (nActualFlags & ALTER_WIDTH_PRECISION_FLAG)
2440 : {
2441 5 : poFieldDefn->SetWidth(poNewFieldDefn->GetWidth());
2442 5 : poFieldDefn->SetPrecision(poNewFieldDefn->GetPrecision());
2443 : }
2444 14 : if (nActualFlags & ALTER_NULLABLE_FLAG)
2445 2 : poFieldDefn->SetNullable(poNewFieldDefn->IsNullable());
2446 14 : if (nActualFlags & ALTER_DEFAULT_FLAG)
2447 2 : poFieldDefn->SetDefault(poNewFieldDefn->GetDefault());
2448 :
2449 14 : return OGRERR_NONE;
2450 : }
2451 :
2452 : /************************************************************************/
2453 : /* AddForeignKeysToTable() */
2454 : /************************************************************************/
2455 :
2456 2 : OGRErr OGRSQLiteTableLayer::AddForeignKeysToTable(const char *pszKeys)
2457 : {
2458 2 : if (HasLayerDefnError())
2459 0 : return OGRERR_FAILURE;
2460 :
2461 2 : if (!m_poDS->GetUpdate())
2462 : {
2463 0 : CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
2464 : "AddForeignKeysToTable");
2465 0 : return OGRERR_FAILURE;
2466 : }
2467 :
2468 2 : ClearInsertStmt();
2469 2 : ResetReading();
2470 :
2471 : /* -------------------------------------------------------------------- */
2472 : /* Build list of old fields, and the list of new fields. */
2473 : /* -------------------------------------------------------------------- */
2474 2 : char *pszNewFieldList = nullptr;
2475 2 : char *pszFieldListForSelect = nullptr;
2476 2 : size_t nBufLen = 0;
2477 :
2478 2 : InitFieldListForRecrerate(pszNewFieldList, pszFieldListForSelect, nBufLen,
2479 : 0);
2480 :
2481 6 : for (int iField = 0; iField < m_poFeatureDefn->GetFieldCount(); iField++)
2482 : {
2483 4 : OGRFieldDefn *poFldDefn = m_poFeatureDefn->GetFieldDefn(iField);
2484 :
2485 4 : snprintf(pszFieldListForSelect + strlen(pszFieldListForSelect),
2486 4 : nBufLen - strlen(pszFieldListForSelect), ", \"%s\"",
2487 8 : SQLEscapeName(poFldDefn->GetNameRef()).c_str());
2488 :
2489 4 : AddColumnDef(pszNewFieldList, nBufLen, poFldDefn);
2490 : }
2491 :
2492 : /* -------------------------------------------------------------------- */
2493 : /* Recreate table. */
2494 : /* -------------------------------------------------------------------- */
2495 4 : CPLString osErrorMsg;
2496 : osErrorMsg.Printf("Failed to add foreign keys to table %s",
2497 2 : m_poFeatureDefn->GetName());
2498 :
2499 2 : OGRErr eErr = RecreateTable(pszFieldListForSelect, pszNewFieldList,
2500 : osErrorMsg.c_str(), pszKeys);
2501 :
2502 2 : CPLFree(pszFieldListForSelect);
2503 2 : CPLFree(pszNewFieldList);
2504 :
2505 2 : if (eErr != OGRERR_NONE)
2506 0 : return eErr;
2507 :
2508 : /* -------------------------------------------------------------------- */
2509 : /* Finish */
2510 : /* -------------------------------------------------------------------- */
2511 :
2512 2 : return OGRERR_NONE;
2513 : }
2514 :
2515 : /************************************************************************/
2516 : /* ReorderFields() */
2517 : /************************************************************************/
2518 :
2519 15 : OGRErr OGRSQLiteTableLayer::ReorderFields(int *panMap)
2520 : {
2521 15 : if (HasLayerDefnError())
2522 0 : return OGRERR_FAILURE;
2523 :
2524 15 : if (!m_poDS->GetUpdate())
2525 : {
2526 0 : CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
2527 : "ReorderFields");
2528 0 : return OGRERR_FAILURE;
2529 : }
2530 :
2531 15 : if (m_poFeatureDefn->GetFieldCount() == 0)
2532 4 : return OGRERR_NONE;
2533 :
2534 11 : OGRErr eErr = OGRCheckPermutation(panMap, m_poFeatureDefn->GetFieldCount());
2535 11 : if (eErr != OGRERR_NONE)
2536 1 : return eErr;
2537 :
2538 10 : ClearInsertStmt();
2539 10 : ResetReading();
2540 :
2541 : /* -------------------------------------------------------------------- */
2542 : /* Build list of old fields, and the list of new fields. */
2543 : /* -------------------------------------------------------------------- */
2544 10 : char *pszNewFieldList = nullptr;
2545 10 : char *pszFieldListForSelect = nullptr;
2546 10 : size_t nBufLen = 0;
2547 :
2548 10 : InitFieldListForRecrerate(pszNewFieldList, pszFieldListForSelect, nBufLen);
2549 :
2550 52 : for (int iField = 0; iField < m_poFeatureDefn->GetFieldCount(); iField++)
2551 : {
2552 42 : OGRFieldDefn *poFldDefn = m_poFeatureDefn->GetFieldDefn(panMap[iField]);
2553 :
2554 42 : snprintf(pszFieldListForSelect + strlen(pszFieldListForSelect),
2555 42 : nBufLen - strlen(pszFieldListForSelect), ", \"%s\"",
2556 84 : SQLEscapeName(poFldDefn->GetNameRef()).c_str());
2557 :
2558 42 : AddColumnDef(pszNewFieldList, nBufLen, poFldDefn);
2559 : }
2560 :
2561 : /* -------------------------------------------------------------------- */
2562 : /* Recreate table. */
2563 : /* -------------------------------------------------------------------- */
2564 20 : CPLString osErrorMsg;
2565 : osErrorMsg.Printf("Failed to reorder fields from table %s",
2566 10 : m_poFeatureDefn->GetName());
2567 :
2568 10 : eErr = RecreateTable(pszFieldListForSelect, pszNewFieldList,
2569 : osErrorMsg.c_str());
2570 :
2571 10 : CPLFree(pszFieldListForSelect);
2572 10 : CPLFree(pszNewFieldList);
2573 :
2574 10 : if (eErr != OGRERR_NONE)
2575 0 : return eErr;
2576 :
2577 : /* -------------------------------------------------------------------- */
2578 : /* Finish */
2579 : /* -------------------------------------------------------------------- */
2580 :
2581 10 : eErr = whileUnsealing(m_poFeatureDefn)->ReorderFieldDefns(panMap);
2582 :
2583 10 : RecomputeOrdinals();
2584 :
2585 10 : return eErr;
2586 : }
2587 :
2588 : /************************************************************************/
2589 : /* BindValues() */
2590 : /************************************************************************/
2591 :
2592 : /* the bBindNullValues is set to TRUE by SetFeature() for UPDATE statements, */
2593 : /* and to FALSE by CreateFeature() for INSERT statements; */
2594 :
2595 6561 : OGRErr OGRSQLiteTableLayer::BindValues(OGRFeature *poFeature,
2596 : sqlite3_stmt *m_hStmtIn,
2597 : bool bBindUnsetAsNull)
2598 : {
2599 6561 : sqlite3 *hDB = m_poDS->GetDB();
2600 :
2601 : /* -------------------------------------------------------------------- */
2602 : /* Bind the geometry */
2603 : /* -------------------------------------------------------------------- */
2604 6561 : int nBindField = 1;
2605 6561 : int nFieldCount = m_poFeatureDefn->GetGeomFieldCount();
2606 12313 : for (int iField = 0; iField < nFieldCount; iField++)
2607 : {
2608 : OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
2609 5752 : m_poFeatureDefn->myGetGeomFieldDefn(iField);
2610 5752 : OGRSQLiteGeomFormat eGeomFormat = poGeomFieldDefn->m_eGeomFormat;
2611 5752 : if (eGeomFormat == OSGF_FGF)
2612 0 : continue;
2613 5752 : OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iField);
2614 5752 : int rc = SQLITE_OK;
2615 5752 : if (poGeom != nullptr)
2616 : {
2617 5592 : if (eGeomFormat == OSGF_WKT)
2618 : {
2619 1 : char *pszWKT = nullptr;
2620 1 : poGeom->exportToWkt(&pszWKT);
2621 1 : rc = sqlite3_bind_text(m_hStmtIn, nBindField++, pszWKT, -1,
2622 : CPLFree);
2623 : }
2624 5591 : else if (eGeomFormat == OSGF_WKB)
2625 : {
2626 5309 : const size_t nWKBLen = poGeom->WkbSize();
2627 5309 : if (nWKBLen >
2628 5309 : static_cast<size_t>(std::numeric_limits<int>::max()))
2629 : {
2630 0 : CPLError(CE_Failure, CPLE_NotSupported,
2631 : "Too large geometry");
2632 0 : return OGRERR_FAILURE;
2633 : }
2634 : GByte *pabyWKB =
2635 5309 : static_cast<GByte *>(VSI_MALLOC_VERBOSE(nWKBLen));
2636 5309 : if (pabyWKB)
2637 : {
2638 5309 : poGeom->exportToWkb(wkbNDR, pabyWKB);
2639 5309 : rc = sqlite3_bind_blob(m_hStmtIn, nBindField++, pabyWKB,
2640 : static_cast<int>(nWKBLen), CPLFree);
2641 : }
2642 : else
2643 : {
2644 0 : return OGRERR_FAILURE;
2645 : }
2646 : }
2647 282 : else if (eGeomFormat == OSGF_SpatiaLite)
2648 : {
2649 282 : int nBLOBLen = 0;
2650 282 : GByte *pabySLBLOB = nullptr;
2651 :
2652 282 : const int nSRSId = poGeomFieldDefn->m_nSRSId;
2653 282 : CPL_IGNORE_RET_VAL(ExportSpatiaLiteGeometry(
2654 282 : poGeom, nSRSId, wkbNDR, m_bSpatialite2D, m_bUseComprGeom,
2655 : &pabySLBLOB, &nBLOBLen));
2656 282 : rc = sqlite3_bind_blob(m_hStmtIn, nBindField++, pabySLBLOB,
2657 : nBLOBLen, CPLFree);
2658 : }
2659 : else
2660 : {
2661 0 : rc = SQLITE_OK;
2662 0 : CPL_IGNORE_RET_VAL(rc);
2663 0 : CPLAssert(false);
2664 : }
2665 : }
2666 : else
2667 : {
2668 160 : rc = sqlite3_bind_null(m_hStmtIn, nBindField++);
2669 : }
2670 :
2671 5752 : if (rc != SQLITE_OK)
2672 : {
2673 0 : CPLError(CE_Failure, CPLE_AppDefined,
2674 : "sqlite3_bind_blob/text() failed:\n %s",
2675 : sqlite3_errmsg(hDB));
2676 0 : return OGRERR_FAILURE;
2677 : }
2678 : }
2679 :
2680 : /* -------------------------------------------------------------------- */
2681 : /* Bind field values. */
2682 : /* -------------------------------------------------------------------- */
2683 6561 : nFieldCount = m_poFeatureDefn->GetFieldCount();
2684 77101 : for (int iField = 0; iField < nFieldCount; iField++)
2685 : {
2686 70540 : if (iField == m_iFIDAsRegularColumnIndex)
2687 3 : continue;
2688 70537 : if (!bBindUnsetAsNull && !poFeature->IsFieldSet(iField))
2689 10 : continue;
2690 :
2691 70527 : int rc = SQLITE_OK;
2692 :
2693 132423 : if ((bBindUnsetAsNull && !poFeature->IsFieldSet(iField)) ||
2694 61896 : poFeature->IsFieldNull(iField))
2695 : {
2696 8685 : rc = sqlite3_bind_null(m_hStmtIn, nBindField++);
2697 : }
2698 : else
2699 : {
2700 : const OGRFieldDefn *poFieldDefn =
2701 61842 : m_poFeatureDefn->GetFieldDefnUnsafe(iField);
2702 61842 : switch (poFieldDefn->GetType())
2703 : {
2704 6982 : case OFTInteger:
2705 : {
2706 6982 : int nFieldVal = poFeature->GetFieldAsIntegerUnsafe(iField);
2707 6982 : rc = sqlite3_bind_int(m_hStmtIn, nBindField++, nFieldVal);
2708 6982 : break;
2709 : }
2710 :
2711 5223 : case OFTInteger64:
2712 : {
2713 : GIntBig nFieldVal =
2714 5223 : poFeature->GetFieldAsInteger64Unsafe(iField);
2715 5223 : rc = sqlite3_bind_int64(m_hStmtIn, nBindField++, nFieldVal);
2716 5223 : break;
2717 : }
2718 :
2719 5364 : case OFTReal:
2720 : {
2721 : double dfFieldVal =
2722 5364 : poFeature->GetFieldAsDoubleUnsafe(iField);
2723 5364 : rc = sqlite3_bind_double(m_hStmtIn, nBindField++,
2724 : dfFieldVal);
2725 5364 : break;
2726 : }
2727 :
2728 5008 : case OFTBinary:
2729 : {
2730 5008 : int nDataLength = 0;
2731 : GByte *pabyData =
2732 5008 : poFeature->GetFieldAsBinary(iField, &nDataLength);
2733 5008 : rc = sqlite3_bind_blob(m_hStmtIn, nBindField++, pabyData,
2734 : nDataLength, SQLITE_TRANSIENT);
2735 5008 : break;
2736 : }
2737 :
2738 5134 : case OFTDateTime:
2739 : {
2740 : char *pszStr =
2741 5134 : OGRGetXMLDateTime(poFeature->GetRawFieldRef(iField));
2742 5134 : rc = sqlite3_bind_text(m_hStmtIn, nBindField++, pszStr, -1,
2743 : SQLITE_TRANSIENT);
2744 5134 : CPLFree(pszStr);
2745 5134 : break;
2746 : }
2747 :
2748 5086 : case OFTDate:
2749 : {
2750 5086 : int nYear = 0;
2751 5086 : int nMonth = 0;
2752 5086 : int nDay = 0;
2753 5086 : int nHour = 0;
2754 5086 : int nMinute = 0;
2755 5086 : int nSecond = 0;
2756 5086 : int nTZ = 0;
2757 5086 : poFeature->GetFieldAsDateTime(iField, &nYear, &nMonth,
2758 : &nDay, &nHour, &nMinute,
2759 : &nSecond, &nTZ);
2760 : char szBuffer[64];
2761 5086 : snprintf(szBuffer, sizeof(szBuffer), "%04d-%02d-%02d",
2762 : nYear, nMonth, nDay);
2763 5086 : rc = sqlite3_bind_text(m_hStmtIn, nBindField++, szBuffer,
2764 : -1, SQLITE_TRANSIENT);
2765 5086 : break;
2766 : }
2767 :
2768 5004 : case OFTTime:
2769 : {
2770 5004 : int nYear = 0;
2771 5004 : int nMonth = 0;
2772 5004 : int nDay = 0;
2773 5004 : int nHour = 0;
2774 5004 : int nMinute = 0;
2775 5004 : int nTZ = 0;
2776 5004 : float fSecond = 0.0f;
2777 5004 : poFeature->GetFieldAsDateTime(iField, &nYear, &nMonth,
2778 : &nDay, &nHour, &nMinute,
2779 : &fSecond, &nTZ);
2780 : char szBuffer[64];
2781 5004 : if (OGR_GET_MS(fSecond) != 0)
2782 5000 : snprintf(szBuffer, sizeof(szBuffer), "%02d:%02d:%06.3f",
2783 : nHour, nMinute, fSecond);
2784 : else
2785 4 : snprintf(szBuffer, sizeof(szBuffer), "%02d:%02d:%02d",
2786 : nHour, nMinute, static_cast<int>(fSecond));
2787 5004 : rc = sqlite3_bind_text(m_hStmtIn, nBindField++, szBuffer,
2788 : -1, SQLITE_TRANSIENT);
2789 5004 : break;
2790 : }
2791 :
2792 15058 : case OFTStringList:
2793 : case OFTIntegerList:
2794 : case OFTInteger64List:
2795 : case OFTRealList:
2796 : {
2797 15058 : char *pszJSon = poFeature->GetFieldAsSerializedJSon(iField);
2798 15058 : rc = sqlite3_bind_text(m_hStmtIn, nBindField++, pszJSon, -1,
2799 : SQLITE_TRANSIENT);
2800 15058 : CPLFree(pszJSon);
2801 15058 : break;
2802 : }
2803 :
2804 8983 : default:
2805 : {
2806 : const char *pszRawValue =
2807 8983 : poFeature->GetFieldAsString(iField);
2808 17966 : std::string osValue(pszRawValue);
2809 :
2810 : // If the field subtype is JSON and the current value cannot
2811 : // be parsed as a valid JSON, encode it as a JSON string.
2812 17966 : if (poFieldDefn->GetType() == OFTString &&
2813 8983 : poFieldDefn->GetSubType() == OFSTJSON)
2814 : {
2815 5 : json_object *poObjProp = nullptr;
2816 5 : if (!OGRJSonParse(
2817 : osValue.c_str(), &poObjProp, false,
2818 5 : static_cast<int>(osValue.length() + 1)))
2819 : {
2820 : // Emit warning once
2821 1 : CPLErrorOnce(
2822 : CE_Warning, CPLE_AppDefined,
2823 : "Field %s is declared as JSON but the "
2824 : "value is not a valid JSON. Storing as "
2825 : "string.",
2826 : poFieldDefn->GetNameRef());
2827 : // Escape and quote
2828 : osValue =
2829 2 : CPLJSONObject(pszRawValue)
2830 1 : .Format(CPLJSONObject::PrettyFormat::Plain);
2831 : }
2832 : else
2833 : {
2834 4 : osValue = json_object_to_json_string(poObjProp);
2835 : }
2836 5 : json_object_put(poObjProp);
2837 : }
2838 :
2839 8983 : if (CSLFindString(m_papszCompressedColumns,
2840 8983 : m_poFeatureDefn->GetFieldDefn(iField)
2841 8983 : ->GetNameRef()) >= 0)
2842 : {
2843 17 : size_t nBytesOut = 0;
2844 17 : void *pOut = CPLZLibDeflate(osValue.c_str(),
2845 : strlen(osValue.c_str()), -1,
2846 : nullptr, 0, &nBytesOut);
2847 17 : if (pOut != nullptr)
2848 : {
2849 17 : rc = sqlite3_bind_blob(
2850 : m_hStmtIn, nBindField++, pOut,
2851 : static_cast<int>(nBytesOut), CPLFree);
2852 : }
2853 : else
2854 0 : rc = SQLITE_ERROR;
2855 : }
2856 : else
2857 : {
2858 8966 : rc = sqlite3_bind_text(m_hStmtIn, nBindField++,
2859 : osValue.c_str(), -1,
2860 : SQLITE_TRANSIENT);
2861 : }
2862 8983 : break;
2863 : }
2864 : }
2865 : }
2866 :
2867 70527 : if (rc != SQLITE_OK)
2868 : {
2869 0 : CPLError(CE_Failure, CPLE_AppDefined,
2870 : "sqlite3_bind_() for column %s failed:\n %s",
2871 0 : m_poFeatureDefn->GetFieldDefn(iField)->GetNameRef(),
2872 : sqlite3_errmsg(hDB));
2873 0 : return OGRERR_FAILURE;
2874 : }
2875 : }
2876 :
2877 6561 : return OGRERR_NONE;
2878 : }
2879 :
2880 : /************************************************************************/
2881 : /* ISetFeature() */
2882 : /************************************************************************/
2883 :
2884 32 : OGRErr OGRSQLiteTableLayer::ISetFeature(OGRFeature *poFeature)
2885 :
2886 : {
2887 32 : if (HasLayerDefnError())
2888 0 : return OGRERR_FAILURE;
2889 :
2890 32 : if (m_pszFIDColumn == nullptr)
2891 : {
2892 0 : CPLError(CE_Failure, CPLE_AppDefined,
2893 : "SetFeature() without any FID column.");
2894 0 : return OGRERR_FAILURE;
2895 : }
2896 :
2897 32 : if (poFeature->GetFID() == OGRNullFID)
2898 : {
2899 0 : CPLError(CE_Failure, CPLE_AppDefined,
2900 : "SetFeature() with unset FID fails.");
2901 0 : return OGRERR_FAILURE;
2902 : }
2903 :
2904 32 : if (!m_poDS->GetUpdate())
2905 : {
2906 0 : CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
2907 : "SetFeature");
2908 0 : return OGRERR_FAILURE;
2909 : }
2910 :
2911 : /* In case the FID column has also been created as a regular field */
2912 32 : if (m_iFIDAsRegularColumnIndex >= 0)
2913 : {
2914 5 : if (!poFeature->IsFieldSetAndNotNull(m_iFIDAsRegularColumnIndex) ||
2915 2 : poFeature->GetFieldAsInteger64(m_iFIDAsRegularColumnIndex) !=
2916 2 : poFeature->GetFID())
2917 : {
2918 2 : CPLError(CE_Failure, CPLE_AppDefined,
2919 : "Inconsistent values of FID and field of same name");
2920 2 : return OGRERR_FAILURE;
2921 : }
2922 : }
2923 :
2924 30 : if (m_bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE)
2925 0 : return OGRERR_FAILURE;
2926 :
2927 30 : sqlite3 *hDB = m_poDS->GetDB();
2928 30 : int bNeedComma = false;
2929 :
2930 : /* -------------------------------------------------------------------- */
2931 : /* Form the UPDATE command. */
2932 : /* -------------------------------------------------------------------- */
2933 60 : CPLString osCommand = CPLSPrintf("UPDATE '%s' SET ", m_pszEscapedTableName);
2934 :
2935 : /* -------------------------------------------------------------------- */
2936 : /* Add geometry field name. */
2937 : /* -------------------------------------------------------------------- */
2938 30 : int nFieldCount = m_poFeatureDefn->GetGeomFieldCount();
2939 60 : for (int iField = 0; iField < nFieldCount; iField++)
2940 : {
2941 : OGRSQLiteGeomFormat eGeomFormat =
2942 30 : m_poFeatureDefn->myGetGeomFieldDefn(iField)->m_eGeomFormat;
2943 30 : if (eGeomFormat == OSGF_FGF)
2944 0 : continue;
2945 30 : if (bNeedComma)
2946 1 : osCommand += ",";
2947 :
2948 30 : osCommand += "\"";
2949 60 : osCommand += SQLEscapeName(
2950 60 : m_poFeatureDefn->GetGeomFieldDefn(iField)->GetNameRef());
2951 30 : osCommand += "\" = ?";
2952 :
2953 30 : bNeedComma = true;
2954 : }
2955 :
2956 : /* -------------------------------------------------------------------- */
2957 : /* Add field names. */
2958 : /* -------------------------------------------------------------------- */
2959 30 : nFieldCount = m_poFeatureDefn->GetFieldCount();
2960 123 : for (int iField = 0; iField < nFieldCount; iField++)
2961 : {
2962 93 : if (iField == m_iFIDAsRegularColumnIndex)
2963 1 : continue;
2964 92 : if (!poFeature->IsFieldSet(iField))
2965 0 : continue;
2966 92 : if (bNeedComma)
2967 91 : osCommand += ",";
2968 :
2969 92 : osCommand += "\"";
2970 : osCommand +=
2971 92 : SQLEscapeName(m_poFeatureDefn->GetFieldDefn(iField)->GetNameRef());
2972 92 : osCommand += "\" = ?";
2973 :
2974 92 : bNeedComma = true;
2975 : }
2976 :
2977 30 : if (!bNeedComma)
2978 0 : return OGRERR_NONE;
2979 :
2980 : /* -------------------------------------------------------------------- */
2981 : /* Merge final command. */
2982 : /* -------------------------------------------------------------------- */
2983 30 : osCommand += " WHERE \"";
2984 30 : osCommand += SQLEscapeName(m_pszFIDColumn);
2985 30 : osCommand += CPLSPrintf("\" = " CPL_FRMT_GIB, poFeature->GetFID());
2986 :
2987 : /* -------------------------------------------------------------------- */
2988 : /* Prepare the statement. */
2989 : /* -------------------------------------------------------------------- */
2990 : #ifdef DEBUG_VERBOSE
2991 : CPLDebug("OGR_SQLITE", "prepare_v2(%s)", osCommand.c_str());
2992 : #endif
2993 :
2994 30 : sqlite3_stmt *hUpdateStmt = nullptr;
2995 30 : int rc = sqlite3_prepare_v2(hDB, osCommand, -1, &hUpdateStmt, nullptr);
2996 :
2997 30 : if (rc != SQLITE_OK)
2998 : {
2999 0 : CPLError(CE_Failure, CPLE_AppDefined,
3000 : "In SetFeature(): sqlite3_prepare_v2(%s):\n %s",
3001 : osCommand.c_str(), sqlite3_errmsg(hDB));
3002 :
3003 0 : return OGRERR_FAILURE;
3004 : }
3005 :
3006 : /* -------------------------------------------------------------------- */
3007 : /* Bind values. */
3008 : /* -------------------------------------------------------------------- */
3009 30 : OGRErr eErr = BindValues(poFeature, hUpdateStmt, false);
3010 30 : if (eErr != OGRERR_NONE)
3011 : {
3012 0 : sqlite3_finalize(hUpdateStmt);
3013 0 : return eErr;
3014 : }
3015 :
3016 : /* -------------------------------------------------------------------- */
3017 : /* Execute the update. */
3018 : /* -------------------------------------------------------------------- */
3019 30 : rc = sqlite3_step(hUpdateStmt);
3020 :
3021 30 : if (rc != SQLITE_OK && rc != SQLITE_DONE)
3022 : {
3023 0 : CPLError(CE_Failure, CPLE_AppDefined, "sqlite3_step() failed:\n %s",
3024 : sqlite3_errmsg(hDB));
3025 :
3026 0 : sqlite3_finalize(hUpdateStmt);
3027 0 : return OGRERR_FAILURE;
3028 : }
3029 :
3030 30 : sqlite3_finalize(hUpdateStmt);
3031 :
3032 30 : eErr =
3033 30 : (sqlite3_changes(hDB) > 0) ? OGRERR_NONE : OGRERR_NON_EXISTING_FEATURE;
3034 30 : if (eErr == OGRERR_NONE)
3035 : {
3036 26 : nFieldCount = m_poFeatureDefn->GetGeomFieldCount();
3037 52 : for (int iField = 0; iField < nFieldCount; iField++)
3038 : {
3039 : OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
3040 26 : m_poFeatureDefn->myGetGeomFieldDefn(iField);
3041 26 : OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iField);
3042 30 : if (poGeomFieldDefn->m_bCachedExtentIsValid && poGeom != nullptr &&
3043 4 : !poGeom->IsEmpty())
3044 : {
3045 4 : OGREnvelope sGeomEnvelope;
3046 4 : poGeom->getEnvelope(&sGeomEnvelope);
3047 4 : poGeomFieldDefn->m_oCachedExtent.Merge(sGeomEnvelope);
3048 : }
3049 : }
3050 26 : ForceStatisticsToBeFlushed();
3051 : }
3052 :
3053 30 : return eErr;
3054 : }
3055 :
3056 : /************************************************************************/
3057 : /* AreTriggersSimilar */
3058 : /************************************************************************/
3059 :
3060 286 : static int AreTriggersSimilar(const char *pszExpectedTrigger,
3061 : const char *pszTriggerSQL)
3062 : {
3063 286 : int i = 0; // Used after for.
3064 96180 : for (; pszTriggerSQL[i] != '\0' && pszExpectedTrigger[i] != '\0'; i++)
3065 : {
3066 95894 : if (pszTriggerSQL[i] == pszExpectedTrigger[i])
3067 94464 : continue;
3068 1430 : if (pszTriggerSQL[i] == '\n' && pszExpectedTrigger[i] == ' ')
3069 1430 : continue;
3070 0 : if (pszTriggerSQL[i] == ' ' && pszExpectedTrigger[i] == '\n')
3071 0 : continue;
3072 0 : return FALSE;
3073 : }
3074 286 : return pszTriggerSQL[i] == '\0' && pszExpectedTrigger[i] == '\0';
3075 : }
3076 :
3077 : /************************************************************************/
3078 : /* ICreateFeature() */
3079 : /************************************************************************/
3080 :
3081 6546 : OGRErr OGRSQLiteTableLayer::ICreateFeature(OGRFeature *poFeature)
3082 :
3083 : {
3084 6546 : sqlite3 *hDB = m_poDS->GetDB();
3085 13092 : CPLString osCommand;
3086 6546 : bool bNeedComma = false;
3087 :
3088 6546 : if (HasLayerDefnError())
3089 0 : return OGRERR_FAILURE;
3090 :
3091 6546 : if (!m_poDS->GetUpdate())
3092 : {
3093 0 : CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
3094 : "CreateFeature");
3095 0 : return OGRERR_FAILURE;
3096 : }
3097 :
3098 6546 : if (m_bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE)
3099 0 : return OGRERR_FAILURE;
3100 :
3101 : // For speed-up, disable Spatialite triggers that :
3102 : // * check the geometry type
3103 : // * update the last_insert columns in geometry_columns_time and the spatial
3104 : // index We do that only if there's no spatial index currently active We'll
3105 : // check ourselves the first constraint and update last_insert at layer
3106 : // closing
3107 6696 : if (!m_bHasCheckedTriggers && m_poDS->HasSpatialite4Layout() &&
3108 150 : m_poFeatureDefn->GetGeomFieldCount() > 0)
3109 : {
3110 144 : m_bHasCheckedTriggers = true;
3111 :
3112 144 : char *pszErrMsg = nullptr;
3113 :
3114 : // Backup INSERT ON triggers
3115 144 : int nRowCount = 0, nColCount = 0;
3116 144 : char **papszResult = nullptr;
3117 : char *pszSQL3 =
3118 144 : sqlite3_mprintf("SELECT name, sql FROM sqlite_master WHERE "
3119 : "tbl_name = '%q' AND type = 'trigger' AND (name "
3120 : "LIKE 'ggi_%%' OR name LIKE 'tmi_%%')",
3121 : m_pszTableName);
3122 144 : sqlite3_get_table(m_poDS->GetDB(), pszSQL3, &papszResult, &nRowCount,
3123 : &nColCount, &pszErrMsg);
3124 144 : sqlite3_free(pszSQL3);
3125 :
3126 144 : if (pszErrMsg)
3127 0 : sqlite3_free(pszErrMsg);
3128 144 : pszErrMsg = nullptr;
3129 :
3130 290 : for (int j = 0; j < m_poFeatureDefn->GetGeomFieldCount(); j++)
3131 : {
3132 : OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
3133 146 : m_poFeatureDefn->myGetGeomFieldDefn(j);
3134 146 : if (!((m_bDeferredSpatialIndexCreation ||
3135 3 : !poGeomFieldDefn->m_bHasSpatialIndex)))
3136 3 : continue;
3137 143 : const char *pszGeomCol = poGeomFieldDefn->GetNameRef();
3138 :
3139 437 : for (int i = 0; i < nRowCount; i++)
3140 : {
3141 294 : const char *pszTriggerName = papszResult[2 * (i + 1) + 0];
3142 294 : const char *pszTriggerSQL = papszResult[2 * (i + 1) + 1];
3143 588 : if (pszTriggerName != nullptr && pszTriggerSQL != nullptr &&
3144 588 : CPLString(pszTriggerName)
3145 294 : .tolower()
3146 588 : .find(CPLString(pszGeomCol).tolower()) !=
3147 : std::string::npos)
3148 : {
3149 286 : const char *pszExpectedTrigger = nullptr;
3150 286 : if (STARTS_WITH(pszTriggerName, "ggi_"))
3151 : {
3152 143 : pszExpectedTrigger = CPLSPrintf(
3153 : "CREATE TRIGGER \"ggi_%s_%s\" BEFORE INSERT ON "
3154 : "\"%s\" "
3155 : "FOR EACH ROW BEGIN "
3156 : "SELECT RAISE(ROLLBACK, '%s.%s violates Geometry "
3157 : "constraint [geom-type or SRID not allowed]') "
3158 : "WHERE (SELECT geometry_type FROM geometry_columns "
3159 : "WHERE Lower(f_table_name) = Lower('%s') AND "
3160 : "Lower(f_geometry_column) = Lower('%s') "
3161 : "AND GeometryConstraints(NEW.\"%s\", "
3162 : "geometry_type, srid) = 1) IS NULL; "
3163 : "END",
3164 : m_pszTableName, pszGeomCol, m_pszTableName,
3165 : m_pszTableName, pszGeomCol, m_pszTableName,
3166 : pszGeomCol, pszGeomCol);
3167 : }
3168 143 : else if (STARTS_WITH(pszTriggerName, "tmi_"))
3169 : {
3170 143 : pszExpectedTrigger = CPLSPrintf(
3171 : "CREATE TRIGGER \"tmi_%s_%s\" AFTER INSERT ON "
3172 : "\"%s\" "
3173 : "FOR EACH ROW BEGIN "
3174 : "UPDATE geometry_columns_time SET last_insert = "
3175 : "strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
3176 : "WHERE Lower(f_table_name) = Lower('%s') AND "
3177 : "Lower(f_geometry_column) = Lower('%s'); "
3178 : "END",
3179 : m_pszTableName, pszGeomCol, m_pszTableName,
3180 : m_pszTableName, pszGeomCol);
3181 : }
3182 : /* Cannot happen due to the tests that lead to that code
3183 : * path */
3184 : /* that check there's no spatial index active */
3185 : /* A further potential optimization would be to rebuild the
3186 : * spatial index */
3187 : /* afterwards... */
3188 : /*else if( STARTS_WITH(pszTriggerName, "gii_") )
3189 : {
3190 : pszExpectedTrigger = CPLSPrintf(
3191 : "CREATE TRIGGER \"gii_%s_%s\" AFTER INSERT ON \"%s\" "
3192 : "FOR EACH ROW BEGIN "
3193 : "UPDATE geometry_columns_time SET last_insert =
3194 : strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') " "WHERE
3195 : Lower(f_table_name) = Lower('%s') AND
3196 : Lower(f_geometry_column) = Lower('%s'); " "DELETE FROM
3197 : \"idx_%s_%s\" WHERE pkid=NEW.ROWID; " "SELECT
3198 : RTreeAlign('idx_%s_%s', NEW.ROWID, NEW.\"%s\"); " "END",
3199 : m_pszTableName, pszGeomCol, m_pszTableName,
3200 : m_pszTableName, pszGeomCol,
3201 : m_pszTableName, pszGeomCol,
3202 : m_pszTableName, pszGeomCol, pszGeomCol);
3203 : }*/
3204 :
3205 572 : if (pszExpectedTrigger != nullptr &&
3206 286 : AreTriggersSimilar(pszExpectedTrigger, pszTriggerSQL))
3207 : {
3208 : // And drop them
3209 : pszSQL3 =
3210 286 : sqlite3_mprintf("DROP TRIGGER %s", pszTriggerName);
3211 286 : int rc = sqlite3_exec(m_poDS->GetDB(), pszSQL3, nullptr,
3212 : nullptr, &pszErrMsg);
3213 286 : if (rc != SQLITE_OK)
3214 0 : CPLDebug("SQLITE", "Error %s",
3215 0 : pszErrMsg ? pszErrMsg : "");
3216 : else
3217 : {
3218 286 : CPLDebug("SQLite", "Dropping trigger %s",
3219 : pszTriggerName);
3220 286 : poGeomFieldDefn->m_aosDisabledTriggers.push_back(
3221 572 : std::pair<CPLString, CPLString>(pszTriggerName,
3222 : pszTriggerSQL));
3223 : }
3224 286 : sqlite3_free(pszSQL3);
3225 286 : if (pszErrMsg)
3226 0 : sqlite3_free(pszErrMsg);
3227 286 : pszErrMsg = nullptr;
3228 : }
3229 : else
3230 : {
3231 0 : CPLDebug("SQLite",
3232 : "Cannot drop %s trigger. Doesn't match "
3233 : "expected definition",
3234 : pszTriggerName);
3235 : }
3236 : }
3237 : }
3238 : }
3239 :
3240 144 : sqlite3_free_table(papszResult);
3241 : }
3242 :
3243 6546 : ResetReading();
3244 :
3245 12268 : for (int j = 0; j < m_poFeatureDefn->GetGeomFieldCount(); j++)
3246 : {
3247 : OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
3248 5736 : m_poFeatureDefn->myGetGeomFieldDefn(j);
3249 5736 : OGRGeometry *poGeom = poFeature->GetGeomFieldRef(j);
3250 5736 : if (!poGeomFieldDefn->m_aosDisabledTriggers.empty() &&
3251 : poGeom != nullptr)
3252 : {
3253 261 : OGRwkbGeometryType eGeomType = poGeomFieldDefn->GetType();
3254 411 : if (eGeomType != wkbUnknown &&
3255 150 : poGeom->getGeometryType() != eGeomType)
3256 : {
3257 42 : CPLError(CE_Failure, CPLE_AppDefined,
3258 : "Cannot insert feature with geometry of type %s%s in "
3259 : "column %s. Type %s%s expected",
3260 14 : OGRToOGCGeomType(poGeom->getGeometryType()),
3261 14 : (wkbFlatten(poGeom->getGeometryType()) !=
3262 14 : poGeom->getGeometryType())
3263 : ? "Z"
3264 : : "",
3265 : poGeomFieldDefn->GetNameRef(),
3266 : OGRToOGCGeomType(eGeomType),
3267 14 : (wkbFlatten(eGeomType) != eGeomType) ? "Z" : "");
3268 14 : return OGRERR_FAILURE;
3269 : }
3270 : }
3271 : }
3272 :
3273 6532 : int bReuseStmt = false;
3274 :
3275 : /* If there's a unset field with a default value, then we must create */
3276 : /* a specific INSERT statement to avoid unset fields to be bound to NULL */
3277 6532 : bool bHasDefaultValue = false;
3278 6532 : int nFieldCount = m_poFeatureDefn->GetFieldCount();
3279 76972 : for (int iField = 0; iField < nFieldCount; iField++)
3280 : {
3281 79076 : if (!poFeature->IsFieldSet(iField) &&
3282 8635 : poFeature->GetFieldDefnRef(iField)->GetDefault() != nullptr)
3283 : {
3284 1 : bHasDefaultValue = true;
3285 1 : break;
3286 : }
3287 : }
3288 :
3289 : /* In case the FID column has also been created as a regular field */
3290 6532 : if (m_iFIDAsRegularColumnIndex >= 0)
3291 : {
3292 3 : if (poFeature->GetFID() == OGRNullFID)
3293 : {
3294 2 : if (poFeature->IsFieldSetAndNotNull(m_iFIDAsRegularColumnIndex))
3295 : {
3296 1 : poFeature->SetFID(
3297 1 : poFeature->GetFieldAsInteger64(m_iFIDAsRegularColumnIndex));
3298 : }
3299 : }
3300 : else
3301 : {
3302 2 : if (!poFeature->IsFieldSetAndNotNull(m_iFIDAsRegularColumnIndex) ||
3303 1 : poFeature->GetFieldAsInteger64(m_iFIDAsRegularColumnIndex) !=
3304 1 : poFeature->GetFID())
3305 : {
3306 1 : CPLError(CE_Failure, CPLE_AppDefined,
3307 : "Inconsistent values of FID and field of same name");
3308 1 : return OGRERR_FAILURE;
3309 : }
3310 : }
3311 : }
3312 :
3313 : int bTemporaryStatement =
3314 6531 : (poFeature->GetFID() != OGRNullFID || bHasDefaultValue);
3315 6531 : if (m_hInsertStmt == nullptr || bTemporaryStatement)
3316 : {
3317 10872 : CPLString osValues;
3318 :
3319 : /* --------------------------------------------------------------------
3320 : */
3321 : /* Form the INSERT command. */
3322 : /* --------------------------------------------------------------------
3323 : */
3324 5436 : osCommand += CPLSPrintf("INSERT INTO '%s' (", m_pszEscapedTableName);
3325 :
3326 : /* --------------------------------------------------------------------
3327 : */
3328 : /* Add FID if we have a cleartext FID column. */
3329 : /* --------------------------------------------------------------------
3330 : */
3331 5436 : if (m_pszFIDColumn != nullptr && poFeature->GetFID() != OGRNullFID)
3332 : {
3333 5039 : osCommand += "\"";
3334 5039 : osCommand += SQLEscapeName(m_pszFIDColumn);
3335 5039 : osCommand += "\"";
3336 :
3337 5039 : osValues += CPLSPrintf(CPL_FRMT_GIB, poFeature->GetFID());
3338 5039 : bNeedComma = true;
3339 : }
3340 :
3341 : /* --------------------------------------------------------------------
3342 : */
3343 : /* Add geometry. */
3344 : /* --------------------------------------------------------------------
3345 : */
3346 5436 : nFieldCount = m_poFeatureDefn->GetGeomFieldCount();
3347 10764 : for (int iField = 0; iField < nFieldCount; iField++)
3348 : {
3349 : OGRSQLiteGeomFormat eGeomFormat =
3350 5328 : m_poFeatureDefn->myGetGeomFieldDefn(iField)->m_eGeomFormat;
3351 5328 : if (eGeomFormat == OSGF_FGF)
3352 0 : continue;
3353 5328 : if (bHasDefaultValue &&
3354 0 : poFeature->GetGeomFieldRef(iField) == nullptr)
3355 0 : continue;
3356 5328 : if (bNeedComma)
3357 : {
3358 5048 : osCommand += ",";
3359 5048 : osValues += ",";
3360 : }
3361 :
3362 5328 : osCommand += "\"";
3363 10656 : osCommand += SQLEscapeName(
3364 10656 : m_poFeatureDefn->GetGeomFieldDefn(iField)->GetNameRef());
3365 5328 : osCommand += "\"";
3366 :
3367 5328 : osValues += "?";
3368 :
3369 5328 : bNeedComma = true;
3370 : }
3371 :
3372 : /* --------------------------------------------------------------------
3373 : */
3374 : /* Add field values. */
3375 : /* --------------------------------------------------------------------
3376 : */
3377 5436 : nFieldCount = m_poFeatureDefn->GetFieldCount();
3378 66837 : for (int iField = 0; iField < nFieldCount; iField++)
3379 : {
3380 61401 : if (iField == m_iFIDAsRegularColumnIndex)
3381 2 : continue;
3382 61399 : if (bHasDefaultValue && !poFeature->IsFieldSet(iField))
3383 10 : continue;
3384 :
3385 61389 : if (bNeedComma)
3386 : {
3387 61274 : osCommand += ",";
3388 61274 : osValues += ",";
3389 : }
3390 :
3391 61389 : osCommand += "\"";
3392 122778 : osCommand += SQLEscapeName(
3393 122778 : m_poFeatureDefn->GetFieldDefn(iField)->GetNameRef());
3394 61389 : osCommand += "\"";
3395 :
3396 61389 : osValues += "?";
3397 :
3398 61389 : bNeedComma = true;
3399 : }
3400 :
3401 : /* --------------------------------------------------------------------
3402 : */
3403 : /* Merge final command. */
3404 : /* --------------------------------------------------------------------
3405 : */
3406 5436 : osCommand += ") VALUES (";
3407 5436 : osCommand += osValues;
3408 5436 : osCommand += ")";
3409 :
3410 5436 : if (bNeedComma == false)
3411 : osCommand = CPLSPrintf("INSERT INTO '%s' DEFAULT VALUES",
3412 5438 : m_pszEscapedTableName);
3413 : }
3414 : else
3415 : {
3416 1095 : bReuseStmt = true;
3417 : }
3418 :
3419 : /* -------------------------------------------------------------------- */
3420 : /* Prepare the statement. */
3421 : /* -------------------------------------------------------------------- */
3422 11967 : if (!bReuseStmt &&
3423 5436 : (m_hInsertStmt == nullptr || osCommand != m_osLastInsertStmt))
3424 : {
3425 : #ifdef DEBUG
3426 5436 : CPLDebug("OGR_SQLITE", "prepare_v2(%s)", osCommand.c_str());
3427 : #endif
3428 :
3429 5436 : ClearInsertStmt();
3430 5436 : if (poFeature->GetFID() == OGRNullFID)
3431 397 : m_osLastInsertStmt = osCommand;
3432 :
3433 : const int rc =
3434 5436 : sqlite3_prepare_v2(hDB, osCommand, -1, &m_hInsertStmt, nullptr);
3435 5436 : if (rc != SQLITE_OK)
3436 : {
3437 0 : CPLError(CE_Failure, CPLE_AppDefined,
3438 : "In CreateFeature(): sqlite3_prepare_v2(%s):\n %s",
3439 : osCommand.c_str(), sqlite3_errmsg(hDB));
3440 :
3441 0 : ClearInsertStmt();
3442 0 : return OGRERR_FAILURE;
3443 : }
3444 : }
3445 :
3446 : /* -------------------------------------------------------------------- */
3447 : /* Bind values. */
3448 : /* -------------------------------------------------------------------- */
3449 6531 : OGRErr eErr = BindValues(poFeature, m_hInsertStmt, !bHasDefaultValue);
3450 6531 : if (eErr != OGRERR_NONE)
3451 : {
3452 0 : sqlite3_reset(m_hInsertStmt);
3453 0 : return eErr;
3454 : }
3455 :
3456 : /* -------------------------------------------------------------------- */
3457 : /* Execute the insert. */
3458 : /* -------------------------------------------------------------------- */
3459 6531 : const int rc = sqlite3_step(m_hInsertStmt);
3460 :
3461 6531 : if (rc != SQLITE_OK && rc != SQLITE_DONE)
3462 : {
3463 3 : CPLError(CE_Failure, CPLE_AppDefined,
3464 : "sqlite3_step() failed:\n %s (%d)", sqlite3_errmsg(hDB), rc);
3465 3 : sqlite3_reset(m_hInsertStmt);
3466 3 : ClearInsertStmt();
3467 3 : return OGRERR_FAILURE;
3468 : }
3469 :
3470 : /* -------------------------------------------------------------------- */
3471 : /* Capture the FID/rowid. */
3472 : /* -------------------------------------------------------------------- */
3473 6528 : const sqlite_int64 nFID = sqlite3_last_insert_rowid(hDB);
3474 6528 : if (nFID > 0)
3475 : {
3476 6524 : poFeature->SetFID(nFID);
3477 6524 : if (m_iFIDAsRegularColumnIndex >= 0)
3478 2 : poFeature->SetField(m_iFIDAsRegularColumnIndex, nFID);
3479 : }
3480 :
3481 6528 : sqlite3_reset(m_hInsertStmt);
3482 :
3483 6528 : if (bTemporaryStatement)
3484 5039 : ClearInsertStmt();
3485 :
3486 6528 : nFieldCount = m_poFeatureDefn->GetGeomFieldCount();
3487 12245 : for (int iField = 0; iField < nFieldCount; iField++)
3488 : {
3489 : OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
3490 5717 : m_poFeatureDefn->myGetGeomFieldDefn(iField);
3491 5717 : OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iField);
3492 :
3493 5717 : if ((poGeomFieldDefn->m_bCachedExtentIsValid || m_nFeatureCount == 0) &&
3494 11434 : poGeom != nullptr && !poGeom->IsEmpty())
3495 : {
3496 5496 : OGREnvelope sGeomEnvelope;
3497 5496 : poGeom->getEnvelope(&sGeomEnvelope);
3498 5496 : poGeomFieldDefn->m_oCachedExtent.Merge(sGeomEnvelope);
3499 5496 : poGeomFieldDefn->m_bCachedExtentIsValid = true;
3500 5496 : ForceStatisticsToBeFlushed();
3501 : }
3502 : }
3503 :
3504 6528 : if (m_nFeatureCount >= 0)
3505 : {
3506 6500 : ForceStatisticsToBeFlushed();
3507 6500 : m_nFeatureCount++;
3508 : }
3509 :
3510 6528 : return OGRERR_NONE;
3511 : }
3512 :
3513 : /************************************************************************/
3514 : /* DeleteFeature() */
3515 : /************************************************************************/
3516 :
3517 13 : OGRErr OGRSQLiteTableLayer::DeleteFeature(GIntBig nFID)
3518 :
3519 : {
3520 26 : CPLString osSQL;
3521 :
3522 13 : if (HasLayerDefnError())
3523 0 : return OGRERR_FAILURE;
3524 :
3525 13 : if (m_pszFIDColumn == nullptr)
3526 : {
3527 0 : CPLError(CE_Failure, CPLE_NotSupported,
3528 : "Can't delete feature on a layer without FID column.");
3529 0 : return OGRERR_FAILURE;
3530 : }
3531 :
3532 13 : if (!m_poDS->GetUpdate())
3533 : {
3534 0 : CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
3535 : "DeleteFeature");
3536 0 : return OGRERR_FAILURE;
3537 : }
3538 :
3539 13 : if (m_bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE)
3540 0 : return OGRERR_FAILURE;
3541 :
3542 13 : ResetReading();
3543 :
3544 : osSQL.Printf("DELETE FROM '%s' WHERE \"%s\" = " CPL_FRMT_GIB,
3545 26 : m_pszEscapedTableName, SQLEscapeName(m_pszFIDColumn).c_str(),
3546 13 : nFID);
3547 :
3548 13 : CPLDebug("OGR_SQLITE", "exec(%s)", osSQL.c_str());
3549 :
3550 13 : if (SQLCommand(m_poDS->GetDB(), osSQL) != OGRERR_NONE)
3551 0 : return OGRERR_FAILURE;
3552 :
3553 13 : OGRErr eErr = (sqlite3_changes(m_poDS->GetDB()) > 0)
3554 13 : ? OGRERR_NONE
3555 13 : : OGRERR_NON_EXISTING_FEATURE;
3556 13 : if (eErr == OGRERR_NONE)
3557 : {
3558 6 : int nFieldCount = m_poFeatureDefn->GetGeomFieldCount();
3559 12 : for (int iField = 0; iField < nFieldCount; iField++)
3560 : {
3561 : OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
3562 6 : m_poFeatureDefn->myGetGeomFieldDefn(iField);
3563 6 : poGeomFieldDefn->m_bCachedExtentIsValid = false;
3564 : }
3565 6 : m_nFeatureCount--;
3566 6 : ForceStatisticsToBeFlushed();
3567 : }
3568 :
3569 13 : return eErr;
3570 : }
3571 :
3572 : /************************************************************************/
3573 : /* CreateSpatialIndex() */
3574 : /************************************************************************/
3575 :
3576 137 : int OGRSQLiteTableLayer::CreateSpatialIndex(int iGeomCol)
3577 : {
3578 274 : CPLString osCommand;
3579 :
3580 137 : if (m_bDeferredCreation)
3581 0 : RunDeferredCreationIfNecessary();
3582 :
3583 137 : if (iGeomCol < 0 || iGeomCol >= m_poFeatureDefn->GetGeomFieldCount())
3584 0 : return FALSE;
3585 :
3586 : osCommand.Printf(
3587 : "SELECT CreateSpatialIndex('%s', '%s')", m_pszEscapedTableName,
3588 274 : SQLEscapeLiteral(
3589 137 : m_poFeatureDefn->GetGeomFieldDefn(iGeomCol)->GetNameRef())
3590 137 : .c_str());
3591 :
3592 137 : char *pszErrMsg = nullptr;
3593 137 : sqlite3 *hDB = m_poDS->GetDB();
3594 : #ifdef DEBUG
3595 137 : CPLDebug("OGR_SQLITE", "exec(%s)", osCommand.c_str());
3596 : #endif
3597 137 : int rc = sqlite3_exec(hDB, osCommand, nullptr, nullptr, &pszErrMsg);
3598 137 : if (rc != SQLITE_OK)
3599 : {
3600 0 : CPLError(CE_Failure, CPLE_AppDefined,
3601 : "Unable to create spatial index:\n%s", pszErrMsg);
3602 0 : sqlite3_free(pszErrMsg);
3603 0 : return FALSE;
3604 : }
3605 :
3606 137 : m_poFeatureDefn->myGetGeomFieldDefn(iGeomCol)->m_bHasSpatialIndex = true;
3607 137 : return TRUE;
3608 : }
3609 :
3610 : /************************************************************************/
3611 : /* RunDeferredCreationIfNecessary() */
3612 : /************************************************************************/
3613 :
3614 11325 : OGRErr OGRSQLiteTableLayer::RunDeferredCreationIfNecessary()
3615 : {
3616 11325 : if (!m_bDeferredCreation)
3617 10881 : return OGRERR_NONE;
3618 444 : m_bDeferredCreation = false;
3619 :
3620 888 : CPLString osCommand;
3621 :
3622 : osCommand.Printf(
3623 : "CREATE TABLE '%s' ( \"%s\" INTEGER PRIMARY KEY AUTOINCREMENT",
3624 444 : m_pszEscapedTableName, SQLEscapeName(m_pszFIDColumn).c_str());
3625 :
3626 444 : if (!m_poDS->IsSpatialiteDB())
3627 : {
3628 475 : for (int i = 0; i < m_poFeatureDefn->GetGeomFieldCount(); i++)
3629 : {
3630 : OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
3631 184 : m_poFeatureDefn->myGetGeomFieldDefn(i);
3632 :
3633 184 : if (poGeomFieldDefn->m_eGeomFormat == OSGF_WKT)
3634 : {
3635 : osCommand += CPLSPrintf(
3636 : ", '%s' VARCHAR",
3637 1 : SQLEscapeLiteral(poGeomFieldDefn->GetNameRef()).c_str());
3638 : }
3639 : else
3640 : {
3641 : osCommand += CPLSPrintf(
3642 : ", '%s' BLOB",
3643 183 : SQLEscapeLiteral(poGeomFieldDefn->GetNameRef()).c_str());
3644 : }
3645 184 : if (!poGeomFieldDefn->IsNullable())
3646 : {
3647 1 : osCommand += " NOT NULL";
3648 : }
3649 : }
3650 : }
3651 :
3652 1678 : for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); i++)
3653 : {
3654 1234 : OGRFieldDefn *poFieldDefn = m_poFeatureDefn->GetFieldDefn(i);
3655 1234 : if (i == m_iFIDAsRegularColumnIndex)
3656 1 : continue;
3657 2466 : CPLString osFieldType(FieldDefnToSQliteFieldDefn(poFieldDefn));
3658 : osCommand += CPLSPrintf(
3659 2466 : ", '%s' %s", SQLEscapeLiteral(poFieldDefn->GetNameRef()).c_str(),
3660 2466 : osFieldType.c_str());
3661 1233 : if (!poFieldDefn->IsNullable())
3662 : {
3663 302 : osCommand += " NOT NULL";
3664 : }
3665 1233 : if (poFieldDefn->IsUnique())
3666 : {
3667 3 : osCommand += " UNIQUE";
3668 : }
3669 1233 : const char *pszDefault = poFieldDefn->GetDefault();
3670 1254 : if (pszDefault != nullptr &&
3671 21 : (!poFieldDefn->IsDefaultDriverSpecific() ||
3672 1 : (pszDefault[0] == '(' &&
3673 1 : pszDefault[strlen(pszDefault) - 1] == ')' &&
3674 1 : (STARTS_WITH_CI(pszDefault + 1, "strftime") ||
3675 0 : STARTS_WITH_CI(pszDefault + 1, " strftime")))))
3676 : {
3677 21 : osCommand += " DEFAULT ";
3678 21 : osCommand += poFieldDefn->GetDefault();
3679 : }
3680 : }
3681 444 : osCommand += ")";
3682 444 : if (m_bStrict)
3683 1 : osCommand += " STRICT";
3684 :
3685 : #ifdef DEBUG
3686 444 : CPLDebug("OGR_SQLITE", "exec(%s)", osCommand.c_str());
3687 : #endif
3688 :
3689 444 : if (SQLCommand(m_poDS->GetDB(), osCommand) != OGRERR_NONE)
3690 0 : return OGRERR_FAILURE;
3691 :
3692 : /* -------------------------------------------------------------------- */
3693 : /* Eventually we should be adding this table to a table of */
3694 : /* "geometric layers", capturing the WKT projection, and */
3695 : /* perhaps some other housekeeping. */
3696 : /* -------------------------------------------------------------------- */
3697 444 : if (m_poDS->HasGeometryColumns())
3698 : {
3699 : /* Sometimes there is an old cruft entry in the geometry_columns
3700 : * table if things were not properly cleaned up before. We make
3701 : * an effort to clean out such cruft.
3702 : */
3703 : osCommand.Printf(
3704 : "DELETE FROM geometry_columns WHERE f_table_name = '%s'",
3705 435 : m_pszEscapedTableName);
3706 :
3707 : #ifdef DEBUG
3708 435 : CPLDebug("OGR_SQLITE", "exec(%s)", osCommand.c_str());
3709 : #endif
3710 435 : if (SQLCommand(m_poDS->GetDB(), osCommand) != OGRERR_NONE)
3711 0 : return OGRERR_FAILURE;
3712 :
3713 770 : for (int i = 0; i < m_poFeatureDefn->GetGeomFieldCount(); i++)
3714 : {
3715 : OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
3716 335 : m_poFeatureDefn->myGetGeomFieldDefn(i);
3717 335 : if (RunAddGeometryColumn(poGeomFieldDefn, false) != OGRERR_NONE)
3718 0 : return OGRERR_FAILURE;
3719 : }
3720 : }
3721 :
3722 444 : if (RecomputeOrdinals() != OGRERR_NONE)
3723 0 : return OGRERR_FAILURE;
3724 :
3725 444 : if (m_poDS->IsSpatialiteDB() && m_poDS->GetLayerCount() == 1)
3726 : {
3727 : /* To create the layer_statistics and spatialite_history tables */
3728 40 : if (SQLCommand(m_poDS->GetDB(), "SELECT UpdateLayerStatistics()") !=
3729 : OGRERR_NONE)
3730 0 : return OGRERR_FAILURE;
3731 : }
3732 :
3733 444 : return OGRERR_NONE;
3734 : }
3735 :
3736 : /************************************************************************/
3737 : /* HasSpatialIndex() */
3738 : /************************************************************************/
3739 :
3740 128 : bool OGRSQLiteTableLayer::HasSpatialIndex(int iGeomCol) const
3741 : {
3742 128 : GetLayerDefn();
3743 128 : if (iGeomCol < 0 || iGeomCol >= m_poFeatureDefn->GetGeomFieldCount())
3744 0 : return false;
3745 : const OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
3746 128 : m_poFeatureDefn->myGetGeomFieldDefn(iGeomCol);
3747 :
3748 128 : const_cast<OGRSQLiteTableLayer *>(this)->CreateSpatialIndexIfNecessary();
3749 :
3750 128 : return poGeomFieldDefn->m_bHasSpatialIndex;
3751 : }
3752 :
3753 : /************************************************************************/
3754 : /* InitFeatureCount() */
3755 : /************************************************************************/
3756 :
3757 444 : void OGRSQLiteTableLayer::InitFeatureCount()
3758 : {
3759 444 : m_nFeatureCount = 0;
3760 444 : ForceStatisticsToBeFlushed();
3761 444 : }
3762 :
3763 : /************************************************************************/
3764 : /* InvalidateCachedFeatureCountAndExtent() */
3765 : /************************************************************************/
3766 :
3767 70 : void OGRSQLiteTableLayer::InvalidateCachedFeatureCountAndExtent()
3768 : {
3769 70 : m_nFeatureCount = -1;
3770 126 : for (int iGeomCol = 0; iGeomCol < GetLayerDefn()->GetGeomFieldCount();
3771 : iGeomCol++)
3772 56 : m_poFeatureDefn->myGetGeomFieldDefn(iGeomCol)->m_bCachedExtentIsValid =
3773 : false;
3774 70 : ForceStatisticsToBeFlushed();
3775 70 : }
3776 :
3777 : /************************************************************************/
3778 : /* DoStatisticsNeedToBeFlushed() */
3779 : /************************************************************************/
3780 :
3781 0 : bool OGRSQLiteTableLayer::DoStatisticsNeedToBeFlushed()
3782 : {
3783 0 : return m_bStatisticsNeedsToBeFlushed && m_poDS->IsSpatialiteDB() &&
3784 0 : m_poDS->IsSpatialiteLoaded();
3785 : }
3786 :
3787 : /************************************************************************/
3788 : /* ForceStatisticsToBeFlushed() */
3789 : /************************************************************************/
3790 :
3791 12556 : void OGRSQLiteTableLayer::ForceStatisticsToBeFlushed()
3792 : {
3793 12556 : m_bStatisticsNeedsToBeFlushed = true;
3794 12556 : }
3795 :
3796 : /************************************************************************/
3797 : /* AreStatisticsValid() */
3798 : /************************************************************************/
3799 :
3800 1 : bool OGRSQLiteTableLayer::AreStatisticsValid()
3801 : {
3802 1 : return m_nFeatureCount >= 0;
3803 : }
3804 :
3805 : /************************************************************************/
3806 : /* LoadStatisticsSpatialite4DB() */
3807 : /************************************************************************/
3808 :
3809 136 : void OGRSQLiteTableLayer::LoadStatisticsSpatialite4DB()
3810 : {
3811 264 : for (int iCol = 0; iCol < GetLayerDefn()->GetGeomFieldCount(); iCol++)
3812 : {
3813 : OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
3814 137 : m_poFeatureDefn->myGetGeomFieldDefn(iCol);
3815 137 : const char *pszGeomCol = poGeomFieldDefn->GetNameRef();
3816 :
3817 137 : CPLString osSQL;
3818 137 : CPLString osLastEvtDate;
3819 : osSQL.Printf(
3820 : "SELECT MAX(last_insert, last_update, last_delete) FROM "
3821 : "geometry_columns_time WHERE "
3822 : "(f_table_name = lower('%s') AND f_geometry_column = lower('%s'))"
3823 : #ifdef WORKAROUND_SQLITE3_BUGS
3824 : " OR 0"
3825 : #endif
3826 : ,
3827 137 : m_pszEscapedTableName, SQLEscapeLiteral(pszGeomCol).c_str());
3828 :
3829 137 : sqlite3 *hDB = m_poDS->GetDB();
3830 137 : int nRowCount = 0;
3831 137 : int nColCount = 0;
3832 137 : char **papszResult = nullptr;
3833 :
3834 137 : sqlite3_get_table(hDB, osSQL.c_str(), &papszResult, &nRowCount,
3835 : &nColCount, nullptr);
3836 :
3837 : /* Make it a Unix timestamp */
3838 137 : int nYear = 0;
3839 137 : int nMonth = 0;
3840 137 : int nDay = 0;
3841 137 : char chSep = 0;
3842 137 : int nHour = 0;
3843 137 : int nMinute = 0;
3844 137 : float fSecond = 0.0f;
3845 265 : if (nRowCount == 1 && nColCount == 1 && papszResult[1] != nullptr &&
3846 128 : sscanf(papszResult[1], "%04d-%02d-%02d%c%02d:%02d:%f", &nYear,
3847 : &nMonth, &nDay, &chSep, &nHour, &nMinute, &fSecond) == 7)
3848 : {
3849 128 : osLastEvtDate = papszResult[1];
3850 : }
3851 :
3852 137 : sqlite3_free_table(papszResult);
3853 137 : papszResult = nullptr;
3854 :
3855 137 : if (osLastEvtDate.empty())
3856 9 : return;
3857 :
3858 : osSQL.Printf(
3859 : "SELECT last_verified, row_count, extent_min_x, extent_min_y, "
3860 : "extent_max_x, extent_max_y FROM geometry_columns_statistics WHERE "
3861 : "(f_table_name = lower('%s') AND f_geometry_column = lower('%s'))"
3862 : #ifdef WORKAROUND_SQLITE3_BUGS
3863 : " OR 0"
3864 : #endif
3865 : ,
3866 128 : m_pszEscapedTableName, SQLEscapeLiteral(pszGeomCol).c_str());
3867 :
3868 128 : nRowCount = 0;
3869 128 : nColCount = 0;
3870 128 : sqlite3_get_table(hDB, osSQL.c_str(), &papszResult, &nRowCount,
3871 : &nColCount, nullptr);
3872 :
3873 164 : if (nRowCount == 1 && nColCount == 6 && papszResult[6] != nullptr &&
3874 36 : sscanf(papszResult[6], "%04d-%02d-%02d%c%02d:%02d:%f", &nYear,
3875 : &nMonth, &nDay, &chSep, &nHour, &nMinute, &fSecond) == 7)
3876 : {
3877 72 : CPLString osLastVerified(papszResult[6]);
3878 :
3879 : /* Check that the information in geometry_columns_statistics is more
3880 : */
3881 : /* recent than geometry_columns_time */
3882 36 : if (osLastVerified.compare(osLastEvtDate) > 0)
3883 : {
3884 14 : char **papszRow = papszResult + 6;
3885 14 : const char *pszRowCount = papszRow[1];
3886 14 : const char *pszMinX = papszRow[2];
3887 14 : const char *pszMinY = papszRow[3];
3888 14 : const char *pszMaxX = papszRow[4];
3889 14 : const char *pszMaxY = papszRow[5];
3890 :
3891 14 : CPLDebug("SQLITE", "Loading statistics for %s,%s",
3892 : m_pszTableName, pszGeomCol);
3893 :
3894 14 : if (pszRowCount != nullptr)
3895 : {
3896 14 : m_nFeatureCount = CPLAtoGIntBig(pszRowCount);
3897 14 : if (m_nFeatureCount == 0)
3898 : {
3899 11 : m_nFeatureCount = -1;
3900 11 : pszMinX = nullptr;
3901 : }
3902 : else
3903 : {
3904 3 : CPLDebug("SQLITE",
3905 : "Layer %s feature count : " CPL_FRMT_GIB,
3906 : m_pszTableName, m_nFeatureCount);
3907 : }
3908 : }
3909 :
3910 14 : if (pszMinX != nullptr && pszMinY != nullptr &&
3911 3 : pszMaxX != nullptr && pszMaxY != nullptr)
3912 : {
3913 3 : poGeomFieldDefn->m_bCachedExtentIsValid = true;
3914 3 : poGeomFieldDefn->m_oCachedExtent.MinX = CPLAtof(pszMinX);
3915 3 : poGeomFieldDefn->m_oCachedExtent.MinY = CPLAtof(pszMinY);
3916 3 : poGeomFieldDefn->m_oCachedExtent.MaxX = CPLAtof(pszMaxX);
3917 3 : poGeomFieldDefn->m_oCachedExtent.MaxY = CPLAtof(pszMaxY);
3918 3 : CPLDebug("SQLITE", "Layer %s extent : %s,%s,%s,%s",
3919 : m_pszTableName, pszMinX, pszMinY, pszMaxX,
3920 : pszMaxY);
3921 : }
3922 : }
3923 : else
3924 : {
3925 22 : CPLDebug("SQLite", "Statistics in %s is not up-to-date",
3926 : m_pszTableName);
3927 : }
3928 : }
3929 :
3930 128 : sqlite3_free_table(papszResult);
3931 128 : papszResult = nullptr;
3932 : }
3933 : }
3934 :
3935 : /************************************************************************/
3936 : /* LoadStatistics() */
3937 : /************************************************************************/
3938 :
3939 390 : void OGRSQLiteTableLayer::LoadStatistics()
3940 : {
3941 390 : if (!m_poDS->IsSpatialiteDB() || !m_poDS->IsSpatialiteLoaded())
3942 387 : return;
3943 :
3944 139 : if (m_poDS->HasSpatialite4Layout())
3945 : {
3946 136 : LoadStatisticsSpatialite4DB();
3947 136 : return;
3948 : }
3949 :
3950 3 : if (GetLayerDefn()->GetGeomFieldCount() != 1)
3951 0 : return;
3952 3 : const char *pszGeomCol = m_poFeatureDefn->GetGeomFieldDefn(0)->GetNameRef();
3953 :
3954 3 : GIntBig nFileTimestamp = m_poDS->GetFileTimestamp();
3955 3 : if (nFileTimestamp == 0)
3956 0 : return;
3957 :
3958 : /* Find the most recent event in the 'spatialite_history' that is */
3959 : /* a UpdateLayerStatistics event on all tables and geometry columns */
3960 6 : CPLString osSQL;
3961 : osSQL.Printf("SELECT MAX(timestamp) FROM spatialite_history WHERE "
3962 : "((table_name = '%s' AND geometry_column = '%s') OR "
3963 : "(table_name = 'ALL-TABLES' AND geometry_column = "
3964 : "'ALL-GEOMETRY-COLUMNS')) AND "
3965 : "event = 'UpdateLayerStatistics'",
3966 3 : m_pszEscapedTableName, SQLEscapeLiteral(pszGeomCol).c_str());
3967 :
3968 3 : sqlite3 *hDB = m_poDS->GetDB();
3969 3 : int nRowCount = 0, nColCount = 0;
3970 3 : char **papszResult = nullptr, *pszErrMsg = nullptr;
3971 :
3972 3 : sqlite3_get_table(hDB, osSQL.c_str(), &papszResult, &nRowCount, &nColCount,
3973 : &pszErrMsg);
3974 :
3975 : /* Make it a Unix timestamp */
3976 : int nYear, nMonth, nDay, nHour, nMinute, nSecond;
3977 : struct tm brokendown;
3978 3 : GIntBig nTS = -1;
3979 3 : if (nRowCount >= 1 && nColCount == 1 && papszResult[1] != nullptr &&
3980 0 : sscanf(papszResult[1], "%04d-%02d-%02d %02d:%02d:%02d", &nYear, &nMonth,
3981 : &nDay, &nHour, &nMinute, &nSecond) == 6)
3982 : {
3983 0 : brokendown.tm_year = nYear - 1900;
3984 0 : brokendown.tm_mon = nMonth - 1;
3985 0 : brokendown.tm_mday = nDay;
3986 0 : brokendown.tm_hour = nHour;
3987 0 : brokendown.tm_min = nMinute;
3988 0 : brokendown.tm_sec = nSecond;
3989 0 : nTS = CPLYMDHMSToUnixTime(&brokendown);
3990 : }
3991 :
3992 : /* If it is equal to the modified timestamp of the DB (as a file) */
3993 : /* then we can safely use the data from the layer_statistics, since */
3994 : /* it will be up-to-date */
3995 : // cppcheck-suppress knownConditionTrueFalse
3996 3 : if (nFileTimestamp == nTS || nFileTimestamp == nTS + 1)
3997 : {
3998 : osSQL.Printf("SELECT row_count, extent_min_x, extent_min_y, "
3999 : "extent_max_x, extent_max_y "
4000 : "FROM layer_statistics WHERE table_name = '%s' AND "
4001 : "geometry_column = '%s'",
4002 : m_pszEscapedTableName,
4003 0 : SQLEscapeLiteral(pszGeomCol).c_str());
4004 :
4005 0 : sqlite3_free_table(papszResult);
4006 0 : papszResult = nullptr;
4007 :
4008 0 : sqlite3_get_table(hDB, osSQL.c_str(), &papszResult, &nRowCount,
4009 : &nColCount, &pszErrMsg);
4010 :
4011 0 : if (nRowCount == 1)
4012 : {
4013 0 : char **papszRow = papszResult + 5;
4014 0 : const char *pszRowCount = papszRow[0];
4015 0 : const char *pszMinX = papszRow[1];
4016 0 : const char *pszMinY = papszRow[2];
4017 0 : const char *pszMaxX = papszRow[3];
4018 0 : const char *pszMaxY = papszRow[4];
4019 :
4020 0 : CPLDebug("SQLITE",
4021 : "File timestamp matches layer statistics timestamp. "
4022 : "Loading statistics for %s",
4023 : m_pszTableName);
4024 :
4025 0 : if (pszRowCount != nullptr)
4026 : {
4027 0 : m_nFeatureCount = CPLAtoGIntBig(pszRowCount);
4028 0 : CPLDebug("SQLITE", "Layer %s feature count : " CPL_FRMT_GIB,
4029 : m_pszTableName, m_nFeatureCount);
4030 : }
4031 :
4032 0 : if (pszMinX != nullptr && pszMinY != nullptr &&
4033 0 : pszMaxX != nullptr && pszMaxY != nullptr)
4034 : {
4035 : OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
4036 0 : m_poFeatureDefn->myGetGeomFieldDefn(0);
4037 0 : poGeomFieldDefn->m_bCachedExtentIsValid = true;
4038 0 : poGeomFieldDefn->m_oCachedExtent.MinX = CPLAtof(pszMinX);
4039 0 : poGeomFieldDefn->m_oCachedExtent.MinY = CPLAtof(pszMinY);
4040 0 : poGeomFieldDefn->m_oCachedExtent.MaxX = CPLAtof(pszMaxX);
4041 0 : poGeomFieldDefn->m_oCachedExtent.MaxY = CPLAtof(pszMaxY);
4042 0 : CPLDebug("SQLITE", "Layer %s extent : %s,%s,%s,%s",
4043 : m_pszTableName, pszMinX, pszMinY, pszMaxX, pszMaxY);
4044 : }
4045 : }
4046 : }
4047 :
4048 3 : if (pszErrMsg)
4049 0 : sqlite3_free(pszErrMsg);
4050 :
4051 3 : sqlite3_free_table(papszResult);
4052 : }
4053 :
4054 : /************************************************************************/
4055 : /* SaveStatistics() */
4056 : /************************************************************************/
4057 :
4058 345 : int OGRSQLiteTableLayer::SaveStatistics()
4059 : {
4060 138 : if (!m_bStatisticsNeedsToBeFlushed || !m_poDS->IsSpatialiteDB() ||
4061 483 : !m_poDS->IsSpatialiteLoaded() || !m_poDS->GetUpdate())
4062 207 : return -1;
4063 138 : if (GetLayerDefn()->GetGeomFieldCount() != 1)
4064 4 : return -1;
4065 : OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
4066 134 : m_poFeatureDefn->myGetGeomFieldDefn(0);
4067 134 : const char *pszGeomCol = poGeomFieldDefn->GetNameRef();
4068 :
4069 268 : CPLString osSQL;
4070 134 : sqlite3 *hDB = m_poDS->GetDB();
4071 134 : char *pszErrMsg = nullptr;
4072 :
4073 : // Update geometry_columns_time.
4074 134 : if (!poGeomFieldDefn->m_aosDisabledTriggers.empty())
4075 : {
4076 123 : char *pszSQL3 = sqlite3_mprintf(
4077 : "UPDATE geometry_columns_time "
4078 : "SET last_insert = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
4079 : "WHERE Lower(f_table_name) = Lower('%q') AND "
4080 : "Lower(f_geometry_column) = Lower('%q')",
4081 : m_pszTableName, poGeomFieldDefn->GetNameRef());
4082 123 : if (sqlite3_exec(m_poDS->GetDB(), pszSQL3, nullptr, nullptr,
4083 123 : &pszErrMsg) != SQLITE_OK)
4084 : {
4085 0 : CPLDebug("SQLITE", "%s: error %s", pszSQL3,
4086 0 : pszErrMsg ? pszErrMsg : "unknown");
4087 0 : sqlite3_free(pszErrMsg);
4088 0 : pszErrMsg = nullptr;
4089 : }
4090 123 : sqlite3_free(pszSQL3);
4091 : }
4092 :
4093 134 : const char *pszStatTableName = m_poDS->HasSpatialite4Layout()
4094 134 : ? "geometry_columns_statistics"
4095 134 : : "layer_statistics";
4096 134 : if (SQLGetInteger(m_poDS->GetDB(),
4097 : CPLSPrintf("SELECT 1 FROM sqlite_master WHERE type IN "
4098 : "('view', 'table') AND name = '%s'",
4099 : pszStatTableName),
4100 134 : nullptr) == 0)
4101 : {
4102 1 : return TRUE;
4103 : }
4104 : const char *pszFTableName =
4105 133 : m_poDS->HasSpatialite4Layout() ? "f_table_name" : "table_name";
4106 133 : const char *pszFGeometryColumn = m_poDS->HasSpatialite4Layout()
4107 133 : ? "f_geometry_column"
4108 133 : : "geometry_column";
4109 266 : CPLString osTableName(m_pszTableName);
4110 266 : CPLString osGeomCol(pszGeomCol);
4111 133 : const char *pszNowValue = "";
4112 133 : if (m_poDS->HasSpatialite4Layout())
4113 : {
4114 133 : osTableName = osTableName.tolower();
4115 133 : osGeomCol = osGeomCol.tolower();
4116 133 : pszNowValue = ", strftime('%Y-%m-%dT%H:%M:%fZ','now')";
4117 : }
4118 :
4119 133 : if (m_nFeatureCount >= 0)
4120 : {
4121 : /* Update or add entry in the layer_statistics table */
4122 129 : if (poGeomFieldDefn->m_bCachedExtentIsValid)
4123 : {
4124 : osSQL.Printf("INSERT OR REPLACE INTO %s (%s"
4125 : "%s, %s, row_count, extent_min_x, "
4126 : "extent_min_y, extent_max_x, extent_max_y%s) VALUES ("
4127 : "%s'%s', '%s', " CPL_FRMT_GIB ", ?, ?, ?, ?%s)",
4128 : pszStatTableName,
4129 109 : m_poDS->HasSpatialite4Layout() ? "" : "raster_layer, ",
4130 : pszFTableName, pszFGeometryColumn,
4131 109 : m_poDS->HasSpatialite4Layout() ? ", last_verified"
4132 : : "",
4133 109 : m_poDS->HasSpatialite4Layout() ? "" : "0 ,",
4134 218 : SQLEscapeLiteral(osTableName).c_str(),
4135 218 : SQLEscapeLiteral(osGeomCol).c_str(), m_nFeatureCount,
4136 654 : pszNowValue);
4137 :
4138 109 : sqlite3_stmt *m_hStmtInsert = nullptr;
4139 : int rc =
4140 109 : sqlite3_prepare_v2(hDB, osSQL, -1, &m_hStmtInsert, nullptr);
4141 109 : if (rc == SQLITE_OK)
4142 109 : rc = sqlite3_bind_double(m_hStmtInsert, 1,
4143 : poGeomFieldDefn->m_oCachedExtent.MinX);
4144 109 : if (rc == SQLITE_OK)
4145 109 : rc = sqlite3_bind_double(m_hStmtInsert, 2,
4146 : poGeomFieldDefn->m_oCachedExtent.MinY);
4147 109 : if (rc == SQLITE_OK)
4148 109 : rc = sqlite3_bind_double(m_hStmtInsert, 3,
4149 : poGeomFieldDefn->m_oCachedExtent.MaxX);
4150 109 : if (rc == SQLITE_OK)
4151 109 : rc = sqlite3_bind_double(m_hStmtInsert, 4,
4152 : poGeomFieldDefn->m_oCachedExtent.MaxY);
4153 109 : if (rc == SQLITE_OK)
4154 109 : rc = sqlite3_step(m_hStmtInsert);
4155 109 : if (rc != SQLITE_DONE)
4156 : {
4157 0 : CPLError(CE_Failure, CPLE_AppDefined,
4158 : "In Initialize(): sqlite3_step(%s):\n %s",
4159 : osSQL.c_str(), sqlite3_errmsg(hDB));
4160 : }
4161 109 : sqlite3_finalize(m_hStmtInsert);
4162 109 : return rc == SQLITE_DONE;
4163 : }
4164 : else
4165 : {
4166 : osSQL.Printf(
4167 : "INSERT OR REPLACE INTO %s (%s"
4168 : "%s, %s, row_count, extent_min_x, "
4169 : "extent_min_y, extent_max_x, extent_max_y%s) VALUES ("
4170 : "%s'%s', '%s', " CPL_FRMT_GIB ", NULL, NULL, NULL, NULL%s)",
4171 : pszStatTableName,
4172 20 : m_poDS->HasSpatialite4Layout() ? "" : "raster_layer, ",
4173 : pszFTableName, pszFGeometryColumn,
4174 20 : m_poDS->HasSpatialite4Layout() ? ", last_verified" : "",
4175 20 : m_poDS->HasSpatialite4Layout() ? "" : "0 ,",
4176 40 : SQLEscapeLiteral(osTableName).c_str(),
4177 40 : SQLEscapeLiteral(osGeomCol).c_str(), m_nFeatureCount,
4178 120 : pszNowValue);
4179 20 : return SQLCommand(hDB, osSQL) == OGRERR_NONE;
4180 : }
4181 : }
4182 : else
4183 : {
4184 : /* Remove any existing entry in layer_statistics if for some reason */
4185 : /* we know that it will out-of-sync */
4186 : osSQL.Printf("DELETE FROM %s WHERE "
4187 : "%s = '%s' AND %s = '%s'",
4188 : pszStatTableName, pszFTableName,
4189 8 : SQLEscapeLiteral(osTableName).c_str(), pszFGeometryColumn,
4190 12 : SQLEscapeLiteral(osGeomCol).c_str());
4191 4 : return SQLCommand(hDB, osSQL) == OGRERR_NONE;
4192 : }
4193 : }
4194 :
4195 : /************************************************************************/
4196 : /* SetCompressedColumns() */
4197 : /************************************************************************/
4198 :
4199 444 : void OGRSQLiteTableLayer::SetCompressedColumns(const char *pszCompressedColumns)
4200 : {
4201 444 : m_papszCompressedColumns =
4202 444 : CSLTokenizeString2(pszCompressedColumns, ",", CSLT_HONOURSTRINGS);
4203 444 : }
|