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 2344 : OGRSQLiteSelectLayerCommonBehaviour::OGRSQLiteSelectLayerCommonBehaviour(
42 : OGRSQLiteBaseDataSource *poDSIn, IOGRSQLiteSelectLayer *m_poLayerIn,
43 2344 : const CPLString &osSQLIn, bool bEmptyLayerIn)
44 : : m_poDS(poDSIn), m_poLayer(m_poLayerIn), m_osSQLBase(osSQLIn),
45 2344 : m_bEmptyLayer(bEmptyLayerIn), m_osSQLCurrent(osSQLIn)
46 : {
47 2344 : }
48 :
49 : /************************************************************************/
50 : /* OGRSQLiteSelectLayer() */
51 : /************************************************************************/
52 :
53 1580 : OGRSQLiteSelectLayer::OGRSQLiteSelectLayer(
54 : OGRSQLiteDataSource *poDSIn, const CPLString &osSQLIn,
55 : sqlite3_stmt *m_hStmtIn, bool bUseStatementForGetNextFeature,
56 1580 : bool bEmptyLayer, bool bAllowMultipleGeomFieldsIn, bool bCanReopenBaseDS)
57 : : OGRSQLiteLayer(poDSIn),
58 : m_poBehavior(new OGRSQLiteSelectLayerCommonBehaviour(
59 1580 : poDSIn, this, osSQLIn, bEmptyLayer)),
60 1580 : m_bCanReopenBaseDS(bCanReopenBaseDS)
61 : {
62 1580 : m_bAllowMultipleGeomFields = bAllowMultipleGeomFieldsIn;
63 :
64 3160 : std::set<CPLString> aosEmpty;
65 1580 : BuildFeatureDefn("SELECT", true, m_hStmtIn, nullptr, aosEmpty);
66 1580 : SetDescription("SELECT");
67 :
68 1580 : if (bUseStatementForGetNextFeature)
69 : {
70 1234 : m_hStmt = m_hStmtIn;
71 1234 : m_bDoStep = false;
72 :
73 : // Try to extract SRS from first geometry
74 1532 : for (int iField = 0;
75 1532 : !bEmptyLayer && iField < m_poFeatureDefn->GetGeomFieldCount();
76 : iField++)
77 : {
78 : OGRSQLiteGeomFieldDefn *poGeomFieldDefn =
79 298 : m_poFeatureDefn->myGetGeomFieldDefn(iField);
80 298 : if (wkbFlatten(poGeomFieldDefn->GetType()) != wkbUnknown)
81 16 : 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 1580 : }
150 :
151 : /************************************************************************/
152 : /* ~OGRSQLiteSelectLayer() */
153 : /************************************************************************/
154 :
155 2562 : OGRSQLiteSelectLayer::~OGRSQLiteSelectLayer()
156 : {
157 1579 : delete m_poBehavior;
158 2562 : }
159 :
160 : /************************************************************************/
161 : /* ResetReading() */
162 : /************************************************************************/
163 :
164 343 : void OGRSQLiteSelectLayer::ResetReading()
165 : {
166 343 : return m_poBehavior->ResetReading();
167 : }
168 :
169 806 : void OGRSQLiteSelectLayerCommonBehaviour::ResetReading()
170 : {
171 806 : if (m_poLayer->HasReadFeature() || m_bAllowResetReadingEvenIfIndexAtZero)
172 : {
173 490 : m_poLayer->BaseResetReading();
174 490 : m_bAllowResetReadingEvenIfIndexAtZero = false;
175 : }
176 806 : }
177 :
178 : /************************************************************************/
179 : /* GetNextFeature() */
180 : /************************************************************************/
181 :
182 3467 : OGRFeature *OGRSQLiteSelectLayer::GetNextFeature()
183 : {
184 3467 : return m_poBehavior->GetNextFeature();
185 : }
186 :
187 5460 : OGRFeature *OGRSQLiteSelectLayerCommonBehaviour::GetNextFeature()
188 : {
189 5460 : if (m_bEmptyLayer)
190 286 : return nullptr;
191 :
192 5174 : 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 185 : GIntBig OGRSQLiteSelectLayer::GetFeatureCount(int bForce)
269 : {
270 185 : return m_poBehavior->GetFeatureCount(bForce);
271 : }
272 :
273 449 : GIntBig OGRSQLiteSelectLayerCommonBehaviour::GetFeatureCount(int bForce)
274 : {
275 449 : if (m_bEmptyLayer)
276 120 : return 0;
277 :
278 329 : if (m_poLayer->GetFeatureQuery() == nullptr &&
279 329 : 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 660 : m_osSQLCurrent.ifind(" INTERSECT ") == std::string::npos &&
283 2 : m_osSQLCurrent.ifind(" EXCEPT ") == std::string::npos)
284 2 : return 1;
285 :
286 327 : if (m_poLayer->GetFeatureQuery() != nullptr ||
287 650 : (m_poLayer->GetFilterGeom() != nullptr && !m_bSpatialFilterInSQL) ||
288 323 : STARTS_WITH_CI(m_osSQLCurrent.c_str(), "PRAGMA table_info("))
289 : {
290 5 : return m_poLayer->BaseGetFeatureCount(bForce);
291 : }
292 :
293 644 : CPLString osFeatureCountSQL("SELECT COUNT(*) FROM (");
294 322 : osFeatureCountSQL += m_osSQLCurrent;
295 322 : osFeatureCountSQL += ")";
296 :
297 322 : CPLDebug("SQLITE", "Running %s", osFeatureCountSQL.c_str());
298 :
299 : /* -------------------------------------------------------------------- */
300 : /* Execute. */
301 : /* -------------------------------------------------------------------- */
302 322 : char *pszErrMsg = nullptr;
303 322 : char **papszResult = nullptr;
304 322 : int nRowCount = 0;
305 322 : int nColCount = 0;
306 322 : int nResult = -1;
307 :
308 322 : if (sqlite3_get_table(m_poDS->GetDB(), osFeatureCountSQL, &papszResult,
309 322 : &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 279 : if (nRowCount == 1 && nColCount == 1)
317 : {
318 279 : nResult = atoi(papszResult[1]);
319 : }
320 :
321 279 : sqlite3_free_table(papszResult);
322 :
323 279 : 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 : /* ISetSpatialFilter() */
361 : /************************************************************************/
362 :
363 165 : OGRErr OGRSQLiteSelectLayer::ISetSpatialFilter(int iGeomField,
364 : const OGRGeometry *poGeomIn)
365 :
366 : {
367 165 : if (!m_bCanReopenBaseDS && iGeomField == 0)
368 : {
369 2 : if (!ValidateGeometryFieldIndexForSetSpatialFilter(iGeomField, poGeomIn,
370 2 : true))
371 0 : return OGRERR_FAILURE;
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 : return OGRLayer::ISetSpatialFilter(iGeomField, poGeomIn);
376 : }
377 : else
378 : {
379 163 : return m_poBehavior->SetSpatialFilter(iGeomField, poGeomIn);
380 : }
381 : }
382 :
383 208 : OGRErr OGRSQLiteSelectLayerCommonBehaviour::SetSpatialFilter(
384 : int iGeomField, const OGRGeometry *poGeomIn)
385 :
386 : {
387 208 : m_bAllowResetReadingEvenIfIndexAtZero = true;
388 :
389 208 : int &iGeomFieldFilter = m_poLayer->GetIGeomFieldFilter();
390 208 : iGeomFieldFilter = iGeomField;
391 208 : if (m_poLayer->InstallFilter(poGeomIn))
392 : {
393 147 : BuildSQL();
394 :
395 147 : ResetReading();
396 : }
397 :
398 208 : return OGRERR_NONE;
399 : }
400 :
401 : /************************************************************************/
402 : /* GetBaseLayer() */
403 : /************************************************************************/
404 :
405 : std::pair<OGRLayer *, IOGRSQLiteGetSpatialWhere *>
406 340 : OGRSQLiteSelectLayerCommonBehaviour::GetBaseLayer(size_t &i)
407 : {
408 340 : char **papszTokens = CSLTokenizeString(m_osSQLBase.c_str());
409 340 : bool bCanInsertFilter = true;
410 340 : int nCountSelect = 0, nCountFrom = 0, nCountWhere = 0;
411 :
412 2427 : for (int iToken = 0; papszTokens[iToken] != nullptr; iToken++)
413 : {
414 2087 : if (EQUAL(papszTokens[iToken], "SELECT"))
415 341 : nCountSelect++;
416 1746 : else if (EQUAL(papszTokens[iToken], "FROM"))
417 341 : nCountFrom++;
418 1405 : else if (EQUAL(papszTokens[iToken], "WHERE"))
419 121 : nCountWhere++;
420 1284 : else if (EQUAL(papszTokens[iToken], "UNION") ||
421 1283 : EQUAL(papszTokens[iToken], "JOIN") ||
422 1283 : EQUAL(papszTokens[iToken], "INTERSECT") ||
423 1283 : EQUAL(papszTokens[iToken], "EXCEPT"))
424 : {
425 1 : bCanInsertFilter = false;
426 : }
427 : }
428 340 : CSLDestroy(papszTokens);
429 :
430 340 : if (!(bCanInsertFilter && nCountSelect == 1 && nCountFrom == 1 &&
431 : nCountWhere <= 1))
432 : {
433 1 : CPLDebug("SQLITE", "SQL expression too complex to analyse");
434 1 : return std::pair(nullptr, nullptr);
435 : }
436 :
437 339 : size_t nFromPos = m_osSQLBase.ifind(" from ");
438 339 : if (nFromPos == std::string::npos)
439 : {
440 0 : return std::pair(nullptr, nullptr);
441 : }
442 :
443 : /* Remove potential quotes around layer name */
444 339 : char chFirst = m_osSQLBase[nFromPos + 6];
445 339 : bool bInQuotes = (chFirst == '\'' || chFirst == '"');
446 678 : CPLString osBaseLayerName;
447 2184 : for (i = nFromPos + 6 + (bInQuotes ? 1 : 0); i < m_osSQLBase.size(); i++)
448 : {
449 2060 : if (m_osSQLBase[i] == chFirst && bInQuotes)
450 : {
451 9 : if (i + 1 < m_osSQLBase.size() && m_osSQLBase[i + 1] == chFirst)
452 : {
453 1 : osBaseLayerName += m_osSQLBase[i];
454 1 : i++;
455 : }
456 : else
457 : {
458 8 : i++;
459 8 : break;
460 : }
461 : }
462 2051 : else if (m_osSQLBase[i] == ' ' && !bInQuotes)
463 207 : break;
464 : else
465 1844 : osBaseLayerName += m_osSQLBase[i];
466 : }
467 :
468 339 : std::pair<OGRLayer *, IOGRSQLiteGetSpatialWhere *> oPair;
469 678 : if (strchr(osBaseLayerName, '(') == nullptr &&
470 339 : m_poLayer->GetLayerDefn()->GetGeomFieldCount() != 0)
471 : {
472 336 : CPLString osNewUnderlyingTableName;
473 : osNewUnderlyingTableName.Printf(
474 : "%s(%s)", osBaseLayerName.c_str(),
475 336 : m_poLayer->GetLayerDefn()->GetGeomFieldDefn(0)->GetNameRef());
476 : oPair =
477 336 : m_poDS->GetLayerWithGetSpatialWhereByName(osNewUnderlyingTableName);
478 : }
479 339 : if (oPair.first == nullptr)
480 338 : oPair = m_poDS->GetLayerWithGetSpatialWhereByName(osBaseLayerName);
481 :
482 339 : if (oPair.first != nullptr && m_poLayer->GetSpatialRef() != nullptr &&
483 63 : oPair.first->GetSpatialRef() != nullptr &&
484 708 : m_poLayer->GetSpatialRef() != oPair.first->GetSpatialRef() &&
485 30 : !m_poLayer->GetSpatialRef()->IsSame(oPair.first->GetSpatialRef()))
486 : {
487 0 : CPLDebug("SQLITE",
488 : "Result layer and base layer don't have the same SRS.");
489 0 : return std::pair(nullptr, nullptr);
490 : }
491 :
492 339 : return oPair;
493 : }
494 :
495 : /************************************************************************/
496 : /* BuildSQL() */
497 : /************************************************************************/
498 :
499 330 : int OGRSQLiteSelectLayerCommonBehaviour::BuildSQL()
500 :
501 : {
502 330 : m_osSQLCurrent = m_osSQLBase;
503 330 : m_bSpatialFilterInSQL = true;
504 :
505 330 : size_t i = 0;
506 330 : std::pair<OGRLayer *, IOGRSQLiteGetSpatialWhere *> oPair = GetBaseLayer(i);
507 330 : OGRLayer *poBaseLayer = oPair.first;
508 330 : if (poBaseLayer == nullptr)
509 : {
510 1 : CPLDebug("SQLITE", "Cannot find base layer");
511 1 : m_bSpatialFilterInSQL = false;
512 1 : return FALSE;
513 : }
514 :
515 658 : CPLString osSpatialWhere;
516 329 : if (m_poLayer->GetFilterGeom() != nullptr)
517 : {
518 : const char *pszGeomCol =
519 127 : m_poLayer->GetLayerDefn()
520 127 : ->GetGeomFieldDefn(m_poLayer->GetIGeomFieldFilter())
521 127 : ->GetNameRef();
522 127 : int nIdx = poBaseLayer->GetLayerDefn()->GetGeomFieldIndex(pszGeomCol);
523 127 : if (nIdx < 0)
524 : {
525 0 : CPLDebug("SQLITE", "Cannot find field %s in base layer",
526 : pszGeomCol);
527 0 : m_bSpatialFilterInSQL = false;
528 : }
529 : else
530 : {
531 : osSpatialWhere =
532 127 : oPair.second->GetSpatialWhere(nIdx, m_poLayer->GetFilterGeom());
533 127 : if (osSpatialWhere.empty())
534 : {
535 51 : CPLDebug("SQLITE", "Cannot get spatial where clause");
536 51 : m_bSpatialFilterInSQL = false;
537 : }
538 : }
539 : }
540 :
541 658 : CPLString osCustomWhere;
542 329 : if (!osSpatialWhere.empty())
543 : {
544 76 : osCustomWhere = osSpatialWhere;
545 : }
546 455 : if (m_poLayer->GetAttrQueryString() != nullptr &&
547 126 : m_poLayer->GetAttrQueryString()[0] != '\0')
548 : {
549 126 : if (!osSpatialWhere.empty())
550 20 : osCustomWhere += " AND (";
551 126 : osCustomWhere += m_poLayer->GetAttrQueryString();
552 126 : if (!osSpatialWhere.empty())
553 20 : osCustomWhere += ")";
554 : }
555 :
556 : /* Nothing to do */
557 329 : if (osCustomWhere.empty())
558 147 : return TRUE;
559 :
560 293 : while (i < m_osSQLBase.size() && m_osSQLBase[i] == ' ')
561 111 : i++;
562 :
563 293 : if (i < m_osSQLBase.size() &&
564 111 : STARTS_WITH_CI(m_osSQLBase.c_str() + i, "WHERE "))
565 : {
566 65 : m_osSQLCurrent = m_osSQLBase.substr(0, i + 6);
567 65 : m_osSQLCurrent += osCustomWhere;
568 65 : m_osSQLCurrent += " AND (";
569 :
570 65 : size_t nEndOfWhere = m_osSQLBase.ifind(" GROUP ");
571 65 : if (nEndOfWhere == std::string::npos)
572 50 : nEndOfWhere = m_osSQLBase.ifind(" ORDER ");
573 65 : if (nEndOfWhere == std::string::npos)
574 34 : nEndOfWhere = m_osSQLBase.ifind(" LIMIT ");
575 :
576 65 : if (nEndOfWhere == std::string::npos)
577 : {
578 19 : m_osSQLCurrent += m_osSQLBase.substr(i + 6);
579 19 : m_osSQLCurrent += ")";
580 : }
581 : else
582 : {
583 46 : m_osSQLCurrent += m_osSQLBase.substr(i + 6, nEndOfWhere - (i + 6));
584 46 : m_osSQLCurrent += ")";
585 46 : m_osSQLCurrent += m_osSQLBase.substr(nEndOfWhere);
586 : }
587 : }
588 163 : else if (i < m_osSQLBase.size() &&
589 46 : (STARTS_WITH_CI(m_osSQLBase.c_str() + i, "GROUP ") ||
590 31 : STARTS_WITH_CI(m_osSQLBase.c_str() + i, "ORDER ") ||
591 15 : STARTS_WITH_CI(m_osSQLBase.c_str() + i, "LIMIT ")))
592 : {
593 46 : m_osSQLCurrent = m_osSQLBase.substr(0, i);
594 46 : m_osSQLCurrent += " WHERE ";
595 46 : m_osSQLCurrent += osCustomWhere;
596 46 : m_osSQLCurrent += " ";
597 46 : m_osSQLCurrent += m_osSQLBase.substr(i);
598 : }
599 71 : else if (i == m_osSQLBase.size())
600 : {
601 71 : m_osSQLCurrent = m_osSQLBase.substr(0, i);
602 71 : m_osSQLCurrent += " WHERE ";
603 71 : m_osSQLCurrent += osCustomWhere;
604 : }
605 : else
606 : {
607 0 : CPLDebug("SQLITE", "SQL expression too complex for the driver to "
608 : "insert attribute and/or spatial filter in it");
609 0 : m_bSpatialFilterInSQL = false;
610 0 : return FALSE;
611 : }
612 :
613 182 : return TRUE;
614 : }
615 :
616 : /************************************************************************/
617 : /* TestCapability() */
618 : /************************************************************************/
619 :
620 59 : int OGRSQLiteSelectLayer::TestCapability(const char *pszCap)
621 : {
622 59 : return m_poBehavior->TestCapability(pszCap);
623 : }
624 :
625 85 : int OGRSQLiteSelectLayerCommonBehaviour::TestCapability(const char *pszCap)
626 :
627 : {
628 85 : if (EQUAL(pszCap, OLCFastSpatialFilter))
629 : {
630 10 : size_t i = 0;
631 10 : const auto oPair = GetBaseLayer(i);
632 10 : if (oPair.first == nullptr)
633 : {
634 0 : CPLDebug("SQLITE", "Cannot find base layer");
635 0 : return FALSE;
636 : }
637 :
638 10 : return oPair.second->HasFastSpatialFilter(0);
639 : }
640 : else
641 75 : return m_poLayer->BaseTestCapability(pszCap);
642 : }
643 :
644 : /************************************************************************/
645 : /* GetExtent() */
646 : /************************************************************************/
647 :
648 14 : OGRErr OGRSQLiteSelectLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent,
649 : bool bForce)
650 : {
651 14 : return m_poBehavior->GetExtent(iGeomField, psExtent, bForce);
652 : }
653 :
654 16 : OGRErr OGRSQLiteSelectLayerCommonBehaviour::GetExtent(int iGeomField,
655 : OGREnvelope *psExtent,
656 : bool bForce)
657 : {
658 32 : if (iGeomField < 0 ||
659 32 : iGeomField >= m_poLayer->GetLayerDefn()->GetGeomFieldCount() ||
660 16 : m_poLayer->GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() ==
661 : wkbNone)
662 : {
663 0 : if (iGeomField != 0)
664 : {
665 0 : CPLError(CE_Failure, CPLE_AppDefined,
666 : "Invalid geometry field index : %d", iGeomField);
667 : }
668 0 : return OGRERR_FAILURE;
669 : }
670 :
671 : /* Caching of extent by SQL string is interesting to speed-up the */
672 : /* establishment of the WFS GetCapabilities document for a MapServer mapfile
673 : */
674 : /* which has several layers, only differing by scale rules */
675 16 : if (iGeomField == 0)
676 : {
677 : const OGREnvelope *psCachedExtent =
678 16 : m_poDS->GetEnvelopeFromSQL(m_osSQLBase);
679 16 : if (psCachedExtent)
680 : {
681 5 : *psExtent = *psCachedExtent;
682 5 : return OGRERR_NONE;
683 : }
684 : }
685 :
686 22 : CPLString osSQLCommand = m_osSQLBase;
687 :
688 : /* ORDER BY are costly to evaluate and are not necessary to establish */
689 : /* the layer extent. */
690 11 : size_t nOrderByPos = osSQLCommand.ifind(" ORDER BY ");
691 11 : if (osSQLCommand.ifind("SELECT ") == 0 &&
692 11 : osSQLCommand.ifind("SELECT ", 1) ==
693 11 : std::string::npos && /* Ensure there's no sub SELECT that could
694 : confuse our heuristics */
695 4 : nOrderByPos != std::string::npos &&
696 4 : osSQLCommand.ifind(" LIMIT ") == std::string::npos &&
697 4 : osSQLCommand.ifind(" UNION ") == std::string::npos &&
698 26 : osSQLCommand.ifind(" INTERSECT ") == std::string::npos &&
699 4 : osSQLCommand.ifind(" EXCEPT ") == std::string::npos)
700 : {
701 4 : osSQLCommand.resize(nOrderByPos);
702 :
703 : OGRLayer *poTmpLayer =
704 4 : m_poDS->ExecuteSQL(osSQLCommand.c_str(), nullptr, nullptr);
705 4 : if (poTmpLayer)
706 : {
707 4 : OGRErr eErr = poTmpLayer->GetExtent(iGeomField, psExtent, bForce);
708 4 : m_poDS->ReleaseResultSet(poTmpLayer);
709 4 : return eErr;
710 : }
711 : }
712 :
713 7 : OGRErr eErr = m_poLayer->BaseGetExtent(iGeomField, psExtent, bForce);
714 7 : if (iGeomField == 0 && eErr == OGRERR_NONE && m_poDS->GetUpdate() == false)
715 5 : m_poDS->SetEnvelopeForSQL(m_osSQLBase, *psExtent);
716 7 : return eErr;
717 : }
|