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