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
This commit is contained in:
drh 2002-04-20 14:24:41 +00:00
parent 67505e78c6
commit 0ac6589202
9 changed files with 94 additions and 143 deletions

View File

@ -1 +1 @@
2.4.7
2.4.8

View File

@ -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

View File

@ -1 +1 @@
ca4abf3fe1f0e66802f9f98a20e0c8b82a6459aa
51572bf71774d7631c7083be90b806e621bc9bee

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.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);

View File

@ -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 <ctype.h>
#include <math.h>
@ -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;

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.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);}

View File

@ -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 <ctype.h>
@ -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

View File

@ -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_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 115
#define OP_Limit 113
#define OP_MAX 115
#define OP_MAX 113
/*
** Prototypes for the VDBE interface. See comments on the implementation

View File

@ -32,10 +32,10 @@ proc runtest {title} {
puts "</blockquote><table border=0 cellpadding=0 cellspacing=0>"
set format {<tr><td>%s</td><td align="right">&nbsp;&nbsp;&nbsp;%.3f</td></tr>}
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 <nosync-init.sql
exec ./sqlite248 sns.db <nosync-init.sql
set ones {zero one two three four five six seven eight nine
ten eleven twelve thirteen fourteen fifteen sixteen seventeen
eighteen nineteen}