EVOLUTION-MANAGER
Edit File: ogrsqliteregexp.cpp
/****************************************************************************** * * Project: OpenGIS Simple Features Reference Implementation * Purpose: SQLite REGEXP function * Author: Even Rouault, even dot rouault at mines dash paris dot org * ****************************************************************************** * Copyright (c) 2012, Even Rouault <even dot rouault at mines-paris dot org> * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************/ /* WARNING: VERY IMPORTANT NOTE: This file MUST not be directly compiled as */ /* a standalone object. It must be included from ogrsqlitevirtualogr.cpp */ /* (actually from ogrsqlitesqlfunctions.cpp) */ #ifndef COMPILATION_ALLOWED #error See comment in file #endif /* This code originates from pcre.c from the sqlite3-pcre extension */ /* from http://laltromondo.dynalias.net/~iki/informatica/soft/sqlite3-pcre/ */ /* whose header is : */ /* * Written by Alexey Tourbin <at@altlinux.org>. * * The author has dedicated the code to the public domain. Anyone is free * to copy, modify, publish, use, compile, sell, or distribute the original * code, either in source code form or as a compiled binary, for any purpose, * commercial or non-commercial, and by any means. */ #include "ogrsqliteregexp.h" #ifdef HAVE_PCRE #include <pcre.h> typedef struct { char *s; pcre *p; pcre_extra *e; } cache_entry; static const int CACHE_SIZE = 16; /************************************************************************/ /* OGRSQLiteREGEXPFunction() */ /************************************************************************/ static void OGRSQLiteREGEXPFunction( sqlite3_context *ctx, CPL_UNUSED int argc, sqlite3_value **argv ) { CPLAssert(argc == 2); const char *re = (const char *) sqlite3_value_text(argv[0]); if (!re) { sqlite3_result_error(ctx, "no regexp", -1); return; } if( sqlite3_value_type(argv[1]) == SQLITE_NULL ) { sqlite3_result_int(ctx, 0); return; } const char *str = (const char *) sqlite3_value_text(argv[1]); if (!str) { sqlite3_result_error(ctx, "no string", -1); return; } /* simple LRU cache */ cache_entry *cache = (cache_entry*) sqlite3_user_data(ctx); CPLAssert(cache); bool found = false; int i = 0; // Used after for. for( ; i < CACHE_SIZE && cache[i].s; i++ ) { if (strcmp(re, cache[i].s) == 0) { found = true; break; } } if( found ) { if( i > 0 ) { cache_entry c = cache[i]; memmove(cache + 1, cache, i * sizeof(cache_entry)); cache[0] = c; } } else { cache_entry c; const char *err = NULL; int pos = 0; c.p = pcre_compile(re, 0, &err, &pos, NULL); if (!c.p) { char *e2 = sqlite3_mprintf("%s: %s (offset %d)", re, err, pos); sqlite3_result_error(ctx, e2, -1); sqlite3_free(e2); return; } c.e = pcre_study(c.p, 0, &err); c.s = VSIStrdup(re); if (!c.s) { sqlite3_result_error(ctx, "strdup: ENOMEM", -1); pcre_free(c.p); pcre_free(c.e); return; } i = CACHE_SIZE - 1; if (cache[i].s) { CPLFree(cache[i].s); CPLAssert(cache[i].p); pcre_free(cache[i].p); pcre_free(cache[i].e); } memmove(cache + 1, cache, i * sizeof(cache_entry)); cache[0] = c; } pcre *p = cache[0].p; CPLAssert(p); pcre_extra *e = cache[0].e; int rc = pcre_exec(p, e, str, static_cast<int>(strlen(str)), 0, 0, NULL, 0); sqlite3_result_int(ctx, rc >= 0); } #endif // HAVE_PCRE /************************************************************************/ /* OGRSQLiteRegisterRegExpFunction() */ /************************************************************************/ static void* OGRSQLiteRegisterRegExpFunction(sqlite3* #ifdef HAVE_PCRE hDB #endif ) { #ifdef HAVE_PCRE /* For debugging purposes mostly */ if( !CPLTestBool(CPLGetConfigOption("OGR_SQLITE_REGEXP", "YES")) ) return NULL; /* Check if we really need to define our own REGEXP function */ int rc = sqlite3_exec(hDB, "SELECT 'a' REGEXP 'a'", NULL, NULL, NULL); if( rc == SQLITE_OK ) { CPLDebug("SQLITE", "REGEXP already available"); return NULL; } cache_entry *cache = (cache_entry*) CPLCalloc(CACHE_SIZE, sizeof(cache_entry)); sqlite3_create_function(hDB, "REGEXP", 2, SQLITE_UTF8, cache, OGRSQLiteREGEXPFunction, NULL, NULL); /* To clear the error flag */ sqlite3_exec(hDB, "SELECT 1", NULL, NULL, NULL); return cache; #else // HAVE_PCRE return NULL; #endif // HAVE_PCRE } /************************************************************************/ /* OGRSQLiteFreeRegExpCache() */ /************************************************************************/ static void OGRSQLiteFreeRegExpCache(void* #ifdef HAVE_PCRE hRegExpCache #endif ) { #ifdef HAVE_PCRE if( hRegExpCache == NULL ) return; cache_entry *cache = (cache_entry*) hRegExpCache; for( int i = 0; i < CACHE_SIZE && cache[i].s; i++ ) { CPLFree(cache[i].s); CPLAssert(cache[i].p); pcre_free(cache[i].p); pcre_free(cache[i].e); } CPLFree(cache); #endif // HAVE_PCRE }