LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/sqlite - ogrsqlitesqlfunctionscommon.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 214 249 85.9 %
Date: 2026-01-23 20:24:11 Functions: 21 22 95.5 %

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

Generated by: LCOV version 1.14