Index: src/ctime.c ================================================================== --- src/ctime.c +++ src/ctime.c @@ -111,10 +111,13 @@ #ifdef SQLITE_ENABLE_MEMSYS5 "ENABLE_MEMSYS5", #endif #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 #ifdef SQLITE_ENABLE_STAT3 Index: src/func.c ================================================================== --- src/func.c +++ src/func.c @@ -711,10 +711,68 @@ sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape)); } } +#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 ** arguments are equal to each other. */ @@ -1588,10 +1646,14 @@ LIKEFUNC(like, 3, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), #else 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; FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions); FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aBuiltinFunc); Index: test/e_expr.test ================================================================== --- test/e_expr.test +++ test/e_expr.test @@ -1061,11 +1061,12 @@ set ::globargs [list] 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. # # There is a regexp function if ICU is enabled though. # @@ -1074,10 +1075,11 @@ SELECT regexp('abc', 'def') } {1 {no such function: regexp}} do_catchsql_test e_expr-18.1.2 { 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. # Index: test/like.test ================================================================== --- test/like.test +++ test/like.test @@ -112,15 +112,19 @@ } } {ABC abc} # 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; } } {{ABC abc xyz} abc abcd} do_test like-2.2 {