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 : /************************************************************************/
38 : /* OGRSQLiteSelectLayerCommonBehaviour() */
39 : /************************************************************************/
40 :
41 2324 : OGRSQLiteSelectLayerCommonBehaviour::OGRSQLiteSelectLayerCommonBehaviour(
42 : OGRSQLiteBaseDataSource *poDSIn, IOGRSQLiteSelectLayer *m_poLayerIn,
43 2324 : const CPLString &osSQLIn, bool bEmptyLayerIn)
44 : : m_poDS(poDSIn), m_poLayer(m_poLayerIn), m_osSQLBase(osSQLIn),
45 2324 : m_bEmptyLayer(bEmptyLayerIn), m_osSQLCurrent(osSQLIn)
46 : {
47 2324 : }
48 :
49 : /************************************************************************/
50 : /* OGRSQLiteSelectLayer() */
51 : /************************************************************************/
52 :
53 1565 : OGRSQLiteSelectLayer::OGRSQLiteSelectLayer(
54 : OGRSQLiteDataSource *poDSIn, const CPLString &osSQLIn,
55 : sqlite3_stmt *m_hStmtIn, bool bUseStatementForGetNextFeature,
56 1565 : bool bEmptyLayer, bool bAllowMultipleGeomFieldsIn, bool bCanReopenBaseDS)
57 : : OGRSQLiteLayer(poDSIn),
58 : m_poBehavior(new OGRSQLiteSelectLayerCommonBehaviour(
59 1565 : poDSIn, this, osSQLIn, bEmptyLayer)),
60 1565 : m_bCanReopenBaseDS(bCanReopenBaseDS)
61 : {
62 1565 : m_bAllowMultipleGeomFields = bAllowMultipleGeomFieldsIn;
63 :
64 3130 : std::set<CPLString> aosEmpty;
65 1565 : BuildFeatureDefn("SELECT", true, m_hStmtIn, nullptr, aosEmpty);
66 1565 : SetDescription("SELECT");
67 :
68 1565 : if (bUseStatementForGetNextFeature)
69 : {
70 1219 : m_hStmt = m_hStmtIn;
71 1219 : m_bDoStep = false;
72 :
73 : // Try to extract SRS from first geometry
74 1516 : for (int iField = 0;
75 1516 : !bEmptyLayer && iField < m_poFeatureDefn->GetGeomFieldCount();
76 : iField++)
77 : {
78 : OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
79 297 : m_poFeatureDefn->myGetGeomFieldDefn(iField);
80 297 : if (wkbFlatten(poGeomFieldDefn->GetType()) != wkbUnknown)
81 15 : continue;
82 : const auto nColType =
83 282 : sqlite3_column_type(m_hStmt, poGeomFieldDefn->m_iCol);
84 282 : if (nColType == SQLITE_BLOB)
85 : {
86 : // Is it a Spatialite geometry ?
87 : const GByte *pabyBlob = reinterpret_cast<const GByte *>(
88 171 : sqlite3_column_blob(m_hStmt, poGeomFieldDefn->m_iCol));
89 171 : if (sqlite3_column_bytes(m_hStmt, poGeomFieldDefn->m_iCol) >
90 163 : 39 &&
91 163 : pabyBlob[0] == 0x00 &&
92 492 : (pabyBlob[1] == wkbNDR || pabyBlob[1] == wkbXDR) &&
93 158 : pabyBlob[38] == 0x7C)
94 : {
95 158 : const int eByteOrder = pabyBlob[1];
96 158 : int nSRSId = 0;
97 158 : memcpy(&nSRSId, pabyBlob + 2, 4);
98 : #ifdef CPL_LSB
99 158 : if (eByteOrder != wkbNDR)
100 0 : CPL_SWAP32PTR(&nSRSId);
101 : #else
102 : if (eByteOrder == wkbNDR)
103 : CPL_SWAP32PTR(&nSRSId);
104 : #endif
105 158 : CPLPushErrorHandler(CPLQuietErrorHandler);
106 158 : OGRSpatialReference *poSRS = m_poDS->FetchSRS(nSRSId);
107 158 : CPLPopErrorHandler();
108 158 : if (poSRS != nullptr)
109 : {
110 100 : poGeomFieldDefn->m_nSRSId = nSRSId;
111 100 : poGeomFieldDefn->SetSpatialRef(poSRS);
112 : }
113 : else
114 58 : CPLErrorReset();
115 :
116 158 : continue;
117 : }
118 : }
119 :
120 : #ifdef SQLITE_HAS_COLUMN_METADATA
121 124 : if (iField == 0 &&
122 14 : (nColType == SQLITE_NULL || nColType == SQLITE_BLOB))
123 : {
124 : const char *pszTableName =
125 123 : sqlite3_column_table_name(m_hStmt, poGeomFieldDefn->m_iCol);
126 123 : if (pszTableName != nullptr)
127 : {
128 : CPLErrorStateBackuper oErrorStateBackuper(
129 230 : CPLQuietErrorHandler);
130 : OGRSQLiteLayer *m_poLayer =
131 115 : cpl::down_cast<OGRSQLiteLayer *>(
132 115 : m_poDS->GetLayerByName(pszTableName));
133 230 : if (m_poLayer != nullptr &&
134 115 : m_poLayer->GetLayerDefn()->GetGeomFieldCount() > 0)
135 : {
136 : OGRSQLiteGeomFieldDefn *poSrcGFldDefn =
137 13 : m_poLayer->myGetLayerDefn()->myGetGeomFieldDefn(0);
138 13 : poGeomFieldDefn->m_nSRSId = poSrcGFldDefn->m_nSRSId;
139 13 : poGeomFieldDefn->SetSpatialRef(
140 13 : poSrcGFldDefn->GetSpatialRef());
141 : }
142 : }
143 : }
144 : #endif
145 : }
146 : }
147 : else
148 346 : sqlite3_finalize(m_hStmtIn);
149 1565 : }
150 :
151 : /************************************************************************/
152 : /* ~OGRSQLiteSelectLayer() */
153 : /************************************************************************/
154 :
155 2534 : OGRSQLiteSelectLayer::~OGRSQLiteSelectLayer()
156 : {
157 1564 : delete m_poBehavior;
158 2534 : }
159 :
160 : /************************************************************************/
161 : /* ResetReading() */
162 : /************************************************************************/
163 :
164 341 : void OGRSQLiteSelectLayer::ResetReading()
165 : {
166 341 : return m_poBehavior->ResetReading();
167 : }
168 :
169 804 : void OGRSQLiteSelectLayerCommonBehaviour::ResetReading()
170 : {
171 804 : if (m_poLayer->HasReadFeature() || m_bAllowResetReadingEvenIfIndexAtZero)
172 : {
173 490 : m_poLayer->BaseResetReading();
174 490 : m_bAllowResetReadingEvenIfIndexAtZero = false;
175 : }
176 804 : }
177 :
178 : /************************************************************************/
179 : /* GetNextFeature() */
180 : /************************************************************************/
181 :
182 3427 : OGRFeature *OGRSQLiteSelectLayer::GetNextFeature()
183 : {
184 3427 : return m_poBehavior->GetNextFeature();
185 : }
186 :
187 5418 : OGRFeature *OGRSQLiteSelectLayerCommonBehaviour::GetNextFeature()
188 : {
189 5418 : if (m_bEmptyLayer)
190 286 : return nullptr;
191 :
192 5132 : return m_poLayer->BaseGetNextFeature();
193 : }
194 :
195 : /************************************************************************/
196 : /* OGRGenSQLResultsLayerHasSpecialField() */
197 : /************************************************************************/
198 :
199 287 : static int HasSpecialFields(swq_expr_node *expr, int nMinIndexForSpecialField)
200 : {
201 287 : if (expr->eNodeType == SNT_COLUMN)
202 : {
203 84 : if (expr->table_index == 0)
204 : {
205 85 : return expr->field_index >= nMinIndexForSpecialField &&
206 1 : expr->field_index <
207 85 : nMinIndexForSpecialField + SPECIAL_FIELD_COUNT;
208 : }
209 : }
210 203 : else if (expr->eNodeType == SNT_OPERATION)
211 : {
212 286 : for (int i = 0; i < expr->nSubExprCount; i++)
213 : {
214 191 : if (HasSpecialFields(expr->papoSubExpr[i],
215 191 : nMinIndexForSpecialField))
216 1 : return TRUE;
217 : }
218 : }
219 202 : return FALSE;
220 : }
221 :
222 : /************************************************************************/
223 : /* SetAttributeFilter() */
224 : /************************************************************************/
225 :
226 205 : OGRErr OGRSQLiteSelectLayer::SetAttributeFilter(const char *pszQuery)
227 : {
228 205 : return m_poBehavior->SetAttributeFilter(pszQuery);
229 : }
230 :
231 : OGRErr
232 239 : OGRSQLiteSelectLayerCommonBehaviour::SetAttributeFilter(const char *pszQuery)
233 :
234 : {
235 239 : char *&m_pszAttrQuertyString = m_poLayer->GetAttrQueryString();
236 239 : if (m_pszAttrQuertyString == nullptr && pszQuery == nullptr)
237 55 : return OGRERR_NONE;
238 :
239 184 : CPLFree(m_pszAttrQuertyString);
240 184 : m_pszAttrQuertyString = (pszQuery) ? CPLStrdup(pszQuery) : nullptr;
241 :
242 184 : m_bAllowResetReadingEvenIfIndexAtZero = true;
243 :
244 368 : OGRFeatureQuery oQuery;
245 :
246 184 : CPLPushErrorHandler(CPLQuietErrorHandler);
247 : const bool bHasSpecialFields =
248 96 : (pszQuery != nullptr && pszQuery[0] != '\0' &&
249 376 : oQuery.Compile(m_poLayer->GetLayerDefn(), pszQuery) == OGRERR_NONE &&
250 96 : HasSpecialFields(static_cast<swq_expr_node *>(oQuery.GetSWQExpr()),
251 96 : m_poLayer->GetLayerDefn()->GetFieldCount()));
252 184 : CPLPopErrorHandler();
253 :
254 184 : if (bHasSpecialFields || !BuildSQL())
255 : {
256 2 : return m_poLayer->BaseSetAttributeFilter(pszQuery);
257 : }
258 :
259 182 : ResetReading();
260 :
261 182 : return OGRERR_NONE;
262 : }
263 :
264 : /************************************************************************/
265 : /* GetNextFeature() */
266 : /************************************************************************/
267 :
268 184 : GIntBig OGRSQLiteSelectLayer::GetFeatureCount(int bForce)
269 : {
270 184 : return m_poBehavior->GetFeatureCount(bForce);
271 : }
272 :
273 445 : GIntBig OGRSQLiteSelectLayerCommonBehaviour::GetFeatureCount(int bForce)
274 : {
275 445 : if (m_bEmptyLayer)
276 117 : return 0;
277 :
278 328 : if (m_poLayer->GetFeatureQuery() == nullptr &&
279 328 : STARTS_WITH_CI(m_osSQLCurrent, "SELECT COUNT(*) FROM") &&
280 2 : m_osSQLCurrent.ifind(" GROUP BY ") == std::string::npos &&
281 2 : m_osSQLCurrent.ifind(" UNION ") == std::string::npos &&
282 658 : m_osSQLCurrent.ifind(" INTERSECT ") == std::string::npos &&
283 2 : m_osSQLCurrent.ifind(" EXCEPT ") == std::string::npos)
284 2 : return 1;
285 :
286 326 : if (m_poLayer->GetFeatureQuery() != nullptr ||
287 648 : (m_poLayer->GetFilterGeom() != nullptr && !m_bSpatialFilterInSQL) ||
288 322 : STARTS_WITH_CI(m_osSQLCurrent.c_str(), "PRAGMA table_info("))
289 : {
290 5 : return m_poLayer->BaseGetFeatureCount(bForce);
291 : }
292 :
293 642 : CPLString osFeatureCountSQL("SELECT COUNT(*) FROM (");
294 321 : osFeatureCountSQL += m_osSQLCurrent;
295 321 : osFeatureCountSQL += ")";
296 :
297 321 : CPLDebug("SQLITE", "Running %s", osFeatureCountSQL.c_str());
298 :
299 : /* -------------------------------------------------------------------- */
300 : /* Execute. */
301 : /* -------------------------------------------------------------------- */
302 321 : char *pszErrMsg = nullptr;
303 321 : char **papszResult = nullptr;
304 321 : int nRowCount = 0;
305 321 : int nColCount = 0;
306 321 : int nResult = -1;
307 :
308 321 : if (sqlite3_get_table(m_poDS->GetDB(), osFeatureCountSQL, &papszResult,
309 321 : &nRowCount, &nColCount, &pszErrMsg) != SQLITE_OK)
310 : {
311 43 : CPLDebug("SQLITE", "Error: %s", pszErrMsg);
312 43 : sqlite3_free(pszErrMsg);
313 43 : return m_poLayer->BaseGetFeatureCount(bForce);
314 : }
315 :
316 278 : if (nRowCount == 1 && nColCount == 1)
317 : {
318 278 : nResult = atoi(papszResult[1]);
319 : }
320 :
321 278 : sqlite3_free_table(papszResult);
322 :
323 278 : return nResult;
324 : }
325 :
326 : /************************************************************************/
327 : /* ResetStatement() */
328 : /************************************************************************/
329 :
330 237 : OGRErr OGRSQLiteSelectLayer::ResetStatement()
331 :
332 : {
333 237 : ClearStatement();
334 :
335 237 : m_iNextShapeId = 0;
336 237 : m_bDoStep = true;
337 :
338 : #ifdef DEBUG
339 237 : CPLDebug("OGR_SQLITE", "prepare_v2(%s)",
340 237 : m_poBehavior->m_osSQLCurrent.c_str());
341 : #endif
342 :
343 237 : const int rc = sqlite3_prepare_v2(
344 237 : m_poDS->GetDB(), m_poBehavior->m_osSQLCurrent,
345 237 : static_cast<int>(m_poBehavior->m_osSQLCurrent.size()), &m_hStmt,
346 : nullptr);
347 :
348 237 : if (rc == SQLITE_OK)
349 237 : return OGRERR_NONE;
350 :
351 0 : CPLError(CE_Failure, CPLE_AppDefined,
352 : "In ResetStatement(): sqlite3_prepare_v2(%s):\n %s",
353 0 : m_poBehavior->m_osSQLCurrent.c_str(),
354 0 : sqlite3_errmsg(m_poDS->GetDB()));
355 0 : m_hStmt = nullptr;
356 0 : return OGRERR_FAILURE;
357 : }
358 :
359 : /************************************************************************/
360 : /* SetSpatialFilter() */
361 : /************************************************************************/
362 :
363 171 : void OGRSQLiteSelectLayer::SetSpatialFilter(int iGeomField,
364 : OGRGeometry *poGeomIn)
365 :
366 : {
367 171 : if (!m_bCanReopenBaseDS && iGeomField == 0)
368 : {
369 3 : if (!ValidateGeometryFieldIndexForSetSpatialFilter(iGeomField, poGeomIn,
370 3 : true))
371 1 : return;
372 : // For a Memory datasource, short-circuit
373 : // OGRSQLiteExecuteSQL::SetSpatialFilter()
374 : // that would try to re-open the Memory datasource, which would fail.
375 2 : OGRLayer::SetSpatialFilter(poGeomIn);
376 : }
377 : else
378 : {
379 168 : m_poBehavior->SetSpatialFilter(iGeomField, poGeomIn);
380 : }
381 : }
382 :
383 215 : void OGRSQLiteSelectLayerCommonBehaviour::SetSpatialFilter(
384 : int iGeomField, OGRGeometry *poGeomIn)
385 :
386 : {
387 215 : if (!m_poLayer->ValidateGeometryFieldIndexForSetSpatialFilter(
388 215 : iGeomField, poGeomIn, true))
389 7 : return;
390 :
391 208 : m_bAllowResetReadingEvenIfIndexAtZero = true;
392 :
393 208 : int &iGeomFieldFilter = m_poLayer->GetIGeomFieldFilter();
394 208 : iGeomFieldFilter = iGeomField;
395 208 : if (m_poLayer->InstallFilter(poGeomIn))
396 : {
397 147 : BuildSQL();
398 :
399 147 : ResetReading();
400 : }
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 58 : int OGRSQLiteSelectLayer::TestCapability(const char *pszCap)
623 : {
624 58 : return m_poBehavior->TestCapability(pszCap);
625 : }
626 :
627 84 : int OGRSQLiteSelectLayerCommonBehaviour::TestCapability(const char *pszCap)
628 :
629 : {
630 84 : 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 74 : return m_poLayer->BaseTestCapability(pszCap);
644 : }
645 :
646 : /************************************************************************/
647 : /* GetExtent() */
648 : /************************************************************************/
649 :
650 18 : OGRErr OGRSQLiteSelectLayer::GetExtent(int iGeomField, OGREnvelope *psExtent,
651 : int bForce)
652 : {
653 18 : return m_poBehavior->GetExtent(iGeomField, psExtent, bForce);
654 : }
655 :
656 22 : OGRErr OGRSQLiteSelectLayerCommonBehaviour::GetExtent(int iGeomField,
657 : OGREnvelope *psExtent,
658 : int bForce)
659 : {
660 41 : if (iGeomField < 0 ||
661 38 : iGeomField >= m_poLayer->GetLayerDefn()->GetGeomFieldCount() ||
662 16 : m_poLayer->GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() ==
663 : wkbNone)
664 : {
665 6 : if (iGeomField != 0)
666 : {
667 6 : CPLError(CE_Failure, CPLE_AppDefined,
668 : "Invalid geometry field index : %d", iGeomField);
669 : }
670 6 : 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 : OGRErr eErr;
716 7 : if (iGeomField == 0)
717 7 : eErr = m_poLayer->BaseGetExtent(psExtent, bForce);
718 : else
719 0 : eErr = m_poLayer->BaseGetExtent(iGeomField, psExtent, bForce);
720 7 : if (iGeomField == 0 && eErr == OGRERR_NONE && m_poDS->GetUpdate() == false)
721 5 : m_poDS->SetEnvelopeForSQL(m_osSQLBase, *psExtent);
722 7 : return eErr;
723 : }
|