From b71090fdfb8600dcf5fa386e21544eb294b081f4 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 23 May 2005 17:26:51 +0000 Subject: [PATCH] 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 --- manifest | 16 +++++------ manifest.uuid | 2 +- src/expr.c | 63 +++++--------------------------------------- src/parse.y | 34 ++++++++++++------------ tool/mkkeywordhash.c | 11 ++++---- 5 files changed, 39 insertions(+), 87 deletions(-) diff --git a/manifest b/manifest index b3cc33eed5..8e0afa62e8 100644 --- a/manifest +++ b/manifest @@ -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 diff --git a/manifest.uuid b/manifest.uuid index f9adbff574..107d1b8a2f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ef4059e3afa1a61a9e59df00cdfedc57d8df9fec \ No newline at end of file +42a626ace126f730f33ecb6c41ac5679d6766a31 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 6237e75d21..7373fdc574 100644 --- a/src/expr.c +++ b/src/expr.c @@ -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 @@ -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); diff --git a/src/parse.y b/src/parse.y index 2b8d052d10..1f7c8af333 100644 --- a/src/parse.y +++ b/src/parse.y @@ -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); } diff --git a/tool/mkkeywordhash.c b/tool/mkkeywordhash.c index 582412452e..5d34257091 100644 --- a/tool/mkkeywordhash.c +++ b/tool/mkkeywordhash.c @@ -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 }, -- 2.47.3