Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OpenGIS Simple Features Reference Implementation
4 : * Purpose: Extension SQL functions used by both SQLite dialect and GPKG driver
5 : * Author: Even Rouault, even dot rouault at spatialys.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2012-2022, Even Rouault <even dot rouault at spatialys.com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : /* WARNING: VERY IMPORTANT NOTE: This file MUST not be directly compiled as */
14 : /* a standalone object. It must be included from ogrsqlitevirtualogr.cpp */
15 : #ifndef COMPILATION_ALLOWED
16 : #error See comment in file
17 : #endif
18 :
19 : #include "gdal_priv.h"
20 : #include "ogr_geocoding.h"
21 :
22 : #include "ogrsqliteregexp.cpp" /* yes the .cpp file, to make it work on Windows with load_extension('gdalXX.dll') */
23 :
24 : #include <algorithm>
25 : #include <cassert>
26 : #include <cmath>
27 : #include <map>
28 :
29 : #include "ogr_swq.h"
30 :
31 : namespace
32 : {
33 : class OGRSQLiteExtensionData
34 : {
35 : #ifdef DEBUG
36 : void *pDummy = nullptr; /* to track memory leaks */
37 : #endif
38 :
39 : std::map<std::pair<int, int>, std::unique_ptr<OGRCoordinateTransformation>>
40 : // cppcheck-suppress unusedStructMember
41 : oCachedTransformsMap{};
42 : std::map<std::string, std::unique_ptr<GDALDataset>> oCachedDS{};
43 :
44 : void *hRegExpCache = nullptr;
45 :
46 : OGRGeocodingSessionH hGeocodingSession = nullptr;
47 :
48 : bool bCaseSensitiveLike = false;
49 :
50 : OGRSQLiteExtensionData(const OGRSQLiteExtensionData &) = delete;
51 : OGRSQLiteExtensionData &operator=(const OGRSQLiteExtensionData &) = delete;
52 :
53 : public:
54 : explicit OGRSQLiteExtensionData(sqlite3 *hDB);
55 : ~OGRSQLiteExtensionData();
56 :
57 : #ifdef DEFINE_OGRSQLiteExtensionData_GetTransform
58 : OGRCoordinateTransformation *GetTransform(int nSrcSRSId, int nDstSRSId);
59 : #endif
60 :
61 : GDALDataset *GetDataset(const char *pszDSName);
62 :
63 112 : OGRGeocodingSessionH GetGeocodingSession()
64 : {
65 112 : return hGeocodingSession;
66 : }
67 :
68 112 : void SetGeocodingSession(OGRGeocodingSessionH hGeocodingSessionIn)
69 : {
70 112 : hGeocodingSession = hGeocodingSessionIn;
71 112 : }
72 :
73 3140 : void SetRegExpCache(void *hRegExpCacheIn)
74 : {
75 3140 : hRegExpCache = hRegExpCacheIn;
76 3140 : }
77 :
78 4 : void SetCaseSensitiveLike(bool b)
79 : {
80 4 : bCaseSensitiveLike = b;
81 4 : }
82 :
83 270687 : bool GetCaseSensitiveLike() const
84 : {
85 270687 : return bCaseSensitiveLike;
86 : }
87 : };
88 :
89 : /************************************************************************/
90 : /* OGRSQLiteExtensionData() */
91 : /************************************************************************/
92 :
93 3140 : OGRSQLiteExtensionData::OGRSQLiteExtensionData(CPL_UNUSED sqlite3 *hDB)
94 : :
95 : #ifdef DEBUG
96 3140 : pDummy(CPLMalloc(1)),
97 : #endif
98 3140 : hRegExpCache(nullptr), hGeocodingSession(nullptr)
99 : {
100 3140 : }
101 :
102 : /************************************************************************/
103 : /* ~OGRSQLiteExtensionData() */
104 : /************************************************************************/
105 :
106 3131 : OGRSQLiteExtensionData::~OGRSQLiteExtensionData()
107 : {
108 : #ifdef DEBUG
109 3131 : CPLFree(pDummy);
110 : #endif
111 :
112 3131 : OGRSQLiteFreeRegExpCache(hRegExpCache);
113 :
114 3131 : OGRGeocodeDestroySession(hGeocodingSession);
115 3131 : }
116 :
117 : /************************************************************************/
118 : /* GetTransform() */
119 : /************************************************************************/
120 :
121 : #ifdef DEFINE_OGRSQLiteExtensionData_GetTransform
122 0 : OGRCoordinateTransformation *OGRSQLiteExtensionData::GetTransform(int nSrcSRSId,
123 : int nDstSRSId)
124 : {
125 0 : auto oIter = oCachedTransformsMap.find(std::pair(nSrcSRSId, nDstSRSId));
126 0 : if (oIter == oCachedTransformsMap.end())
127 : {
128 0 : std::unique_ptr<OGRCoordinateTransformation> poCT;
129 0 : OGRSpatialReference oSrcSRS, oDstSRS;
130 0 : oSrcSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
131 0 : oDstSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
132 0 : if (oSrcSRS.importFromEPSG(nSrcSRSId) == OGRERR_NONE &&
133 0 : oDstSRS.importFromEPSG(nDstSRSId) == OGRERR_NONE)
134 : {
135 0 : poCT.reset(OGRCreateCoordinateTransformation(&oSrcSRS, &oDstSRS));
136 : }
137 0 : oIter = oCachedTransformsMap
138 0 : .insert({std::pair(nSrcSRSId, nDstSRSId), std::move(poCT)})
139 : .first;
140 : }
141 0 : return oIter->second.get();
142 : }
143 : #endif
144 :
145 : /************************************************************************/
146 : /* GetDataset() */
147 : /************************************************************************/
148 :
149 15 : GDALDataset *OGRSQLiteExtensionData::GetDataset(const char *pszDSName)
150 : {
151 15 : auto oIter = oCachedDS.find(pszDSName);
152 15 : if (oIter != oCachedDS.end())
153 11 : return oIter->second.get();
154 :
155 : auto poDS = std::unique_ptr<GDALDataset>(
156 8 : GDALDataset::Open(pszDSName, GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR));
157 4 : if (!poDS)
158 : {
159 0 : return nullptr;
160 : }
161 4 : oIter = oCachedDS.insert({pszDSName, std::move(poDS)}).first;
162 4 : return oIter->second.get();
163 : }
164 :
165 : } // namespace
166 :
167 : /************************************************************************/
168 : /* OGRSQLITE_gdal_get_pixel_value() */
169 : /************************************************************************/
170 :
171 17 : static void OGRSQLITE_gdal_get_pixel_value(sqlite3_context *pContext, int argc,
172 : sqlite3_value **argv)
173 : {
174 17 : if (!CPLTestBool(
175 : CPLGetConfigOption("OGR_SQLITE_ALLOW_EXTERNAL_ACCESS", "NO")))
176 : {
177 1 : CPLError(CE_Failure, CPLE_AppDefined,
178 : "gdal_get_pixel_value() SQL function not available "
179 : "if OGR_SQLITE_ALLOW_EXTERNAL_ACCESS configuration option "
180 : "is not set");
181 1 : sqlite3_result_null(pContext);
182 1 : return;
183 : }
184 :
185 16 : if (sqlite3_value_type(argv[0]) != SQLITE_TEXT)
186 : {
187 1 : CPLError(CE_Failure, CPLE_AppDefined,
188 : "Invalid arguments to gdal_get_layer_pixel_value()");
189 1 : sqlite3_result_null(pContext);
190 1 : return;
191 : }
192 : const char *pszDSName =
193 15 : reinterpret_cast<const char *>(sqlite3_value_text(argv[0]));
194 :
195 : OGRSQLiteExtensionData *poModule =
196 15 : static_cast<OGRSQLiteExtensionData *>(sqlite3_user_data(pContext));
197 15 : auto poDS = poModule->GetDataset(pszDSName);
198 15 : if (!poDS)
199 : {
200 0 : sqlite3_result_null(pContext);
201 0 : return;
202 : }
203 :
204 15 : OGRSQLite_gdal_get_pixel_value_common("gdal_get_layer_pixel_value",
205 : pContext, argc, argv, poDS);
206 : }
207 :
208 : /************************************************************************/
209 : /* OGRSQLITE_LIKE() */
210 : /************************************************************************/
211 :
212 279474 : static void OGRSQLITE_LIKE(sqlite3_context *pContext, int argc,
213 : sqlite3_value **argv)
214 : {
215 : OGRSQLiteExtensionData *poModule =
216 279474 : static_cast<OGRSQLiteExtensionData *>(sqlite3_user_data(pContext));
217 :
218 : // A LIKE B is implemented as like(B, A)
219 : // A LIKE B ESCAPE C is implemented as like(B, A, C)
220 : const char *pattern =
221 279474 : reinterpret_cast<const char *>(sqlite3_value_text(argv[0]));
222 : const char *input =
223 279474 : reinterpret_cast<const char *>(sqlite3_value_text(argv[1]));
224 279474 : if (!input || !pattern)
225 : {
226 8781 : sqlite3_result_null(pContext);
227 8781 : return;
228 : }
229 270693 : char chEscape = '\\';
230 270693 : if (argc == 3)
231 : {
232 : const char *escape =
233 12 : reinterpret_cast<const char *>(sqlite3_value_text(argv[2]));
234 12 : if (!escape || escape[1] != 0)
235 : {
236 6 : sqlite3_result_null(pContext);
237 6 : return;
238 : }
239 6 : chEscape = escape[0];
240 : }
241 :
242 270687 : const bool insensitive = !poModule->GetCaseSensitiveLike();
243 270687 : constexpr bool bUTF8Strings = true;
244 270687 : sqlite3_result_int(pContext, swq_test_like(input, pattern, chEscape,
245 : insensitive, bUTF8Strings));
246 : }
247 :
248 : /************************************************************************/
249 : /* OGRSQLITE_STDDEV_Step() */
250 : /************************************************************************/
251 :
252 : // Welford's online algorithm for variance:
253 : // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm
254 : struct OGRSQLITE_STDDEV_Context
255 : {
256 : int64_t nValues;
257 : double dfMean;
258 : double dfM2; // Accumulator for squared distance from the mean
259 : };
260 :
261 8 : static void OGRSQLITE_STDDEV_Step(sqlite3_context *pContext, int /* argc*/,
262 : sqlite3_value **argv)
263 : {
264 : auto pAggCtxt =
265 8 : static_cast<OGRSQLITE_STDDEV_Context *>(sqlite3_aggregate_context(
266 : pContext, static_cast<int>(sizeof(OGRSQLITE_STDDEV_Context))));
267 8 : const auto eType = sqlite3_value_type(argv[0]);
268 8 : if (eType != SQLITE_INTEGER && eType != SQLITE_FLOAT)
269 4 : return;
270 :
271 4 : const double dfValue = sqlite3_value_double(argv[0]);
272 4 : pAggCtxt->nValues++;
273 4 : const double dfDelta = dfValue - pAggCtxt->dfMean;
274 4 : pAggCtxt->dfMean += dfDelta / pAggCtxt->nValues;
275 4 : const double dfDelta2 = dfValue - pAggCtxt->dfMean;
276 4 : pAggCtxt->dfM2 += dfDelta * dfDelta2;
277 : }
278 :
279 : /************************************************************************/
280 : /* OGRSQLITE_STDDEV_POP_Finalize() */
281 : /************************************************************************/
282 :
283 1 : static void OGRSQLITE_STDDEV_POP_Finalize(sqlite3_context *pContext)
284 : {
285 : auto pAggCtxt =
286 1 : static_cast<OGRSQLITE_STDDEV_Context *>(sqlite3_aggregate_context(
287 : pContext, static_cast<int>(sizeof(OGRSQLITE_STDDEV_Context))));
288 1 : if (pAggCtxt->nValues > 0)
289 : {
290 1 : sqlite3_result_double(pContext,
291 1 : sqrt(pAggCtxt->dfM2 / pAggCtxt->nValues));
292 : }
293 1 : }
294 :
295 : /************************************************************************/
296 : /* OGRSQLITE_STDDEV_SAMP_Finalize() */
297 : /************************************************************************/
298 :
299 1 : static void OGRSQLITE_STDDEV_SAMP_Finalize(sqlite3_context *pContext)
300 : {
301 : auto pAggCtxt =
302 1 : static_cast<OGRSQLITE_STDDEV_Context *>(sqlite3_aggregate_context(
303 : pContext, static_cast<int>(sizeof(OGRSQLITE_STDDEV_Context))));
304 1 : if (pAggCtxt->nValues > 1)
305 : {
306 1 : sqlite3_result_double(pContext,
307 1 : sqrt(pAggCtxt->dfM2 / (pAggCtxt->nValues - 1)));
308 : }
309 1 : }
310 :
311 : /************************************************************************/
312 : /* OGRSQLITE_Percentile_Step() */
313 : /************************************************************************/
314 :
315 : // Percentile related code inspired from https://sqlite.org/src/file/ext/misc/percentile.c
316 : // of https://www.sqlite.org/draft/percentile.html
317 :
318 : // Constant added to Percentile::rPct, since rPct is initialized to 0 when unset.
319 : constexpr double PERCENT_ADD_CONSTANT = 1;
320 :
321 : namespace
322 : {
323 : struct Percentile
324 : {
325 : double rPct; /* PERCENT_ADD_CONSTANT more than the value for P */
326 : std::vector<double> *values; /* Array of Y values */
327 : };
328 : } // namespace
329 :
330 : /*
331 : ** The "step" function for percentile(Y,P) is called once for each
332 : ** input row.
333 : */
334 31 : static void OGRSQLITE_Percentile_Step(sqlite3_context *pCtx, int argc,
335 : sqlite3_value **argv)
336 : {
337 31 : assert(argc == 2 || argc == 1);
338 :
339 : double rPct;
340 :
341 31 : if (argc == 1)
342 : {
343 : /* Requirement 13: median(Y) is the same as percentile(Y,50). */
344 9 : rPct = 50.0;
345 : }
346 22 : else if (sqlite3_user_data(pCtx) == nullptr)
347 : {
348 : /* Requirement 3: P must be a number between 0 and 100 */
349 12 : const int eType = sqlite3_value_numeric_type(argv[1]);
350 12 : rPct = sqlite3_value_double(argv[1]);
351 12 : if ((eType != SQLITE_INTEGER && eType != SQLITE_FLOAT) || rPct < 0.0 ||
352 : rPct > 100.0)
353 : {
354 3 : sqlite3_result_error(pCtx,
355 : "2nd argument to percentile() is not "
356 : "a number between 0.0 and 100.0",
357 : -1);
358 11 : return;
359 : }
360 : }
361 : else
362 : {
363 : /* Requirement 3: P must be a number between 0 and 1 */
364 10 : const int eType = sqlite3_value_numeric_type(argv[1]);
365 10 : rPct = sqlite3_value_double(argv[1]);
366 10 : if ((eType != SQLITE_INTEGER && eType != SQLITE_FLOAT) || rPct < 0.0 ||
367 : rPct > 1.0)
368 : {
369 3 : sqlite3_result_error(pCtx,
370 : "2nd argument to percentile_cont() is not "
371 : "a number between 0.0 and 1.0",
372 : -1);
373 3 : return;
374 : }
375 7 : rPct *= 100.0;
376 : }
377 :
378 : /* Allocate the session context. */
379 : auto p = static_cast<Percentile *>(
380 25 : sqlite3_aggregate_context(pCtx, sizeof(Percentile)));
381 25 : if (!p)
382 0 : return;
383 :
384 : /* Remember the P value. Throw an error if the P value is different
385 : ** from any prior row, per Requirement (2). */
386 25 : if (p->rPct == 0.0)
387 : {
388 11 : p->rPct = rPct + PERCENT_ADD_CONSTANT;
389 : }
390 14 : else if (p->rPct != rPct + PERCENT_ADD_CONSTANT)
391 : {
392 1 : sqlite3_result_error(pCtx,
393 : "2nd argument to percentile() is not the "
394 : "same for all input rows",
395 : -1);
396 1 : return;
397 : }
398 :
399 : /* Ignore rows for which the value is NULL */
400 24 : const int eType = sqlite3_value_type(argv[0]);
401 24 : if (eType == SQLITE_NULL)
402 3 : return;
403 :
404 : /* If not NULL, then Y must be numeric. Otherwise throw an error.
405 : ** Requirement 4 */
406 21 : if (eType != SQLITE_INTEGER && eType != SQLITE_FLOAT)
407 : {
408 1 : sqlite3_result_error(pCtx,
409 : "1st argument to percentile() is not "
410 : "numeric",
411 : -1);
412 1 : return;
413 : }
414 :
415 : /* Ignore rows for which the value is NaN */
416 20 : const double v = sqlite3_value_double(argv[0]);
417 20 : if (std::isnan(v))
418 : {
419 0 : return;
420 : }
421 :
422 20 : if (!p->values)
423 11 : p->values = new std::vector<double>();
424 : try
425 : {
426 20 : p->values->push_back(v);
427 : }
428 0 : catch (const std::exception &)
429 : {
430 0 : delete p->values;
431 0 : memset(p, 0, sizeof(*p));
432 0 : sqlite3_result_error_nomem(pCtx);
433 0 : return;
434 : }
435 : }
436 :
437 : /************************************************************************/
438 : /* OGRSQLITE_Percentile_Finalize() */
439 : /************************************************************************/
440 :
441 : /*
442 : ** Called to compute the final output of percentile() and to clean
443 : ** up all allocated memory.
444 : */
445 14 : static void OGRSQLITE_Percentile_Finalize(sqlite3_context *pCtx)
446 : {
447 14 : auto p = static_cast<Percentile *>(sqlite3_aggregate_context(pCtx, 0));
448 14 : if (!p)
449 3 : return;
450 11 : if (!p->values)
451 0 : return;
452 11 : if (!p->values->empty())
453 : {
454 11 : std::sort(p->values->begin(), p->values->end());
455 22 : const double ix = (p->rPct - PERCENT_ADD_CONSTANT) *
456 11 : static_cast<double>(p->values->size() - 1) * 0.01;
457 11 : const size_t i1 = static_cast<size_t>(ix);
458 : const size_t i2 =
459 3 : ix == static_cast<double>(i1) || i1 == p->values->size() - 1
460 14 : ? i1
461 11 : : i1 + 1;
462 11 : const double v1 = (*p->values)[i1];
463 11 : const double v2 = (*p->values)[i2];
464 11 : const double vx = v1 + (v2 - v1) * static_cast<double>(ix - i1);
465 11 : sqlite3_result_double(pCtx, vx);
466 : }
467 11 : delete p->values;
468 11 : memset(p, 0, sizeof(*p));
469 : }
470 :
471 : /************************************************************************/
472 : /* OGRSQLITE_Mode_Step() */
473 : /************************************************************************/
474 :
475 : namespace
476 : {
477 : struct Mode
478 : {
479 : std::map<double, uint64_t> *numericValues;
480 : std::map<std::string, uint64_t> *stringValues;
481 : double mostFrequentNumValue;
482 : std::string *mostFrequentStr;
483 : uint64_t mostFrequentValueCount;
484 : bool mostFrequentValueIsStr;
485 : };
486 : } // namespace
487 :
488 19 : static void OGRSQLITE_Mode_Step(sqlite3_context *pCtx, int /*argc*/,
489 : sqlite3_value **argv)
490 : {
491 19 : const int eType = sqlite3_value_type(argv[0]);
492 19 : if (eType == SQLITE_NULL)
493 1 : return;
494 :
495 18 : if (eType == SQLITE_BLOB)
496 : {
497 0 : sqlite3_result_error(pCtx, "BLOB argument not supported for mode()",
498 : -1);
499 0 : return;
500 : }
501 :
502 : /* Allocate the session context. */
503 18 : auto p = static_cast<Mode *>(sqlite3_aggregate_context(pCtx, sizeof(Mode)));
504 18 : if (!p)
505 0 : return;
506 :
507 : try
508 : {
509 18 : if (eType == SQLITE_TEXT)
510 : {
511 : const char *pszStr =
512 9 : reinterpret_cast<const char *>(sqlite3_value_text(argv[0]));
513 9 : if (!p->stringValues)
514 : {
515 3 : p->stringValues = new std::map<std::string, uint64_t>();
516 3 : p->mostFrequentStr = new std::string();
517 : }
518 9 : const uint64_t count = ++(*p->stringValues)[pszStr];
519 9 : if (count > p->mostFrequentValueCount)
520 : {
521 4 : p->mostFrequentValueCount = count;
522 4 : p->mostFrequentValueIsStr = true;
523 4 : *(p->mostFrequentStr) = pszStr;
524 : }
525 : }
526 : else
527 : {
528 9 : const double v = sqlite3_value_double(argv[0]);
529 9 : if (std::isnan(v))
530 0 : return;
531 9 : if (!p->numericValues)
532 3 : p->numericValues = new std::map<double, uint64_t>();
533 9 : const uint64_t count = ++(*p->numericValues)[v];
534 9 : if (count > p->mostFrequentValueCount)
535 : {
536 4 : p->mostFrequentValueCount = count;
537 4 : p->mostFrequentValueIsStr = false;
538 4 : p->mostFrequentNumValue = v;
539 : }
540 : }
541 : }
542 0 : catch (const std::exception &)
543 : {
544 0 : delete p->stringValues;
545 0 : delete p->numericValues;
546 0 : delete p->mostFrequentStr;
547 0 : memset(p, 0, sizeof(*p));
548 0 : sqlite3_result_error_nomem(pCtx);
549 0 : return;
550 : }
551 : }
552 :
553 : /************************************************************************/
554 : /* OGRSQLITE_Mode_Finalize() */
555 : /************************************************************************/
556 :
557 5 : static void OGRSQLITE_Mode_Finalize(sqlite3_context *pCtx)
558 : {
559 5 : auto p = static_cast<Mode *>(sqlite3_aggregate_context(pCtx, 0));
560 5 : if (!p)
561 1 : return;
562 :
563 4 : if (p->mostFrequentValueCount)
564 : {
565 4 : if (p->mostFrequentValueIsStr)
566 : {
567 3 : sqlite3_result_text(pCtx, p->mostFrequentStr->c_str(), -1,
568 : SQLITE_TRANSIENT);
569 : }
570 : else
571 : {
572 1 : sqlite3_result_double(pCtx, p->mostFrequentNumValue);
573 : }
574 : }
575 :
576 4 : delete p->stringValues;
577 4 : delete p->numericValues;
578 4 : delete p->mostFrequentStr;
579 4 : memset(p, 0, sizeof(*p));
580 : }
581 :
582 : /************************************************************************/
583 : /* OGRSQLiteRegisterSQLFunctionsCommon() */
584 : /************************************************************************/
585 :
586 : #ifndef SQLITE_DETERMINISTIC
587 : #define SQLITE_DETERMINISTIC 0
588 : #endif
589 :
590 : #ifndef SQLITE_INNOCUOUS
591 : #define SQLITE_INNOCUOUS 0
592 : #endif
593 :
594 : #define UTF8_INNOCUOUS (SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_INNOCUOUS)
595 :
596 3140 : static OGRSQLiteExtensionData *OGRSQLiteRegisterSQLFunctionsCommon(sqlite3 *hDB)
597 : {
598 3140 : OGRSQLiteExtensionData *pData = new OGRSQLiteExtensionData(hDB);
599 :
600 3140 : sqlite3_create_function(hDB, "gdal_get_pixel_value", 5, SQLITE_UTF8, pData,
601 : OGRSQLITE_gdal_get_pixel_value, nullptr, nullptr);
602 3140 : sqlite3_create_function(hDB, "gdal_get_pixel_value", 6, SQLITE_UTF8, pData,
603 : OGRSQLITE_gdal_get_pixel_value, nullptr, nullptr);
604 :
605 3140 : if (CPLTestBool(CPLGetConfigOption("OGR_SQLITE_USE_CUSTOM_LIKE", "YES")))
606 : {
607 3140 : sqlite3_create_function(hDB, "LIKE", 2, UTF8_INNOCUOUS, pData,
608 : OGRSQLITE_LIKE, nullptr, nullptr);
609 3140 : sqlite3_create_function(hDB, "LIKE", 3, UTF8_INNOCUOUS, pData,
610 : OGRSQLITE_LIKE, nullptr, nullptr);
611 : }
612 :
613 3140 : sqlite3_create_function(hDB, "STDDEV_POP", 1, UTF8_INNOCUOUS, nullptr,
614 : nullptr, OGRSQLITE_STDDEV_Step,
615 : OGRSQLITE_STDDEV_POP_Finalize);
616 :
617 3140 : sqlite3_create_function(hDB, "STDDEV_SAMP", 1, UTF8_INNOCUOUS, nullptr,
618 : nullptr, OGRSQLITE_STDDEV_Step,
619 : OGRSQLITE_STDDEV_SAMP_Finalize);
620 :
621 3140 : sqlite3_create_function(hDB, "median", 1, UTF8_INNOCUOUS, nullptr, nullptr,
622 : OGRSQLITE_Percentile_Step,
623 : OGRSQLITE_Percentile_Finalize);
624 :
625 3140 : sqlite3_create_function(hDB, "percentile", 2, UTF8_INNOCUOUS, nullptr,
626 : nullptr, OGRSQLITE_Percentile_Step,
627 : OGRSQLITE_Percentile_Finalize);
628 :
629 3140 : sqlite3_create_function(
630 : hDB, "percentile_cont", 2, UTF8_INNOCUOUS,
631 : const_cast<char *>("percentile_cont"), // any non-null ptr
632 : nullptr, OGRSQLITE_Percentile_Step, OGRSQLITE_Percentile_Finalize);
633 :
634 3140 : sqlite3_create_function(hDB, "mode", 1, UTF8_INNOCUOUS, nullptr, nullptr,
635 : OGRSQLITE_Mode_Step, OGRSQLITE_Mode_Finalize);
636 :
637 3140 : pData->SetRegExpCache(OGRSQLiteRegisterRegExpFunction(hDB));
638 :
639 3140 : return pData;
640 : }
641 :
642 : /************************************************************************/
643 : /* OGRSQLiteUnregisterSQLFunctions() */
644 : /************************************************************************/
645 :
646 3493 : static void OGRSQLiteUnregisterSQLFunctions(void *hHandle)
647 : {
648 3493 : OGRSQLiteExtensionData *pData =
649 : static_cast<OGRSQLiteExtensionData *>(hHandle);
650 3493 : delete pData;
651 3493 : }
652 :
653 : #ifdef DEFINE_OGRSQLiteSQLFunctionsSetCaseSensitiveLike
654 : /************************************************************************/
655 : /* OGRSQLiteSQLFunctionsSetCaseSensitiveLike() */
656 : /************************************************************************/
657 :
658 4 : static void OGRSQLiteSQLFunctionsSetCaseSensitiveLike(void *hHandle, bool b)
659 : {
660 4 : OGRSQLiteExtensionData *pData =
661 : static_cast<OGRSQLiteExtensionData *>(hHandle);
662 4 : pData->SetCaseSensitiveLike(b);
663 4 : }
664 : #endif
|