1 : /******************************************************************************
2 : * $Id: ogrsqliteregexp.cpp 25052 2012-10-05 23:30:16Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: SQLite REGEXP function
6 : * Author: Even Rouault, even dot rouault at mines dash paris dot org
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2012, Even Rouault <even dot rouault at mines dash paris dot org>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : /* This code originates from pcre.c from the sqlite3-pcre extension */
31 : /* from http://laltromondo.dynalias.net/~iki/informatica/soft/sqlite3-pcre/ */
32 : /* whose header is : */
33 : /*
34 : * Written by Alexey Tourbin <at@altlinux.org>.
35 : *
36 : * The author has dedicated the code to the public domain. Anyone is free
37 : * to copy, modify, publish, use, compile, sell, or distribute the original
38 : * code, either in source code form or as a compiled binary, for any purpose,
39 : * commercial or non-commercial, and by any means.
40 : */
41 :
42 :
43 : #include "ogrsqliteregexp.h"
44 :
45 : #ifdef HAVE_PCRE
46 :
47 : #include <pcre.h>
48 :
49 : typedef struct {
50 : char *s;
51 : pcre *p;
52 : pcre_extra *e;
53 : } cache_entry;
54 :
55 : #ifndef CACHE_SIZE
56 : #define CACHE_SIZE 16
57 : #endif
58 :
59 : /************************************************************************/
60 : /* OGRSQLiteREGEXPFunction() */
61 : /************************************************************************/
62 :
63 : static
64 95 : void OGRSQLiteREGEXPFunction(sqlite3_context *ctx, int argc, sqlite3_value **argv)
65 : {
66 : const char *re, *str;
67 : pcre *p;
68 : pcre_extra *e;
69 :
70 95 : CPLAssert(argc == 2);
71 :
72 95 : re = (const char *) sqlite3_value_text(argv[0]);
73 95 : if (!re) {
74 2 : sqlite3_result_error(ctx, "no regexp", -1);
75 2 : return;
76 : }
77 :
78 93 : if( sqlite3_value_type(argv[1]) == SQLITE_NULL )
79 : {
80 2 : sqlite3_result_int(ctx, 0);
81 2 : return;
82 : }
83 :
84 91 : str = (const char *) sqlite3_value_text(argv[1]);
85 91 : if (!str) {
86 0 : sqlite3_result_error(ctx, "no string", -1);
87 0 : return;
88 : }
89 :
90 : /* simple LRU cache */
91 : int i;
92 91 : int found = 0;
93 91 : cache_entry *cache = (cache_entry*) sqlite3_user_data(ctx);
94 :
95 91 : CPLAssert(cache);
96 :
97 913 : for (i = 0; i < CACHE_SIZE && cache[i].s; i++)
98 : {
99 828 : if (strcmp(re, cache[i].s) == 0) {
100 6 : found = 1;
101 6 : break;
102 : }
103 : }
104 :
105 91 : if (found)
106 : {
107 6 : if (i > 0)
108 : {
109 4 : cache_entry c = cache[i];
110 4 : memmove(cache + 1, cache, i * sizeof(cache_entry));
111 4 : cache[0] = c;
112 : }
113 : }
114 : else
115 : {
116 : cache_entry c;
117 : const char *err;
118 : int pos;
119 85 : c.p = pcre_compile(re, 0, &err, &pos, NULL);
120 85 : if (!c.p)
121 : {
122 2 : char *e2 = sqlite3_mprintf("%s: %s (offset %d)", re, err, pos);
123 2 : sqlite3_result_error(ctx, e2, -1);
124 2 : sqlite3_free(e2);
125 2 : return;
126 : }
127 83 : c.e = pcre_study(c.p, 0, &err);
128 83 : c.s = VSIStrdup(re);
129 83 : if (!c.s)
130 : {
131 0 : sqlite3_result_error(ctx, "strdup: ENOMEM", -1);
132 0 : pcre_free(c.p);
133 0 : pcre_free(c.e);
134 0 : return;
135 : }
136 83 : i = CACHE_SIZE - 1;
137 83 : if (cache[i].s)
138 : {
139 36 : CPLFree(cache[i].s);
140 36 : CPLAssert(cache[i].p);
141 36 : pcre_free(cache[i].p);
142 36 : pcre_free(cache[i].e);
143 : }
144 83 : memmove(cache + 1, cache, i * sizeof(cache_entry));
145 83 : cache[0] = c;
146 : }
147 89 : p = cache[0].p;
148 89 : e = cache[0].e;
149 :
150 : int rc;
151 89 : CPLAssert(p);
152 89 : rc = pcre_exec(p, e, str, strlen(str), 0, 0, NULL, 0);
153 89 : sqlite3_result_int(ctx, rc >= 0);
154 : }
155 :
156 : #endif // HAVE_PCRE
157 :
158 : /************************************************************************/
159 : /* OGRSQLiteRegisterRegExpFunction() */
160 : /************************************************************************/
161 :
162 634 : void* OGRSQLiteRegisterRegExpFunction(sqlite3* hDB)
163 : {
164 : #ifdef HAVE_PCRE
165 :
166 : /* For debugging purposes mostly */
167 634 : if( !CSLTestBoolean(CPLGetConfigOption("OGR_SQLITE_REGEXP", "YES")) )
168 0 : return NULL;
169 :
170 : /* Check if we really need to define our own REGEXP function */
171 634 : int rc = sqlite3_exec(hDB, "SELECT 'a' REGEXP 'a'", NULL, NULL, NULL);
172 634 : if( rc == SQLITE_OK )
173 : {
174 15 : CPLDebug("SQLITE", "REGEXP already available");
175 15 : return NULL;
176 : }
177 :
178 619 : cache_entry *cache = (cache_entry*) CPLCalloc(CACHE_SIZE, sizeof(cache_entry));
179 : sqlite3_create_function(hDB, "REGEXP", 2, SQLITE_UTF8, cache,
180 619 : OGRSQLiteREGEXPFunction, NULL, NULL);
181 :
182 : /* To clear the error flag */
183 619 : sqlite3_exec(hDB, "SELECT 1", NULL, NULL, NULL);
184 :
185 619 : return cache;
186 : #else // HAVE_PCRE
187 : return NULL;
188 : #endif // HAVE_PCRE
189 : }
190 :
191 : /************************************************************************/
192 : /* OGRSQLiteFreeRegExpCache() */
193 : /************************************************************************/
194 :
195 874 : void OGRSQLiteFreeRegExpCache(void* hRegExpCache)
196 : {
197 : #ifdef HAVE_PCRE
198 874 : if( hRegExpCache == NULL )
199 255 : return;
200 :
201 619 : cache_entry *cache = (cache_entry*) hRegExpCache;
202 : int i;
203 666 : for (i = 0; i < CACHE_SIZE && cache[i].s; i++)
204 : {
205 47 : CPLFree(cache[i].s);
206 47 : CPLAssert(cache[i].p);
207 47 : pcre_free(cache[i].p);
208 47 : pcre_free(cache[i].e);
209 : }
210 619 : CPLFree(cache);
211 : #endif // HAVE_PCRE
212 : }
|