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 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "cpl_port.h"
31 : #include "ogrsqliteutility.h"
32 :
33 : #include <cstdlib>
34 : #include <string>
35 : #include <iostream>
36 : #include <sstream>
37 :
38 : #include "cpl_error.h"
39 : #include "ogr_p.h"
40 :
41 13809 : SQLResult::SQLResult(char **result, int nRow, int nCol)
42 13809 : : papszResult(result), nRowCount(nRow), nColCount(nCol)
43 : {
44 13809 : }
45 :
46 27618 : SQLResult::~SQLResult()
47 : {
48 13809 : if (papszResult)
49 : {
50 13809 : sqlite3_free_table(papszResult);
51 : }
52 13809 : }
53 :
54 2 : void SQLResult::LimitRowCount(int nLimit)
55 : {
56 2 : nRowCount = nLimit;
57 2 : }
58 :
59 : /* Runs a SQL command and ignores the result (good for INSERT/UPDATE/CREATE) */
60 26773 : OGRErr SQLCommand(sqlite3 *poDb, const char *pszSQL)
61 : {
62 26773 : CPLAssert(poDb != nullptr);
63 26773 : CPLAssert(pszSQL != nullptr);
64 :
65 26773 : char *pszErrMsg = nullptr;
66 : #ifdef DEBUG_VERBOSE
67 : CPLDebug("GPKG", "exec(%s)", pszSQL);
68 : #endif
69 26773 : int rc = sqlite3_exec(poDb, pszSQL, nullptr, nullptr, &pszErrMsg);
70 :
71 26773 : if (rc != SQLITE_OK)
72 : {
73 7 : CPLError(CE_Failure, CPLE_AppDefined, "sqlite3_exec(%s) failed: %s",
74 7 : pszSQL, pszErrMsg ? pszErrMsg : "");
75 7 : sqlite3_free(pszErrMsg);
76 7 : return OGRERR_FAILURE;
77 : }
78 :
79 26766 : return OGRERR_NONE;
80 : }
81 :
82 13810 : std::unique_ptr<SQLResult> SQLQuery(sqlite3 *poDb, const char *pszSQL)
83 : {
84 13810 : CPLAssert(poDb != nullptr);
85 13810 : CPLAssert(pszSQL != nullptr);
86 :
87 : #ifdef DEBUG_VERBOSE
88 : CPLDebug("GPKG", "get_table(%s)", pszSQL);
89 : #endif
90 :
91 13810 : char **papszResult = nullptr;
92 13810 : char *pszErrMsg = nullptr;
93 : int nRowCount, nColCount;
94 13810 : int rc = sqlite3_get_table(poDb, pszSQL, &(papszResult), &(nRowCount),
95 : &(nColCount), &(pszErrMsg));
96 :
97 13810 : if (rc != SQLITE_OK)
98 : {
99 1 : CPLError(CE_Failure, CPLE_AppDefined,
100 : "sqlite3_get_table(%s) failed: %s", pszSQL, pszErrMsg);
101 1 : sqlite3_free(pszErrMsg);
102 1 : return nullptr;
103 : }
104 :
105 13809 : return std::make_unique<SQLResult>(papszResult, nRowCount, nColCount);
106 : }
107 :
108 96027 : const char *SQLResult::GetValue(int iColNum, int iRowNum) const
109 : {
110 96027 : const int nCols = nColCount;
111 : #ifdef DEBUG
112 96027 : const int nRows = nRowCount;
113 96027 : CPL_IGNORE_RET_VAL(nRows);
114 :
115 96027 : CPLAssert(iColNum >= 0 && iColNum < nCols);
116 96027 : CPLAssert(iRowNum >= 0 && iRowNum < nRows);
117 : #endif
118 96027 : return papszResult[nCols + iRowNum * nCols + iColNum];
119 : }
120 :
121 16073 : int SQLResult::GetValueAsInteger(int iColNum, int iRowNum) const
122 : {
123 16073 : const char *pszValue = GetValue(iColNum, iRowNum);
124 16073 : if (!pszValue)
125 100 : return 0;
126 :
127 15973 : return atoi(pszValue);
128 : }
129 :
130 : /* Returns the first row of first column of SQL as integer */
131 42062 : GIntBig SQLGetInteger64(sqlite3 *poDb, const char *pszSQL, OGRErr *err)
132 : {
133 42062 : CPLAssert(poDb != nullptr);
134 :
135 42062 : sqlite3_stmt *poStmt = nullptr;
136 :
137 : /* Prepare the SQL */
138 : #ifdef DEBUG_VERBOSE
139 : CPLDebug("GPKG", "get(%s)", pszSQL);
140 : #endif
141 42062 : int rc = sqlite3_prepare_v2(poDb, pszSQL, -1, &poStmt, nullptr);
142 42062 : if (rc != SQLITE_OK)
143 : {
144 2 : CPLError(CE_Failure, CPLE_AppDefined,
145 : "sqlite3_prepare_v2(%s) failed: %s", pszSQL,
146 : sqlite3_errmsg(poDb));
147 2 : if (err)
148 1 : *err = OGRERR_FAILURE;
149 2 : return 0;
150 : }
151 :
152 : /* Execute and fetch first row */
153 42060 : rc = sqlite3_step(poStmt);
154 42060 : if (rc != SQLITE_ROW)
155 : {
156 5618 : if (err)
157 1909 : *err = OGRERR_FAILURE;
158 5618 : sqlite3_finalize(poStmt);
159 5618 : return 0;
160 : }
161 :
162 : /* Read the integer from the row */
163 36442 : GIntBig i = sqlite3_column_int64(poStmt, 0);
164 36442 : sqlite3_finalize(poStmt);
165 :
166 36442 : if (err)
167 26064 : *err = OGRERR_NONE;
168 36442 : return i;
169 : }
170 :
171 18738 : int SQLGetInteger(sqlite3 *poDb, const char *pszSQL, OGRErr *err)
172 : {
173 18738 : return static_cast<int>(SQLGetInteger64(poDb, pszSQL, err));
174 : }
175 :
176 : /************************************************************************/
177 : /* SQLUnescape() */
178 : /************************************************************************/
179 :
180 16430 : CPLString SQLUnescape(const char *pszVal)
181 : {
182 16430 : char chQuoteChar = pszVal[0];
183 16430 : if (chQuoteChar != '\'' && chQuoteChar != '"')
184 16055 : return pszVal;
185 :
186 750 : CPLString osRet;
187 375 : pszVal++;
188 3082 : while (*pszVal != '\0')
189 : {
190 3082 : if (*pszVal == chQuoteChar)
191 : {
192 381 : if (pszVal[1] == chQuoteChar)
193 6 : pszVal++;
194 : else
195 375 : break;
196 : }
197 2707 : osRet += *pszVal;
198 2707 : pszVal++;
199 : }
200 375 : return osRet;
201 : }
202 :
203 : /************************************************************************/
204 : /* SQLEscapeLiteral() */
205 : /************************************************************************/
206 :
207 6106 : CPLString SQLEscapeLiteral(const char *pszLiteral)
208 : {
209 6106 : CPLString osVal;
210 68537 : for (int i = 0; pszLiteral[i] != '\0'; i++)
211 : {
212 62431 : if (pszLiteral[i] == '\'')
213 1 : osVal += '\'';
214 62431 : osVal += pszLiteral[i];
215 : }
216 6106 : return osVal;
217 : }
218 :
219 : /************************************************************************/
220 : /* SQLEscapeName() */
221 : /************************************************************************/
222 :
223 229110 : CPLString SQLEscapeName(const char *pszName)
224 : {
225 229110 : CPLString osRet;
226 1823870 : while (*pszName != '\0')
227 : {
228 1594760 : if (*pszName == '"')
229 4 : osRet += "\"\"";
230 : else
231 1594750 : osRet += *pszName;
232 1594760 : pszName++;
233 : }
234 229110 : return osRet;
235 : }
236 :
237 : /************************************************************************/
238 : /* SQLTokenize() */
239 : /************************************************************************/
240 :
241 8 : char **SQLTokenize(const char *pszStr)
242 : {
243 8 : char **papszTokens = nullptr;
244 8 : bool bInQuote = false;
245 8 : char chQuoteChar = '\0';
246 8 : bool bInSpace = true;
247 8 : CPLString osCurrentToken;
248 416 : while (*pszStr != '\0')
249 : {
250 408 : if (*pszStr == ' ' && !bInQuote)
251 : {
252 40 : if (!bInSpace)
253 : {
254 35 : papszTokens = CSLAddString(papszTokens, osCurrentToken);
255 35 : osCurrentToken.clear();
256 : }
257 40 : bInSpace = true;
258 : }
259 368 : else if ((*pszStr == '(' || *pszStr == ')' || *pszStr == ',') &&
260 4 : !bInQuote)
261 : {
262 4 : if (!bInSpace)
263 : {
264 3 : papszTokens = CSLAddString(papszTokens, osCurrentToken);
265 3 : osCurrentToken.clear();
266 : }
267 4 : osCurrentToken.clear();
268 4 : osCurrentToken += *pszStr;
269 4 : papszTokens = CSLAddString(papszTokens, osCurrentToken);
270 4 : osCurrentToken.clear();
271 4 : bInSpace = true;
272 : }
273 364 : else if (*pszStr == '"' || *pszStr == '\'')
274 : {
275 28 : if (bInQuote && *pszStr == chQuoteChar && pszStr[1] == chQuoteChar)
276 : {
277 5 : osCurrentToken += *pszStr;
278 5 : osCurrentToken += *pszStr;
279 5 : pszStr += 2;
280 5 : continue;
281 : }
282 23 : else if (bInQuote && *pszStr == chQuoteChar)
283 : {
284 9 : osCurrentToken += *pszStr;
285 9 : papszTokens = CSLAddString(papszTokens, osCurrentToken);
286 9 : osCurrentToken.clear();
287 9 : bInSpace = true;
288 9 : bInQuote = false;
289 9 : chQuoteChar = '\0';
290 : }
291 14 : else if (bInQuote)
292 : {
293 5 : osCurrentToken += *pszStr;
294 : }
295 : else
296 : {
297 9 : chQuoteChar = *pszStr;
298 9 : osCurrentToken.clear();
299 9 : osCurrentToken += chQuoteChar;
300 9 : bInQuote = true;
301 9 : bInSpace = false;
302 : }
303 : }
304 : else
305 : {
306 336 : osCurrentToken += *pszStr;
307 336 : bInSpace = false;
308 : }
309 403 : pszStr++;
310 : }
311 :
312 8 : if (!osCurrentToken.empty())
313 3 : papszTokens = CSLAddString(papszTokens, osCurrentToken);
314 :
315 16 : return papszTokens;
316 : }
317 :
318 : /************************************************************************/
319 : /* SQLGetUniqueFieldUCConstraints() */
320 : /************************************************************************/
321 :
322 : /* Return set of field names (in upper case) that have a UNIQUE constraint,
323 : * only on that single column.
324 : */
325 :
326 1382 : std::set<std::string> SQLGetUniqueFieldUCConstraints(
327 : sqlite3 *poDb, const char *pszTableName,
328 : const std::vector<SQLSqliteMasterContent> &sqliteMasterContent)
329 : {
330 : // set names (in upper case) of fields with unique constraint
331 1382 : std::set<std::string> uniqueFieldsUC;
332 :
333 : // Unique fields detection
334 2764 : const std::string upperTableName{CPLString(pszTableName).toupper()};
335 2764 : std::string tableDefinition;
336 :
337 1382 : if (sqliteMasterContent.empty())
338 : {
339 1380 : char *pszTableDefinitionSQL = sqlite3_mprintf(
340 : "SELECT sql, type FROM sqlite_master "
341 : "WHERE type IN ('table', 'view') AND UPPER(name)='%q'",
342 : upperTableName.c_str());
343 1380 : auto oResultTable = SQLQuery(poDb, pszTableDefinitionSQL);
344 1380 : sqlite3_free(pszTableDefinitionSQL);
345 :
346 1380 : if (!oResultTable || oResultTable->RowCount() == 0)
347 : {
348 2 : if (oResultTable)
349 2 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find table %s",
350 : pszTableName);
351 :
352 2 : return uniqueFieldsUC;
353 : }
354 1378 : if (std::string(oResultTable->GetValue(1, 0)) == "view")
355 : {
356 1 : return uniqueFieldsUC;
357 : }
358 1377 : tableDefinition = oResultTable->GetValue(0, 0);
359 : }
360 : else
361 : {
362 107 : for (const auto &row : sqliteMasterContent)
363 : {
364 142 : if (row.osType == "table" &&
365 142 : CPLString(row.osTableName).toupper() == upperTableName)
366 : {
367 2 : tableDefinition = row.osSQL;
368 2 : break;
369 : }
370 105 : else if (row.osType == "view" &&
371 105 : CPLString(row.osTableName).toupper() == upperTableName)
372 : {
373 0 : return uniqueFieldsUC;
374 : }
375 : }
376 2 : if (tableDefinition.empty())
377 : {
378 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find table %s",
379 : pszTableName);
380 :
381 0 : return uniqueFieldsUC;
382 : }
383 : }
384 :
385 : // Parses strings like "colum_name1" KEYWORD1 KEYWORD2 'some string',
386 : // `column_name2`,"column_name3"
387 : const auto GetNextToken =
388 935 : [](const std::string &osStr, size_t &pos, bool keepQuotes)
389 : {
390 935 : if (pos >= osStr.size())
391 117 : return std::string();
392 818 : pos = osStr.find_first_not_of(" \t\n\r", pos);
393 818 : if (pos == std::string::npos)
394 1 : return std::string();
395 :
396 1634 : std::string osToken;
397 817 : if (osStr[pos] == '"' || osStr[pos] == '\'' || osStr[pos] == '`')
398 : {
399 88 : const char chQuoteChar = osStr[pos];
400 88 : if (keepQuotes)
401 1 : osToken += chQuoteChar;
402 88 : ++pos;
403 864 : while (pos < osStr.size())
404 : {
405 864 : if (osStr[pos] == chQuoteChar)
406 : {
407 88 : if (pos + 1 < osStr.size() && osStr[pos + 1] == chQuoteChar)
408 : {
409 0 : osToken += chQuoteChar;
410 0 : pos += 2;
411 : }
412 : else
413 : {
414 88 : if (keepQuotes)
415 1 : osToken += chQuoteChar;
416 88 : pos++;
417 88 : break;
418 : }
419 : }
420 : else
421 : {
422 776 : osToken += osStr[pos];
423 776 : pos++;
424 : }
425 : }
426 : }
427 729 : else if (osStr[pos] == ',')
428 : {
429 193 : osToken = ',';
430 193 : pos++;
431 : }
432 : else
433 : {
434 536 : size_t pos2 = osStr.find_first_of(" \t\n\r,", pos);
435 536 : if (pos2 == std::string::npos)
436 66 : osToken = osStr.substr(pos);
437 : else
438 470 : osToken = osStr.substr(pos, pos2 - pos);
439 536 : pos = pos2;
440 : }
441 817 : return osToken;
442 : };
443 :
444 : // Parses CREATE TABLE definition for column UNIQUE keywords
445 : {
446 1379 : const auto nPosStart = tableDefinition.find('(');
447 1379 : const auto nPosEnd = tableDefinition.rfind(')');
448 1379 : if (nPosStart != std::string::npos && nPosEnd != std::string::npos &&
449 2758 : nPosEnd > nPosStart &&
450 2758 : CPLString(tableDefinition).toupper().find("UNIQUE") !=
451 : std::string::npos)
452 : {
453 : tableDefinition =
454 45 : tableDefinition.substr(nPosStart + 1, nPosEnd - nPosStart - 1);
455 45 : size_t pos = 0;
456 : while (true)
457 : {
458 : const std::string osColName =
459 282 : GetNextToken(tableDefinition, pos, false);
460 282 : if (osColName.empty())
461 : {
462 45 : break;
463 : }
464 : while (true)
465 : {
466 : const std::string osToken =
467 595 : GetNextToken(tableDefinition, pos, true);
468 595 : if (osToken.empty() || osToken == ",")
469 237 : break;
470 358 : if (EQUAL(osToken.c_str(), "UNIQUE"))
471 : {
472 29 : uniqueFieldsUC.insert(CPLString(osColName).toupper());
473 : }
474 358 : }
475 237 : }
476 : }
477 : }
478 :
479 : // Search indexes:
480 :
481 : const auto ProcessIndexDefinition =
482 115 : [&uniqueFieldsUC, &GetNextToken](const std::string &indexDefinitionIn)
483 : {
484 29 : const auto nPosStart = indexDefinitionIn.find('(');
485 29 : const auto nPosEnd = indexDefinitionIn.rfind(')');
486 29 : if (nPosStart != std::string::npos && nPosEnd != std::string::npos &&
487 : nPosEnd > nPosStart)
488 : {
489 : std::string indexDefinitionMod = indexDefinitionIn.substr(
490 58 : nPosStart + 1, nPosEnd - nPosStart - 1);
491 29 : size_t pos = 0;
492 : const std::string osColName =
493 58 : GetNextToken(indexDefinitionMod, pos, false);
494 : // Only matches index on single columns
495 29 : if (GetNextToken(indexDefinitionMod, pos, false).empty())
496 : {
497 28 : uniqueFieldsUC.insert(CPLString(osColName).toupper());
498 : }
499 : }
500 29 : };
501 :
502 1379 : if (sqliteMasterContent.empty())
503 : {
504 1377 : char *pszTableDefinitionSQL = sqlite3_mprintf(
505 : "SELECT sql FROM sqlite_master WHERE type='index' AND"
506 : " UPPER(tbl_name)='%q' AND UPPER(sql) "
507 : "LIKE 'CREATE UNIQUE INDEX%%'",
508 : upperTableName.c_str());
509 2754 : auto oResultTable = SQLQuery(poDb, pszTableDefinitionSQL);
510 1377 : sqlite3_free(pszTableDefinitionSQL);
511 :
512 1377 : if (!oResultTable)
513 : {
514 0 : CPLError(CE_Failure, CPLE_AppDefined,
515 : "Error searching indexes for table %s", pszTableName);
516 : }
517 1377 : else if (oResultTable->RowCount() >= 0)
518 : {
519 1404 : for (int rowCnt = 0; rowCnt < oResultTable->RowCount(); ++rowCnt)
520 : {
521 54 : std::string indexDefinition{oResultTable->GetValue(0, rowCnt)};
522 27 : ProcessIndexDefinition(indexDefinition);
523 : }
524 : }
525 : }
526 : else
527 : {
528 116 : for (const auto &row : sqliteMasterContent)
529 : {
530 58 : if (row.osType == "index" &&
531 172 : CPLString(row.osTableName).toupper() == upperTableName &&
532 4 : STARTS_WITH_CI(row.osSQL.c_str(), "CREATE UNIQUE INDEX"))
533 : {
534 4 : std::string indexDefinition = row.osSQL;
535 2 : ProcessIndexDefinition(indexDefinition);
536 : }
537 : }
538 : }
539 :
540 1379 : return uniqueFieldsUC;
541 : }
542 :
543 : /************************************************************************/
544 : /* OGRSQLiteRTreeRequiresTrustedSchemaOn() */
545 : /************************************************************************/
546 :
547 : /** Whether the use of a RTree in triggers or views requires trusted_schema
548 : * PRAGMA to be set to ON */
549 905 : bool OGRSQLiteRTreeRequiresTrustedSchemaOn()
550 : {
551 40 : static bool b = []()
552 : {
553 40 : sqlite3 *hDB = nullptr;
554 : int rc =
555 40 : sqlite3_open_v2(":memory:", &hDB, SQLITE_OPEN_READWRITE, nullptr);
556 40 : if (rc != SQLITE_OK)
557 : {
558 0 : CPLError(CE_Failure, CPLE_AppDefined,
559 : "sqlite3_open_v2(:memory:) failed");
560 0 : sqlite3_close(hDB);
561 0 : return false;
562 : }
563 40 : rc = sqlite3_exec(hDB,
564 : "CREATE VIRTUAL TABLE foo_rtree USING rtree(id, "
565 : "minx, miny, maxx, maxy);",
566 : nullptr, nullptr, nullptr);
567 40 : if (rc != SQLITE_OK)
568 : {
569 0 : CPLError(CE_Failure, CPLE_AppDefined,
570 : "CREATE VIRTUAL TABLE foo_rtree failed");
571 0 : sqlite3_close(hDB);
572 0 : return false;
573 : }
574 40 : rc = sqlite3_exec(hDB, "CREATE VIEW v AS SELECT * FROM foo_rtree;",
575 : nullptr, nullptr, nullptr);
576 40 : if (rc != SQLITE_OK)
577 : {
578 0 : CPLError(CE_Failure, CPLE_AppDefined,
579 : "CREATE VIEW v AS SELECT * FROM foo_rtree failed");
580 0 : sqlite3_close(hDB);
581 0 : return false;
582 : }
583 : // Try to read the virtual table from a view. As of today (sqlite 3.43.1)
584 : // this require trusted_schema = ON
585 40 : rc = sqlite3_exec(hDB, "SELECT * FROM v", nullptr, nullptr, nullptr);
586 40 : bool bRequiresTrustedSchemaOn = false;
587 40 : if (rc != SQLITE_OK)
588 : {
589 40 : CPL_IGNORE_RET_VAL(sqlite3_exec(hDB, "PRAGMA trusted_schema = ON",
590 : nullptr, nullptr, nullptr));
591 : rc =
592 40 : sqlite3_exec(hDB, "SELECT * FROM v", nullptr, nullptr, nullptr);
593 40 : if (rc == SQLITE_OK)
594 40 : bRequiresTrustedSchemaOn = true;
595 : }
596 40 : sqlite3_close(hDB);
597 40 : return bRequiresTrustedSchemaOn;
598 905 : }();
599 905 : return b;
600 : }
601 :
602 : /************************************************************************/
603 : /* OGRSQLiteIsSpatialFunctionReturningGeometry() */
604 : /************************************************************************/
605 :
606 2033 : bool OGRSQLiteIsSpatialFunctionReturningGeometry(const char *pszName)
607 : {
608 2033 : const char *const apszFunctions[] = {
609 : "SetSRID(",
610 : "IsValidDetail(",
611 : "Boundary(",
612 : "Envelope(",
613 : "ST_Expand(",
614 : "ST_Reverse(",
615 : "ST_ForceLHR(",
616 : "ST_ForcePolygonCW(",
617 : "ST_ForcePolygonCCW(",
618 : "SanitizeGeometry(",
619 : "EnsureClosedRings(",
620 : "RemoveRepeatedPoints(",
621 : "CastToPoint(",
622 : "CastToLinestring(",
623 : "CastToPolygon(",
624 : "CastToMultiPoint(",
625 : "CastToMultiLinestring(",
626 : "CastToMultiPolygon(",
627 : "CastToGeometryCollection(",
628 : "CastToMulti(",
629 : "ST_Multi(",
630 : "CastToSingle(",
631 : "CastToXY(",
632 : "CastToXYZ(",
633 : "CastToXYM(",
634 : "CastToXYZM(",
635 : "StartPoint(",
636 : "ST_EndPoint(",
637 : "PointOnSurface(",
638 : "Simplify(",
639 : "ST_Generalize(",
640 : "SimplifyPreserveTopology(",
641 : "PointN(",
642 : "AddPoint(",
643 : "SetPoint(",
644 : "SetStartPoint(",
645 : "SetEndPoint(",
646 : "RemovePoint(",
647 : "Centroid(",
648 : "ExteriorRing(",
649 : "InteriorRingN(",
650 : "GeometryN(",
651 : "ST_AddMeasure(",
652 : "ST_Locate_Along_Measure(",
653 : "ST_LocateAlong(",
654 : "ST_Locate_Between_Measures(",
655 : "ST_LocateBetween(",
656 : "ST_TrajectoryInterpolarePoint(",
657 : "Intersection(",
658 : "Difference(",
659 : "GUnion(",
660 : "ST_Union(", // UNION is not a valid function name
661 : "SymDifference(",
662 : "Buffer(",
663 : "ConvexHull(",
664 : "OffsetCurve(",
665 : "SingleSidedBuffer(",
666 : "SharedPaths(",
667 : "Line_Interpolate_Point(",
668 : "Line_Interpolate_Equidistant_Points(",
669 : "Line_Substring(",
670 : "ClosestPoint(",
671 : "ShortestLine(",
672 : "Snap(",
673 : "Collect(",
674 : "LineMerge(",
675 : "BuildArea(",
676 : "Polygonize(",
677 : "MakePolygon(",
678 : "UnaryUnion(",
679 : "UnaryUnion(",
680 : "DrapeLine(",
681 : "DrapeLineExceptions(",
682 : "DissolveSegments(",
683 : "DissolvePoints(",
684 : "LinesFromRings(",
685 : "LinesCutAtNodes(",
686 : "RingsCutAtNodes(",
687 : "CollectionExtract(",
688 : "ExtractMultiPoint(",
689 : "ExtractMultiLinestring(",
690 : "ExtractMultiPolygon(",
691 : "DelaunayTriangulation(",
692 : "VoronojDiagram(",
693 : "ConcaveHull(",
694 : "MakeValid(",
695 : "MakeValidDiscarded(",
696 : "Segmentize(",
697 : "Split(",
698 : "SplitLeft(",
699 : "SplitRight(",
700 : "SnapAndSplit(",
701 : "Project(",
702 : "SnapToGrid(",
703 : "ST_Node(",
704 : "SelfIntersections(",
705 : "ST_Subdivide(",
706 : "Transform(",
707 : "TransformXY(",
708 : "TransformXYZ(",
709 : "ShiftCoords(",
710 : "ShiftCoordinates(",
711 : "ST_Translate(",
712 : "ST_Shift_Longitude(",
713 : "NormalizeLonLat(",
714 : "ScaleCoords(",
715 : "ScaleCoordinates(",
716 : "RotateCoords(",
717 : "RotateCoordinates(",
718 : "ReflectCoords(",
719 : "ReflectCoordinates(",
720 : "SwapCoords(",
721 : "SwapCoordinates(",
722 : "ATM_Transform(",
723 : "gpkgMakePoint(",
724 : "gpkgMakePointZ(",
725 : "gpkgMakePointZM(",
726 : "gpkgMakePointM(",
727 : "AsGPB(",
728 : "GeomFromGPB(",
729 : "CastAutomagic(",
730 : };
731 247170 : for (const char *pszFunction : apszFunctions)
732 : {
733 245153 : if (STARTS_WITH_CI(pszName, pszFunction) ||
734 245152 : (!STARTS_WITH_CI(pszFunction, "ST_") &&
735 206585 : STARTS_WITH_CI(pszName, "ST_") &&
736 3301 : STARTS_WITH_CI(pszName + strlen("ST_"), pszFunction)))
737 : {
738 16 : return true;
739 : }
740 : }
741 2017 : return false;
742 : }
743 :
744 0 : double SQLResult::GetValueAsDouble(int iColNum, int iRowNum) const
745 : {
746 0 : const char *pszValue = GetValue(iColNum, iRowNum);
747 0 : if (!pszValue)
748 0 : return 0;
749 :
750 0 : return CPLStrtod(pszValue, nullptr);
751 : }
|