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 : }
|