Coverage Report

Created: 2026-08-11 08:26

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