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