Coverage Report

Created: 2026-03-30 09:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrsf_frmts/sqlite/ogrsqliteselectlayer.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  OpenGIS Simple Features Reference Implementation
4
 * Purpose:  Implements OGRSQLiteSelectLayer class, layer access to the results
5
 *           of a SELECT statement executed via ExecuteSQL().
6
 * Author:   Frank Warmerdam, warmerdam@pobox.com
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 2004, Frank Warmerdam
10
 * Copyright (c) 2010-2014, Even Rouault <even dot rouault at spatialys.com>
11
 *
12
 * SPDX-License-Identifier: MIT
13
 ****************************************************************************/
14
15
#include "cpl_port.h"
16
#include "ogr_sqlite.h"
17
18
#include <cstddef>
19
#include <cstdlib>
20
#include <cstring>
21
#include <set>
22
#include <string>
23
#include <utility>
24
25
#include "cpl_conv.h"
26
#include "cpl_error.h"
27
#include "cpl_string.h"
28
#include "ogr_core.h"
29
#include "ogr_feature.h"
30
#include "ogr_geometry.h"
31
#include "ogr_p.h"
32
#include "ogr_spatialref.h"
33
#include "ogrsf_frmts.h"
34
#include "sqlite3.h"
35
#include "ogr_swq.h"
36
37
50.8k
IOGRSQLiteSelectLayer::~IOGRSQLiteSelectLayer() = default;
38
39
/************************************************************************/
40
/*                OGRSQLiteSelectLayerCommonBehaviour()                 */
41
/************************************************************************/
42
43
OGRSQLiteSelectLayerCommonBehaviour::OGRSQLiteSelectLayerCommonBehaviour(
44
    OGRSQLiteBaseDataSource *poDSIn, IOGRSQLiteSelectLayer *m_poLayerIn,
45
    const CPLString &osSQLIn, bool bEmptyLayerIn)
46
50.8k
    : m_poDS(poDSIn), m_poLayer(m_poLayerIn), m_osSQLBase(osSQLIn),
47
50.8k
      m_bEmptyLayer(bEmptyLayerIn), m_osSQLCurrent(osSQLIn)
48
50.8k
{
49
50.8k
}
50
51
/************************************************************************/
52
/*                        OGRSQLiteSelectLayer()                        */
53
/************************************************************************/
54
55
OGRSQLiteSelectLayer::OGRSQLiteSelectLayer(
56
    OGRSQLiteDataSource *poDSIn, const CPLString &osSQLIn,
57
    sqlite3_stmt *m_hStmtIn, bool bUseStatementForGetNextFeature,
58
    bool bEmptyLayer, bool bAllowMultipleGeomFieldsIn, bool bCanReopenBaseDS)
59
50.8k
    : OGRSQLiteLayer(poDSIn),
60
50.8k
      m_poBehavior(new OGRSQLiteSelectLayerCommonBehaviour(
61
50.8k
          poDSIn, this, osSQLIn, bEmptyLayer)),
62
50.8k
      m_bCanReopenBaseDS(bCanReopenBaseDS)
63
50.8k
{
64
50.8k
    m_bAllowMultipleGeomFields = bAllowMultipleGeomFieldsIn;
65
66
50.8k
    std::set<CPLString> aosEmpty;
67
50.8k
    BuildFeatureDefn("SELECT", true, m_hStmtIn, nullptr, aosEmpty);
68
50.8k
    SetDescription("SELECT");
69
70
50.8k
    if (bUseStatementForGetNextFeature)
71
17.2k
    {
72
17.2k
        m_hStmt = m_hStmtIn;
73
17.2k
        m_bDoStep = false;
74
75
        // Try to extract SRS from first geometry
76
17.2k
        for (int iField = 0;
77
17.2k
             !bEmptyLayer && iField < m_poFeatureDefn->GetGeomFieldCount();
78
17.2k
             iField++)
79
13
        {
80
13
            OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
81
13
                m_poFeatureDefn->myGetGeomFieldDefn(iField);
82
13
            if (wkbFlatten(poGeomFieldDefn->GetType()) != wkbUnknown)
83
0
                continue;
84
13
            const auto nColType =
85
13
                sqlite3_column_type(m_hStmt, poGeomFieldDefn->m_iCol);
86
13
            if (nColType == SQLITE_BLOB)
87
13
            {
88
                // Is it a Spatialite geometry ?
89
13
                const GByte *pabyBlob = reinterpret_cast<const GByte *>(
90
13
                    sqlite3_column_blob(m_hStmt, poGeomFieldDefn->m_iCol));
91
13
                if (sqlite3_column_bytes(m_hStmt, poGeomFieldDefn->m_iCol) >
92
13
                        39 &&
93
1
                    pabyBlob[0] == 0x00 &&
94
0
                    (pabyBlob[1] == wkbNDR || pabyBlob[1] == wkbXDR) &&
95
0
                    pabyBlob[38] == 0x7C)
96
0
                {
97
0
                    const int eByteOrder = pabyBlob[1];
98
0
                    int nSRSId = 0;
99
0
                    memcpy(&nSRSId, pabyBlob + 2, 4);
100
0
#ifdef CPL_LSB
101
0
                    if (eByteOrder != wkbNDR)
102
0
                        CPL_SWAP32PTR(&nSRSId);
103
#else
104
                    if (eByteOrder == wkbNDR)
105
                        CPL_SWAP32PTR(&nSRSId);
106
#endif
107
0
                    CPLPushErrorHandler(CPLQuietErrorHandler);
108
0
                    OGRSpatialReference *poSRS = m_poDS->FetchSRS(nSRSId);
109
0
                    CPLPopErrorHandler();
110
0
                    if (poSRS != nullptr)
111
0
                    {
112
0
                        poGeomFieldDefn->m_nSRSId = nSRSId;
113
0
                        poGeomFieldDefn->SetSpatialRef(poSRS);
114
0
                    }
115
0
                    else
116
0
                        CPLErrorReset();
117
118
0
                    continue;
119
0
                }
120
13
            }
121
122
13
#ifdef SQLITE_HAS_COLUMN_METADATA
123
13
            if (iField == 0 &&
124
13
                (nColType == SQLITE_NULL || nColType == SQLITE_BLOB))
125
13
            {
126
13
                const char *pszTableName =
127
13
                    sqlite3_column_table_name(m_hStmt, poGeomFieldDefn->m_iCol);
128
13
                if (pszTableName != nullptr)
129
13
                {
130
13
                    CPLErrorStateBackuper oErrorStateBackuper(
131
13
                        CPLQuietErrorHandler);
132
13
                    OGRSQLiteLayer *m_poLayer =
133
13
                        cpl::down_cast<OGRSQLiteLayer *>(
134
13
                            m_poDS->GetLayerByName(pszTableName));
135
13
                    if (m_poLayer != nullptr &&
136
13
                        m_poLayer->GetLayerDefn()->GetGeomFieldCount() > 0)
137
1
                    {
138
1
                        OGRSQLiteGeomFieldDefn *poSrcGFldDefn =
139
1
                            m_poLayer->myGetLayerDefn()->myGetGeomFieldDefn(0);
140
1
                        poGeomFieldDefn->m_nSRSId = poSrcGFldDefn->m_nSRSId;
141
1
                        poGeomFieldDefn->SetSpatialRef(
142
1
                            poSrcGFldDefn->GetSpatialRef());
143
1
                    }
144
13
                }
145
13
            }
146
13
#endif
147
13
        }
148
17.2k
    }
149
33.5k
    else
150
33.5k
        sqlite3_finalize(m_hStmtIn);
151
50.8k
}
152
153
/************************************************************************/
154
/*                       ~OGRSQLiteSelectLayer()                        */
155
/************************************************************************/
156
157
OGRSQLiteSelectLayer::~OGRSQLiteSelectLayer()
158
50.8k
{
159
50.8k
    delete m_poBehavior;
160
50.8k
}
161
162
/************************************************************************/
163
/*                            ResetReading()                            */
164
/************************************************************************/
165
166
void OGRSQLiteSelectLayer::ResetReading()
167
0
{
168
0
    m_poBehavior->ResetReading();
169
0
}
170
171
void OGRSQLiteSelectLayerCommonBehaviour::ResetReading()
172
0
{
173
0
    if (m_poLayer->HasReadFeature() || m_bAllowResetReadingEvenIfIndexAtZero)
174
0
    {
175
0
        m_poLayer->BaseResetReading();
176
0
        m_bAllowResetReadingEvenIfIndexAtZero = false;
177
0
    }
178
0
}
179
180
/************************************************************************/
181
/*                           GetNextFeature()                           */
182
/************************************************************************/
183
184
OGRFeature *OGRSQLiteSelectLayer::GetNextFeature()
185
213k
{
186
213k
    return m_poBehavior->GetNextFeature();
187
213k
}
188
189
OGRFeature *OGRSQLiteSelectLayerCommonBehaviour::GetNextFeature()
190
213k
{
191
213k
    if (m_bEmptyLayer)
192
33.4k
        return nullptr;
193
194
180k
    return m_poLayer->BaseGetNextFeature();
195
213k
}
196
197
/************************************************************************/
198
/*                OGRGenSQLResultsLayerHasSpecialField()                */
199
/************************************************************************/
200
201
static int HasSpecialFields(swq_expr_node *expr, int nMinIndexForSpecialField)
202
0
{
203
0
    if (expr->eNodeType == SNT_COLUMN)
204
0
    {
205
0
        if (expr->table_index == 0)
206
0
        {
207
0
            return expr->field_index >= nMinIndexForSpecialField &&
208
0
                   expr->field_index <
209
0
                       nMinIndexForSpecialField + SPECIAL_FIELD_COUNT;
210
0
        }
211
0
    }
212
0
    else if (expr->eNodeType == SNT_OPERATION)
213
0
    {
214
0
        for (int i = 0; i < expr->nSubExprCount; i++)
215
0
        {
216
0
            if (HasSpecialFields(expr->papoSubExpr[i],
217
0
                                 nMinIndexForSpecialField))
218
0
                return TRUE;
219
0
        }
220
0
    }
221
0
    return FALSE;
222
0
}
223
224
/************************************************************************/
225
/*                         SetAttributeFilter()                         */
226
/************************************************************************/
227
228
OGRErr OGRSQLiteSelectLayer::SetAttributeFilter(const char *pszQuery)
229
0
{
230
0
    return m_poBehavior->SetAttributeFilter(pszQuery);
231
0
}
232
233
OGRErr
234
OGRSQLiteSelectLayerCommonBehaviour::SetAttributeFilter(const char *pszQuery)
235
236
0
{
237
0
    char *&m_pszAttrQuertyString = m_poLayer->GetAttrQueryString();
238
0
    if (m_pszAttrQuertyString == nullptr && pszQuery == nullptr)
239
0
        return OGRERR_NONE;
240
241
0
    CPLFree(m_pszAttrQuertyString);
242
0
    m_pszAttrQuertyString = (pszQuery) ? CPLStrdup(pszQuery) : nullptr;
243
244
0
    m_bAllowResetReadingEvenIfIndexAtZero = true;
245
246
0
    OGRFeatureQuery oQuery;
247
248
0
    CPLPushErrorHandler(CPLQuietErrorHandler);
249
0
    const bool bHasSpecialFields =
250
0
        (pszQuery != nullptr && pszQuery[0] != '\0' &&
251
0
         oQuery.Compile(m_poLayer->GetLayerDefn(), pszQuery) == OGRERR_NONE &&
252
0
         HasSpecialFields(static_cast<swq_expr_node *>(oQuery.GetSWQExpr()),
253
0
                          m_poLayer->GetLayerDefn()->GetFieldCount()));
254
0
    CPLPopErrorHandler();
255
256
0
    if (bHasSpecialFields || !BuildSQL())
257
0
    {
258
0
        return m_poLayer->BaseSetAttributeFilter(pszQuery);
259
0
    }
260
261
0
    ResetReading();
262
263
0
    return OGRERR_NONE;
264
0
}
265
266
/************************************************************************/
267
/*                           GetNextFeature()                           */
268
/************************************************************************/
269
270
GIntBig OGRSQLiteSelectLayer::GetFeatureCount(int bForce)
271
0
{
272
0
    return m_poBehavior->GetFeatureCount(bForce);
273
0
}
274
275
GIntBig OGRSQLiteSelectLayerCommonBehaviour::GetFeatureCount(int bForce)
276
0
{
277
0
    if (m_bEmptyLayer)
278
0
        return 0;
279
280
0
    if (m_poLayer->GetFeatureQuery() == nullptr &&
281
0
        STARTS_WITH_CI(m_osSQLCurrent, "SELECT COUNT(*) FROM") &&
282
0
        m_osSQLCurrent.ifind(" GROUP BY ") == std::string::npos &&
283
0
        m_osSQLCurrent.ifind(" UNION ") == std::string::npos &&
284
0
        m_osSQLCurrent.ifind(" INTERSECT ") == std::string::npos &&
285
0
        m_osSQLCurrent.ifind(" EXCEPT ") == std::string::npos)
286
0
        return 1;
287
288
0
    if (m_poLayer->GetFeatureQuery() != nullptr ||
289
0
        (m_poLayer->GetFilterGeom() != nullptr && !m_bSpatialFilterInSQL) ||
290
0
        STARTS_WITH_CI(m_osSQLCurrent.c_str(), "PRAGMA table_info("))
291
0
    {
292
0
        return m_poLayer->BaseGetFeatureCount(bForce);
293
0
    }
294
295
0
    CPLString osFeatureCountSQL("SELECT COUNT(*) FROM (");
296
0
    osFeatureCountSQL += m_osSQLCurrent;
297
0
    osFeatureCountSQL += ")";
298
299
0
    CPLDebug("SQLITE", "Running %s", osFeatureCountSQL.c_str());
300
301
    /* -------------------------------------------------------------------- */
302
    /*      Execute.                                                        */
303
    /* -------------------------------------------------------------------- */
304
0
    char *pszErrMsg = nullptr;
305
0
    char **papszResult = nullptr;
306
0
    int nRowCount = 0;
307
0
    int nColCount = 0;
308
0
    int nResult = -1;
309
310
0
    if (sqlite3_get_table(m_poDS->GetDB(), osFeatureCountSQL, &papszResult,
311
0
                          &nRowCount, &nColCount, &pszErrMsg) != SQLITE_OK)
312
0
    {
313
0
        CPLDebug("SQLITE", "Error: %s", pszErrMsg);
314
0
        sqlite3_free(pszErrMsg);
315
0
        return m_poLayer->BaseGetFeatureCount(bForce);
316
0
    }
317
318
0
    if (nRowCount == 1 && nColCount == 1)
319
0
    {
320
0
        nResult = atoi(papszResult[1]);
321
0
    }
322
323
0
    sqlite3_free_table(papszResult);
324
325
0
    return nResult;
326
0
}
327
328
/************************************************************************/
329
/*                           ResetStatement()                           */
330
/************************************************************************/
331
332
OGRErr OGRSQLiteSelectLayer::ResetStatement()
333
334
0
{
335
0
    ClearStatement();
336
337
0
    m_iNextShapeId = 0;
338
0
    m_bDoStep = true;
339
340
#ifdef DEBUG
341
    CPLDebug("OGR_SQLITE", "prepare_v2(%s)",
342
             m_poBehavior->m_osSQLCurrent.c_str());
343
#endif
344
345
0
    const int rc = sqlite3_prepare_v2(
346
0
        m_poDS->GetDB(), m_poBehavior->m_osSQLCurrent,
347
0
        static_cast<int>(m_poBehavior->m_osSQLCurrent.size()), &m_hStmt,
348
0
        nullptr);
349
350
0
    if (rc == SQLITE_OK)
351
0
        return OGRERR_NONE;
352
353
0
    CPLError(CE_Failure, CPLE_AppDefined,
354
0
             "In ResetStatement(): sqlite3_prepare_v2(%s):\n  %s",
355
0
             m_poBehavior->m_osSQLCurrent.c_str(),
356
0
             sqlite3_errmsg(m_poDS->GetDB()));
357
0
    m_hStmt = nullptr;
358
0
    return OGRERR_FAILURE;
359
0
}
360
361
/************************************************************************/
362
/*                         ISetSpatialFilter()                          */
363
/************************************************************************/
364
365
OGRErr OGRSQLiteSelectLayer::ISetSpatialFilter(int iGeomField,
366
                                               const OGRGeometry *poGeomIn)
367
368
0
{
369
0
    if (!m_bCanReopenBaseDS && iGeomField == 0)
370
0
    {
371
0
        if (!ValidateGeometryFieldIndexForSetSpatialFilter(iGeomField, poGeomIn,
372
0
                                                           true))
373
0
            return OGRERR_FAILURE;
374
        // For a Memory datasource, short-circuit
375
        // OGRSQLiteExecuteSQL::SetSpatialFilter()
376
        // that would try to re-open the Memory datasource, which would fail.
377
0
        return OGRLayer::ISetSpatialFilter(iGeomField, poGeomIn);
378
0
    }
379
0
    else
380
0
    {
381
0
        return m_poBehavior->SetSpatialFilter(iGeomField, poGeomIn);
382
0
    }
383
0
}
384
385
OGRErr OGRSQLiteSelectLayerCommonBehaviour::SetSpatialFilter(
386
    int iGeomField, const OGRGeometry *poGeomIn)
387
388
0
{
389
0
    m_bAllowResetReadingEvenIfIndexAtZero = true;
390
391
0
    int &iGeomFieldFilter = m_poLayer->GetIGeomFieldFilter();
392
0
    iGeomFieldFilter = iGeomField;
393
0
    if (m_poLayer->InstallFilter(poGeomIn))
394
0
    {
395
0
        BuildSQL();
396
397
0
        ResetReading();
398
0
    }
399
400
0
    return OGRERR_NONE;
401
0
}
402
403
/************************************************************************/
404
/*                            GetBaseLayer()                            */
405
/************************************************************************/
406
407
std::pair<OGRLayer *, IOGRSQLiteGetSpatialWhere *>
408
OGRSQLiteSelectLayerCommonBehaviour::GetBaseLayer(size_t &i) const
409
0
{
410
0
    char **papszTokens = CSLTokenizeString(m_osSQLBase.c_str());
411
0
    bool bCanInsertFilter = true;
412
0
    int nCountSelect = 0, nCountFrom = 0, nCountWhere = 0;
413
414
0
    for (int iToken = 0; papszTokens[iToken] != nullptr; iToken++)
415
0
    {
416
0
        if (EQUAL(papszTokens[iToken], "SELECT"))
417
0
            nCountSelect++;
418
0
        else if (EQUAL(papszTokens[iToken], "FROM"))
419
0
            nCountFrom++;
420
0
        else if (EQUAL(papszTokens[iToken], "WHERE"))
421
0
            nCountWhere++;
422
0
        else if (EQUAL(papszTokens[iToken], "UNION") ||
423
0
                 EQUAL(papszTokens[iToken], "JOIN") ||
424
0
                 EQUAL(papszTokens[iToken], "INTERSECT") ||
425
0
                 EQUAL(papszTokens[iToken], "EXCEPT"))
426
0
        {
427
0
            bCanInsertFilter = false;
428
0
        }
429
0
    }
430
0
    CSLDestroy(papszTokens);
431
432
0
    if (!(bCanInsertFilter && nCountSelect == 1 && nCountFrom == 1 &&
433
0
          nCountWhere <= 1))
434
0
    {
435
0
        CPLDebug("SQLITE", "SQL expression too complex to analyse");
436
0
        return std::pair(nullptr, nullptr);
437
0
    }
438
439
0
    size_t nFromPos = m_osSQLBase.ifind(" from ");
440
0
    if (nFromPos == std::string::npos)
441
0
    {
442
0
        return std::pair(nullptr, nullptr);
443
0
    }
444
445
    /* Remove potential quotes around layer name */
446
0
    char chFirst = m_osSQLBase[nFromPos + 6];
447
0
    bool bInQuotes = (chFirst == '\'' || chFirst == '"');
448
0
    CPLString osBaseLayerName;
449
0
    for (i = nFromPos + 6 + (bInQuotes ? 1 : 0); i < m_osSQLBase.size(); i++)
450
0
    {
451
0
        if (m_osSQLBase[i] == chFirst && bInQuotes)
452
0
        {
453
0
            if (i + 1 < m_osSQLBase.size() && m_osSQLBase[i + 1] == chFirst)
454
0
            {
455
0
                osBaseLayerName += m_osSQLBase[i];
456
0
                i++;
457
0
            }
458
0
            else
459
0
            {
460
0
                i++;
461
0
                break;
462
0
            }
463
0
        }
464
0
        else if (m_osSQLBase[i] == ' ' && !bInQuotes)
465
0
            break;
466
0
        else
467
0
            osBaseLayerName += m_osSQLBase[i];
468
0
    }
469
470
0
    std::pair<OGRLayer *, IOGRSQLiteGetSpatialWhere *> oPair;
471
0
    if (strchr(osBaseLayerName, '(') == nullptr &&
472
0
        m_poLayer->GetLayerDefn()->GetGeomFieldCount() != 0)
473
0
    {
474
0
        CPLString osNewUnderlyingTableName;
475
0
        osNewUnderlyingTableName.Printf(
476
0
            "%s(%s)", osBaseLayerName.c_str(),
477
0
            m_poLayer->GetLayerDefn()->GetGeomFieldDefn(0)->GetNameRef());
478
0
        oPair =
479
0
            m_poDS->GetLayerWithGetSpatialWhereByName(osNewUnderlyingTableName);
480
0
    }
481
0
    if (oPair.first == nullptr)
482
0
        oPair = m_poDS->GetLayerWithGetSpatialWhereByName(osBaseLayerName);
483
484
0
    if (oPair.first != nullptr && m_poLayer->GetSpatialRef() != nullptr &&
485
0
        oPair.first->GetSpatialRef() != nullptr &&
486
0
        m_poLayer->GetSpatialRef() != oPair.first->GetSpatialRef() &&
487
0
        !m_poLayer->GetSpatialRef()->IsSame(oPair.first->GetSpatialRef()))
488
0
    {
489
0
        CPLDebug("SQLITE",
490
0
                 "Result layer and base layer don't have the same SRS.");
491
0
        return std::pair(nullptr, nullptr);
492
0
    }
493
494
0
    return oPair;
495
0
}
496
497
/************************************************************************/
498
/*                              BuildSQL()                              */
499
/************************************************************************/
500
501
int OGRSQLiteSelectLayerCommonBehaviour::BuildSQL()
502
503
0
{
504
0
    m_osSQLCurrent = m_osSQLBase;
505
0
    m_bSpatialFilterInSQL = true;
506
507
0
    size_t i = 0;
508
0
    std::pair<OGRLayer *, IOGRSQLiteGetSpatialWhere *> oPair = GetBaseLayer(i);
509
0
    OGRLayer *poBaseLayer = oPair.first;
510
0
    if (poBaseLayer == nullptr)
511
0
    {
512
0
        CPLDebug("SQLITE", "Cannot find base layer");
513
0
        m_bSpatialFilterInSQL = false;
514
0
        return FALSE;
515
0
    }
516
517
0
    CPLString osSpatialWhere;
518
0
    if (m_poLayer->GetFilterGeom() != nullptr)
519
0
    {
520
0
        const char *pszGeomCol =
521
0
            m_poLayer->GetLayerDefn()
522
0
                ->GetGeomFieldDefn(m_poLayer->GetIGeomFieldFilter())
523
0
                ->GetNameRef();
524
0
        int nIdx = poBaseLayer->GetLayerDefn()->GetGeomFieldIndex(pszGeomCol);
525
0
        if (nIdx < 0)
526
0
        {
527
0
            CPLDebug("SQLITE", "Cannot find field %s in base layer",
528
0
                     pszGeomCol);
529
0
            m_bSpatialFilterInSQL = false;
530
0
        }
531
0
        else
532
0
        {
533
0
            osSpatialWhere =
534
0
                oPair.second->GetSpatialWhere(nIdx, m_poLayer->GetFilterGeom());
535
0
            if (osSpatialWhere.empty())
536
0
            {
537
0
                CPLDebug("SQLITE", "Cannot get spatial where clause");
538
0
                m_bSpatialFilterInSQL = false;
539
0
            }
540
0
        }
541
0
    }
542
543
0
    CPLString osCustomWhere;
544
0
    if (!osSpatialWhere.empty())
545
0
    {
546
0
        osCustomWhere = osSpatialWhere;
547
0
    }
548
0
    if (m_poLayer->GetAttrQueryString() != nullptr &&
549
0
        m_poLayer->GetAttrQueryString()[0] != '\0')
550
0
    {
551
0
        if (!osSpatialWhere.empty())
552
0
            osCustomWhere += " AND (";
553
0
        osCustomWhere += m_poLayer->GetAttrQueryString();
554
0
        if (!osSpatialWhere.empty())
555
0
            osCustomWhere += ")";
556
0
    }
557
558
    /* Nothing to do */
559
0
    if (osCustomWhere.empty())
560
0
        return TRUE;
561
562
0
    while (i < m_osSQLBase.size() && m_osSQLBase[i] == ' ')
563
0
        i++;
564
565
0
    if (i < m_osSQLBase.size() &&
566
0
        STARTS_WITH_CI(m_osSQLBase.c_str() + i, "WHERE "))
567
0
    {
568
0
        m_osSQLCurrent = m_osSQLBase.substr(0, i + 6);
569
0
        m_osSQLCurrent += osCustomWhere;
570
0
        m_osSQLCurrent += " AND (";
571
572
0
        size_t nEndOfWhere = m_osSQLBase.ifind(" GROUP ");
573
0
        if (nEndOfWhere == std::string::npos)
574
0
            nEndOfWhere = m_osSQLBase.ifind(" ORDER ");
575
0
        if (nEndOfWhere == std::string::npos)
576
0
            nEndOfWhere = m_osSQLBase.ifind(" LIMIT ");
577
578
0
        if (nEndOfWhere == std::string::npos)
579
0
        {
580
0
            m_osSQLCurrent += m_osSQLBase.substr(i + 6);
581
0
            m_osSQLCurrent += ")";
582
0
        }
583
0
        else
584
0
        {
585
0
            m_osSQLCurrent += m_osSQLBase.substr(i + 6, nEndOfWhere - (i + 6));
586
0
            m_osSQLCurrent += ")";
587
0
            m_osSQLCurrent += m_osSQLBase.substr(nEndOfWhere);
588
0
        }
589
0
    }
590
0
    else if (i < m_osSQLBase.size() &&
591
0
             (STARTS_WITH_CI(m_osSQLBase.c_str() + i, "GROUP ") ||
592
0
              STARTS_WITH_CI(m_osSQLBase.c_str() + i, "ORDER ") ||
593
0
              STARTS_WITH_CI(m_osSQLBase.c_str() + i, "LIMIT ")))
594
0
    {
595
0
        m_osSQLCurrent = m_osSQLBase.substr(0, i);
596
0
        m_osSQLCurrent += " WHERE ";
597
0
        m_osSQLCurrent += osCustomWhere;
598
0
        m_osSQLCurrent += " ";
599
0
        m_osSQLCurrent += m_osSQLBase.substr(i);
600
0
    }
601
0
    else if (i == m_osSQLBase.size())
602
0
    {
603
0
        m_osSQLCurrent = m_osSQLBase.substr(0, i);
604
0
        m_osSQLCurrent += " WHERE ";
605
0
        m_osSQLCurrent += osCustomWhere;
606
0
    }
607
0
    else
608
0
    {
609
0
        CPLDebug("SQLITE", "SQL expression too complex for the driver to "
610
0
                           "insert attribute and/or spatial filter in it");
611
0
        m_bSpatialFilterInSQL = false;
612
0
        return FALSE;
613
0
    }
614
615
0
    return TRUE;
616
0
}
617
618
/************************************************************************/
619
/*                           TestCapability()                           */
620
/************************************************************************/
621
622
int OGRSQLiteSelectLayer::TestCapability(const char *pszCap) const
623
0
{
624
0
    return m_poBehavior->TestCapability(pszCap);
625
0
}
626
627
int OGRSQLiteSelectLayerCommonBehaviour::TestCapability(
628
    const char *pszCap) const
629
630
0
{
631
0
    if (EQUAL(pszCap, OLCFastSpatialFilter))
632
0
    {
633
0
        size_t i = 0;
634
0
        const auto oPair = GetBaseLayer(i);
635
0
        if (oPair.first == nullptr)
636
0
        {
637
0
            CPLDebug("SQLITE", "Cannot find base layer");
638
0
            return FALSE;
639
0
        }
640
641
0
        return oPair.second->HasFastSpatialFilter(0);
642
0
    }
643
0
    else
644
0
        return m_poLayer->BaseTestCapability(pszCap);
645
0
}
646
647
/************************************************************************/
648
/*                             GetExtent()                              */
649
/************************************************************************/
650
651
OGRErr OGRSQLiteSelectLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent,
652
                                        bool bForce)
653
0
{
654
0
    return m_poBehavior->GetExtent(iGeomField, psExtent, bForce);
655
0
}
656
657
OGRErr OGRSQLiteSelectLayerCommonBehaviour::GetExtent(int iGeomField,
658
                                                      OGREnvelope *psExtent,
659
                                                      bool bForce)
660
0
{
661
0
    if (iGeomField < 0 ||
662
0
        iGeomField >= m_poLayer->GetLayerDefn()->GetGeomFieldCount() ||
663
0
        m_poLayer->GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() ==
664
0
            wkbNone)
665
0
    {
666
0
        if (iGeomField != 0)
667
0
        {
668
0
            CPLError(CE_Failure, CPLE_AppDefined,
669
0
                     "Invalid geometry field index : %d", iGeomField);
670
0
        }
671
0
        return OGRERR_FAILURE;
672
0
    }
673
674
    /* Caching of extent by SQL string is interesting to speed-up the */
675
    /* establishment of the WFS GetCapabilities document for a MapServer mapfile
676
     */
677
    /* which has several layers, only differing by scale rules */
678
0
    if (iGeomField == 0)
679
0
    {
680
0
        const OGREnvelope *psCachedExtent =
681
0
            m_poDS->GetEnvelopeFromSQL(m_osSQLBase);
682
0
        if (psCachedExtent)
683
0
        {
684
0
            *psExtent = *psCachedExtent;
685
0
            return OGRERR_NONE;
686
0
        }
687
0
    }
688
689
0
    CPLString osSQLCommand = m_osSQLBase;
690
691
    /* ORDER BY are costly to evaluate and are not necessary to establish */
692
    /* the layer extent. */
693
0
    size_t nOrderByPos = osSQLCommand.ifind(" ORDER BY ");
694
0
    if (osSQLCommand.ifind("SELECT ") == 0 &&
695
0
        osSQLCommand.ifind("SELECT ", 1) ==
696
0
            std::string::npos && /* Ensure there's no sub SELECT that could
697
                                    confuse our heuristics */
698
0
        nOrderByPos != std::string::npos &&
699
0
        osSQLCommand.ifind(" LIMIT ") == std::string::npos &&
700
0
        osSQLCommand.ifind(" UNION ") == std::string::npos &&
701
0
        osSQLCommand.ifind(" INTERSECT ") == std::string::npos &&
702
0
        osSQLCommand.ifind(" EXCEPT ") == std::string::npos)
703
0
    {
704
0
        osSQLCommand.resize(nOrderByPos);
705
706
0
        OGRLayer *poTmpLayer =
707
0
            m_poDS->ExecuteSQL(osSQLCommand.c_str(), nullptr, nullptr);
708
0
        if (poTmpLayer)
709
0
        {
710
0
            OGRErr eErr = poTmpLayer->GetExtent(iGeomField, psExtent, bForce);
711
0
            m_poDS->ReleaseResultSet(poTmpLayer);
712
0
            return eErr;
713
0
        }
714
0
    }
715
716
0
    OGRErr eErr = m_poLayer->BaseGetExtent(iGeomField, psExtent, bForce);
717
0
    if (iGeomField == 0 && eErr == OGRERR_NONE && m_poDS->GetUpdate() == false)
718
0
        m_poDS->SetEnvelopeForSQL(m_osSQLBase, *psExtent);
719
0
    return eErr;
720
0
}