1 : /******************************************************************************
2 : * $Id: ogrsqliteregexp.cpp 25406 2012-12-30 20:07:19Z 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 : /* WARNING: VERY IMPORTANT NOTE: This file MUST not be directly compiled as */
31 : /* a standalone object. It must be included from ogrsqlitevirtualogr.cpp */
32 : /* (actually from ogrsqlitesqlfunctions.cpp) */
33 : #ifndef COMPILATION_ALLOWED
34 : #error See comment in file
35 : #endif
36 :
37 : /* This code originates from pcre.c from the sqlite3-pcre extension */
38 : /* from http://laltromondo.dynalias.net/~iki/informatica/soft/sqlite3-pcre/ */
39 : /* whose header is : */
40 : /*
41 : * Written by Alexey Tourbin <at@altlinux.org>.
42 : *
43 : * The author has dedicated the code to the public domain. Anyone is free
44 : * to copy, modify, publish, use, compile, sell, or distribute the original
45 : * code, either in source code form or as a compiled binary, for any purpose,
46 : * commercial or non-commercial, and by any means.
47 : */
48 :
49 :
50 : #include "ogrsqliteregexp.h"
51 :
52 : #ifdef HAVE_PCRE
53 :
54 : #include <pcre.h>
55 :
56 : typedef struct {
57 : char *s;
58 : pcre *p;
59 : pcre_extra *e;
60 : } cache_entry;
61 :
62 : #ifndef CACHE_SIZE
63 : #define CACHE_SIZE 16
64 : #endif
65 :
66 : /************************************************************************/
67 : /* OGRSQLiteREGEXPFunction() */
68 : /************************************************************************/
69 :
70 : static
71 80 : void OGRSQLiteREGEXPFunction(sqlite3_context *ctx, int argc, sqlite3_value **argv)
72 : {
73 : const char *re, *str;
74 : pcre *p;
75 : pcre_extra *e;
76 :
77 80 : CPLAssert(argc == 2);
78 :
79 80 : re = (const char *) sqlite3_value_text(argv[0]);
80 80 : if (!re) {
81 2 : sqlite3_result_error(ctx, "no regexp", -1);
82 2 : return;
83 : }
84 :
85 78 : if( sqlite3_value_type(argv[1]) == SQLITE_NULL )
86 : {
87 2 : sqlite3_result_int(ctx, 0);
88 2 : return;
89 : }
90 :
91 76 : str = (const char *) sqlite3_value_text(argv[1]);
92 76 : if (!str) {
93 0 : sqlite3_result_error(ctx, "no string", -1);
94 0 : return;
95 : }
96 :
97 : /* simple LRU cache */
98 : int i;
99 76 : int found = 0;
100 76 : cache_entry *cache = (cache_entry*) sqlite3_user_data(ctx);
101 :
102 76 : CPLAssert(cache);
103 :
104 898 : for (i = 0; i < CACHE_SIZE && cache[i].s; i++)
105 : {
106 828 : if (strcmp(re, cache[i].s) == 0) {
107 6 : found = 1;
108 6 : break;
109 : }
110 : }
111 :
112 76 : if (found)
113 : {
114 6 : if (i > 0)
115 : {
116 4 : cache_entry c = cache[i];
117 4 : memmove(cache + 1, cache, i * sizeof(cache_entry));
118 4 : cache[0] = c;
119 : }
120 : }
121 : else
122 : {
123 : cache_entry c;
124 : const char *err;
125 : int pos;
126 70 : c.p = pcre_compile(re, 0, &err, &pos, NULL);
127 70 : if (!c.p)
128 : {
129 2 : char *e2 = sqlite3_mprintf("%s: %s (offset %d)", re, err, pos);
130 2 : sqlite3_result_error(ctx, e2, -1);
131 2 : sqlite3_free(e2);
132 2 : return;
133 : }
134 68 : c.e = pcre_study(c.p, 0, &err);
135 68 : c.s = VSIStrdup(re);
136 68 : if (!c.s)
137 : {
138 0 : sqlite3_result_error(ctx, "strdup: ENOMEM", -1);
139 0 : pcre_free(c.p);
140 0 : pcre_free(c.e);
141 0 : return;
142 : }
143 68 : i = CACHE_SIZE - 1;
144 68 : if (cache[i].s)
145 : {
146 36 : CPLFree(cache[i].s);
147 36 : CPLAssert(cache[i].p);
148 36 : pcre_free(cache[i].p);
149 36 : pcre_free(cache[i].e);
150 : }
151 68 : memmove(cache + 1, cache, i * sizeof(cache_entry));
152 68 : cache[0] = c;
153 : }
154 74 : p = cache[0].p;
155 74 : e = cache[0].e;
156 :
157 : int rc;
158 74 : CPLAssert(p);
159 74 : rc = pcre_exec(p, e, str, strlen(str), 0, 0, NULL, 0);
160 74 : sqlite3_result_int(ctx, rc >= 0);
161 : }
162 :
163 : #endif // HAVE_PCRE
164 :
165 : /************************************************************************/
166 : /* OGRSQLiteRegisterRegExpFunction() */
167 : /************************************************************************/
168 :
169 : static
170 751 : void* OGRSQLiteRegisterRegExpFunction(sqlite3* hDB)
171 : {
172 : #ifdef HAVE_PCRE
173 :
174 : /* For debugging purposes mostly */
175 751 : if( !CSLTestBoolean(CPLGetConfigOption("OGR_SQLITE_REGEXP", "YES")) )
176 0 : return NULL;
177 :
178 : /* Check if we really need to define our own REGEXP function */
179 751 : int rc = sqlite3_exec(hDB, "SELECT 'a' REGEXP 'a'", NULL, NULL, NULL);
180 751 : if( rc == SQLITE_OK )
181 : {
182 0 : CPLDebug("SQLITE", "REGEXP already available");
183 0 : return NULL;
184 : }
185 :
186 751 : cache_entry *cache = (cache_entry*) CPLCalloc(CACHE_SIZE, sizeof(cache_entry));
187 : sqlite3_create_function(hDB, "REGEXP", 2, SQLITE_UTF8, cache,
188 751 : OGRSQLiteREGEXPFunction, NULL, NULL);
189 :
190 : /* To clear the error flag */
191 751 : sqlite3_exec(hDB, "SELECT 1", NULL, NULL, NULL);
192 :
193 751 : return cache;
194 : #else // HAVE_PCRE
195 : return NULL;
196 : #endif // HAVE_PCRE
197 : }
198 :
199 : /************************************************************************/
200 : /* OGRSQLiteFreeRegExpCache() */
201 : /************************************************************************/
202 :
203 : static
204 751 : void OGRSQLiteFreeRegExpCache(void* hRegExpCache)
205 : {
206 : #ifdef HAVE_PCRE
207 751 : if( hRegExpCache == NULL )
208 0 : return;
209 :
210 751 : cache_entry *cache = (cache_entry*) hRegExpCache;
211 : int i;
212 783 : for (i = 0; i < CACHE_SIZE && cache[i].s; i++)
213 : {
214 32 : CPLFree(cache[i].s);
215 32 : CPLAssert(cache[i].p);
216 32 : pcre_free(cache[i].p);
217 32 : pcre_free(cache[i].e);
218 : }
219 751 : CPLFree(cache);
220 : #endif // HAVE_PCRE
221 : }
|