The REGEXP operator is recognized. It tries to invoke a function named

regexp() which does not exist in the native build.  But users who want to
can add an appropriate regexp() function using sqlite3_create_function(). (CVS 2478)

FossilOrigin-Name: 42a626ace126f730f33ecb6c41ac5679d6766a31
This commit is contained in:
drh 2005-05-23 17:26:51 +00:00
parent 15ccce1c0d
commit b71090fdfb
5 changed files with 39 additions and 87 deletions

View File

@ -1,5 +1,5 @@
C Make\ssure\sthat\sthe\suse\sof\sa\sdouble-quoted\sstring\sliteral\sdoes\snot\strick\nthe\soptimizer\sinto\susing\sa\scorrelated\ssubquery\swhen\sa\sstatic\nsubquery\swould\ssuffice.\s(CVS\s2477)
D 2005-05-23T15:06:39
C The\sREGEXP\soperator\sis\srecognized.\s\sIt\stries\sto\sinvoke\sa\sfunction\snamed\r\nregexp()\swhich\sdoes\snot\sexist\sin\sthe\snative\sbuild.\s\sBut\susers\swho\swant\sto\r\ncan\sadd\san\sappropriate\sregexp()\sfunction\susing\ssqlite3_create_function().\s(CVS\s2478)
D 2005-05-23T17:26:51
F Makefile.in 5c00d0037104de2a50ac7647a5f12769795957a3
F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@ -36,7 +36,7 @@ F src/build.c 6770abc63df9f3ed9f44c50411bb63692cb4589f
F src/date.c 2134ef4388256e8247405178df8a61bd60dc180a
F src/delete.c 75b53db21aa1879d3655bbbc208007db31d58a63
F src/experimental.c 50c1e3b34f752f4ac10c36f287db095c2b61766d
F src/expr.c f2ff12d9970d844564ec8b3ce4ea702bf6730b6a
F src/expr.c d0fbb951fd260feb2e2028c5ec078e98daca5bb6
F src/func.c d09df82e35ef988cd28a3ffd63cd772271b7def9
F src/hash.c 2b1b13f7400e179631c83a1be0c664608c8f021f
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
@ -54,7 +54,7 @@ F src/os_win.c 2bbbe6fbb010763c3fa79d5e951afca9b138c6b5
F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
F src/pager.c f86d79d37eb4e30d8e2201dbe12497370719320c
F src/pager.h 0d9153d6269d60d04af3dd84a0cc0a96253cf4a4
F src/parse.y 3e314b3a96b199b0501ed426f2cee3392ffce806
F src/parse.y 72cd7553f05fbc7b63ea9476108d0da6237f2818
F src/pragma.c 0ed94a1aa982802a9cf2a932c48d99b60683fa53
F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
@ -223,7 +223,7 @@ F tool/lempar.c f0c30abcae762a7d1eb37cd88b2232ab8dd625fb
F tool/memleak.awk 4e7690a51bf3ed757e611273d43fe3f65b510133
F tool/memleak2.awk 9cc20c8e8f3c675efac71ea0721ee6874a1566e8
F tool/memleak3.tcl 009da0ea82dc5893edca76cf1a21fb7260e9412e
F tool/mkkeywordhash.c 02ac5c523fd6d55364cd70aded5c36ba6651a6bf
F tool/mkkeywordhash.c 596389943f516bf6eaddd46659e7b87b16ea7c33
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e x
F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
F tool/report1.txt 9eae07f26a8fc53889b45fc833a66a33daa22816
@ -279,7 +279,7 @@ F www/tclsqlite.tcl 425be741b8ae664f55cb1ef2371aab0a75109cf9
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
F www/whentouse.tcl 528299b8316726dbcc5548e9aa0648c8b1bd055b
P f7b76d02e003faf0310b87949d3cb0f38062853f
R 7f9d3157fe368f24bc8a9f1b20f7fe23
P ef4059e3afa1a61a9e59df00cdfedc57d8df9fec
R 8996a199d8872550587b98a7437c931f
U drh
Z b4157a0f7dc132bb0373ae1877998e51
Z 797c50f3e25833784eb0ca0d6800d861

View File

@ -1 +1 @@
ef4059e3afa1a61a9e59df00cdfedc57d8df9fec
42a626ace126f730f33ecb6c41ac5679d6766a31

View File

@ -12,7 +12,7 @@
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.199 2005/05/23 15:06:39 drh Exp $
** $Id: expr.c,v 1.200 2005/05/23 17:26:51 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@ -994,49 +994,6 @@ lookupname_end_2:
}
}
/*
** pExpr is a node that defines a function of some kind. It might
** be a syntactic function like "count(x)" or it might be a function
** that implements an operator, like "a LIKE b".
**
** This routine makes *pzName point to the name of the function and
** *pnName hold the number of characters in the function name.
*/
static void getFunctionName(Expr *pExpr, const char **pzName, int *pnName){
switch( pExpr->op ){
case TK_FUNCTION: {
*pzName = pExpr->token.z;
*pnName = pExpr->token.n;
break;
}
case TK_LIKE: {
*pzName = "like";
*pnName = 4;
break;
}
case TK_GLOB: {
*pzName = "glob";
*pnName = 4;
break;
}
case TK_CTIME: {
*pzName = "current_time";
*pnName = 12;
break;
}
case TK_CDATE: {
*pzName = "current_date";
*pnName = 12;
break;
}
case TK_CTIMESTAMP: {
*pzName = "current_timestamp";
*pnName = 17;
break;
}
}
}
/*
** This routine is designed as an xFunc for walkExprTree().
**
@ -1111,11 +1068,7 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
/* Resolve function names
*/
case TK_CTIME:
case TK_CTIMESTAMP:
case TK_CDATE:
case TK_GLOB:
case TK_LIKE:
case TK_CONST_FUNC:
case TK_FUNCTION: {
ExprList *pList = pExpr->pList; /* The argument list */
int n = pList ? pList->nExpr : 0; /* Number of arguments */
@ -1128,7 +1081,8 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
FuncDef *pDef; /* Information about the function */
int enc = pParse->db->enc; /* The database encoding */
getFunctionName(pExpr, &zId, &nId);
zId = pExpr->token.z;
nId = pExpr->token.n;
pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
if( pDef==0 ){
pDef = sqlite3FindFunction(pParse->db, zId, nId, -1, enc, 0);
@ -1544,11 +1498,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
sqlite3VdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg);
break;
}
case TK_CDATE:
case TK_CTIME:
case TK_CTIMESTAMP:
case TK_GLOB:
case TK_LIKE:
case TK_CONST_FUNC:
case TK_FUNCTION: {
ExprList *pList = pExpr->pList;
int nExpr = pList ? pList->nExpr : 0;
@ -1559,7 +1509,8 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
int i;
u8 enc = pParse->db->enc;
CollSeq *pColl = 0;
getFunctionName(pExpr, &zId, &nId);
zId = pExpr->token.z;
nId = pExpr->token.n;
pDef = sqlite3FindFunction(pParse->db, zId, nId, nExpr, enc, 0);
assert( pDef!=0 );
nExpr = sqlite3ExprCodeExprList(pParse, pList);

View File

@ -14,7 +14,7 @@
** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $Id: parse.y,v 1.171 2005/04/22 02:38:38 drh Exp $
** @(#) $Id: parse.y,v 1.172 2005/05/23 17:26:51 drh Exp $
*/
%token_prefix TK_
%token_type {Token}
@ -48,8 +48,8 @@ struct LimitVal {
** GLOB, NOT LIKE, and NOT GLOB operators.
*/
struct LikeOp {
int opcode; /* Either TK_GLOB or TK_LIKE */
int not; /* True if the NOT keyword is present */
Token operator; /* "like" or "glob" or "regexp" */
int not; /* True if the NOT keyword is present */
};
/*
@ -75,7 +75,7 @@ struct AttachKey { int type; Token key; };
// add them to the parse.h output file.
//
%nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
COLUMN AGG_FUNCTION.
COLUMN AGG_FUNCTION CONST_FUNC.
// Input is a single SQL command
input ::= cmdlist.
@ -153,13 +153,13 @@ id(A) ::= ID(X). {A = X;}
%fallback ID
ABORT AFTER ASC ATTACH BEFORE BEGIN CASCADE CONFLICT
DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
GLOB IGNORE IMMEDIATE INITIALLY INSTEAD LIKE MATCH KEY
IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH KEY
OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW STATEMENT
TEMP TRIGGER VACUUM VIEW
%ifdef SQLITE_OMIT_COMPOUND_SELECT
EXCEPT INTERSECT UNION
%endif
REINDEX RENAME CDATE CTIME CTIMESTAMP ALTER
REINDEX RENAME CTIME_KW ALTER
.
// Define operator precedence early so that this is the first occurance
@ -176,7 +176,7 @@ id(A) ::= ID(X). {A = X;}
%left OR.
%left AND.
%right NOT.
%left IS LIKE GLOB BETWEEN IN ISNULL NOTNULL NE EQ.
%left IS LIKE_KW BETWEEN IN ISNULL NOTNULL NE EQ.
%left GT LE LT GE.
%right ESCAPE.
%left BITAND BITOR LSHIFT RSHIFT.
@ -627,9 +627,12 @@ expr(A) ::= ID(X) LP STAR RP(E). {
A = sqlite3ExprFunction(0, &X);
sqlite3ExprSpan(A,&X,&E);
}
term(A) ::= CTIME(OP). {A = sqlite3Expr(@OP,0,0,0);}
term(A) ::= CDATE(OP). {A = sqlite3Expr(@OP,0,0,0);}
term(A) ::= CTIMESTAMP(OP). {A = sqlite3Expr(@OP,0,0,0);}
term(A) ::= CTIME_KW(OP). {
/* The CURRENT_TIME, CURRENT_DATE, and CURRENT_TIMESTAMP values are
** treated as functions that return constants */
A = sqlite3ExprFunction(0,&OP);
if( A ) A->op = TK_CONST_FUNC;
}
expr(A) ::= expr(X) AND(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) OR(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) LT(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
@ -649,21 +652,18 @@ expr(A) ::= expr(X) SLASH(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) REM(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) CONCAT(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
%type likeop {struct LikeOp}
likeop(A) ::= LIKE. {A.opcode = TK_LIKE; A.not = 0;}
likeop(A) ::= GLOB. {A.opcode = TK_GLOB; A.not = 0;}
likeop(A) ::= NOT LIKE. {A.opcode = TK_LIKE; A.not = 1;}
likeop(A) ::= NOT GLOB. {A.opcode = TK_GLOB; A.not = 1;}
likeop(A) ::= LIKE_KW(X). {A.operator = X; A.not = 0;}
likeop(A) ::= NOT LIKE_KW(X). {A.operator = X; A.not = 1;}
%type escape {Expr*}
escape(X) ::= ESCAPE expr(A). [ESCAPE] {X = A;}
escape(X) ::= . [ESCAPE] {X = 0;}
expr(A) ::= expr(X) likeop(OP) expr(Y) escape(E). [LIKE] {
expr(A) ::= expr(X) likeop(OP) expr(Y) escape(E). [LIKE_KW] {
ExprList *pList = sqlite3ExprListAppend(0, Y, 0);
pList = sqlite3ExprListAppend(pList, X, 0);
if( E ){
pList = sqlite3ExprListAppend(pList, E, 0);
}
A = sqlite3ExprFunction(pList, 0);
if( A ) A->op = OP.opcode;
A = sqlite3ExprFunction(pList, &OP.operator);
if( OP.not ) A = sqlite3Expr(TK_NOT, A, 0, 0);
sqlite3ExprSpan(A, &X->span, &Y->span);
}

View File

@ -125,9 +125,9 @@ static Keyword aKeywordTable[] = {
{ "CONSTRAINT", "TK_CONSTRAINT", ALWAYS },
{ "CREATE", "TK_CREATE", ALWAYS },
{ "CROSS", "TK_JOIN_KW", ALWAYS },
{ "CURRENT_DATE", "TK_CDATE", ALWAYS },
{ "CURRENT_TIME", "TK_CTIME", ALWAYS },
{ "CURRENT_TIMESTAMP","TK_CTIMESTAMP", ALWAYS },
{ "CURRENT_DATE", "TK_CTIME_KW", ALWAYS },
{ "CURRENT_TIME", "TK_CTIME_KW", ALWAYS },
{ "CURRENT_TIMESTAMP","TK_CTIME_KW", ALWAYS },
{ "DATABASE", "TK_DATABASE", ATTACH },
{ "DEFAULT", "TK_DEFAULT", ALWAYS },
{ "DEFERRED", "TK_DEFERRED", ALWAYS },
@ -150,7 +150,7 @@ static Keyword aKeywordTable[] = {
{ "FOREIGN", "TK_FOREIGN", FKEY },
{ "FROM", "TK_FROM", ALWAYS },
{ "FULL", "TK_JOIN_KW", ALWAYS },
{ "GLOB", "TK_GLOB", ALWAYS },
{ "GLOB", "TK_LIKE_KW", ALWAYS },
{ "GROUP", "TK_GROUP", ALWAYS },
{ "HAVING", "TK_HAVING", ALWAYS },
{ "IGNORE", "TK_IGNORE", CONFLICT|TRIGGER },
@ -168,7 +168,7 @@ static Keyword aKeywordTable[] = {
{ "JOIN", "TK_JOIN", ALWAYS },
{ "KEY", "TK_KEY", ALWAYS },
{ "LEFT", "TK_JOIN_KW", ALWAYS },
{ "LIKE", "TK_LIKE", ALWAYS },
{ "LIKE", "TK_LIKE_KW", ALWAYS },
{ "LIMIT", "TK_LIMIT", ALWAYS },
{ "MATCH", "TK_MATCH", ALWAYS },
{ "NATURAL", "TK_JOIN_KW", ALWAYS },
@ -185,6 +185,7 @@ static Keyword aKeywordTable[] = {
{ "PRIMARY", "TK_PRIMARY", ALWAYS },
{ "RAISE", "TK_RAISE", TRIGGER },
{ "REFERENCES", "TK_REFERENCES", FKEY },
{ "REGEXP", "TK_LIKE_KW", ALWAYS },
{ "REINDEX", "TK_REINDEX", REINDEX },
{ "RENAME", "TK_RENAME", ALTER },
{ "REPLACE", "TK_REPLACE", CONFLICT },