From c88729662be53131f33a7d732fa2f21f34150c82 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 12 Sep 2012 18:45:31 +0000 Subject: [PATCH] Add an implementation of the REGEXP operator and function. Only defined if compiled with SQLITE_ENABLE_REGEXP. FossilOrigin-Name: 8398f77c5a689c795c5b1e8eea41a3b128dba2fd --- manifest | 21 +++++++++------- manifest.uuid | 2 +- src/ctime.c | 3 +++ src/func.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++ test/e_expr.test | 4 +++- test/like.test | 6 ++++- 6 files changed, 86 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index d2a266f241..69de9a7e31 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Update\sversion\snumber\sto\s3.7.15.\s\sDelete\ssome\sobsolete\sbuild\sscripts. -D 2012-09-12T00:11:20.574 +C Add\san\simplementation\sof\sthe\sREGEXP\soperator\sand\sfunction.\s\sOnly\sdefined\nif\scompiled\swith\sSQLITE_ENABLE_REGEXP. +D 2012-09-12T18:45:31.050 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in abd5c10d21d1395f140d9e50ea999df8fa4d6376 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -127,13 +127,13 @@ F src/btreeInt.h 4e5c2bd0f9b36b2a815a6d84f771a61a65830621 F src/build.c a3b700afd475e6387da59be6f2e86161e80d6d87 F src/callback.c 0cb4228cdcd827dcc5def98fb099edcc9142dbcd F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac -F src/ctime.c 500d019da966631ad957c37705642be87524463b +F src/ctime.c a67101c1a1175167b5f40d4a626bf2eae7a1a2c4 F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4 F src/delete.c 335f36750dc6ac88d580aa36a6487459be9889de F src/expr.c 217840a107dcc1e5dbb57cea311daad04bedbb9a F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 9c77d842dc9961d92a06a65abb80c64ef1750296 -F src/func.c b4e88b92838fdab8e0088cc8411c06664b4dcf55 +F src/func.c 2290b491113e37df29c721c4b69a8aaf641b7664 F src/global.c 4cfdca5cb0edd33c4d021baec4ede958cb2c793b F src/hash.c a4031441741932da9e7a65bee2b36b5d0e81c073 F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970 @@ -379,7 +379,7 @@ F test/e_createtable.test 48598b15e8fe6554d301e7b65a10c9851f177e84 F test/e_delete.test 89aa84d3d1bd284a0689ede04bce10226a5aeaa5 F test/e_droptrigger.test afd5c4d27dec607f5997a66bf7e2498a082cb235 F test/e_dropview.test 583411e470458c5d76148542cfb5a5fa84c8f93e -F test/e_expr.test 5489424d3d9a452ac3701cdf4b680ae31a157894 +F test/e_expr.test 5bc5c9a9eca98ae9a2be449869be7dea5105ed9b F test/e_fkey.test 057eed81a41a2b21b1790032f4e8aaba0b2b0e17 F test/e_fts3.test 5c02288842e4f941896fd44afdef564dd5fc1459 F test/e_insert.test c6ac239a97cb16dfbd0c16496f8cd871b4068c0c @@ -564,7 +564,7 @@ F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa F test/keyword1.test a2400977a2e4fde43bf33754c2929fda34dbca05 F test/lastinsert.test 474d519c68cb79d07ecae56a763aa7f322c72f51 F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200 -F test/like.test 7b4aaa4a8192fdec90e0a905984c92a688c51e48 +F test/like.test 25bca9aab5ea225d98516deefcfe63f7980753bc F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da F test/limit.test 2db7b3b34fb925b8e847d583d2eb67531d0ce67e F test/loadext.test 2b5e249c51c986a5aff1f0950cf7ba30976c8f22 @@ -1012,7 +1012,10 @@ F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 67d8a99aceb56384a81b3f30d6c71743146d2cc9 -P bf8a9ca5b58404112a8af666f5840b462b7bbfe1 -R 847379dec46339e4d4e3d3e07e9871f0 +P 9402f81fade5fcae0a3a6efdc7a5cdf71fc2e79f +R b672680dc581b045b45a052a3b299996 +T *branch * regexp +T *sym-regexp * +T -sym-trunk * U drh -Z a42f3ee2165757bae1503891985c3bca +Z 41a8b832e7bd7f20e716b240445415a6 diff --git a/manifest.uuid b/manifest.uuid index 9a08d83f21..10a7768f61 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9402f81fade5fcae0a3a6efdc7a5cdf71fc2e79f \ No newline at end of file +8398f77c5a689c795c5b1e8eea41a3b128dba2fd \ No newline at end of file diff --git a/src/ctime.c b/src/ctime.c index 61cf4e3df1..11074d1440 100644 --- a/src/ctime.c +++ b/src/ctime.c @@ -114,6 +114,9 @@ static const char * const azCompileOpt[] = { #ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK "ENABLE_OVERSIZE_CELL_CHECK", #endif +#ifdef SQLITE_ENABLE_REGEXP + "ENABLE_REGEXP", +#endif #ifdef SQLITE_ENABLE_RTREE "ENABLE_RTREE", #endif diff --git a/src/func.c b/src/func.c index 9d81d0c741..962a9895f7 100644 --- a/src/func.c +++ b/src/func.c @@ -713,6 +713,64 @@ static void likeFunc( } } +#if defined(SQLITE_ENABLE_REGEXP) +#include +#include + +/* +** Free a regex_t object obtained from sqlite_malloc(). +*/ +static void regexpFree(void *pToFree){ + regex_t *pRe = (regex_t*)pToFree; + regfree(pRe); + sqlite3_free(pRe); +} + +/* +** Implementation of the regexp() SQL function. This function implements +** the build-in REGEXP operator. The first argument to the function is the +** pattern and the second argument is the string. So, the SQL statements: +** +** A REGEXP B +** +** is implemented as regexp(B,A). +*/ +static void regexpFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + regex_t *pRe; + int rc; + char zErr[100]; + + pRe = sqlite3_get_auxdata(context, 0); + if( pRe==0 ){ + pRe = sqlite3_malloc( sizeof(*pRe) ); + if( pRe==0 ){ + sqlite3_result_error_nomem(context); + return; + } + memset(pRe, 0, sizeof(*pRe)); + rc = regcomp(pRe, (const char*)sqlite3_value_text(argv[0]), + REG_NOSUB|REG_EXTENDED); + if( rc ){ + regerror(rc, pRe, zErr, sizeof(zErr)); + sqlite3_result_error(context, zErr, -1); + regfree(pRe); + }else{ + sqlite3_set_auxdata(context, 0, pRe, regexpFree); + } + } + rc = regexec(pRe, (const char*)sqlite3_value_text(argv[1]), 0, 0, 0); + if( rc==0 ){ + sqlite3_result_int(context, 1); + }else{ + sqlite3_result_int(context, 0); + } +} +#endif /* defined(SQLITE_ENABLE_REGEXP) */ + /* ** Implementation of the NULLIF(x,y) function. The result is the first ** argument if the arguments are different. The result is NULL if the @@ -1590,6 +1648,10 @@ void sqlite3RegisterGlobalFunctions(void){ LIKEFUNC(like, 2, &likeInfoNorm, SQLITE_FUNC_LIKE), LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE), #endif + +#if defined(SQLITE_ENABLE_REGEXP) + FUNCTION(regexp, 2, 0, 0, regexpFunc ), +#endif }; int i; diff --git a/test/e_expr.test b/test/e_expr.test index 74d0c40712..9d36337ad4 100644 --- a/test/e_expr.test +++ b/test/e_expr.test @@ -1063,7 +1063,8 @@ do_execsql_test e_expr-17.3.3 { SELECT 'X' NOT GLOB 'Y' } 0 do_test e_expr-17.3.4 { set globargs } {Y X} sqlite3 db test.db -# EVIDENCE-OF: R-41650-20872 No regexp() user function is defined by +if 0 { +# xxxxEVIDENCE-OF: R-41650-20872 No regexp() user function is defined by # default and so use of the REGEXP operator will normally result in an # error message. # @@ -1077,6 +1078,7 @@ ifcapable !icu { SELECT 'abc' REGEXP 'def' } {1 {no such function: REGEXP}} } +} # EVIDENCE-OF: R-33693-50180 The REGEXP operator is a special syntax for # the regexp() user function. diff --git a/test/like.test b/test/like.test index 767efd5828..f779ee9aa2 100644 --- a/test/like.test +++ b/test/like.test @@ -114,11 +114,15 @@ do_test like-1.10 { # Tests of the REGEXP operator # -do_test like-2.1 { +db eval {SELECT sqlite_compileoption_used('ENABLE_REGEXP') AS has_regexp} break; +if {$has_regexp==0} { proc test_regexp {a b} { return [regexp $a $b] } db function regexp -argcount 2 test_regexp + puts "# installing substitute REGEXP function" +} +do_test like-2.1 { execsql { SELECT x FROM t1 WHERE x REGEXP 'abc' ORDER BY 1; } -- 2.39.5