From: drh Date: Sat, 20 Apr 2002 14:24:41 +0000 (+0000) Subject: Fix for ticket #1: Implement the GLOB and LIKE operators as functions that X-Git-Tag: version-3.6.10~5538 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0ac65892029701ce75bfc6d4286f837c2d8618d7;p=thirdparty%2Fsqlite.git Fix for ticket #1: Implement the GLOB and LIKE operators as functions that can be overridden. This way, a developer can change the LIKE operator to be case sensitive, for example. (CVS 537) FossilOrigin-Name: 51572bf71774d7631c7083be90b806e621bc9bee --- diff --git a/VERSION b/VERSION index e30309f735..f041bc6dba 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.4.7 +2.4.8 diff --git a/manifest b/manifest index d1483440c8..6b8e1adb8d 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C Add\ssupport\sfor\ssaving\sthe\ssqlite\sshell\scommand-line\shistory\sacross\ssessions.\s(CVS\s536) -D 2002-04-19T12:34:06 +C Fix\sfor\sticket\s#1:\sImplement\sthe\sGLOB\sand\sLIKE\soperators\sas\sfunctions\sthat\ncan\sbe\soverridden.\s\sThis\sway,\sa\sdeveloper\scan\schange\sthe\sLIKE\soperator\sto\nbe\scase\ssensitive,\sfor\sexample.\s(CVS\s537) +D 2002-04-20T14:24:42 F Makefile.in 50f1b3351df109b5774771350d8c1b8d3640130d F Makefile.template 89e373b2dad0321df00400fa968dc14b61a03296 F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0 -F VERSION bb2c45e1821c29d3e52ea953e25a4c4a2d2f15e7 +F VERSION 5446cf3087aa40ee419d025faa144cfb7da913b7 F aclocal.m4 11faa843caa38fd451bc6aeb43e248d1723a269d F config.guess f38b1e93d1e0fa6f5a6913e9e7b12774b9232588 F config.log 6a73d03433669b10a3f0c221198c3f26b9413914 @@ -24,8 +24,8 @@ F src/btree.c 7dd7ddc66459982dd0cb9800958c1f8d65a32d9f F src/btree.h 8abeabfe6e0b1a990b64fa457592a6482f6674f3 F src/build.c d01b81f41481e733e27ab2fa8e1bfcc64f24257d F src/delete.c 6a6b8192cdff5e4b083da3bc63de099f3790d01f -F src/expr.c e7a1e22bc2ebcd789f0f8c0db544cf16ad664054 -F src/func.c dca9df811298cd0beb3724d40cee348e884352b2 +F src/expr.c cf8d2ea17e419fc83b23e080195b2952e0be4164 +F src/func.c a31dcba85bc2ecb9b752980289cf7e6cd0cafbce F src/hash.c cc259475e358baaf299b00a2c7370f2b03dda892 F src/hash.h dca065dda89d4575f3176e75e9a3dc0f4b4fb8b9 F src/insert.c 31233f44fc79edbb43523a830e54736a8e222ff4 @@ -35,7 +35,7 @@ F src/os.c 5ab8b6b4590d0c1ab8e96c67996c170e4462e0fc F src/os.h 4a361fccfbc4e7609b3e1557f604f94c1e96ad10 F src/pager.c ba5740104cc27b342cd43eebfdc44d60f64a3ded F src/pager.h 6fddfddd3b73aa8abc081b973886320e3c614f0e -F src/parse.y 9a8a2311dd95101bb02b3991042e619eea49729a +F src/parse.y 0ce56f1c751657f01e18a4b4ac1aa4d29525ac20 F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe F src/select.c 92aef3f69e90dc065d680d88b1f075409e9249bb @@ -52,8 +52,8 @@ F src/threadtest.c 81f0598e0f031c1bd506af337fdc1b7e8dff263f F src/tokenize.c 5624d342601f616157ba266abccc1368a5afee70 F src/update.c 7dd714a6a7fa47f849ebb36b6d915974d6c6accb F src/util.c b34cd91387bbfdc79319ea451a7d120cef478120 -F src/vdbe.c 9213ff1ab136eabcf3e8a58157765a01274bf8e9 -F src/vdbe.h f9be1f6e9a336c3ff4d14ea7489ee976e07460cc +F src/vdbe.c 0ed88fff32273c103a24396d491b71bc69b4b596 +F src/vdbe.h 67840a462e1daedb958cca0ccc97db140d3d9152 F src/where.c 9d36f6c9fea4af71501770c13089f824cb9b033c F test/all.test 6aa106eee4d7127afa5cee97c51a783a79694ead F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578 @@ -110,7 +110,7 @@ F tool/opNames.awk 5ba1f48aa854ee3b7c3d2b54233665bc3e649ea2 F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c F tool/renumberOps.awk 6d067177ad5f8d711b79577b462da9b3634bd0a9 F tool/report1.txt 9eae07f26a8fc53889b45fc833a66a33daa22816 -F tool/speedtest.tcl 6d89431651f2eb800fb0998a8de44b84168e08b9 +F tool/speedtest.tcl 8287851340fd4a9500a69e9b10fb5ed9e6b0d0c3 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4 @@ -131,7 +131,7 @@ F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 -P 6c32c07e8218caffebd4503e7d8a90226ac81cdc -R fdf61026ce1ec867dd8bbc684e7b26b1 +P ca4abf3fe1f0e66802f9f98a20e0c8b82a6459aa +R 296e96183752df57d48880aeba4ee595 U drh -Z efe3d88b41e036fdbd5e6a43e4d0b877 +Z 1714d41230ea0b8c518108a22a7c1e16 diff --git a/manifest.uuid b/manifest.uuid index 1fc9a30e56..359ebe3d97 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ca4abf3fe1f0e66802f9f98a20e0c8b82a6459aa \ No newline at end of file +51572bf71774d7631c7083be90b806e621bc9bee \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 5b0e732c66..9184758b66 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.57 2002/03/24 13:13:29 drh Exp $ +** $Id: expr.c,v 1.58 2002/04/20 14:24:42 drh Exp $ */ #include "sqliteInt.h" @@ -705,8 +705,6 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){ case TK_GE: op = OP_Ge; break; case TK_NE: op = OP_Ne; break; case TK_EQ: op = OP_Eq; break; - case TK_LIKE: op = OP_Like; break; - case TK_GLOB: op = OP_Glob; break; case TK_ISNULL: op = OP_IsNull; break; case TK_NOTNULL: op = OP_NotNull; break; case TK_NOT: op = OP_Not; break; @@ -784,9 +782,7 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){ case TK_GT: case TK_GE: case TK_NE: - case TK_EQ: - case TK_LIKE: - case TK_GLOB: { + case TK_EQ: { int dest; sqliteVdbeAddOp(v, OP_Integer, 1, 0); sqliteExprCode(pParse, pExpr->pLeft); @@ -938,8 +934,6 @@ void sqliteExprIfTrue(Parse *pParse, Expr *pExpr, int dest){ case TK_GE: op = OP_Ge; break; case TK_NE: op = OP_Ne; break; case TK_EQ: op = OP_Eq; break; - case TK_LIKE: op = OP_Like; break; - case TK_GLOB: op = OP_Glob; break; case TK_ISNULL: op = OP_IsNull; break; case TK_NOTNULL: op = OP_NotNull; break; default: break; @@ -966,9 +960,7 @@ void sqliteExprIfTrue(Parse *pParse, Expr *pExpr, int dest){ case TK_GT: case TK_GE: case TK_NE: - case TK_EQ: - case TK_LIKE: - case TK_GLOB: { + case TK_EQ: { sqliteExprCode(pParse, pExpr->pLeft); sqliteExprCode(pParse, pExpr->pRight); sqliteVdbeAddOp(v, op, 0, dest); @@ -1026,8 +1018,6 @@ void sqliteExprIfFalse(Parse *pParse, Expr *pExpr, int dest){ case TK_GE: op = OP_Lt; break; case TK_NE: op = OP_Eq; break; case TK_EQ: op = OP_Ne; break; - case TK_LIKE: op = OP_Like; break; - case TK_GLOB: op = OP_Glob; break; case TK_ISNULL: op = OP_NotNull; break; case TK_NOTNULL: op = OP_IsNull; break; default: break; @@ -1060,13 +1050,6 @@ void sqliteExprIfFalse(Parse *pParse, Expr *pExpr, int dest){ sqliteVdbeAddOp(v, op, 0, dest); break; } - case TK_LIKE: - case TK_GLOB: { - sqliteExprCode(pParse, pExpr->pLeft); - sqliteExprCode(pParse, pExpr->pRight); - sqliteVdbeAddOp(v, op, 1, dest); - break; - } case TK_ISNULL: case TK_NOTNULL: { sqliteExprCode(pParse, pExpr->pLeft); diff --git a/src/func.c b/src/func.c index c75a65beea..ac4c05f448 100644 --- a/src/func.c +++ b/src/func.c @@ -16,7 +16,7 @@ ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. ** -** $Id: func.c,v 1.15 2002/04/06 14:10:47 drh Exp $ +** $Id: func.c,v 1.16 2002/04/20 14:24:42 drh Exp $ */ #include #include @@ -200,11 +200,39 @@ static void randomFunc(sqlite_func *context, int argc, const char **argv){ ** Implementation of the last_insert_rowid() SQL function. The return ** value is the same as the sqlite_last_insert_rowid() API function. */ -static void last_insert_rowid(sqlite_func *context, int arg, char **argv){ +static void last_insert_rowid(sqlite_func *context, int arg, const char **argv){ sqlite *db = sqlite_user_data(context); sqlite_set_result_int(context, sqlite_last_insert_rowid(db)); } +/* +** Implementation of the like() SQL function. This function implements +** the build-in LIKE operator. The first argument to the function is the +** string and the second argument is the pattern. So, the SQL statements: +** +** A LIKE B +** +** is implemented as like(A,B). +*/ +static void likeFunc(sqlite_func *context, int arg, const char **argv){ + sqlite_set_result_int(context, + sqliteLikeCompare(argv[0] ? argv[0] : "",argv[1] ? argv[1] : "")); +} + +/* +** Implementation of the glob() SQL function. This function implements +** the build-in GLOB operator. The first argument to the function is the +** string and the second argument is the pattern. So, the SQL statements: +** +** A GLOB B +** +** is implemented as glob(A,B). +*/ +static void globFunc(sqlite_func *context, int arg, const char **argv){ + sqlite_set_result_int(context, + sqliteGlobCompare(argv[0] ? argv[0] : "",argv[1] ? argv[1] : "")); +} + /* ** An instance of the following structure holds the context of a ** sum() or avg() aggregate computation. @@ -394,6 +422,8 @@ void sqliteRegisterBuildinFunctions(sqlite *db){ { "coalesce", 0, 0 }, { "coalesce", 1, 0 }, { "random", -1, randomFunc }, + { "like", 2, likeFunc }, + { "glob", 2, globFunc }, }; static struct { char *zName; diff --git a/src/parse.y b/src/parse.y index 4838543187..cf89bb1155 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.61 2002/04/06 13:57:43 drh Exp $ +** @(#) $Id: parse.y,v 1.62 2002/04/20 14:24:42 drh Exp $ */ %token_prefix TK_ %token_type {Token} @@ -431,18 +431,21 @@ expr(A) ::= expr(X) BITAND expr(Y). {A = sqliteExpr(TK_BITAND, X, Y, 0);} expr(A) ::= expr(X) BITOR expr(Y). {A = sqliteExpr(TK_BITOR, X, Y, 0);} expr(A) ::= expr(X) LSHIFT expr(Y). {A = sqliteExpr(TK_LSHIFT, X, Y, 0);} expr(A) ::= expr(X) RSHIFT expr(Y). {A = sqliteExpr(TK_RSHIFT, X, Y, 0);} -expr(A) ::= expr(X) LIKE expr(Y). {A = sqliteExpr(TK_LIKE, X, Y, 0);} -expr(A) ::= expr(X) NOT LIKE expr(Y). { - A = sqliteExpr(TK_LIKE, X, Y, 0); - A = sqliteExpr(TK_NOT, A, 0, 0); - sqliteExprSpan(A,&X->span,&Y->span); -} -expr(A) ::= expr(X) GLOB expr(Y). {A = sqliteExpr(TK_GLOB,X,Y,0);} -expr(A) ::= expr(X) NOT GLOB expr(Y). { - A = sqliteExpr(TK_GLOB, X, Y, 0); +expr(A) ::= expr(X) likeop(OP) expr(Y). [LIKE] { + ExprList *pList = sqliteExprListAppend(0, Y, 0); + pList = sqliteExprListAppend(pList, X, 0); + A = sqliteExprFunction(pList, &OP); + sqliteExprSpan(A, &X->span, &Y->span); +} +expr(A) ::= expr(X) NOT likeop(OP) expr(Y). [LIKE] { + ExprList *pList = sqliteExprListAppend(0, Y, 0); + pList = sqliteExprListAppend(pList, X, 0); + A = sqliteExprFunction(pList, &OP); A = sqliteExpr(TK_NOT, A, 0, 0); sqliteExprSpan(A,&X->span,&Y->span); } +likeop(A) ::= LIKE(X). {A = X;} +likeop(A) ::= GLOB(X). {A = X;} expr(A) ::= expr(X) PLUS expr(Y). {A = sqliteExpr(TK_PLUS, X, Y, 0);} expr(A) ::= expr(X) MINUS expr(Y). {A = sqliteExpr(TK_MINUS, X, Y, 0);} expr(A) ::= expr(X) STAR expr(Y). {A = sqliteExpr(TK_STAR, X, Y, 0);} diff --git a/src/vdbe.c b/src/vdbe.c index 2c9a35b32a..319fbd027b 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -30,7 +30,7 @@ ** But other routines are also provided to help in building up ** a program instruction by instruction. ** -** $Id: vdbe.c,v 1.138 2002/04/12 10:09:00 drh Exp $ +** $Id: vdbe.c,v 1.139 2002/04/20 14:24:42 drh Exp $ */ #include "sqliteInt.h" #include @@ -1058,11 +1058,11 @@ static char *zOpName[] = { 0, "MustBeInt", "Add", "AddImm", "Subtract", "Multiply", "Divide", "Remainder", "BitAnd", "BitOr", "BitNot", "ShiftLeft", "ShiftRight", - "AbsValue", "Like", "Glob", "Eq", - "Ne", "Lt", "Le", "Gt", - "Ge", "IsNull", "NotNull", "Negative", - "And", "Or", "Not", "Concat", - "Noop", "Function", "Limit", + "AbsValue", "Eq", "Ne", "Lt", + "Le", "Gt", "Ge", "IsNull", + "NotNull", "Negative", "And", "Or", + "Not", "Concat", "Noop", "Function", + "Limit", }; /* @@ -2011,69 +2011,6 @@ case OP_Ge: { break; } -/* Opcode: Like P1 P2 * -** -** Pop the top two elements from the stack. The top-most is a -** "like" pattern -- the right operand of the SQL "LIKE" operator. -** The lower element is the string to compare against the like -** pattern. Jump to P2 if the two compare, and fall through without -** jumping if they do not. The '%' in the top-most element matches -** any sequence of zero or more characters in the lower element. The -** '_' character in the topmost matches any single character of the -** lower element. Case is ignored for this comparison. -** -** If P1 is not zero, the sense of the test is inverted and we -** have a "NOT LIKE" operator. The jump is made if the two values -** are different. -*/ -case OP_Like: { - int tos = p->tos; - int nos = tos - 1; - int c; - VERIFY( if( nos<0 ) goto not_enough_stack; ) - if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem; - c = sqliteLikeCompare((unsigned char*)zStack[tos], - (unsigned char*)zStack[nos]); - POPSTACK; - POPSTACK; - if( pOp->p1 ) c = !c; - if( c ) pc = pOp->p2-1; - break; -} - -/* Opcode: Glob P1 P2 * -** -** Pop the top two elements from the stack. The top-most is a -** "glob" pattern. The lower element is the string to compare -** against the glob pattern. -** -** Jump to P2 if the two compare, and fall through without -** jumping if they do not. The '*' in the top-most element matches -** any sequence of zero or more characters in the lower element. The -** '?' character in the topmost matches any single character of the -** lower element. [...] matches a range of characters. [^...] -** matches any character not in the range. Case is significant -** for globs. -** -** If P1 is not zero, the sense of the test is inverted and we -** have a "NOT GLOB" operator. The jump is made if the two values -** are different. -*/ -case OP_Glob: { - int tos = p->tos; - int nos = tos - 1; - int c; - VERIFY( if( nos<0 ) goto not_enough_stack; ) - if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem; - c = sqliteGlobCompare((unsigned char*)zStack[tos], - (unsigned char*)zStack[nos]); - POPSTACK; - POPSTACK; - if( pOp->p1 ) c = !c; - if( c ) pc = pOp->p2-1; - break; -} - /* Opcode: And * * * ** ** Pop two values off the stack. Take the logical AND of the diff --git a/src/vdbe.h b/src/vdbe.h index 201cfa051a..f75b67551f 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -15,7 +15,7 @@ ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** -** $Id: vdbe.h,v 1.49 2002/02/28 03:31:12 drh Exp $ +** $Id: vdbe.h,v 1.50 2002/04/20 14:24:43 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ @@ -180,27 +180,25 @@ typedef struct VdbeOp VdbeOp; #define OP_ShiftLeft 95 #define OP_ShiftRight 96 #define OP_AbsValue 97 -#define OP_Like 98 -#define OP_Glob 99 -#define OP_Eq 100 -#define OP_Ne 101 -#define OP_Lt 102 -#define OP_Le 103 -#define OP_Gt 104 -#define OP_Ge 105 -#define OP_IsNull 106 -#define OP_NotNull 107 -#define OP_Negative 108 -#define OP_And 109 -#define OP_Or 110 -#define OP_Not 111 -#define OP_Concat 112 -#define OP_Noop 113 -#define OP_Function 114 - -#define OP_Limit 115 - -#define OP_MAX 115 +#define OP_Eq 98 +#define OP_Ne 99 +#define OP_Lt 100 +#define OP_Le 101 +#define OP_Gt 102 +#define OP_Ge 103 +#define OP_IsNull 104 +#define OP_NotNull 105 +#define OP_Negative 106 +#define OP_And 107 +#define OP_Or 108 +#define OP_Not 109 +#define OP_Concat 110 +#define OP_Noop 111 +#define OP_Function 112 + +#define OP_Limit 113 + +#define OP_MAX 113 /* ** Prototypes for the VDBE interface. See comments on the implementation diff --git a/tool/speedtest.tcl b/tool/speedtest.tcl index 7090e2e425..0e187dd52f 100644 --- a/tool/speedtest.tcl +++ b/tool/speedtest.tcl @@ -32,10 +32,10 @@ proc runtest {title} { puts "" set format {} set delay 1000 - exec sync; after $delay; - set t [time "exec psql drh <$sqlfile" 1] - set t [expr {[lindex $t 0]/1000000.0}] - puts [format $format PostgreSQL: $t] +# exec sync; after $delay; +# set t [time "exec psql drh <$sqlfile" 1] +# set t [expr {[lindex $t 0]/1000000.0}] +# puts [format $format PostgreSQL: $t] exec sync; after $delay; set t [time "exec mysql -f drh <$sqlfile" 1] set t [expr {[lindex $t 0]/1000000.0}] @@ -47,11 +47,11 @@ proc runtest {title} { # set t [expr {[lindex $t 0]/1000000.0}] # puts [format $format {SQLite 2.4 (cache=100):} $t] exec sync; after $delay; - set t [time "exec ./sqlite240 s2k.db <$sqlfile" 1] + set t [time "exec ./sqlite248 s2k.db <$sqlfile" 1] set t [expr {[lindex $t 0]/1000000.0}] puts [format $format {SQLite 2.4:} $t] exec sync; after $delay; - set t [time "exec ./sqlite240 sns.db <$sqlfile" 1] + set t [time "exec ./sqlite248 sns.db <$sqlfile" 1] set t [expr {[lindex $t 0]/1000000.0}] puts [format $format {SQLite 2.4 (nosync):} $t] # set t [time "exec ./sqlite-t1 st1.db <$sqlfile" 1] @@ -78,14 +78,14 @@ puts $fd { PRAGMA default_synchronous=on; } close $fd -exec ./sqlite240 s2k.db <2kinit.sql +exec ./sqlite248 s2k.db <2kinit.sql set fd [open nosync-init.sql w] puts $fd { PRAGMA default_cache_size=2000; PRAGMA default_synchronous=off; } close $fd -exec ./sqlite240 sns.db
%s   %.3f