Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: SQLite/GeoPackage Translator
4 : * Purpose: Utility functions for OGR SQLite/GeoPackage driver.
5 : * Author: Paul Ramsey, pramsey@boundlessgeo.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2013, Paul Ramsey <pramsey@boundlessgeo.com>
9 : * Copyright (c) 2020, Alessandro Pasotti <elpaso@itopen.it>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_port.h"
15 : #include "ogrsqliteutility.h"
16 :
17 : #include <cstdlib>
18 : #include <string>
19 : #include <iostream>
20 : #include <sstream>
21 :
22 : #include "cpl_error.h"
23 : #include "ogr_p.h"
24 : #include "gdal_priv.h"
25 :
26 15415 : SQLResult::SQLResult(char **result, int nRow, int nCol)
27 15415 : : papszResult(result), nRowCount(nRow), nColCount(nCol)
28 : {
29 15415 : }
30 :
31 30830 : SQLResult::~SQLResult()
32 : {
33 15415 : if (papszResult)
34 : {
35 15415 : sqlite3_free_table(papszResult);
36 : }
37 15415 : }
38 :
39 2 : void SQLResult::LimitRowCount(int nLimit)
40 : {
41 2 : nRowCount = nLimit;
42 2 : }
43 :
44 : /* Runs a SQL command and ignores the result (good for INSERT/UPDATE/CREATE) */
45 28177 : OGRErr SQLCommand(sqlite3 *poDb, const char *pszSQL)
46 : {
47 28177 : CPLAssert(poDb != nullptr);
48 28177 : CPLAssert(pszSQL != nullptr);
49 :
50 28177 : char *pszErrMsg = nullptr;
51 : #ifdef DEBUG_VERBOSE
52 : CPLDebug("GPKG", "exec(%s)", pszSQL);
53 : #endif
54 28177 : int rc = sqlite3_exec(poDb, pszSQL, nullptr, nullptr, &pszErrMsg);
55 :
56 28177 : if (rc != SQLITE_OK)
57 : {
58 7 : CPLError(CE_Failure, CPLE_AppDefined, "sqlite3_exec(%s) failed: %s",
59 7 : pszSQL, pszErrMsg ? pszErrMsg : "");
60 7 : sqlite3_free(pszErrMsg);
61 7 : return OGRERR_FAILURE;
62 : }
63 :
64 28170 : return OGRERR_NONE;
65 : }
66 :
67 15416 : std::unique_ptr<SQLResult> SQLQuery(sqlite3 *poDb, const char *pszSQL)
68 : {
69 15416 : CPLAssert(poDb != nullptr);
70 15416 : CPLAssert(pszSQL != nullptr);
71 :
72 : #ifdef DEBUG_VERBOSE
73 : CPLDebug("GPKG", "get_table(%s)", pszSQL);
74 : #endif
75 :
76 15416 : char **papszResult = nullptr;
77 15416 : char *pszErrMsg = nullptr;
78 : int nRowCount, nColCount;
79 15416 : int rc = sqlite3_get_table(poDb, pszSQL, &(papszResult), &(nRowCount),
80 : &(nColCount), &(pszErrMsg));
81 :
82 15416 : if (rc != SQLITE_OK)
83 : {
84 1 : CPLError(CE_Failure, CPLE_AppDefined,
85 : "sqlite3_get_table(%s) failed: %s", pszSQL, pszErrMsg);
86 1 : sqlite3_free(pszErrMsg);
87 1 : return nullptr;
88 : }
89 :
90 15415 : return std::make_unique<SQLResult>(papszResult, nRowCount, nColCount);
91 : }
92 :
93 105950 : const char *SQLResult::GetValue(int iColNum, int iRowNum) const
94 : {
95 105950 : const int nCols = nColCount;
96 : #ifdef DEBUG
97 105950 : const int nRows = nRowCount;
98 105950 : CPL_IGNORE_RET_VAL(nRows);
99 :
100 105950 : CPLAssert(iColNum >= 0 && iColNum < nCols);
101 105950 : CPLAssert(iRowNum >= 0 && iRowNum < nRows);
102 : #endif
103 105950 : return papszResult[nCols + iRowNum * nCols + iColNum];
104 : }
105 :
106 17993 : int SQLResult::GetValueAsInteger(int iColNum, int iRowNum) const
107 : {
108 17993 : const char *pszValue = GetValue(iColNum, iRowNum);
109 17993 : if (!pszValue)
110 100 : return 0;
111 :
112 17893 : return atoi(pszValue);
113 : }
114 :
115 : /* Returns the first row of first column of SQL as integer */
116 43976 : GIntBig SQLGetInteger64(sqlite3 *poDb, const char *pszSQL, OGRErr *err)
117 : {
118 43976 : CPLAssert(poDb != nullptr);
119 :
120 43976 : sqlite3_stmt *poStmt = nullptr;
121 :
122 : /* Prepare the SQL */
123 : #ifdef DEBUG_VERBOSE
124 : CPLDebug("GPKG", "get(%s)", pszSQL);
125 : #endif
126 43976 : int rc = sqlite3_prepare_v2(poDb, pszSQL, -1, &poStmt, nullptr);
127 43976 : if (rc != SQLITE_OK)
128 : {
129 2 : CPLError(CE_Failure, CPLE_AppDefined,
130 : "sqlite3_prepare_v2(%s) failed: %s", pszSQL,
131 : sqlite3_errmsg(poDb));
132 2 : if (err)
133 1 : *err = OGRERR_FAILURE;
134 2 : return 0;
135 : }
136 :
137 : /* Execute and fetch first row */
138 43974 : rc = sqlite3_step(poStmt);
139 43974 : if (rc != SQLITE_ROW)
140 : {
141 6041 : if (err)
142 1953 : *err = OGRERR_FAILURE;
143 6041 : sqlite3_finalize(poStmt);
144 6041 : return 0;
145 : }
146 :
147 : /* Read the integer from the row */
148 37933 : GIntBig i = sqlite3_column_int64(poStmt, 0);
149 37933 : sqlite3_finalize(poStmt);
150 :
151 37933 : if (err)
152 26432 : *err = OGRERR_NONE;
153 37933 : return i;
154 : }
155 :
156 20540 : int SQLGetInteger(sqlite3 *poDb, const char *pszSQL, OGRErr *err)
157 : {
158 20540 : return static_cast<int>(SQLGetInteger64(poDb, pszSQL, err));
159 : }
160 :
161 : /************************************************************************/
162 : /* SQLUnescape() */
163 : /************************************************************************/
164 :
165 17222 : CPLString SQLUnescape(const char *pszVal)
166 : {
167 17222 : char chQuoteChar = pszVal[0];
168 17222 : if (chQuoteChar != '\'' && chQuoteChar != '"')
169 16764 : return pszVal;
170 :
171 916 : CPLString osRet;
172 458 : pszVal++;
173 3693 : while (*pszVal != '\0')
174 : {
175 3693 : if (*pszVal == chQuoteChar)
176 : {
177 467 : if (pszVal[1] == chQuoteChar)
178 9 : pszVal++;
179 : else
180 458 : break;
181 : }
182 3235 : osRet += *pszVal;
183 3235 : pszVal++;
184 : }
185 458 : return osRet;
186 : }
187 :
188 : /************************************************************************/
189 : /* SQLEscapeLiteral() */
190 : /************************************************************************/
191 :
192 6435 : CPLString SQLEscapeLiteral(const char *pszLiteral)
193 : {
194 6435 : CPLString osVal;
195 70879 : for (int i = 0; pszLiteral[i] != '\0'; i++)
196 : {
197 64444 : if (pszLiteral[i] == '\'')
198 1 : osVal += '\'';
199 64444 : osVal += pszLiteral[i];
200 : }
201 6435 : return osVal;
202 : }
203 :
204 : /************************************************************************/
205 : /* SQLEscapeName() */
206 : /************************************************************************/
207 :
208 233015 : CPLString SQLEscapeName(const char *pszName)
209 : {
210 233015 : CPLString osRet;
211 1854020 : while (*pszName != '\0')
212 : {
213 1621010 : if (*pszName == '"')
214 46 : osRet += "\"\"";
215 : else
216 1620960 : osRet += *pszName;
217 1621010 : pszName++;
218 : }
219 233015 : return osRet;
220 : }
221 :
222 : /************************************************************************/
223 : /* SQLTokenize() */
224 : /************************************************************************/
225 :
226 31 : char **SQLTokenize(const char *pszStr)
227 : {
228 31 : char **papszTokens = nullptr;
229 31 : bool bInQuote = false;
230 31 : char chQuoteChar = '\0';
231 31 : bool bInSpace = true;
232 31 : CPLString osCurrentToken;
233 1191 : while (*pszStr != '\0')
234 : {
235 1160 : if (*pszStr == ' ' && !bInQuote)
236 : {
237 120 : if (!bInSpace)
238 : {
239 108 : papszTokens = CSLAddString(papszTokens, osCurrentToken);
240 108 : osCurrentToken.clear();
241 : }
242 120 : bInSpace = true;
243 : }
244 1040 : else if ((*pszStr == '(' || *pszStr == ')' || *pszStr == ',') &&
245 4 : !bInQuote)
246 : {
247 4 : if (!bInSpace)
248 : {
249 3 : papszTokens = CSLAddString(papszTokens, osCurrentToken);
250 3 : osCurrentToken.clear();
251 : }
252 4 : osCurrentToken.clear();
253 4 : osCurrentToken += *pszStr;
254 4 : papszTokens = CSLAddString(papszTokens, osCurrentToken);
255 4 : osCurrentToken.clear();
256 4 : bInSpace = true;
257 : }
258 1036 : else if (*pszStr == '"' || *pszStr == '\'')
259 : {
260 59 : if (bInQuote && *pszStr == chQuoteChar && pszStr[1] == chQuoteChar)
261 : {
262 8 : osCurrentToken += *pszStr;
263 8 : osCurrentToken += *pszStr;
264 8 : pszStr += 2;
265 8 : continue;
266 : }
267 51 : else if (bInQuote && *pszStr == chQuoteChar)
268 : {
269 22 : osCurrentToken += *pszStr;
270 22 : papszTokens = CSLAddString(papszTokens, osCurrentToken);
271 22 : osCurrentToken.clear();
272 22 : bInSpace = true;
273 22 : bInQuote = false;
274 22 : chQuoteChar = '\0';
275 : }
276 29 : else if (bInQuote)
277 : {
278 7 : osCurrentToken += *pszStr;
279 : }
280 : else
281 : {
282 22 : chQuoteChar = *pszStr;
283 22 : osCurrentToken.clear();
284 22 : osCurrentToken += chQuoteChar;
285 22 : bInQuote = true;
286 22 : bInSpace = false;
287 : }
288 : }
289 : else
290 : {
291 977 : osCurrentToken += *pszStr;
292 977 : bInSpace = false;
293 : }
294 1152 : pszStr++;
295 : }
296 :
297 31 : if (!osCurrentToken.empty())
298 15 : papszTokens = CSLAddString(papszTokens, osCurrentToken);
299 :
300 62 : return papszTokens;
301 : }
302 :
303 : /************************************************************************/
304 : /* SQLGetUniqueFieldUCConstraints() */
305 : /************************************************************************/
306 :
307 : /* Return set of field names (in upper case) that have a UNIQUE constraint,
308 : * only on that single column.
309 : */
310 :
311 1481 : std::set<std::string> SQLGetUniqueFieldUCConstraints(
312 : sqlite3 *poDb, const char *pszTableName,
313 : const std::vector<SQLSqliteMasterContent> &sqliteMasterContent)
314 : {
315 : // set names (in upper case) of fields with unique constraint
316 1481 : std::set<std::string> uniqueFieldsUC;
317 :
318 : // Unique fields detection
319 2962 : const std::string upperTableName{CPLString(pszTableName).toupper()};
320 2962 : std::string tableDefinition;
321 :
322 1481 : if (sqliteMasterContent.empty())
323 : {
324 1479 : char *pszTableDefinitionSQL = sqlite3_mprintf(
325 : "SELECT sql, type FROM sqlite_master "
326 : "WHERE type IN ('table', 'view') AND UPPER(name)='%q'",
327 : upperTableName.c_str());
328 1479 : auto oResultTable = SQLQuery(poDb, pszTableDefinitionSQL);
329 1479 : sqlite3_free(pszTableDefinitionSQL);
330 :
331 1479 : if (!oResultTable || oResultTable->RowCount() == 0)
332 : {
333 2 : if (oResultTable)
334 2 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find table %s",
335 : pszTableName);
336 :
337 2 : return uniqueFieldsUC;
338 : }
339 1477 : if (std::string(oResultTable->GetValue(1, 0)) == "view")
340 : {
341 1 : return uniqueFieldsUC;
342 : }
343 1476 : tableDefinition = oResultTable->GetValue(0, 0);
344 : }
345 : else
346 : {
347 107 : for (const auto &row : sqliteMasterContent)
348 : {
349 142 : if (row.osType == "table" &&
350 142 : CPLString(row.osTableName).toupper() == upperTableName)
351 : {
352 2 : tableDefinition = row.osSQL;
353 2 : break;
354 : }
355 105 : else if (row.osType == "view" &&
356 105 : CPLString(row.osTableName).toupper() == upperTableName)
357 : {
358 0 : return uniqueFieldsUC;
359 : }
360 : }
361 2 : if (tableDefinition.empty())
362 : {
363 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find table %s",
364 : pszTableName);
365 :
366 0 : return uniqueFieldsUC;
367 : }
368 : }
369 :
370 : // Parses strings like "colum_name1" KEYWORD1 KEYWORD2 'some string',
371 : // `column_name2`,"column_name3"
372 : const auto GetNextToken =
373 1293 : [](const std::string &osStr, size_t &pos, bool keepQuotes)
374 : {
375 1293 : if (pos >= osStr.size())
376 160 : return std::string();
377 1133 : pos = osStr.find_first_not_of(" \t\n\r", pos);
378 1133 : if (pos == std::string::npos)
379 1 : return std::string();
380 :
381 2264 : std::string osToken;
382 1132 : if (osStr[pos] == '"' || osStr[pos] == '\'' || osStr[pos] == '`')
383 : {
384 168 : const char chQuoteChar = osStr[pos];
385 168 : if (keepQuotes)
386 81 : osToken += chQuoteChar;
387 168 : ++pos;
388 1611 : while (pos < osStr.size())
389 : {
390 1611 : if (osStr[pos] == chQuoteChar)
391 : {
392 168 : if (pos + 1 < osStr.size() && osStr[pos + 1] == chQuoteChar)
393 : {
394 0 : osToken += chQuoteChar;
395 0 : pos += 2;
396 : }
397 : else
398 : {
399 168 : if (keepQuotes)
400 81 : osToken += chQuoteChar;
401 168 : pos++;
402 168 : break;
403 : }
404 : }
405 : else
406 : {
407 1443 : osToken += osStr[pos];
408 1443 : pos++;
409 : }
410 : }
411 : }
412 964 : else if (osStr[pos] == ',' || osStr[pos] == '(' || osStr[pos] == ')')
413 : {
414 246 : osToken = osStr[pos];
415 246 : pos++;
416 : }
417 : else
418 : {
419 718 : size_t pos2 = osStr.find_first_of(") \t\n\r,", pos);
420 718 : if (pos2 == std::string::npos)
421 46 : osToken = osStr.substr(pos);
422 : else
423 672 : osToken = osStr.substr(pos, pos2 - pos);
424 718 : pos = pos2;
425 : }
426 1132 : return osToken;
427 : };
428 :
429 : // Parses CREATE TABLE definition for column UNIQUE keywords
430 : {
431 1478 : const auto nPosStart = tableDefinition.find('(');
432 1478 : const auto nPosEnd = tableDefinition.rfind(')');
433 1478 : if (nPosStart != std::string::npos && nPosEnd != std::string::npos &&
434 2956 : nPosEnd > nPosStart &&
435 2956 : CPLString(tableDefinition).toupper().find("UNIQUE") !=
436 : std::string::npos)
437 : {
438 : tableDefinition =
439 45 : tableDefinition.substr(nPosStart + 1, nPosEnd - nPosStart - 1);
440 45 : size_t pos = 0;
441 45 : bool bHasConstraint = false;
442 : while (true)
443 : {
444 285 : size_t posBackup = pos;
445 285 : if (EQUAL(
446 : GetNextToken(tableDefinition, posBackup, true).c_str(),
447 : "CONSTRAINT"))
448 : {
449 1 : bHasConstraint = true;
450 1 : break;
451 : }
452 :
453 : const std::string osColName =
454 284 : GetNextToken(tableDefinition, pos, false);
455 284 : if (osColName.empty())
456 : {
457 44 : break;
458 : }
459 : while (true)
460 : {
461 : const std::string osToken =
462 641 : GetNextToken(tableDefinition, pos, true);
463 641 : if (osToken.empty() || osToken == ",")
464 240 : break;
465 401 : if (EQUAL(osToken.c_str(), "UNIQUE"))
466 : {
467 29 : uniqueFieldsUC.insert(CPLString(osColName).toupper());
468 : }
469 401 : }
470 240 : }
471 :
472 : // Process https://www.sqlite.org/syntax/table-constraint.html
473 45 : if (bHasConstraint)
474 : {
475 : while (true)
476 : {
477 3 : if (!EQUAL(GetNextToken(tableDefinition, pos, true).c_str(),
478 : "CONSTRAINT"))
479 : {
480 1 : break;
481 : }
482 :
483 : const std::string osConstraintName =
484 3 : GetNextToken(tableDefinition, pos, false);
485 3 : if (osConstraintName.empty())
486 : {
487 0 : break;
488 : }
489 :
490 : const std::string osConstraintType =
491 3 : GetNextToken(tableDefinition, pos, true);
492 3 : if (osConstraintType.empty())
493 : {
494 0 : break;
495 : }
496 :
497 3 : if (EQUAL(osConstraintType.c_str(), "UNIQUE"))
498 : {
499 : std::string osToken =
500 2 : GetNextToken(tableDefinition, pos, true);
501 2 : if (osToken != "(")
502 0 : break;
503 :
504 : const std::string osColName =
505 2 : GetNextToken(tableDefinition, pos, false);
506 2 : osToken = GetNextToken(tableDefinition, pos, true);
507 2 : if (osToken == ")")
508 : {
509 : // Only takes into account single column unique constraint
510 : uniqueFieldsUC.insert(
511 1 : CPLString(osColName).toupper());
512 : }
513 : else
514 : {
515 : // Skip tokens until ')'
516 1 : if (!osToken.empty())
517 : {
518 1 : do
519 : {
520 4 : osToken = GetNextToken(tableDefinition, pos,
521 2 : true);
522 2 : } while (!osToken.empty() && osToken != ")");
523 : }
524 1 : if (osToken.empty())
525 0 : break;
526 : }
527 2 : osToken = GetNextToken(tableDefinition, pos, true);
528 2 : if (osToken != ",")
529 1 : break;
530 : }
531 : else
532 : {
533 : // Skip ignored constraint types by looking for the
534 : // next "," token, that is not inside parenthesis.
535 1 : int nCountParenthesis = 0;
536 1 : std::string osToken;
537 : while (true)
538 : {
539 6 : osToken = GetNextToken(tableDefinition, pos, true);
540 6 : if (osToken.empty())
541 0 : break;
542 6 : if (nCountParenthesis == 0 && osToken == ",")
543 1 : break;
544 5 : else if (osToken == "(")
545 1 : nCountParenthesis++;
546 4 : else if (osToken == ")")
547 : {
548 1 : nCountParenthesis--;
549 1 : if (nCountParenthesis < 0)
550 : {
551 0 : break;
552 : }
553 : }
554 : }
555 1 : if (!(nCountParenthesis == 0 && osToken == ","))
556 0 : break;
557 : }
558 2 : }
559 : }
560 : }
561 : }
562 :
563 : // Search indexes:
564 :
565 : const auto ProcessIndexDefinition =
566 115 : [&uniqueFieldsUC, &GetNextToken](const std::string &indexDefinitionIn)
567 : {
568 29 : const auto nPosStart = indexDefinitionIn.find('(');
569 29 : const auto nPosEnd = indexDefinitionIn.rfind(')');
570 29 : if (nPosStart != std::string::npos && nPosEnd != std::string::npos &&
571 : nPosEnd > nPosStart)
572 : {
573 : std::string indexDefinitionMod = indexDefinitionIn.substr(
574 58 : nPosStart + 1, nPosEnd - nPosStart - 1);
575 29 : size_t pos = 0;
576 : const std::string osColName =
577 58 : GetNextToken(indexDefinitionMod, pos, false);
578 : // Only matches index on single columns
579 29 : if (GetNextToken(indexDefinitionMod, pos, false).empty())
580 : {
581 28 : uniqueFieldsUC.insert(CPLString(osColName).toupper());
582 : }
583 : }
584 29 : };
585 :
586 1478 : if (sqliteMasterContent.empty())
587 : {
588 1476 : char *pszTableDefinitionSQL = sqlite3_mprintf(
589 : "SELECT sql FROM sqlite_master WHERE type='index' AND"
590 : " UPPER(tbl_name)='%q' AND UPPER(sql) "
591 : "LIKE 'CREATE UNIQUE INDEX%%'",
592 : upperTableName.c_str());
593 2952 : auto oResultTable = SQLQuery(poDb, pszTableDefinitionSQL);
594 1476 : sqlite3_free(pszTableDefinitionSQL);
595 :
596 1476 : if (!oResultTable)
597 : {
598 0 : CPLError(CE_Failure, CPLE_AppDefined,
599 : "Error searching indexes for table %s", pszTableName);
600 : }
601 1476 : else if (oResultTable->RowCount() >= 0)
602 : {
603 1503 : for (int rowCnt = 0; rowCnt < oResultTable->RowCount(); ++rowCnt)
604 : {
605 54 : std::string indexDefinition{oResultTable->GetValue(0, rowCnt)};
606 27 : ProcessIndexDefinition(indexDefinition);
607 : }
608 : }
609 : }
610 : else
611 : {
612 116 : for (const auto &row : sqliteMasterContent)
613 : {
614 58 : if (row.osType == "index" &&
615 172 : CPLString(row.osTableName).toupper() == upperTableName &&
616 4 : STARTS_WITH_CI(row.osSQL.c_str(), "CREATE UNIQUE INDEX"))
617 : {
618 4 : std::string indexDefinition = row.osSQL;
619 2 : ProcessIndexDefinition(indexDefinition);
620 : }
621 : }
622 : }
623 :
624 1478 : return uniqueFieldsUC;
625 : }
626 :
627 : /************************************************************************/
628 : /* OGRSQLiteRTreeRequiresTrustedSchemaOn() */
629 : /************************************************************************/
630 :
631 : /** Whether the use of a RTree in triggers or views requires trusted_schema
632 : * PRAGMA to be set to ON */
633 958 : bool OGRSQLiteRTreeRequiresTrustedSchemaOn()
634 : {
635 43 : static bool b = []()
636 : {
637 43 : sqlite3 *hDB = nullptr;
638 : int rc =
639 43 : sqlite3_open_v2(":memory:", &hDB, SQLITE_OPEN_READWRITE, nullptr);
640 43 : if (rc != SQLITE_OK)
641 : {
642 0 : CPLError(CE_Failure, CPLE_AppDefined,
643 : "sqlite3_open_v2(:memory:) failed");
644 0 : sqlite3_close(hDB);
645 0 : return false;
646 : }
647 43 : rc = sqlite3_exec(hDB,
648 : "CREATE VIRTUAL TABLE foo_rtree USING rtree(id, "
649 : "minx, miny, maxx, maxy);",
650 : nullptr, nullptr, nullptr);
651 43 : if (rc != SQLITE_OK)
652 : {
653 0 : CPLError(CE_Failure, CPLE_AppDefined,
654 : "CREATE VIRTUAL TABLE foo_rtree failed");
655 0 : sqlite3_close(hDB);
656 0 : return false;
657 : }
658 43 : rc = sqlite3_exec(hDB, "CREATE VIEW v AS SELECT * FROM foo_rtree;",
659 : nullptr, nullptr, nullptr);
660 43 : if (rc != SQLITE_OK)
661 : {
662 0 : CPLError(CE_Failure, CPLE_AppDefined,
663 : "CREATE VIEW v AS SELECT * FROM foo_rtree failed");
664 0 : sqlite3_close(hDB);
665 0 : return false;
666 : }
667 : // Try to read the virtual table from a view. As of today (sqlite 3.43.1)
668 : // this require trusted_schema = ON
669 43 : rc = sqlite3_exec(hDB, "SELECT * FROM v", nullptr, nullptr, nullptr);
670 43 : bool bRequiresTrustedSchemaOn = false;
671 43 : if (rc != SQLITE_OK)
672 : {
673 43 : CPL_IGNORE_RET_VAL(sqlite3_exec(hDB, "PRAGMA trusted_schema = ON",
674 : nullptr, nullptr, nullptr));
675 : rc =
676 43 : sqlite3_exec(hDB, "SELECT * FROM v", nullptr, nullptr, nullptr);
677 43 : if (rc == SQLITE_OK)
678 43 : bRequiresTrustedSchemaOn = true;
679 : }
680 43 : sqlite3_close(hDB);
681 43 : return bRequiresTrustedSchemaOn;
682 958 : }();
683 958 : return b;
684 : }
685 :
686 : /************************************************************************/
687 : /* OGRSQLiteIsSpatialFunctionReturningGeometry() */
688 : /************************************************************************/
689 :
690 2208 : bool OGRSQLiteIsSpatialFunctionReturningGeometry(const char *pszName)
691 : {
692 2208 : const char *const apszFunctions[] = {
693 : "SetSRID(",
694 : "IsValidDetail(",
695 : "Boundary(",
696 : "Envelope(",
697 : "ST_Expand(",
698 : "ST_Reverse(",
699 : "ST_ForceLHR(",
700 : "ST_ForcePolygonCW(",
701 : "ST_ForcePolygonCCW(",
702 : "SanitizeGeometry(",
703 : "EnsureClosedRings(",
704 : "RemoveRepeatedPoints(",
705 : "CastToPoint(",
706 : "CastToLinestring(",
707 : "CastToPolygon(",
708 : "CastToMultiPoint(",
709 : "CastToMultiLinestring(",
710 : "CastToMultiPolygon(",
711 : "CastToGeometryCollection(",
712 : "CastToMulti(",
713 : "ST_Multi(",
714 : "CastToSingle(",
715 : "CastToXY(",
716 : "CastToXYZ(",
717 : "CastToXYM(",
718 : "CastToXYZM(",
719 : "StartPoint(",
720 : "ST_EndPoint(",
721 : "PointOnSurface(",
722 : "Simplify(",
723 : "ST_Generalize(",
724 : "SimplifyPreserveTopology(",
725 : "PointN(",
726 : "AddPoint(",
727 : "SetPoint(",
728 : "SetStartPoint(",
729 : "SetEndPoint(",
730 : "RemovePoint(",
731 : "Centroid(",
732 : "ExteriorRing(",
733 : "InteriorRingN(",
734 : "GeometryN(",
735 : "ST_AddMeasure(",
736 : "ST_Locate_Along_Measure(",
737 : "ST_LocateAlong(",
738 : "ST_Locate_Between_Measures(",
739 : "ST_LocateBetween(",
740 : "ST_TrajectoryInterpolarePoint(",
741 : "Intersection(",
742 : "Difference(",
743 : "GUnion(",
744 : "ST_Union(", // UNION is not a valid function name
745 : "SymDifference(",
746 : "Buffer(",
747 : "ConvexHull(",
748 : "OffsetCurve(",
749 : "SingleSidedBuffer(",
750 : "SharedPaths(",
751 : "Line_Interpolate_Point(",
752 : "Line_Interpolate_Equidistant_Points(",
753 : "Line_Substring(",
754 : "ClosestPoint(",
755 : "ShortestLine(",
756 : "Snap(",
757 : "Collect(",
758 : "LineMerge(",
759 : "BuildArea(",
760 : "Polygonize(",
761 : "MakePolygon(",
762 : "UnaryUnion(",
763 : "UnaryUnion(",
764 : "DrapeLine(",
765 : "DrapeLineExceptions(",
766 : "DissolveSegments(",
767 : "DissolvePoints(",
768 : "LinesFromRings(",
769 : "LinesCutAtNodes(",
770 : "RingsCutAtNodes(",
771 : "CollectionExtract(",
772 : "ExtractMultiPoint(",
773 : "ExtractMultiLinestring(",
774 : "ExtractMultiPolygon(",
775 : "DelaunayTriangulation(",
776 : "VoronojDiagram(",
777 : "ConcaveHull(",
778 : "MakeValid(",
779 : "MakeValidDiscarded(",
780 : "Segmentize(",
781 : "Split(",
782 : "SplitLeft(",
783 : "SplitRight(",
784 : "SnapAndSplit(",
785 : "Project(",
786 : "SnapToGrid(",
787 : "ST_Node(",
788 : "SelfIntersections(",
789 : "ST_Subdivide(",
790 : "Transform(",
791 : "TransformXY(",
792 : "TransformXYZ(",
793 : "ShiftCoords(",
794 : "ShiftCoordinates(",
795 : "ST_Translate(",
796 : "ST_Shift_Longitude(",
797 : "NormalizeLonLat(",
798 : "ScaleCoords(",
799 : "ScaleCoordinates(",
800 : "RotateCoords(",
801 : "RotateCoordinates(",
802 : "ReflectCoords(",
803 : "ReflectCoordinates(",
804 : "SwapCoords(",
805 : "SwapCoordinates(",
806 : "ATM_Transform(",
807 : "gpkgMakePoint(",
808 : "gpkgMakePointZ(",
809 : "gpkgMakePointZM(",
810 : "gpkgMakePointM(",
811 : "AsGPB(",
812 : "GeomFromGPB(",
813 : "CastAutomagic(",
814 : };
815 268520 : for (const char *pszFunction : apszFunctions)
816 : {
817 266328 : if (STARTS_WITH_CI(pszName, pszFunction) ||
818 266327 : (!STARTS_WITH_CI(pszFunction, "ST_") &&
819 224435 : STARTS_WITH_CI(pszName, "ST_") &&
820 4015 : STARTS_WITH_CI(pszName + strlen("ST_"), pszFunction)))
821 : {
822 16 : return true;
823 : }
824 : }
825 2192 : return false;
826 : }
827 :
828 0 : double SQLResult::GetValueAsDouble(int iColNum, int iRowNum) const
829 : {
830 0 : const char *pszValue = GetValue(iColNum, iRowNum);
831 0 : if (!pszValue)
832 0 : return 0;
833 :
834 0 : return CPLStrtod(pszValue, nullptr);
835 : }
836 :
837 : /************************************************************************/
838 : /* OGRSQLite_gdal_get_pixel_value_common() */
839 : /************************************************************************/
840 :
841 27 : void OGRSQLite_gdal_get_pixel_value_common(const char *pszFunctionName,
842 : sqlite3_context *pContext, int argc,
843 : sqlite3_value **argv,
844 : GDALDataset *poDS)
845 : {
846 27 : if (sqlite3_value_type(argv[1]) != SQLITE_INTEGER ||
847 25 : sqlite3_value_type(argv[2]) != SQLITE_TEXT ||
848 23 : (sqlite3_value_type(argv[3]) != SQLITE_INTEGER &&
849 2 : sqlite3_value_type(argv[3]) != SQLITE_FLOAT) ||
850 21 : (sqlite3_value_type(argv[4]) != SQLITE_INTEGER &&
851 54 : sqlite3_value_type(argv[4]) != SQLITE_FLOAT) ||
852 2 : (argc == 6 && sqlite3_value_type(argv[5]) != SQLITE_TEXT))
853 : {
854 8 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid arguments to %s()",
855 : pszFunctionName);
856 8 : sqlite3_result_null(pContext);
857 8 : return;
858 : }
859 :
860 19 : const int nBand = sqlite3_value_int(argv[1]);
861 19 : auto poBand = poDS->GetRasterBand(nBand);
862 19 : if (!poBand)
863 : {
864 2 : sqlite3_result_null(pContext);
865 2 : return;
866 : }
867 :
868 : const char *pszCoordType =
869 17 : reinterpret_cast<const char *>(sqlite3_value_text(argv[2]));
870 : double x, y;
871 17 : if (EQUAL(pszCoordType, "georef"))
872 : {
873 6 : const double X = sqlite3_value_double(argv[3]);
874 6 : const double Y = sqlite3_value_double(argv[4]);
875 : double adfGeoTransform[6];
876 6 : if (poDS->GetGeoTransform(adfGeoTransform) != CE_None)
877 : {
878 0 : sqlite3_result_null(pContext);
879 0 : return;
880 : }
881 : double adfInvGT[6];
882 6 : if (!GDALInvGeoTransform(adfGeoTransform, adfInvGT))
883 : {
884 0 : sqlite3_result_null(pContext);
885 0 : return;
886 : }
887 6 : x = adfInvGT[0] + X * adfInvGT[1] + Y * adfInvGT[2];
888 6 : y = adfInvGT[3] + X * adfInvGT[4] + Y * adfInvGT[5];
889 : }
890 11 : else if (EQUAL(pszCoordType, "pixel"))
891 : {
892 9 : x = sqlite3_value_int(argv[3]);
893 9 : y = sqlite3_value_int(argv[4]);
894 : }
895 : else
896 : {
897 2 : CPLError(CE_Failure, CPLE_AppDefined,
898 : "Invalid value for 3rd argument of gdal_get_pixel_value(): "
899 : "only 'georef' or 'pixel' are supported");
900 2 : sqlite3_result_null(pContext);
901 2 : return;
902 : }
903 28 : if (x < 0 || x >= poDS->GetRasterXSize() || y < 0 ||
904 13 : y >= poDS->GetRasterYSize())
905 : {
906 2 : sqlite3_result_null(pContext);
907 2 : return;
908 : }
909 :
910 : const auto eInterpolation =
911 15 : argc == 6 ? GDALRasterIOGetResampleAlg(reinterpret_cast<const char *>(
912 2 : sqlite3_value_text(argv[5])))
913 13 : : GRIORA_NearestNeighbour;
914 :
915 13 : const auto eDT = poBand->GetRasterDataType();
916 13 : if (eDT == GDT_Int64 && eInterpolation == GRIORA_NearestNeighbour)
917 : {
918 1 : int64_t nValue = 0;
919 1 : if (poBand->RasterIO(GF_Read, static_cast<int>(x), static_cast<int>(y),
920 : 1, 1, &nValue, 1, 1, GDT_Int64, 0, 0,
921 1 : nullptr) != CE_None)
922 : {
923 0 : sqlite3_result_null(pContext);
924 0 : return;
925 : }
926 1 : return sqlite3_result_int64(pContext, nValue);
927 : }
928 12 : else if (eDT == GDT_UInt64 && eInterpolation == GRIORA_NearestNeighbour)
929 : {
930 2 : uint64_t nValue = 0;
931 2 : if (poBand->RasterIO(GF_Read, static_cast<int>(x), static_cast<int>(y),
932 : 1, 1, &nValue, 1, 1, GDT_UInt64, 0, 0,
933 2 : nullptr) != CE_None)
934 : {
935 0 : sqlite3_result_null(pContext);
936 0 : return;
937 : }
938 2 : if (nValue > static_cast<uint64_t>(INT64_MAX))
939 : {
940 : // Not ideal
941 1 : return sqlite3_result_double(pContext, static_cast<double>(nValue));
942 : }
943 : else
944 : {
945 1 : return sqlite3_result_int64(pContext, static_cast<int64_t>(nValue));
946 : }
947 : }
948 : else
949 : {
950 10 : double dfValue = 0;
951 20 : if (poBand->InterpolateAtPoint(x, y, eInterpolation, &dfValue,
952 10 : nullptr) != CE_None)
953 : {
954 0 : sqlite3_result_null(pContext);
955 0 : return;
956 : }
957 10 : return sqlite3_result_double(pContext, dfValue);
958 : }
959 : }
|