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