LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/sqlite - ogrsqlitesqlfunctionscommon.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 198 233 85.0 %
Date: 2024-11-25 13:07:18 Functions: 20 21 95.2 %

          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

Generated by: LCOV version 1.14