LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/sqlite - ogrsqliteregexp.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 72 86 83.7 %
Date: 2024-04-29 15:10:10 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  SQLite REGEXP function
       5             :  * Author:   Even Rouault, even dot rouault at spatialys.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2012, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : /* WARNING: VERY IMPORTANT NOTE: This file MUST not be directly compiled as */
      30             : /* a standalone object. It must be included from ogrsqlitevirtualogr.cpp */
      31             : /* (actually from ogrsqlitesqlfunctions.cpp) */
      32             : #ifndef COMPILATION_ALLOWED
      33             : #error See comment in file
      34             : #endif
      35             : 
      36             : /* This code originates from pcre.c from the sqlite3-pcre extension */
      37             : /* from http://laltromondo.dynalias.net/~iki/informatica/soft/sqlite3-pcre/ */
      38             : /* whose header is : */
      39             : /*
      40             :  * Written by Alexey Tourbin <at@altlinux.org>.
      41             :  *
      42             :  * The author has dedicated the code to the public domain.  Anyone is free
      43             :  * to copy, modify, publish, use, compile, sell, or distribute the original
      44             :  * code, either in source code form or as a compiled binary, for any purpose,
      45             :  * commercial or non-commercial, and by any means.
      46             :  */
      47             : 
      48             : // The pcre2 variant has been ported from
      49             : // https://github.com/pfmoore/sqlite-pcre2/blob/main/src/pcre.c which has the
      50             : // same license as above.
      51             : 
      52             : #include "ogrsqliteregexp.h"
      53             : #include "sqlite3.h"
      54             : 
      55             : #ifdef HAVE_PCRE2
      56             : 
      57             : #define PCRE2_CODE_UNIT_WIDTH 8
      58             : #include <pcre2.h>
      59             : 
      60             : typedef struct
      61             : {
      62             :     char *s;
      63             :     pcre2_code *p;
      64             : } cache_entry;
      65             : 
      66             : constexpr int CACHE_SIZE = 16;
      67             : 
      68          38 : static pcre2_code *re_compile_with_cache(sqlite3_context *ctx, const char *re)
      69             : {
      70          38 :     cache_entry *cache = static_cast<cache_entry *>(sqlite3_user_data(ctx));
      71             : 
      72          38 :     CPLAssert(cache);
      73             : 
      74          38 :     bool found = false;
      75             :     int i;
      76         449 :     for (i = 0; i < CACHE_SIZE && cache[i].s; i++)
      77         414 :         if (strcmp(re, cache[i].s) == 0)
      78             :         {
      79           3 :             found = true;
      80           3 :             break;
      81             :         }
      82             : 
      83          38 :     if (found)
      84             :     {
      85           3 :         if (i > 0)
      86             :         {
      87             :             /* Get the found entry */
      88           2 :             cache_entry c = cache[i];
      89             :             /* Move 0..i-1 up one - args are (dest, src, size) */
      90           2 :             memmove(cache + 1, cache, i * sizeof(cache_entry));
      91             :             /* Put the found entry at the start */
      92           2 :             cache[0] = c;
      93             :         }
      94             :     }
      95             :     else
      96             :     {
      97             :         /* Create a new entry */
      98          35 :         int errorcode = 0;
      99          35 :         PCRE2_SIZE pos = 0;
     100          35 :         uint32_t has_jit = 0;
     101             :         PCRE2_UCHAR8 err_buff[256];
     102             : 
     103             :         pcre2_code *pat =
     104          35 :             pcre2_compile(reinterpret_cast<const PCRE2_UCHAR8 *>(re),
     105             :                           PCRE2_ZERO_TERMINATED, 0, &errorcode, &pos, nullptr);
     106          35 :         if (!pat)
     107             :         {
     108           1 :             pcre2_get_error_message(errorcode, err_buff, sizeof(err_buff));
     109           1 :             char *e2 = sqlite3_mprintf("%s: %s (offset %d)", re, err_buff, pos);
     110           1 :             sqlite3_result_error(ctx, e2, -1);
     111           1 :             sqlite3_free(e2);
     112           1 :             return nullptr;
     113             :         }
     114          34 :         pcre2_config(PCRE2_CONFIG_JIT, &has_jit);
     115          34 :         if (has_jit)
     116             :         {
     117          34 :             errorcode = pcre2_jit_compile(pat, 0);
     118          34 :             if (errorcode)
     119             :             {
     120           0 :                 pcre2_get_error_message(errorcode, err_buff, sizeof(err_buff));
     121           0 :                 char *e2 = sqlite3_mprintf("%s: %s", re, err_buff);
     122           0 :                 sqlite3_result_error(ctx, e2, -1);
     123           0 :                 sqlite3_free(e2);
     124           0 :                 pcre2_code_free(pat);
     125           0 :                 return nullptr;
     126             :             }
     127             :         }
     128             :         /* Free the last cache entry if necessary */
     129          34 :         i = CACHE_SIZE - 1;
     130          34 :         if (cache[i].s)
     131             :         {
     132          18 :             VSIFree(cache[i].s);
     133          18 :             CPLAssert(cache[i].p);
     134          18 :             pcre2_code_free(cache[i].p);
     135             :         }
     136             :         /* Move everything up to make space */
     137          34 :         memmove(cache + 1, cache, i * sizeof(cache_entry));
     138          34 :         cache[0].s = VSIStrdup(re);
     139          34 :         cache[0].p = pat;
     140             :     }
     141             : 
     142          37 :     return cache[0].p;
     143             : }
     144             : 
     145             : /************************************************************************/
     146             : /*                         OGRSQLiteREGEXPFunction()                    */
     147             : /************************************************************************/
     148             : 
     149          40 : static void OGRSQLiteREGEXPFunction(sqlite3_context *ctx, CPL_UNUSED int argc,
     150             :                                     sqlite3_value **argv)
     151             : {
     152          40 :     CPLAssert(argc == 2);
     153             : 
     154          40 :     const char *re = (const char *)sqlite3_value_text(argv[0]);
     155          40 :     if (!re)
     156             :     {
     157           1 :         sqlite3_result_error(ctx, "no regexp", -1);
     158           1 :         return;
     159             :     }
     160             : 
     161          39 :     if (sqlite3_value_type(argv[1]) == SQLITE_NULL)
     162             :     {
     163           1 :         sqlite3_result_int(ctx, 0);
     164           1 :         return;
     165             :     }
     166             : 
     167          38 :     const char *str = (const char *)sqlite3_value_text(argv[1]);
     168          38 :     if (!str)
     169             :     {
     170           0 :         sqlite3_result_error(ctx, "no string", -1);
     171           0 :         return;
     172             :     }
     173             : 
     174          38 :     pcre2_code *p = re_compile_with_cache(ctx, re);
     175          38 :     if (!p)
     176           1 :         return;
     177             : 
     178          37 :     pcre2_match_data *md = pcre2_match_data_create_from_pattern(p, nullptr);
     179          37 :     if (!md)
     180             :     {
     181           0 :         sqlite3_result_error(ctx, "could not create match data block", -1);
     182           0 :         return;
     183             :     }
     184          37 :     int rc = pcre2_match(p, reinterpret_cast<const PCRE2_UCHAR8 *>(str),
     185             :                          PCRE2_ZERO_TERMINATED, 0, 0, md, nullptr);
     186          37 :     sqlite3_result_int(ctx, rc >= 0);
     187             : }
     188             : 
     189             : #elif defined(HAVE_PCRE)
     190             : 
     191             : #include <pcre.h>
     192             : 
     193             : typedef struct
     194             : {
     195             :     char *s;
     196             :     pcre *p;
     197             :     pcre_extra *e;
     198             : } cache_entry;
     199             : 
     200             : constexpr int CACHE_SIZE = 16;
     201             : 
     202             : /************************************************************************/
     203             : /*                         OGRSQLiteREGEXPFunction()                    */
     204             : /************************************************************************/
     205             : 
     206             : static void OGRSQLiteREGEXPFunction(sqlite3_context *ctx, CPL_UNUSED int argc,
     207             :                                     sqlite3_value **argv)
     208             : {
     209             :     CPLAssert(argc == 2);
     210             : 
     211             :     const char *re = (const char *)sqlite3_value_text(argv[0]);
     212             :     if (!re)
     213             :     {
     214             :         sqlite3_result_error(ctx, "no regexp", -1);
     215             :         return;
     216             :     }
     217             : 
     218             :     if (sqlite3_value_type(argv[1]) == SQLITE_NULL)
     219             :     {
     220             :         sqlite3_result_int(ctx, 0);
     221             :         return;
     222             :     }
     223             : 
     224             :     const char *str = (const char *)sqlite3_value_text(argv[1]);
     225             :     if (!str)
     226             :     {
     227             :         sqlite3_result_error(ctx, "no string", -1);
     228             :         return;
     229             :     }
     230             : 
     231             :     /* simple LRU cache */
     232             :     cache_entry *cache = (cache_entry *)sqlite3_user_data(ctx);
     233             :     CPLAssert(cache);
     234             : 
     235             :     bool found = false;
     236             :     int i = 0;  // Used after for.
     237             :     for (; i < CACHE_SIZE && cache[i].s; i++)
     238             :     {
     239             :         if (strcmp(re, cache[i].s) == 0)
     240             :         {
     241             :             found = true;
     242             :             break;
     243             :         }
     244             :     }
     245             : 
     246             :     if (found)
     247             :     {
     248             :         if (i > 0)
     249             :         {
     250             :             cache_entry c = cache[i];
     251             :             memmove(cache + 1, cache, i * sizeof(cache_entry));
     252             :             cache[0] = c;
     253             :         }
     254             :     }
     255             :     else
     256             :     {
     257             :         cache_entry c;
     258             :         const char *err = nullptr;
     259             :         int pos = 0;
     260             :         c.p = pcre_compile(re, 0, &err, &pos, nullptr);
     261             :         if (!c.p)
     262             :         {
     263             :             char *e2 = sqlite3_mprintf("%s: %s (offset %d)", re, err, pos);
     264             :             sqlite3_result_error(ctx, e2, -1);
     265             :             sqlite3_free(e2);
     266             :             return;
     267             :         }
     268             :         c.e = pcre_study(c.p, 0, &err);
     269             :         c.s = VSIStrdup(re);
     270             :         if (!c.s)
     271             :         {
     272             :             sqlite3_result_error(ctx, "strdup: ENOMEM", -1);
     273             :             pcre_free(c.p);
     274             :             pcre_free(c.e);
     275             :             return;
     276             :         }
     277             :         i = CACHE_SIZE - 1;
     278             :         if (cache[i].s)
     279             :         {
     280             :             CPLFree(cache[i].s);
     281             :             CPLAssert(cache[i].p);
     282             :             pcre_free(cache[i].p);
     283             :             pcre_free(cache[i].e);
     284             :         }
     285             :         memmove(cache + 1, cache, i * sizeof(cache_entry));
     286             :         cache[0] = c;
     287             :     }
     288             :     pcre *p = cache[0].p;
     289             :     CPLAssert(p);
     290             :     pcre_extra *e = cache[0].e;
     291             : 
     292             :     int rc =
     293             :         pcre_exec(p, e, str, static_cast<int>(strlen(str)), 0, 0, nullptr, 0);
     294             :     sqlite3_result_int(ctx, rc >= 0);
     295             : }
     296             : 
     297             : #endif  // HAVE_PCRE
     298             : 
     299             : /************************************************************************/
     300             : /*                        OGRSQLiteRegisterRegExpFunction()             */
     301             : /************************************************************************/
     302             : 
     303        2889 : static void *OGRSQLiteRegisterRegExpFunction(sqlite3 *
     304             : #if defined(HAVE_PCRE) || defined(HAVE_PCRE2)
     305             :                                                  hDB
     306             : #endif
     307             : )
     308             : {
     309             : #if defined(HAVE_PCRE) || defined(HAVE_PCRE2)
     310             : 
     311             :     /* For debugging purposes mostly */
     312        1218 :     if (!CPLTestBool(CPLGetConfigOption("OGR_SQLITE_REGEXP", "YES")))
     313           0 :         return nullptr;
     314             : 
     315             :     /* Check if we really need to define our own REGEXP function */
     316             :     int rc =
     317        1218 :         sqlite3_exec(hDB, "SELECT 'a' REGEXP 'a'", nullptr, nullptr, nullptr);
     318        1218 :     if (rc == SQLITE_OK)
     319             :     {
     320           0 :         CPLDebug("SQLITE", "REGEXP already available");
     321           0 :         return nullptr;
     322             :     }
     323             : 
     324             :     cache_entry *cache =
     325        1218 :         (cache_entry *)CPLCalloc(CACHE_SIZE, sizeof(cache_entry));
     326        1218 :     sqlite3_create_function(hDB, "REGEXP", 2, SQLITE_UTF8, cache,
     327             :                             OGRSQLiteREGEXPFunction, nullptr, nullptr);
     328             : 
     329             :     /* To clear the error flag */
     330        1218 :     sqlite3_exec(hDB, "SELECT 1", nullptr, nullptr, nullptr);
     331             : 
     332        1218 :     return cache;
     333             : #else   // HAVE_PCRE
     334        1671 :     return nullptr;
     335             : #endif  // HAVE_PCRE
     336             : }
     337             : 
     338             : /************************************************************************/
     339             : /*                         OGRSQLiteFreeRegExpCache()                   */
     340             : /************************************************************************/
     341             : 
     342        2889 : static void OGRSQLiteFreeRegExpCache(void *
     343             : #if defined(HAVE_PCRE) || defined(HAVE_PCRE2)
     344             :                                          hRegExpCache
     345             : #endif
     346             : )
     347             : {
     348             : #ifdef HAVE_PCRE2
     349        1218 :     if (hRegExpCache == nullptr)
     350           0 :         return;
     351             : 
     352        1218 :     cache_entry *cache = (cache_entry *)hRegExpCache;
     353        1234 :     for (int i = 0; i < CACHE_SIZE && cache[i].s; i++)
     354             :     {
     355          16 :         CPLFree(cache[i].s);
     356          16 :         CPLAssert(cache[i].p);
     357          16 :         pcre2_code_free(cache[i].p);
     358             :     }
     359        1218 :     CPLFree(cache);
     360             : #elif defined(HAVE_PCRE)
     361             :     if (hRegExpCache == nullptr)
     362             :         return;
     363             : 
     364             :     cache_entry *cache = (cache_entry *)hRegExpCache;
     365             :     for (int i = 0; i < CACHE_SIZE && cache[i].s; i++)
     366             :     {
     367             :         CPLFree(cache[i].s);
     368             :         CPLAssert(cache[i].p);
     369             :         pcre_free(cache[i].p);
     370             :         pcre_free(cache[i].e);
     371             :     }
     372             :     CPLFree(cache);
     373             : #endif  // HAVE_PCRE
     374        1671 : }

Generated by: LCOV version 1.14