/src/gdal/ogr/ogrsf_frmts/sqlite/ogrsqliteexecutesql.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: OpenGIS Simple Features Reference Implementation |
4 | | * Purpose: Run SQL requests with SQLite SQL engine |
5 | | * Author: Even Rouault, even dot rouault at spatialys.com |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2012-2013, Even Rouault <even dot rouault at spatialys.com> |
9 | | * |
10 | | * SPDX-License-Identifier: MIT |
11 | | ****************************************************************************/ |
12 | | |
13 | | #include "ogr_sqlite.h" |
14 | | #include "ogrsqliteexecutesql.h" |
15 | | #include "ogrsqlitevirtualogr.h" |
16 | | #include "ogrsqliteutility.h" |
17 | | |
18 | | #include <cctype> |
19 | | #include <cstdio> |
20 | | #include <cstring> |
21 | | |
22 | | #include "cpl_conv.h" |
23 | | #include "cpl_error.h" |
24 | | #include "cpl_multiproc.h" |
25 | | #include "cpl_port.h" |
26 | | #include "cpl_string.h" |
27 | | #include "cpl_vsi.h" |
28 | | #include "gdal_priv.h" |
29 | | #include "ogr_api.h" |
30 | | #include "ogr_core.h" |
31 | | #include "ogr_feature.h" |
32 | | #include "ogr_geometry.h" |
33 | | #include "ogr_spatialref.h" |
34 | | #include "sqlite3.h" |
35 | | |
36 | | /************************************************************************/ |
37 | | /* OGR2SQLITEExtractUnquotedString() */ |
38 | | /************************************************************************/ |
39 | | |
40 | | static CPLString OGR2SQLITEExtractUnquotedString(const char **ppszSQLCommand) |
41 | 0 | { |
42 | 0 | CPLString osRet; |
43 | 0 | const char *pszSQLCommand = *ppszSQLCommand; |
44 | 0 | if (*pszSQLCommand == '"' || *pszSQLCommand == '\'') |
45 | 0 | { |
46 | 0 | const char chQuoteChar = *pszSQLCommand; |
47 | 0 | pszSQLCommand++; |
48 | |
|
49 | 0 | while (*pszSQLCommand != '\0') |
50 | 0 | { |
51 | 0 | if (*pszSQLCommand == chQuoteChar && |
52 | 0 | pszSQLCommand[1] == chQuoteChar) |
53 | 0 | { |
54 | 0 | pszSQLCommand++; |
55 | 0 | osRet += chQuoteChar; |
56 | 0 | } |
57 | 0 | else if (*pszSQLCommand == chQuoteChar) |
58 | 0 | { |
59 | 0 | pszSQLCommand++; |
60 | 0 | break; |
61 | 0 | } |
62 | 0 | else |
63 | 0 | osRet += *pszSQLCommand; |
64 | | |
65 | 0 | pszSQLCommand++; |
66 | 0 | } |
67 | 0 | } |
68 | 0 | else |
69 | 0 | { |
70 | 0 | bool bNotATableName = false; |
71 | 0 | char chQuoteChar = 0; |
72 | 0 | int nParenthesisLevel = 0; |
73 | 0 | while (*pszSQLCommand != '\0') |
74 | 0 | { |
75 | 0 | if (*pszSQLCommand == chQuoteChar && |
76 | 0 | pszSQLCommand[1] == chQuoteChar) |
77 | 0 | { |
78 | 0 | osRet += *pszSQLCommand; |
79 | 0 | pszSQLCommand++; |
80 | 0 | } |
81 | 0 | else if (*pszSQLCommand == chQuoteChar) |
82 | 0 | { |
83 | 0 | chQuoteChar = 0; |
84 | 0 | } |
85 | 0 | else if (chQuoteChar == 0) |
86 | 0 | { |
87 | 0 | if (*pszSQLCommand == '(') |
88 | 0 | { |
89 | 0 | bNotATableName = true; |
90 | 0 | nParenthesisLevel++; |
91 | 0 | } |
92 | 0 | else if (*pszSQLCommand == ')') |
93 | 0 | { |
94 | 0 | nParenthesisLevel--; |
95 | 0 | if (nParenthesisLevel < 0) |
96 | 0 | break; |
97 | 0 | } |
98 | 0 | else if (*pszSQLCommand == '"' || *pszSQLCommand == '\'') |
99 | 0 | { |
100 | 0 | chQuoteChar = *pszSQLCommand; |
101 | 0 | } |
102 | 0 | else if (nParenthesisLevel == 0 && |
103 | 0 | (isspace(static_cast<unsigned char>(*pszSQLCommand)) || |
104 | 0 | *pszSQLCommand == '.' || *pszSQLCommand == ',')) |
105 | 0 | { |
106 | 0 | break; |
107 | 0 | } |
108 | 0 | } |
109 | | |
110 | 0 | osRet += *pszSQLCommand; |
111 | 0 | pszSQLCommand++; |
112 | 0 | } |
113 | 0 | if (bNotATableName) |
114 | 0 | osRet.clear(); |
115 | 0 | } |
116 | |
|
117 | 0 | *ppszSQLCommand = pszSQLCommand; |
118 | |
|
119 | 0 | return osRet; |
120 | 0 | } |
121 | | |
122 | | /************************************************************************/ |
123 | | /* OGR2SQLITEExtractLayerDesc() */ |
124 | | /************************************************************************/ |
125 | | |
126 | | static LayerDesc OGR2SQLITEExtractLayerDesc(const char **ppszSQLCommand) |
127 | 0 | { |
128 | 0 | std::string osStr; |
129 | 0 | const char *pszSQLCommand = *ppszSQLCommand; |
130 | 0 | LayerDesc oLayerDesc; |
131 | |
|
132 | 0 | while (isspace(static_cast<unsigned char>(*pszSQLCommand))) |
133 | 0 | pszSQLCommand++; |
134 | |
|
135 | 0 | const char *pszOriginalStrStart = pszSQLCommand; |
136 | 0 | oLayerDesc.osOriginalStr = pszSQLCommand; |
137 | |
|
138 | 0 | osStr = OGR2SQLITEExtractUnquotedString(&pszSQLCommand); |
139 | |
|
140 | 0 | if (*pszSQLCommand == '.') |
141 | 0 | { |
142 | 0 | oLayerDesc.osDSName = osStr; |
143 | 0 | pszSQLCommand++; |
144 | 0 | oLayerDesc.osLayerName = |
145 | 0 | OGR2SQLITEExtractUnquotedString(&pszSQLCommand); |
146 | 0 | } |
147 | 0 | else |
148 | 0 | { |
149 | 0 | oLayerDesc.osLayerName = std::move(osStr); |
150 | 0 | } |
151 | |
|
152 | 0 | oLayerDesc.osOriginalStr.resize(pszSQLCommand - pszOriginalStrStart); |
153 | |
|
154 | 0 | *ppszSQLCommand = pszSQLCommand; |
155 | |
|
156 | 0 | return oLayerDesc; |
157 | 0 | } |
158 | | |
159 | | /************************************************************************/ |
160 | | /* OGR2SQLITEAddLayer() */ |
161 | | /************************************************************************/ |
162 | | |
163 | | static void OGR2SQLITEAddLayer(const char *&pszStart, int &nNum, |
164 | | const char *&pszSQLCommand, |
165 | | std::set<LayerDesc> &oSet, |
166 | | CPLString &osModifiedSQL) |
167 | 0 | { |
168 | 0 | CPLString osTruncated(pszStart); |
169 | 0 | osTruncated.resize(pszSQLCommand - pszStart); |
170 | 0 | osModifiedSQL += osTruncated; |
171 | 0 | pszStart = pszSQLCommand; |
172 | 0 | LayerDesc oLayerDesc = OGR2SQLITEExtractLayerDesc(&pszSQLCommand); |
173 | 0 | bool bInsert = true; |
174 | 0 | if (oLayerDesc.osDSName.empty()) |
175 | 0 | { |
176 | 0 | osTruncated = pszStart; |
177 | 0 | osTruncated.resize(pszSQLCommand - pszStart); |
178 | 0 | osModifiedSQL += osTruncated; |
179 | 0 | } |
180 | 0 | else |
181 | 0 | { |
182 | 0 | std::set<LayerDesc>::iterator oIter = oSet.find(oLayerDesc); |
183 | 0 | if (oIter == oSet.end()) |
184 | 0 | { |
185 | 0 | oLayerDesc.osSubstitutedName = |
186 | 0 | CPLString().Printf("_OGR_%d", nNum++); |
187 | 0 | osModifiedSQL += "'"; |
188 | 0 | osModifiedSQL += oLayerDesc.osSubstitutedName; |
189 | 0 | osModifiedSQL += "'"; |
190 | 0 | } |
191 | 0 | else |
192 | 0 | { |
193 | 0 | osModifiedSQL += (*oIter).osSubstitutedName; |
194 | 0 | bInsert = false; |
195 | 0 | } |
196 | 0 | } |
197 | 0 | if (bInsert) |
198 | 0 | { |
199 | 0 | oSet.insert(std::move(oLayerDesc)); |
200 | 0 | } |
201 | 0 | pszStart = pszSQLCommand; |
202 | 0 | } |
203 | | |
204 | | /************************************************************************/ |
205 | | /* StartsAsSQLITEKeyWord() */ |
206 | | /************************************************************************/ |
207 | | |
208 | | static int StartsAsSQLITEKeyWord(const char *pszStr) |
209 | 0 | { |
210 | 0 | for (const char *pszKeyword : {"WHERE", "GROUP", "ORDER", "JOIN", "UNION", |
211 | 0 | "INTERSECT", "EXCEPT", "LIMIT"}) |
212 | 0 | { |
213 | 0 | if (STARTS_WITH_CI(pszStr, pszKeyword)) |
214 | 0 | return TRUE; |
215 | 0 | } |
216 | 0 | return FALSE; |
217 | 0 | } |
218 | | |
219 | | /************************************************************************/ |
220 | | /* OGR2SQLITEGetPotentialLayerNames() */ |
221 | | /************************************************************************/ |
222 | | |
223 | | static void OGR2SQLITEGetPotentialLayerNamesInternal( |
224 | | const char **ppszSQLCommand, std::set<LayerDesc> &oSetLayers, |
225 | | std::set<CPLString> &oSetSpatialIndex, CPLString &osModifiedSQL, int &nNum) |
226 | 0 | { |
227 | 0 | const char *pszSQLCommand = *ppszSQLCommand; |
228 | 0 | const char *pszStart = pszSQLCommand; |
229 | 0 | char ch = '\0'; |
230 | 0 | int nParenthesisLevel = 0; |
231 | 0 | bool bLookforFTableName = false; |
232 | |
|
233 | 0 | while ((ch = *pszSQLCommand) != '\0') |
234 | 0 | { |
235 | 0 | if (ch == '(') |
236 | 0 | nParenthesisLevel++; |
237 | 0 | else if (ch == ')') |
238 | 0 | { |
239 | 0 | nParenthesisLevel--; |
240 | 0 | if (nParenthesisLevel < 0) |
241 | 0 | { |
242 | 0 | pszSQLCommand++; |
243 | 0 | break; |
244 | 0 | } |
245 | 0 | } |
246 | | |
247 | | /* Skip literals and strings */ |
248 | 0 | if (ch == '\'' || ch == '"') |
249 | 0 | { |
250 | 0 | char chEscapeChar = ch; |
251 | 0 | pszSQLCommand++; |
252 | 0 | while ((ch = *pszSQLCommand) != '\0') |
253 | 0 | { |
254 | 0 | if (ch == chEscapeChar && pszSQLCommand[1] == chEscapeChar) |
255 | 0 | pszSQLCommand++; |
256 | 0 | else if (ch == chEscapeChar) |
257 | 0 | { |
258 | 0 | pszSQLCommand++; |
259 | 0 | break; |
260 | 0 | } |
261 | 0 | pszSQLCommand++; |
262 | 0 | } |
263 | 0 | } |
264 | | |
265 | 0 | else if (STARTS_WITH_CI(pszSQLCommand, "ogr_layer_")) |
266 | 0 | { |
267 | 0 | while (*pszSQLCommand != '\0' && *pszSQLCommand != '(') |
268 | 0 | pszSQLCommand++; |
269 | |
|
270 | 0 | if (*pszSQLCommand != '(') |
271 | 0 | break; |
272 | | |
273 | 0 | pszSQLCommand++; |
274 | 0 | nParenthesisLevel++; |
275 | |
|
276 | 0 | while (isspace(static_cast<unsigned char>(*pszSQLCommand))) |
277 | 0 | pszSQLCommand++; |
278 | |
|
279 | 0 | OGR2SQLITEAddLayer(pszStart, nNum, pszSQLCommand, oSetLayers, |
280 | 0 | osModifiedSQL); |
281 | 0 | } |
282 | | |
283 | 0 | else if (bLookforFTableName && |
284 | 0 | STARTS_WITH_CI(pszSQLCommand, "f_table_name") && |
285 | 0 | (pszSQLCommand[strlen("f_table_name")] == '=' || |
286 | 0 | isspace(static_cast<unsigned char>( |
287 | 0 | pszSQLCommand[strlen("f_table_name")])))) |
288 | 0 | { |
289 | 0 | pszSQLCommand += strlen("f_table_name"); |
290 | |
|
291 | 0 | while (isspace(static_cast<unsigned char>(*pszSQLCommand))) |
292 | 0 | pszSQLCommand++; |
293 | |
|
294 | 0 | if (*pszSQLCommand == '=') |
295 | 0 | { |
296 | 0 | pszSQLCommand++; |
297 | |
|
298 | 0 | while (isspace(static_cast<unsigned char>(*pszSQLCommand))) |
299 | 0 | pszSQLCommand++; |
300 | |
|
301 | 0 | oSetSpatialIndex.insert( |
302 | 0 | OGR2SQLITEExtractUnquotedString(&pszSQLCommand)); |
303 | 0 | } |
304 | |
|
305 | 0 | bLookforFTableName = false; |
306 | 0 | } |
307 | | |
308 | 0 | else if (STARTS_WITH_CI(pszSQLCommand, "FROM") && |
309 | 0 | isspace( |
310 | 0 | static_cast<unsigned char>(pszSQLCommand[strlen("FROM")]))) |
311 | 0 | { |
312 | 0 | pszSQLCommand += strlen("FROM") + 1; |
313 | |
|
314 | 0 | while (isspace(static_cast<unsigned char>(*pszSQLCommand))) |
315 | 0 | pszSQLCommand++; |
316 | |
|
317 | 0 | if (STARTS_WITH_CI(pszSQLCommand, "SpatialIndex") && |
318 | 0 | isspace(static_cast<unsigned char>( |
319 | 0 | pszSQLCommand[strlen("SpatialIndex")]))) |
320 | 0 | { |
321 | 0 | pszSQLCommand += strlen("SpatialIndex") + 1; |
322 | |
|
323 | 0 | bLookforFTableName = true; |
324 | |
|
325 | 0 | continue; |
326 | 0 | } |
327 | | |
328 | 0 | if (*pszSQLCommand == '(') |
329 | 0 | { |
330 | 0 | pszSQLCommand++; |
331 | |
|
332 | 0 | CPLString osTruncated(pszStart); |
333 | 0 | osTruncated.resize(pszSQLCommand - pszStart); |
334 | 0 | osModifiedSQL += osTruncated; |
335 | |
|
336 | 0 | OGR2SQLITEGetPotentialLayerNamesInternal( |
337 | 0 | &pszSQLCommand, oSetLayers, oSetSpatialIndex, osModifiedSQL, |
338 | 0 | nNum); |
339 | |
|
340 | 0 | pszStart = pszSQLCommand; |
341 | 0 | } |
342 | 0 | else |
343 | 0 | OGR2SQLITEAddLayer(pszStart, nNum, pszSQLCommand, oSetLayers, |
344 | 0 | osModifiedSQL); |
345 | |
|
346 | 0 | while (*pszSQLCommand != '\0') |
347 | 0 | { |
348 | 0 | if (isspace(static_cast<unsigned char>(*pszSQLCommand))) |
349 | 0 | { |
350 | 0 | pszSQLCommand++; |
351 | 0 | while (isspace(static_cast<unsigned char>(*pszSQLCommand))) |
352 | 0 | pszSQLCommand++; |
353 | |
|
354 | 0 | if (STARTS_WITH_CI(pszSQLCommand, "AS")) |
355 | 0 | { |
356 | 0 | pszSQLCommand += 2; |
357 | 0 | while ( |
358 | 0 | isspace(static_cast<unsigned char>(*pszSQLCommand))) |
359 | 0 | pszSQLCommand++; |
360 | 0 | } |
361 | | |
362 | | /* Skip alias */ |
363 | 0 | if (*pszSQLCommand != '\0' && *pszSQLCommand != ',') |
364 | 0 | { |
365 | 0 | if (StartsAsSQLITEKeyWord(pszSQLCommand)) |
366 | 0 | break; |
367 | 0 | OGR2SQLITEExtractUnquotedString(&pszSQLCommand); |
368 | 0 | } |
369 | 0 | } |
370 | 0 | else if (*pszSQLCommand == ',') |
371 | 0 | { |
372 | 0 | pszSQLCommand++; |
373 | 0 | while (isspace(static_cast<unsigned char>(*pszSQLCommand))) |
374 | 0 | pszSQLCommand++; |
375 | |
|
376 | 0 | if (*pszSQLCommand == '(') |
377 | 0 | { |
378 | 0 | pszSQLCommand++; |
379 | |
|
380 | 0 | CPLString osTruncated(pszStart); |
381 | 0 | osTruncated.resize(pszSQLCommand - pszStart); |
382 | 0 | osModifiedSQL += osTruncated; |
383 | |
|
384 | 0 | OGR2SQLITEGetPotentialLayerNamesInternal( |
385 | 0 | &pszSQLCommand, oSetLayers, oSetSpatialIndex, |
386 | 0 | osModifiedSQL, nNum); |
387 | |
|
388 | 0 | pszStart = pszSQLCommand; |
389 | 0 | } |
390 | 0 | else |
391 | 0 | OGR2SQLITEAddLayer(pszStart, nNum, pszSQLCommand, |
392 | 0 | oSetLayers, osModifiedSQL); |
393 | 0 | } |
394 | 0 | else |
395 | 0 | break; |
396 | 0 | } |
397 | 0 | } |
398 | 0 | else if (STARTS_WITH_CI(pszSQLCommand, "JOIN") && |
399 | 0 | isspace( |
400 | 0 | static_cast<unsigned char>(pszSQLCommand[strlen("JOIN")]))) |
401 | 0 | { |
402 | 0 | pszSQLCommand += strlen("JOIN") + 1; |
403 | 0 | OGR2SQLITEAddLayer(pszStart, nNum, pszSQLCommand, oSetLayers, |
404 | 0 | osModifiedSQL); |
405 | 0 | } |
406 | 0 | else if (STARTS_WITH_CI(pszSQLCommand, "INTO") && |
407 | 0 | isspace( |
408 | 0 | static_cast<unsigned char>(pszSQLCommand[strlen("INTO")]))) |
409 | 0 | { |
410 | 0 | pszSQLCommand += strlen("INTO") + 1; |
411 | 0 | OGR2SQLITEAddLayer(pszStart, nNum, pszSQLCommand, oSetLayers, |
412 | 0 | osModifiedSQL); |
413 | 0 | } |
414 | 0 | else if (STARTS_WITH_CI(pszSQLCommand, "UPDATE") && |
415 | 0 | isspace(static_cast<unsigned char>( |
416 | 0 | pszSQLCommand[strlen("UPDATE")]))) |
417 | 0 | { |
418 | 0 | pszSQLCommand += strlen("UPDATE") + 1; |
419 | 0 | OGR2SQLITEAddLayer(pszStart, nNum, pszSQLCommand, oSetLayers, |
420 | 0 | osModifiedSQL); |
421 | 0 | } |
422 | 0 | else |
423 | 0 | pszSQLCommand++; |
424 | 0 | } |
425 | |
|
426 | 0 | CPLString osTruncated(pszStart); |
427 | 0 | osTruncated.resize(pszSQLCommand - pszStart); |
428 | 0 | osModifiedSQL += osTruncated; |
429 | |
|
430 | 0 | *ppszSQLCommand = pszSQLCommand; |
431 | 0 | } |
432 | | |
433 | | static void OGR2SQLITEGetPotentialLayerNames( |
434 | | const char *pszSQLCommand, std::set<LayerDesc> &oSetLayers, |
435 | | std::set<CPLString> &oSetSpatialIndex, CPLString &osModifiedSQL) |
436 | 0 | { |
437 | 0 | int nNum = 1; |
438 | 0 | OGR2SQLITEGetPotentialLayerNamesInternal( |
439 | 0 | &pszSQLCommand, oSetLayers, oSetSpatialIndex, osModifiedSQL, nNum); |
440 | 0 | } |
441 | | |
442 | | /************************************************************************/ |
443 | | /* OGRSQLiteGetReferencedLayers() */ |
444 | | /************************************************************************/ |
445 | | |
446 | | std::set<LayerDesc> OGRSQLiteGetReferencedLayers(const char *pszStatement) |
447 | 0 | { |
448 | | /* -------------------------------------------------------------------- */ |
449 | | /* Analyze the statement to determine which tables will be used. */ |
450 | | /* -------------------------------------------------------------------- */ |
451 | 0 | std::set<LayerDesc> oSetLayers; |
452 | 0 | std::set<CPLString> oSetSpatialIndex; |
453 | 0 | CPLString osModifiedSQL; |
454 | 0 | OGR2SQLITEGetPotentialLayerNames(pszStatement, oSetLayers, oSetSpatialIndex, |
455 | 0 | osModifiedSQL); |
456 | |
|
457 | 0 | return oSetLayers; |
458 | 0 | } |
459 | | |
460 | | #ifndef HAVE_SQLITE3EXT_H |
461 | | OGRLayer *OGRSQLiteExecuteSQL(GDALDataset *, const char *, OGRGeometry *, |
462 | | const char *) |
463 | | { |
464 | | CPLError(CE_Failure, CPLE_NotSupported, |
465 | | "SQL SQLite dialect not supported due to GDAL being built " |
466 | | "without sqlite3ext.h header"); |
467 | | return nullptr; |
468 | | } |
469 | | |
470 | | #else |
471 | | |
472 | | /************************************************************************/ |
473 | | /* OGRSQLiteExecuteSQLLayer */ |
474 | | /************************************************************************/ |
475 | | |
476 | | class OGRSQLiteExecuteSQLLayer final : public OGRSQLiteSelectLayer |
477 | | { |
478 | | char *m_pszTmpDBName = nullptr; |
479 | | bool m_bStringsAsUTF8 = false; |
480 | | |
481 | | CPL_DISALLOW_COPY_ASSIGN(OGRSQLiteExecuteSQLLayer) |
482 | | |
483 | | public: |
484 | | OGRSQLiteExecuteSQLLayer(char *pszTmpDBName, OGRSQLiteDataSource *poDS, |
485 | | const CPLString &osSQL, sqlite3_stmt *hStmt, |
486 | | bool bUseStatementForGetNextFeature, |
487 | | bool bEmptyLayer, bool bCanReopenBaseDS, |
488 | | bool bStringsAsUTF8); |
489 | | virtual ~OGRSQLiteExecuteSQLLayer(); |
490 | | |
491 | | int TestCapability(const char *pszCap) override; |
492 | | }; |
493 | | |
494 | | /************************************************************************/ |
495 | | /* OGRSQLiteExecuteSQLLayer() */ |
496 | | /************************************************************************/ |
497 | | |
498 | | OGRSQLiteExecuteSQLLayer::OGRSQLiteExecuteSQLLayer( |
499 | | char *pszTmpDBNameIn, OGRSQLiteDataSource *poDSIn, const CPLString &osSQL, |
500 | | sqlite3_stmt *hStmtIn, bool bUseStatementForGetNextFeature, |
501 | | bool bEmptyLayer, bool bCanReopenBaseDS, bool bStringsAsUTF8) |
502 | 0 | : OGRSQLiteSelectLayer(poDSIn, osSQL, hStmtIn, |
503 | 0 | bUseStatementForGetNextFeature, bEmptyLayer, true, |
504 | 0 | bCanReopenBaseDS), |
505 | 0 | m_pszTmpDBName(pszTmpDBNameIn), m_bStringsAsUTF8(bStringsAsUTF8) |
506 | 0 | { |
507 | 0 | } |
508 | | |
509 | | /************************************************************************/ |
510 | | /* ~OGRSQLiteExecuteSQLLayer() */ |
511 | | /************************************************************************/ |
512 | | |
513 | | OGRSQLiteExecuteSQLLayer::~OGRSQLiteExecuteSQLLayer() |
514 | 0 | { |
515 | | // This is a bit peculiar: we must "finalize" the OGRLayer, since |
516 | | // it has objects that depend on the datasource, that we are just |
517 | | // going to destroy afterwards. The issue here is that we destroy |
518 | | // our own datasource, |
519 | 0 | Finalize(); |
520 | |
|
521 | 0 | delete m_poDS; |
522 | 0 | VSIUnlink(m_pszTmpDBName); |
523 | 0 | CPLFree(m_pszTmpDBName); |
524 | 0 | } |
525 | | |
526 | | /************************************************************************/ |
527 | | /* TestCapability() */ |
528 | | /************************************************************************/ |
529 | | |
530 | | int OGRSQLiteExecuteSQLLayer::TestCapability(const char *pszCap) |
531 | 0 | { |
532 | 0 | if (EQUAL(pszCap, OLCStringsAsUTF8)) |
533 | 0 | return m_bStringsAsUTF8; |
534 | 0 | return OGRSQLiteSelectLayer::TestCapability(pszCap); |
535 | 0 | } |
536 | | |
537 | | /************************************************************************/ |
538 | | /* OGR2SQLITE_IgnoreAllFieldsExceptGeometry() */ |
539 | | /************************************************************************/ |
540 | | |
541 | | #ifdef HAVE_SPATIALITE |
542 | | static void OGR2SQLITE_IgnoreAllFieldsExceptGeometry(OGRLayer *poLayer) |
543 | | { |
544 | | char **papszIgnored = nullptr; |
545 | | papszIgnored = CSLAddString(papszIgnored, "OGR_STYLE"); |
546 | | OGRFeatureDefn *poFeatureDefn = poLayer->GetLayerDefn(); |
547 | | for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++) |
548 | | { |
549 | | papszIgnored = CSLAddString( |
550 | | papszIgnored, poFeatureDefn->GetFieldDefn(i)->GetNameRef()); |
551 | | } |
552 | | poLayer->SetIgnoredFields(const_cast<const char **>(papszIgnored)); |
553 | | CSLDestroy(papszIgnored); |
554 | | } |
555 | | #endif |
556 | | |
557 | | /************************************************************************/ |
558 | | /* OGR2SQLITEDealWithSpatialColumn() */ |
559 | | /************************************************************************/ |
560 | | #if HAVE_SPATIALITE |
561 | | #define WHEN_SPATIALITE(arg) arg |
562 | | #else |
563 | | #define WHEN_SPATIALITE(arg) |
564 | | #endif |
565 | | |
566 | | static int OGR2SQLITEDealWithSpatialColumn( |
567 | | OGRLayer *poLayer, int iGeomCol, const LayerDesc &oLayerDesc, |
568 | | const CPLString &osTableName, OGRSQLiteDataSource *poSQLiteDS, sqlite3 *hDB, |
569 | | bool bSpatialiteDB, const std::set<LayerDesc> &WHEN_SPATIALITE(oSetLayers), |
570 | | const std::set<CPLString> &WHEN_SPATIALITE(oSetSpatialIndex)) |
571 | 0 | { |
572 | 0 | OGRGeomFieldDefn *poGeomField = |
573 | 0 | poLayer->GetLayerDefn()->GetGeomFieldDefn(iGeomCol); |
574 | 0 | CPLString osGeomColRaw; |
575 | 0 | if (iGeomCol == 0) |
576 | 0 | osGeomColRaw = OGR2SQLITE_GetNameForGeometryColumn(poLayer); |
577 | 0 | else |
578 | 0 | osGeomColRaw = poGeomField->GetNameRef(); |
579 | 0 | const char *pszGeomColRaw = osGeomColRaw.c_str(); |
580 | |
|
581 | 0 | CPLString osGeomColEscaped(SQLEscapeLiteral(pszGeomColRaw)); |
582 | 0 | const char *pszGeomColEscaped = osGeomColEscaped.c_str(); |
583 | |
|
584 | 0 | CPLString osLayerNameEscaped(SQLEscapeLiteral(osTableName)); |
585 | 0 | const char *pszLayerNameEscaped = osLayerNameEscaped.c_str(); |
586 | |
|
587 | 0 | CPLString osIdxNameRaw( |
588 | 0 | CPLSPrintf("idx_%s_%s", oLayerDesc.osLayerName.c_str(), pszGeomColRaw)); |
589 | 0 | CPLString osIdxNameEscaped(SQLEscapeName(osIdxNameRaw)); |
590 | | |
591 | | /* Make sure that the SRS is injected in spatial_ref_sys */ |
592 | 0 | const OGRSpatialReference *poSRS = poGeomField->GetSpatialRef(); |
593 | 0 | if (iGeomCol == 0 && poSRS == nullptr) |
594 | 0 | poSRS = poLayer->GetSpatialRef(); |
595 | 0 | int nSRSId = poSQLiteDS->GetUndefinedSRID(); |
596 | 0 | if (poSRS != nullptr) |
597 | 0 | nSRSId = poSQLiteDS->FetchSRSId(poSRS); |
598 | |
|
599 | 0 | CPLString osSQL; |
600 | | #ifdef HAVE_SPATIALITE |
601 | | bool bCreateSpatialIndex = false; |
602 | | #endif |
603 | 0 | if (!bSpatialiteDB) |
604 | 0 | { |
605 | 0 | osSQL.Printf("INSERT INTO geometry_columns (f_table_name, " |
606 | 0 | "f_geometry_column, geometry_format, geometry_type, " |
607 | 0 | "coord_dimension, srid) " |
608 | 0 | "VALUES ('%s','%s','SpatiaLite',%d,%d,%d)", |
609 | 0 | pszLayerNameEscaped, pszGeomColEscaped, |
610 | 0 | static_cast<int>(wkbFlatten(poLayer->GetGeomType())), |
611 | 0 | wkbHasZ(poLayer->GetGeomType()) ? 3 : 2, nSRSId); |
612 | 0 | } |
613 | | #ifdef HAVE_SPATIALITE |
614 | | else |
615 | | { |
616 | | /* We detect the need for creating a spatial index by 2 means : */ |
617 | | |
618 | | /* 1) if there's an explicit reference to a |
619 | | * 'idx_layername_geometrycolumn' */ |
620 | | /* table in the SQL --> old/traditional way of requesting spatial |
621 | | * indices */ |
622 | | /* with spatialite. */ |
623 | | |
624 | | std::set<LayerDesc>::const_iterator oIter2 = oSetLayers.begin(); |
625 | | for (; oIter2 != oSetLayers.end(); ++oIter2) |
626 | | { |
627 | | const LayerDesc &oLayerDescIter = *oIter2; |
628 | | if (EQUAL(oLayerDescIter.osLayerName, osIdxNameRaw)) |
629 | | { |
630 | | bCreateSpatialIndex = true; |
631 | | break; |
632 | | } |
633 | | } |
634 | | |
635 | | /* 2) or if there's a SELECT FROM SpatialIndex WHERE f_table_name = |
636 | | * 'layername' */ |
637 | | if (!bCreateSpatialIndex) |
638 | | { |
639 | | std::set<CPLString>::const_iterator oIter3 = |
640 | | oSetSpatialIndex.begin(); |
641 | | for (; oIter3 != oSetSpatialIndex.end(); ++oIter3) |
642 | | { |
643 | | const CPLString &osNameIter = *oIter3; |
644 | | if (EQUAL(osNameIter, oLayerDesc.osLayerName)) |
645 | | { |
646 | | bCreateSpatialIndex = true; |
647 | | break; |
648 | | } |
649 | | } |
650 | | } |
651 | | |
652 | | if (poSQLiteDS->HasSpatialite4Layout()) |
653 | | { |
654 | | const auto eGeomType = poLayer->GetGeomType(); |
655 | | int nGeomType = eGeomType; |
656 | | int nCoordDimension = 2; |
657 | | if (wkbHasZ(eGeomType)) |
658 | | { |
659 | | nGeomType += 1000; |
660 | | nCoordDimension = 3; |
661 | | } |
662 | | |
663 | | osSQL.Printf("INSERT INTO geometry_columns (f_table_name, " |
664 | | "f_geometry_column, geometry_type, coord_dimension, " |
665 | | "srid, spatial_index_enabled) " |
666 | | "VALUES (Lower('%s'),Lower('%s'),%d ,%d ,%d, %d)", |
667 | | pszLayerNameEscaped, pszGeomColEscaped, nGeomType, |
668 | | nCoordDimension, nSRSId, |
669 | | static_cast<int>(bCreateSpatialIndex)); |
670 | | } |
671 | | else |
672 | | { |
673 | | const char *pszGeometryType = |
674 | | OGRToOGCGeomType(poLayer->GetGeomType()); |
675 | | if (pszGeometryType[0] == '\0') |
676 | | pszGeometryType = "GEOMETRY"; |
677 | | |
678 | | osSQL.Printf("INSERT INTO geometry_columns (f_table_name, " |
679 | | "f_geometry_column, type, coord_dimension, " |
680 | | "srid, spatial_index_enabled) " |
681 | | "VALUES ('%s','%s','%s','%s',%d, %d)", |
682 | | pszLayerNameEscaped, pszGeomColEscaped, |
683 | | pszGeometryType, |
684 | | wkbHasZ(poLayer->GetGeomType()) ? "XYZ" : "XY", nSRSId, |
685 | | static_cast<int>(bCreateSpatialIndex)); |
686 | | } |
687 | | } |
688 | | #endif // HAVE_SPATIALITE |
689 | 0 | char *pszErrMsg = nullptr; |
690 | 0 | int rc = sqlite3_exec(hDB, osSQL.c_str(), nullptr, nullptr, &pszErrMsg); |
691 | 0 | if (pszErrMsg != nullptr) |
692 | 0 | { |
693 | 0 | CPLDebug("SQLITE", "%s -> %s", osSQL.c_str(), pszErrMsg); |
694 | 0 | sqlite3_free(pszErrMsg); |
695 | 0 | } |
696 | |
|
697 | | #ifdef HAVE_SPATIALITE |
698 | | /* -------------------------------------------------------------------- */ |
699 | | /* Should we create a spatial index ?. */ |
700 | | /* -------------------------------------------------------------------- */ |
701 | | if (!bSpatialiteDB || !bCreateSpatialIndex) |
702 | | return rc == SQLITE_OK; |
703 | | |
704 | | CPLDebug("SQLITE", "Create spatial index %s", osIdxNameRaw.c_str()); |
705 | | |
706 | | /* ENABLE_VIRTUAL_OGR_SPATIAL_INDEX is not defined */ |
707 | | #ifdef ENABLE_VIRTUAL_OGR_SPATIAL_INDEX |
708 | | osSQL.Printf( |
709 | | "CREATE VIRTUAL TABLE \"%s\" USING " |
710 | | "VirtualOGRSpatialIndex(%d, '%s', pkid, xmin, xmax, ymin, ymax)", |
711 | | osIdxNameEscaped.c_str(), nExtraDS, |
712 | | SQLEscapeLiteral(oLayerDesc.osLayerName).c_str()); |
713 | | |
714 | | rc = sqlite3_exec(hDB, osSQL.c_str(), NULL, NULL, NULL); |
715 | | if (rc != SQLITE_OK) |
716 | | { |
717 | | CPLDebug("SQLITE", "Error occurred during spatial index creation : %s", |
718 | | sqlite3_errmsg(hDB)); |
719 | | } |
720 | | #else // ENABLE_VIRTUAL_OGR_SPATIAL_INDEX |
721 | | rc = sqlite3_exec(hDB, "BEGIN", nullptr, nullptr, nullptr); |
722 | | |
723 | | osSQL.Printf("CREATE VIRTUAL TABLE \"%s\" " |
724 | | "USING rtree(pkid, xmin, xmax, ymin, ymax)", |
725 | | osIdxNameEscaped.c_str()); |
726 | | |
727 | | if (rc == SQLITE_OK) |
728 | | rc = sqlite3_exec(hDB, osSQL.c_str(), nullptr, nullptr, nullptr); |
729 | | |
730 | | sqlite3_stmt *hStmt = nullptr; |
731 | | if (rc == SQLITE_OK) |
732 | | { |
733 | | const char *pszInsertInto = |
734 | | CPLSPrintf("INSERT INTO \"%s\" (pkid, xmin, xmax, ymin, ymax) " |
735 | | "VALUES (?,?,?,?,?)", |
736 | | osIdxNameEscaped.c_str()); |
737 | | rc = sqlite3_prepare_v2(hDB, pszInsertInto, -1, &hStmt, nullptr); |
738 | | } |
739 | | |
740 | | OGR2SQLITE_IgnoreAllFieldsExceptGeometry(poLayer); |
741 | | poLayer->ResetReading(); |
742 | | |
743 | | OGRFeature *poFeature = nullptr; |
744 | | OGREnvelope sEnvelope; |
745 | | while (rc == SQLITE_OK && |
746 | | (poFeature = poLayer->GetNextFeature()) != nullptr) |
747 | | { |
748 | | OGRGeometry *poGeom = poFeature->GetGeometryRef(); |
749 | | if (poGeom != nullptr && !poGeom->IsEmpty()) |
750 | | { |
751 | | poGeom->getEnvelope(&sEnvelope); |
752 | | sqlite3_bind_int64(hStmt, 1, |
753 | | static_cast<sqlite3_int64>(poFeature->GetFID())); |
754 | | sqlite3_bind_double(hStmt, 2, sEnvelope.MinX); |
755 | | sqlite3_bind_double(hStmt, 3, sEnvelope.MaxX); |
756 | | sqlite3_bind_double(hStmt, 4, sEnvelope.MinY); |
757 | | sqlite3_bind_double(hStmt, 5, sEnvelope.MaxY); |
758 | | rc = sqlite3_step(hStmt); |
759 | | if (rc == SQLITE_OK || rc == SQLITE_DONE) |
760 | | rc = sqlite3_reset(hStmt); |
761 | | } |
762 | | delete poFeature; |
763 | | } |
764 | | |
765 | | poLayer->SetIgnoredFields(nullptr); |
766 | | |
767 | | sqlite3_finalize(hStmt); |
768 | | |
769 | | if (rc == SQLITE_OK) |
770 | | rc = sqlite3_exec(hDB, "COMMIT", nullptr, nullptr, nullptr); |
771 | | else |
772 | | { |
773 | | CPLDebug("SQLITE", "Error occurred during spatial index creation : %s", |
774 | | sqlite3_errmsg(hDB)); |
775 | | rc = sqlite3_exec(hDB, "ROLLBACK", nullptr, nullptr, nullptr); |
776 | | } |
777 | | #endif // ENABLE_VIRTUAL_OGR_SPATIAL_INDEX |
778 | | |
779 | | #endif // HAVE_SPATIALITE |
780 | |
|
781 | 0 | return rc == SQLITE_OK; |
782 | 0 | } |
783 | | |
784 | | /************************************************************************/ |
785 | | /* OGRSQLiteExecuteSQL() */ |
786 | | /************************************************************************/ |
787 | | |
788 | | OGRLayer *OGRSQLiteExecuteSQL(GDALDataset *poDS, const char *pszStatement, |
789 | | OGRGeometry *poSpatialFilter, |
790 | | CPL_UNUSED const char *pszDialect) |
791 | 0 | { |
792 | 0 | while (*pszStatement != '\0' && |
793 | 0 | isspace(static_cast<unsigned char>(*pszStatement))) |
794 | 0 | pszStatement++; |
795 | |
|
796 | 0 | if (STARTS_WITH_CI(pszStatement, "ALTER TABLE ") || |
797 | 0 | STARTS_WITH_CI(pszStatement, "DROP TABLE ") || |
798 | 0 | STARTS_WITH_CI(pszStatement, "CREATE INDEX ") || |
799 | 0 | STARTS_WITH_CI(pszStatement, "DROP INDEX ")) |
800 | 0 | { |
801 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
802 | 0 | "SQL command not supported with SQLite dialect. " |
803 | 0 | "Use OGRSQL dialect instead."); |
804 | 0 | return nullptr; |
805 | 0 | } |
806 | 0 | else if (STARTS_WITH_CI(pszStatement, "CREATE VIRTUAL TABLE ") && |
807 | 0 | CPLTestBool(CPLGetConfigOption( |
808 | 0 | "OGR_SQLITE_DIALECT_ALLOW_CREATE_VIRTUAL_TABLE", "NO"))) |
809 | 0 | { |
810 | | // for ogr_virtualogr.py::ogr_virtualogr_run_sql() only. This is |
811 | | // just a convenient way of testing VirtualOGR() with |
812 | | // CREATE VIRTUAL TABLE ... USING VirtualOGR(...) |
813 | | // but there is no possible use of that given we run that into |
814 | | // an ephemeral database. |
815 | 0 | } |
816 | 0 | else |
817 | 0 | { |
818 | 0 | bool bUnderstoodStatement = false; |
819 | 0 | for (const char *pszKeyword : {"SELECT", "WITH", "EXPLAIN", "INSERT", |
820 | 0 | "UPDATE", "DELETE", "REPLACE"}) |
821 | 0 | { |
822 | 0 | if (STARTS_WITH_CI(pszStatement, pszKeyword) && |
823 | 0 | std::isspace(static_cast<unsigned char>( |
824 | 0 | pszStatement[strlen(pszKeyword)]))) |
825 | 0 | { |
826 | 0 | bUnderstoodStatement = true; |
827 | 0 | break; |
828 | 0 | } |
829 | 0 | } |
830 | 0 | if (!bUnderstoodStatement) |
831 | 0 | { |
832 | 0 | CPLError(CE_Failure, CPLE_NotSupported, "Unsupported SQL command."); |
833 | 0 | return nullptr; |
834 | 0 | } |
835 | 0 | } |
836 | | |
837 | 0 | char *pszTmpDBName = static_cast<char *>(CPLMalloc(256)); |
838 | 0 | snprintf(pszTmpDBName, 256, "%s", VSIMemGenerateHiddenFilename("temp.db")); |
839 | |
|
840 | 0 | OGRSQLiteDataSource *poSQLiteDS = nullptr; |
841 | 0 | bool bSpatialiteDB = false; |
842 | | |
843 | | /* -------------------------------------------------------------------- */ |
844 | | /* Create in-memory sqlite/spatialite DB */ |
845 | | /* -------------------------------------------------------------------- */ |
846 | |
|
847 | | #ifdef HAVE_SPATIALITE |
848 | | |
849 | | /* -------------------------------------------------------------------- */ |
850 | | /* Creating an empty SpatiaLite DB (with spatial_ref_sys populated */ |
851 | | /* has a significant cost. So at the first attempt, let's make */ |
852 | | /* one and cache it for later use. */ |
853 | | /* -------------------------------------------------------------------- */ |
854 | | #if 1 |
855 | | static size_t nEmptyDBSize = 0; |
856 | | static GByte *pabyEmptyDB = nullptr; |
857 | | { |
858 | | static CPLMutex *hMutex = nullptr; |
859 | | CPLMutexHolder oMutexHolder(&hMutex); |
860 | | static bool bTried = false; |
861 | | if (!bTried && CPLTestBool(CPLGetConfigOption( |
862 | | "OGR_SQLITE_DIALECT_USE_SPATIALITE", "YES"))) |
863 | | { |
864 | | bTried = true; |
865 | | char *pszCachedFilename = static_cast<char *>(CPLMalloc(256)); |
866 | | snprintf(pszCachedFilename, 256, "%s", |
867 | | VSIMemGenerateHiddenFilename("reference.db")); |
868 | | char **papszOptions = CSLAddString(nullptr, "SPATIALITE=YES"); |
869 | | OGRSQLiteDataSource *poCachedDS = new OGRSQLiteDataSource(); |
870 | | const int nRet = |
871 | | poCachedDS->Create(pszCachedFilename, papszOptions); |
872 | | CSLDestroy(papszOptions); |
873 | | papszOptions = nullptr; |
874 | | delete poCachedDS; |
875 | | if (nRet) |
876 | | { |
877 | | /* Note: the reference file keeps the ownership of the data, so |
878 | | * that */ |
879 | | /* it gets released with VSICleanupFileManager() */ |
880 | | vsi_l_offset nEmptyDBSizeLarge = 0; |
881 | | pabyEmptyDB = VSIGetMemFileBuffer(pszCachedFilename, |
882 | | &nEmptyDBSizeLarge, FALSE); |
883 | | nEmptyDBSize = static_cast<size_t>(nEmptyDBSizeLarge); |
884 | | } |
885 | | CPLFree(pszCachedFilename); |
886 | | } |
887 | | } |
888 | | |
889 | | /* The following configuration option is useful mostly for debugging/testing |
890 | | */ |
891 | | if (pabyEmptyDB != nullptr && |
892 | | CPLTestBool( |
893 | | CPLGetConfigOption("OGR_SQLITE_DIALECT_USE_SPATIALITE", "YES"))) |
894 | | { |
895 | | GByte *pabyEmptyDBClone = |
896 | | static_cast<GByte *>(VSI_MALLOC_VERBOSE(nEmptyDBSize)); |
897 | | if (pabyEmptyDBClone == nullptr) |
898 | | { |
899 | | CPLFree(pszTmpDBName); |
900 | | return nullptr; |
901 | | } |
902 | | memcpy(pabyEmptyDBClone, pabyEmptyDB, nEmptyDBSize); |
903 | | VSIFCloseL(VSIFileFromMemBuffer(pszTmpDBName, pabyEmptyDBClone, |
904 | | nEmptyDBSize, TRUE)); |
905 | | |
906 | | poSQLiteDS = new OGRSQLiteDataSource(); |
907 | | GDALOpenInfo oOpenInfo(pszTmpDBName, GDAL_OF_VECTOR | GDAL_OF_UPDATE); |
908 | | CPLConfigOptionSetter oSetter("OGR_SQLITE_STATIC_VIRTUAL_OGR", "NO", |
909 | | false); |
910 | | const int nRet = poSQLiteDS->Open(&oOpenInfo); |
911 | | if (!nRet) |
912 | | { |
913 | | /* should not happen really ! */ |
914 | | delete poSQLiteDS; |
915 | | VSIUnlink(pszTmpDBName); |
916 | | CPLFree(pszTmpDBName); |
917 | | return nullptr; |
918 | | } |
919 | | bSpatialiteDB = true; |
920 | | } |
921 | | #else |
922 | | /* No caching version */ |
923 | | poSQLiteDS = new OGRSQLiteDataSource(); |
924 | | char **papszOptions = CSLAddString(NULL, "SPATIALITE=YES"); |
925 | | { |
926 | | CPLConfigOptionSetter oSetter("OGR_SQLITE_STATIC_VIRTUAL_OGR", "NO", |
927 | | false); |
928 | | const int nRet = poSQLiteDS->Create(pszTmpDBName, papszOptions); |
929 | | CSLDestroy(papszOptions); |
930 | | papszOptions = nullptr; |
931 | | if (nRet) |
932 | | { |
933 | | bSpatialiteDB = true; |
934 | | } |
935 | | } |
936 | | #endif |
937 | | |
938 | | else |
939 | | { |
940 | | delete poSQLiteDS; |
941 | | poSQLiteDS = nullptr; |
942 | | #else // HAVE_SPATIALITE |
943 | 0 | if (true) |
944 | 0 | { |
945 | 0 | #endif // HAVE_SPATIALITE |
946 | | |
947 | | // cppcheck-suppress redundantAssignment |
948 | 0 | poSQLiteDS = new OGRSQLiteDataSource(); |
949 | 0 | CPLConfigOptionSetter oSetter("OGR_SQLITE_STATIC_VIRTUAL_OGR", "NO", |
950 | 0 | false); |
951 | 0 | const int nRet = poSQLiteDS->Create(pszTmpDBName, nullptr); |
952 | 0 | if (!nRet) |
953 | 0 | { |
954 | 0 | delete poSQLiteDS; |
955 | 0 | VSIUnlink(pszTmpDBName); |
956 | 0 | CPLFree(pszTmpDBName); |
957 | 0 | return nullptr; |
958 | 0 | } |
959 | 0 | } |
960 | | |
961 | | /* -------------------------------------------------------------------- */ |
962 | | /* Attach the Virtual Table OGR2SQLITE module to it. */ |
963 | | /* -------------------------------------------------------------------- */ |
964 | 0 | OGR2SQLITEModule *poModule = OGR2SQLITE_Setup(poDS, poSQLiteDS); |
965 | 0 | if (!poModule) |
966 | 0 | { |
967 | 0 | delete poSQLiteDS; |
968 | 0 | VSIUnlink(pszTmpDBName); |
969 | 0 | CPLFree(pszTmpDBName); |
970 | 0 | return nullptr; |
971 | 0 | } |
972 | 0 | sqlite3 *hDB = poSQLiteDS->GetDB(); |
973 | | |
974 | | /* -------------------------------------------------------------------- */ |
975 | | /* Analysze the statement to determine which tables will be used. */ |
976 | | /* -------------------------------------------------------------------- */ |
977 | 0 | std::set<LayerDesc> oSetLayers; |
978 | 0 | std::set<CPLString> oSetSpatialIndex; |
979 | 0 | CPLString osModifiedSQL; |
980 | 0 | OGR2SQLITEGetPotentialLayerNames(pszStatement, oSetLayers, oSetSpatialIndex, |
981 | 0 | osModifiedSQL); |
982 | 0 | std::set<LayerDesc>::iterator oIter = oSetLayers.begin(); |
983 | |
|
984 | 0 | if (strcmp(pszStatement, osModifiedSQL.c_str()) != 0) |
985 | 0 | CPLDebug("OGR", "Modified SQL: %s", osModifiedSQL.c_str()); |
986 | 0 | pszStatement = osModifiedSQL.c_str(); /* do not use it anymore */ |
987 | |
|
988 | 0 | const bool bFoundOGRStyle = |
989 | 0 | (osModifiedSQL.ifind("OGR_STYLE") != std::string::npos); |
990 | | |
991 | | /* -------------------------------------------------------------------- */ |
992 | | /* For each of those tables, create a Virtual Table. */ |
993 | | /* -------------------------------------------------------------------- */ |
994 | 0 | OGRLayer *poSingleSrcLayer = nullptr; |
995 | 0 | bool bStringsAsUTF8 = true; |
996 | 0 | for (; oIter != oSetLayers.end(); ++oIter) |
997 | 0 | { |
998 | 0 | const LayerDesc &oLayerDesc = *oIter; |
999 | | /*CPLDebug("OGR", "Layer desc : %s, %s, %s, %s", |
1000 | | oLayerDesc.osOriginalStr.c_str(), |
1001 | | oLayerDesc.osSubstitutedName.c_str(), |
1002 | | oLayerDesc.osDSName.c_str(), |
1003 | | oLayerDesc.osLayerName.c_str());*/ |
1004 | |
|
1005 | 0 | CPLString osSQL; |
1006 | 0 | OGRLayer *poLayer = nullptr; |
1007 | 0 | CPLString osTableName; |
1008 | 0 | int nExtraDS = -1; |
1009 | 0 | if (oLayerDesc.osDSName.empty()) |
1010 | 0 | { |
1011 | 0 | poLayer = poDS->GetLayerByName(oLayerDesc.osLayerName); |
1012 | | /* Might be a false positive (unlikely) */ |
1013 | 0 | if (poLayer == nullptr) |
1014 | 0 | continue; |
1015 | | |
1016 | 0 | osTableName = oLayerDesc.osLayerName; |
1017 | 0 | } |
1018 | 0 | else |
1019 | 0 | { |
1020 | 0 | auto poOtherDS = std::unique_ptr<GDALDataset>( |
1021 | 0 | GDALDataset::Open(oLayerDesc.osDSName, GDAL_OF_VECTOR, nullptr, |
1022 | 0 | nullptr, nullptr)); |
1023 | 0 | if (poOtherDS == nullptr) |
1024 | 0 | { |
1025 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1026 | 0 | "Cannot open datasource '%s'", |
1027 | 0 | oLayerDesc.osDSName.c_str()); |
1028 | 0 | delete poSQLiteDS; |
1029 | 0 | VSIUnlink(pszTmpDBName); |
1030 | 0 | CPLFree(pszTmpDBName); |
1031 | 0 | return nullptr; |
1032 | 0 | } |
1033 | | |
1034 | 0 | poLayer = poOtherDS->GetLayerByName(oLayerDesc.osLayerName); |
1035 | 0 | if (poLayer == nullptr) |
1036 | 0 | { |
1037 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1038 | 0 | "Cannot find layer '%s' in '%s'", |
1039 | 0 | oLayerDesc.osLayerName.c_str(), |
1040 | 0 | oLayerDesc.osDSName.c_str()); |
1041 | 0 | delete poSQLiteDS; |
1042 | 0 | VSIUnlink(pszTmpDBName); |
1043 | 0 | CPLFree(pszTmpDBName); |
1044 | 0 | return nullptr; |
1045 | 0 | } |
1046 | | |
1047 | 0 | osTableName = oLayerDesc.osSubstitutedName; |
1048 | |
|
1049 | 0 | nExtraDS = OGR2SQLITE_AddExtraDS(poModule, poOtherDS.release()); |
1050 | 0 | } |
1051 | | |
1052 | 0 | if (!poLayer->TestCapability(OLCStringsAsUTF8)) |
1053 | 0 | bStringsAsUTF8 = false; |
1054 | |
|
1055 | 0 | if (oSetLayers.size() == 1) |
1056 | 0 | poSingleSrcLayer = poLayer; |
1057 | |
|
1058 | 0 | osSQL.Printf( |
1059 | 0 | "CREATE VIRTUAL TABLE \"%s\" USING VirtualOGR(%d,'%s',%d,%d)", |
1060 | 0 | SQLEscapeName(osTableName).c_str(), nExtraDS, |
1061 | 0 | SQLEscapeLiteral(oLayerDesc.osLayerName).c_str(), |
1062 | 0 | bFoundOGRStyle ? 1 : 0, TRUE /*bExposeOGRNativeData*/); |
1063 | |
|
1064 | 0 | char *pszErrMsg = nullptr; |
1065 | 0 | int rc = sqlite3_exec(hDB, osSQL.c_str(), nullptr, nullptr, &pszErrMsg); |
1066 | 0 | if (rc != SQLITE_OK) |
1067 | 0 | { |
1068 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1069 | 0 | "Cannot create virtual table for layer '%s' : %s", |
1070 | 0 | osTableName.c_str(), pszErrMsg); |
1071 | 0 | sqlite3_free(pszErrMsg); |
1072 | 0 | continue; |
1073 | 0 | } |
1074 | | |
1075 | 0 | for (int i = 0; i < poLayer->GetLayerDefn()->GetGeomFieldCount(); i++) |
1076 | 0 | { |
1077 | 0 | OGR2SQLITEDealWithSpatialColumn(poLayer, i, oLayerDesc, osTableName, |
1078 | 0 | poSQLiteDS, hDB, bSpatialiteDB, |
1079 | 0 | oSetLayers, oSetSpatialIndex); |
1080 | 0 | } |
1081 | 0 | } |
1082 | | |
1083 | | /* -------------------------------------------------------------------- */ |
1084 | | /* Reload, so that virtual tables are recognized */ |
1085 | | /* -------------------------------------------------------------------- */ |
1086 | 0 | poSQLiteDS->ReloadLayers(); |
1087 | | |
1088 | | /* -------------------------------------------------------------------- */ |
1089 | | /* Prepare the statement. */ |
1090 | | /* -------------------------------------------------------------------- */ |
1091 | | /* This will speed-up layer creation */ |
1092 | | /* ORDER BY are costly to evaluate and are not necessary to establish */ |
1093 | | /* the layer definition. */ |
1094 | 0 | bool bUseStatementForGetNextFeature = true; |
1095 | 0 | bool bEmptyLayer = false; |
1096 | |
|
1097 | 0 | sqlite3_stmt *hSQLStmt = nullptr; |
1098 | 0 | int rc = sqlite3_prepare_v2(hDB, pszStatement, -1, &hSQLStmt, nullptr); |
1099 | |
|
1100 | 0 | if (rc != SQLITE_OK) |
1101 | 0 | { |
1102 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1103 | 0 | "In ExecuteSQL(): sqlite3_prepare_v2(%s):\n %s", pszStatement, |
1104 | 0 | sqlite3_errmsg(hDB)); |
1105 | |
|
1106 | 0 | if (hSQLStmt != nullptr) |
1107 | 0 | { |
1108 | 0 | sqlite3_finalize(hSQLStmt); |
1109 | 0 | } |
1110 | |
|
1111 | 0 | delete poSQLiteDS; |
1112 | 0 | VSIUnlink(pszTmpDBName); |
1113 | 0 | CPLFree(pszTmpDBName); |
1114 | |
|
1115 | 0 | return nullptr; |
1116 | 0 | } |
1117 | | |
1118 | | /* -------------------------------------------------------------------- */ |
1119 | | /* Do we get a resultset? */ |
1120 | | /* -------------------------------------------------------------------- */ |
1121 | 0 | rc = sqlite3_step(hSQLStmt); |
1122 | 0 | if (rc != SQLITE_ROW) |
1123 | 0 | { |
1124 | 0 | if (rc != SQLITE_DONE) |
1125 | 0 | { |
1126 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1127 | 0 | "In ExecuteSQL(): sqlite3_step(%s):\n %s", pszStatement, |
1128 | 0 | sqlite3_errmsg(hDB)); |
1129 | |
|
1130 | 0 | sqlite3_finalize(hSQLStmt); |
1131 | |
|
1132 | 0 | delete poSQLiteDS; |
1133 | 0 | VSIUnlink(pszTmpDBName); |
1134 | 0 | CPLFree(pszTmpDBName); |
1135 | |
|
1136 | 0 | return nullptr; |
1137 | 0 | } |
1138 | | |
1139 | 0 | if (!STARTS_WITH_CI(pszStatement, "SELECT ")) |
1140 | 0 | { |
1141 | |
|
1142 | 0 | sqlite3_finalize(hSQLStmt); |
1143 | |
|
1144 | 0 | delete poSQLiteDS; |
1145 | 0 | VSIUnlink(pszTmpDBName); |
1146 | 0 | CPLFree(pszTmpDBName); |
1147 | |
|
1148 | 0 | return nullptr; |
1149 | 0 | } |
1150 | | |
1151 | 0 | bUseStatementForGetNextFeature = false; |
1152 | 0 | bEmptyLayer = true; |
1153 | 0 | } |
1154 | | |
1155 | | /* -------------------------------------------------------------------- */ |
1156 | | /* Create layer. */ |
1157 | | /* -------------------------------------------------------------------- */ |
1158 | | |
1159 | 0 | auto poDrv = poDS->GetDriver(); |
1160 | 0 | const bool bCanReopenBaseDS = |
1161 | 0 | !(poDrv && (EQUAL(poDrv->GetDescription(), "MEM") || |
1162 | 0 | EQUAL(poDrv->GetDescription(), "Memory"))); |
1163 | 0 | OGRSQLiteSelectLayer *poLayer = new OGRSQLiteExecuteSQLLayer( |
1164 | 0 | pszTmpDBName, poSQLiteDS, pszStatement, hSQLStmt, |
1165 | 0 | bUseStatementForGetNextFeature, bEmptyLayer, bCanReopenBaseDS, |
1166 | 0 | bStringsAsUTF8); |
1167 | |
|
1168 | 0 | if (poSpatialFilter != nullptr) |
1169 | 0 | { |
1170 | 0 | const auto nErrorCounter = CPLGetErrorCounter(); |
1171 | 0 | poLayer->SetSpatialFilter(0, poSpatialFilter); |
1172 | 0 | if (CPLGetErrorCounter() > nErrorCounter && |
1173 | 0 | CPLGetLastErrorType() != CE_None) |
1174 | 0 | { |
1175 | 0 | delete poLayer; |
1176 | 0 | return nullptr; |
1177 | 0 | } |
1178 | 0 | } |
1179 | | |
1180 | 0 | if (poSingleSrcLayer != nullptr) |
1181 | 0 | poLayer->SetMetadata(poSingleSrcLayer->GetMetadata("NATIVE_DATA"), |
1182 | 0 | "NATIVE_DATA"); |
1183 | |
|
1184 | 0 | return poLayer; |
1185 | 0 | } |
1186 | | |
1187 | | #endif // HAVE_SQLITE3EXT_H |