The case_sensitive_like pragma added.
Test cases added for the LIKE optimization. (CVS 2592) FossilOrigin-Name: 72ee21c05e618b6f46f5460f8c85779c72fe32d7
This commit is contained in:
parent
3d94662a06
commit
55ef4d9758
27
manifest
27
manifest
@ -1,5 +1,5 @@
|
||||
C Provide\sgrave\saccent\squoting\sof\sidentifiers\sfor\sMySQL\scompatibility.\nTicket\s#1337.\s(CVS\s2591)
|
||||
D 2005-08-13T18:15:43
|
||||
C The\scase_sensitive_like\spragma\sadded.\nTest\scases\sadded\sfor\sthe\sLIKE\soptimization.\s(CVS\s2592)
|
||||
D 2005-08-14T01:20:38
|
||||
F Makefile.in 22ea9c0fe748f591712d8fe3c6d972c6c173a165
|
||||
F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7
|
||||
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
||||
@ -35,17 +35,17 @@ F src/auth.c 31e2304bef67f44d635655f44234387ea7d21454
|
||||
F src/btree.c 667227e4375d8bf6abd748cf6bad7a2004bf5d87
|
||||
F src/btree.h 41a71ce027db9ddee72cb43df2316bbe3a1d92af
|
||||
F src/build.c bd16c6865a0171e7ce397ea2868f67f81ab5eebf
|
||||
F src/callback.c 0910b611e0c158f107ee3ff86f8a371654971e2b
|
||||
F src/callback.c 9a1162c8f9dae9fad6d548339669aacb5f6cf76b
|
||||
F src/date.c 7444b0900a28da77e57e3337a636873cff0ae940
|
||||
F src/delete.c be1fc25c9e109cd8cbab42a43ee696263da7c04b
|
||||
F src/experimental.c 50c1e3b34f752f4ac10c36f287db095c2b61766d
|
||||
F src/expr.c cad7f9197587db4897192cf21a8629b3b102c682
|
||||
F src/func.c a90ea5021616b211cb35bd3df3e9cb81dd56e6b7
|
||||
F src/func.c 5b12db87f0bc7d978eaf87c7a348ada5d1934da4
|
||||
F src/hash.c 2b1b13f7400e179631c83a1be0c664608c8f021f
|
||||
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
|
||||
F src/insert.c 484c73bc1309f283a31baa0e114f3ee980536397
|
||||
F src/legacy.c d58ea507bce885298a2c8c3cbb0f4bff5d47830b
|
||||
F src/main.c fc984008243a41ae70ebffb4076d09a20d92871d
|
||||
F src/main.c dce7e4bf2280e57de1492dec61c7310d14b5e179
|
||||
F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070
|
||||
F src/os.h c4b34bd4d6fea51a420f337468b907f4edecb161
|
||||
F src/os_common.h 0e7f428ba0a6c40a61bc56c4e96f493231301b73
|
||||
@ -58,17 +58,17 @@ F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
|
||||
F src/pager.c ee3bbc4cd590a0266c791b4ed537cbd9a9d03566
|
||||
F src/pager.h 0d9153d6269d60d04af3dd84a0cc0a96253cf4a4
|
||||
F src/parse.y d57cdd2adc0923762b40314f08683c836a2e0c90
|
||||
F src/pragma.c 59ab7073465a11a531af2796e0385727194accb8
|
||||
F src/pragma.c 69413fbdc0c6aaa493a776ea52c1b3e6cf35dfb2
|
||||
F src/prepare.c fa0f6068d9b8ec6d5c419c65d4d8ff747d49c5c6
|
||||
F src/printf.c 772b15c3395fa60bdbf3aaa03d480ecde38bf192
|
||||
F src/random.c 90adff4e73a3b249eb4f1fc2a6ff9cf78c7233a4
|
||||
F src/select.c c611471052773b94af771693686bd5bcdbbb0dba
|
||||
F src/shell.c 86c16f0d534aa51cc82cf9f66903d4eb681580e7
|
||||
F src/sqlite.h.in a3b75a6b2e66865fba4ec1b698d00c7d95fe27a2
|
||||
F src/sqliteInt.h 67693a8ed955e96e0f87eb4a2c9793125f27f20c
|
||||
F src/sqliteInt.h 40370b51b902b4789ca6d4a016d00fa981803661
|
||||
F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9
|
||||
F src/tclsqlite.c 96feead1f1d301efa1d3ac6b89ecea7592ab18f9
|
||||
F src/test1.c 8a2b5ccc4be7450d41100778f346cbcf540febdd
|
||||
F src/test1.c a2333add4a25e47c268ea83df32cc7adf086d5d9
|
||||
F src/test2.c 792f203be69fea88668fa221321194f0a28dfdfa
|
||||
F src/test3.c f4e6a16a602091696619a1171bda25c0e3df49f7
|
||||
F src/test4.c a8fd681e139e1c61f22a77d07fc3a99cb28fff3f
|
||||
@ -83,10 +83,10 @@ F src/vdbe.c 69f33e22c7d0a64b23fbb69e6da95a1bb6869032
|
||||
F src/vdbe.h 68e80f65658e7fd85561721f617bdebf8bb84b59
|
||||
F src/vdbeInt.h 9be9a6c43d38124bd03cc5cf05715605b1789fd9
|
||||
F src/vdbeapi.c dc5b78cabf8d6e33318bd3d4ed25307d2aadce9a
|
||||
F src/vdbeaux.c d53139d819b887dac608ac4ae9a501baee3cd311
|
||||
F src/vdbeaux.c c7ea38ba42659eeaea091b1cda29989c1e82fa43
|
||||
F src/vdbefifo.c b8805850afe13b43f1de78d58088cb5d66f88e1e
|
||||
F src/vdbemem.c 89154caae3b8d4d0397e1235390fc4ff8aba4233
|
||||
F src/where.c 27d6432ea5fa255008ef80cb1d8e5e58ea8d615f
|
||||
F src/where.c de4b36842d64b6d12fc1896407d526bf88b67d22
|
||||
F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42
|
||||
F test/all.test 7f0988442ab811dfa41793b5b550f5828ce316f3
|
||||
F test/alter.test 9d6837a3d946b73df692b7cef2a7644d2e2f6bc6
|
||||
@ -159,6 +159,7 @@ F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
|
||||
F test/journal1.test 36f2d1bb9bf03f790f43fbdb439e44c0657fab19
|
||||
F test/lastinsert.test eaa89c6ee1f13062d87139fd32c1e56753d2fd89
|
||||
F test/laststmtchanges.test 19a6d0c11f7a31dc45465b495f7b845a62cbec17
|
||||
F test/like.test b94052f73f10504f61cf102774a6048297d35aab
|
||||
F test/limit.test 270b076f31c5c32f7187de5727e74da4de43e477
|
||||
F test/lock.test 9b7afcb24f53d24da502abb33daaad2cd6d44107
|
||||
F test/lock2.test 59c3dd7d9b24d1bf7ec91b2d1541c37e97939d5f
|
||||
@ -291,7 +292,7 @@ F www/tclsqlite.tcl 3df553505b6efcad08f91e9b975deb2e6c9bb955
|
||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||
F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
|
||||
F www/whentouse.tcl 528299b8316726dbcc5548e9aa0648c8b1bd055b
|
||||
P 7961ec0ccbc99d890689013b9602635941f308a6
|
||||
R 8fe3c3a40a20fda764293dad136929fd
|
||||
P 6b7a4e97528a4e179e0bbae69469cb1a3d1f794b
|
||||
R 2a56cedc95809568a05ccebaeb474ad2
|
||||
U drh
|
||||
Z 59ce15d25edf70c7b49901f8f0f074fa
|
||||
Z a91f4cb932b10939dc2be2a7a630b49e
|
||||
|
@ -1 +1 @@
|
||||
6b7a4e97528a4e179e0bbae69469cb1a3d1f794b
|
||||
72ee21c05e618b6f46f5460f8c85779c72fe32d7
|
@ -13,7 +13,7 @@
|
||||
** This file contains functions used to access the internal hash tables
|
||||
** of user defined functions and collation sequences.
|
||||
**
|
||||
** $Id: callback.c,v 1.2 2005/05/25 10:45:10 danielk1977 Exp $
|
||||
** $Id: callback.c,v 1.3 2005/08/14 01:20:38 drh Exp $
|
||||
*/
|
||||
|
||||
#include "sqliteInt.h"
|
||||
@ -147,7 +147,7 @@ int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){
|
||||
** the collation sequence name. A pointer to this string is stored in
|
||||
** each collation sequence structure.
|
||||
*/
|
||||
static CollSeq * findCollSeqEntry(
|
||||
static CollSeq *findCollSeqEntry(
|
||||
sqlite3 *db,
|
||||
const char *zName,
|
||||
int nName,
|
||||
@ -286,10 +286,9 @@ FuncDef *sqlite3FindFunction(
|
||||
** new entry to the hash table and return it.
|
||||
*/
|
||||
if( createFlag && bestmatch<6 &&
|
||||
(pBest = sqliteMalloc(sizeof(*pBest)+nName+1)) ){
|
||||
(pBest = sqliteMalloc(sizeof(*pBest)+nName)) ){
|
||||
pBest->nArg = nArg;
|
||||
pBest->pNext = pFirst;
|
||||
pBest->zName = (char*)&pBest[1];
|
||||
pBest->iPrefEnc = enc;
|
||||
memcpy(pBest->zName, zName, nName);
|
||||
pBest->zName[nName] = 0;
|
||||
|
135
src/func.c
135
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.103 2005/08/13 03:07:47 drh Exp $
|
||||
** $Id: func.c,v 1.104 2005/08/14 01:20:38 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -26,6 +26,9 @@
|
||||
#include "vdbeInt.h"
|
||||
#include "os.h"
|
||||
|
||||
/*
|
||||
** Return the collating function associated with a function.
|
||||
*/
|
||||
static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){
|
||||
return context->pColl;
|
||||
}
|
||||
@ -308,16 +311,14 @@ struct compareInfo {
|
||||
u8 matchSet;
|
||||
u8 noCase;
|
||||
};
|
||||
|
||||
static const struct compareInfo globInfo = { '*', '?', '[', 0 };
|
||||
#ifndef SQLITE_CASE_SENSITIVE_LIKE
|
||||
/* The correct SQL-92 behavior is for the LIKE operator to ignore
|
||||
** case. Thus 'a' LIKE 'A' would be true. */
|
||||
static const struct compareInfo likeInfo = { '%', '_', 0, 1 };
|
||||
#else
|
||||
/* If SQLITE_CASE_SENSITIVE_LIKE is defined, then the LIKE operator
|
||||
** is case sensitive causing 'a' LIKE 'A' to be false */
|
||||
static const struct compareInfo likeInfo = { '%', '_', 0, 0 };
|
||||
#endif
|
||||
/* The correct SQL-92 behavior is for the LIKE operator to ignore
|
||||
** case. Thus 'a' LIKE 'A' would be true. */
|
||||
static const struct compareInfo likeInfoNorm = { '%', '_', 0, 1 };
|
||||
/* If SQLITE_CASE_SENSITIVE_LIKE is defined, then the LIKE operator
|
||||
** is case sensitive causing 'a' LIKE 'A' to be false */
|
||||
static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 };
|
||||
|
||||
/*
|
||||
** X is a pointer to the first byte of a UTF-8 character. Increment
|
||||
@ -459,6 +460,15 @@ static int patternCompare(
|
||||
return *zString==0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Count the number of times that the LIKE operator (or GLOB which is
|
||||
** just a variation of LIKE) gets called. This is used for testing
|
||||
** only.
|
||||
*/
|
||||
#ifdef SQLITE_TEST
|
||||
int sqlite3_like_count = 0;
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Implementation of the like() SQL function. This function implements
|
||||
@ -469,8 +479,8 @@ static int patternCompare(
|
||||
**
|
||||
** is implemented as like(B,A).
|
||||
**
|
||||
** If the pointer retrieved by via a call to sqlite3_user_data() is
|
||||
** not NULL, then this function uses UTF-16. Otherwise UTF-8.
|
||||
** This same function (with a different compareInfo structure) computes
|
||||
** the GLOB operator.
|
||||
*/
|
||||
static void likeFunc(
|
||||
sqlite3_context *context,
|
||||
@ -493,24 +503,11 @@ static void likeFunc(
|
||||
escape = sqlite3ReadUtf8(zEsc);
|
||||
}
|
||||
if( zA && zB ){
|
||||
sqlite3_result_int(context, patternCompare(zA, zB, &likeInfo, escape));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** 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(B,A).
|
||||
*/
|
||||
static void globFunc(sqlite3_context *context, int arg, sqlite3_value **argv){
|
||||
const unsigned char *zA = sqlite3_value_text(argv[0]);
|
||||
const unsigned char *zB = sqlite3_value_text(argv[1]);
|
||||
if( zA && zB ){
|
||||
sqlite3_result_int(context, patternCompare(zA, zB, &globInfo, 0));
|
||||
struct compareInfo *pInfo = sqlite3_user_data(context);
|
||||
#ifdef SQLITE_TEST
|
||||
sqlite3_like_count++;
|
||||
#endif
|
||||
sqlite3_result_int(context, patternCompare(zA, zB, pInfo, escape));
|
||||
}
|
||||
}
|
||||
|
||||
@ -971,9 +968,6 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
|
||||
{ "coalesce", 1, 0, SQLITE_UTF8, 0, 0 },
|
||||
{ "ifnull", 2, 0, SQLITE_UTF8, 1, ifnullFunc },
|
||||
{ "random", -1, 0, SQLITE_UTF8, 0, randomFunc },
|
||||
{ "like", 2, 0, SQLITE_UTF8, 0, likeFunc },
|
||||
{ "like", 3, 0, SQLITE_UTF8, 0, likeFunc },
|
||||
{ "glob", 2, 0, SQLITE_UTF8, 0, globFunc },
|
||||
{ "nullif", 2, 0, SQLITE_UTF8, 1, nullifFunc },
|
||||
{ "sqlite_version", 0, 0, SQLITE_UTF8, 0, versionFunc},
|
||||
{ "quote", 1, 0, SQLITE_UTF8, 0, quoteFunc },
|
||||
@ -1045,8 +1039,77 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
|
||||
}
|
||||
sqlite3RegisterDateTimeFunctions(db);
|
||||
#ifdef SQLITE_SSE
|
||||
{
|
||||
sqlite3SseFunctions(db);
|
||||
}
|
||||
sqlite3SseFunctions(db);
|
||||
#endif
|
||||
#ifdef SQLITE_CASE_SENSITIVE_LIKE
|
||||
sqlite3RegisterLikeFunctions(db, 1);
|
||||
#else
|
||||
sqlite3RegisterLikeFunctions(db, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the LIKEOPT flag on the 2-argument function with the given name.
|
||||
*/
|
||||
static void setLikeOptFlag(sqlite3 *db, const char *zName){
|
||||
FuncDef *pDef;
|
||||
pDef = sqlite3FindFunction(db, zName, strlen(zName), 2, SQLITE_UTF8, 0);
|
||||
if( pDef ){
|
||||
pDef->flags = SQLITE_FUNC_LIKEOPT;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Register the built-in LIKE and GLOB functions. The caseSensitive
|
||||
** parameter determines whether or not the LIKE operator is case
|
||||
** sensitive. GLOB is always case sensitive.
|
||||
*/
|
||||
void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
|
||||
struct compareInfo *pInfo;
|
||||
if( caseSensitive ){
|
||||
pInfo = (struct compareInfo*)&likeInfoAlt;
|
||||
}else{
|
||||
pInfo = (struct compareInfo*)&likeInfoNorm;
|
||||
}
|
||||
sqlite3_create_function(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0);
|
||||
sqlite3_create_function(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0);
|
||||
sqlite3_create_function(db, "glob", 2, SQLITE_UTF8,
|
||||
(struct compareInfo*)&globInfo, likeFunc, 0,0);
|
||||
setLikeOptFlag(db, "glob");
|
||||
if( caseSensitive ){
|
||||
setLikeOptFlag(db, "like");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** pExpr points to an expression which implements a function. If
|
||||
** it is appropriate to apply the LIKE optimization to that function
|
||||
** then set aWc[0] through aWc[2] to the wildcard characters and
|
||||
** return TRUE. If the function is not a LIKE-style function then
|
||||
** return FALSE.
|
||||
*/
|
||||
int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, char *aWc){
|
||||
FuncDef *pDef;
|
||||
if( pExpr->op!=TK_FUNCTION ){
|
||||
return 0;
|
||||
}
|
||||
if( pExpr->pList->nExpr!=2 ){
|
||||
return 0;
|
||||
}
|
||||
pDef = sqlite3FindFunction(db, pExpr->token.z, pExpr->token.n, 2,
|
||||
SQLITE_UTF8, 0);
|
||||
if( pDef==0 || (pDef->flags & SQLITE_FUNC_LIKEOPT)==0 ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The memcpy() statement assumes that the wildcard characters are
|
||||
** the first three statements in the compareInfo structure. The
|
||||
** asserts() that follow verify that assumption
|
||||
*/
|
||||
memcpy(aWc, pDef->pUserData, 3);
|
||||
assert( (char*)&likeInfoAlt == (char*)&likeInfoAlt.matchAll );
|
||||
assert( &((char*)&likeInfoAlt)[1] == (char*)&likeInfoAlt.matchOne );
|
||||
assert( &((char*)&likeInfoAlt)[2] == (char*)&likeInfoAlt.matchSet );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
** other files are for internal use by SQLite and should not be
|
||||
** accessed by users of the library.
|
||||
**
|
||||
** $Id: main.c,v 1.297 2005/08/11 02:10:19 drh Exp $
|
||||
** $Id: main.c,v 1.298 2005/08/14 01:20:39 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -471,6 +471,7 @@ int sqlite3_create_function(
|
||||
|
||||
p = sqlite3FindFunction(db, zFunctionName, nName, nArg, enc, 1);
|
||||
if( p==0 ) return SQLITE_NOMEM;
|
||||
p->flags = 0;
|
||||
p->xFunc = xFunc;
|
||||
p->xStep = xStep;
|
||||
p->xFinalize = xFinal;
|
||||
|
21
src/pragma.c
21
src/pragma.c
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** This file contains code used to implement the PRAGMA command.
|
||||
**
|
||||
** $Id: pragma.c,v 1.97 2005/08/13 00:56:27 drh Exp $
|
||||
** $Id: pragma.c,v 1.98 2005/08/14 01:20:39 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -603,14 +603,25 @@ void sqlite3Pragma(
|
||||
#ifndef NDEBUG
|
||||
if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
|
||||
extern void sqlite3ParserTrace(FILE*, char *);
|
||||
if( getBoolean(zRight) ){
|
||||
sqlite3ParserTrace(stderr, "parser: ");
|
||||
}else{
|
||||
sqlite3ParserTrace(0, 0);
|
||||
if( zRight ){
|
||||
if( getBoolean(zRight) ){
|
||||
sqlite3ParserTrace(stderr, "parser: ");
|
||||
}else{
|
||||
sqlite3ParserTrace(0, 0);
|
||||
}
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
|
||||
/* Reinstall the LIKE and GLOB functions. The variant of LIKE
|
||||
** used will be case sensitive or not depending on the RHS.
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft, "case_sensitive_like")==0 ){
|
||||
if( zRight ){
|
||||
sqlite3RegisterLikeFunctions(db, getBoolean(zRight));
|
||||
}
|
||||
}else
|
||||
|
||||
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
|
||||
if( sqlite3StrICmp(zLeft, "integrity_check")==0 ){
|
||||
int i, j, addr;
|
||||
|
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.401 2005/08/12 22:56:09 drh Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.402 2005/08/14 01:20:39 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITEINT_H_
|
||||
#define _SQLITEINT_H_
|
||||
@ -496,17 +496,23 @@ struct sqlite3 {
|
||||
** points to a linked list of these structures.
|
||||
*/
|
||||
struct FuncDef {
|
||||
char *zName; /* SQL name of the function */
|
||||
int nArg; /* Number of arguments. -1 means unlimited */
|
||||
i16 nArg; /* Number of arguments. -1 means unlimited */
|
||||
u8 iPrefEnc; /* Preferred text encoding (SQLITE_UTF8, 16LE, 16BE) */
|
||||
u8 needCollSeq; /* True if sqlite3GetFuncCollSeq() might be called */
|
||||
u8 flags; /* Some combination of SQLITE_FUNC_* */
|
||||
void *pUserData; /* User data parameter */
|
||||
FuncDef *pNext; /* Next function with same name */
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**); /* Regular function */
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**); /* Aggregate step */
|
||||
void (*xFinalize)(sqlite3_context*); /* Aggregate finializer */
|
||||
u8 needCollSeq; /* True if sqlite3GetFuncCollSeq() might be called */
|
||||
char zName[1]; /* SQL name of the function. MUST BE LAST */
|
||||
};
|
||||
|
||||
/*
|
||||
** Possible values for FuncDef.flags
|
||||
*/
|
||||
#define SQLITE_FUNC_LIKEOPT 0x01 /* Candidate for the LIKE optimization */
|
||||
|
||||
/*
|
||||
** information about each column of an SQL table is held in an instance
|
||||
** of this structure.
|
||||
@ -1576,6 +1582,8 @@ int sqlite3InvokeBusyHandler(BusyHandler*);
|
||||
int sqlite3FindDb(sqlite3*, Token*);
|
||||
void sqlite3AnalysisLoad(sqlite3*,int iDB);
|
||||
void sqlite3DefaultRowEst(Index*);
|
||||
void sqlite3RegisterLikeFunctions(sqlite3*, int);
|
||||
int sqlite3IsLikeFunction(sqlite3*,Expr*,char*);
|
||||
|
||||
#ifdef SQLITE_SSE
|
||||
#include "sseInt.h"
|
||||
|
23
src/test1.c
23
src/test1.c
@ -13,7 +13,7 @@
|
||||
** is not included in the SQLite library. It is used for automated
|
||||
** testing of the SQLite library.
|
||||
**
|
||||
** $Id: test1.c,v 1.153 2005/08/11 02:10:19 drh Exp $
|
||||
** $Id: test1.c,v 1.154 2005/08/14 01:20:39 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "tcl.h"
|
||||
@ -2797,6 +2797,12 @@ static void set_options(Tcl_Interp *interp){
|
||||
Tcl_SetVar2(interp,"sqlite_options","default_autovacuum","1",TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_BETWEEN_OPTIMIZATION
|
||||
Tcl_SetVar2(interp, "sqlite_options", "between_opt", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "between_opt", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_BLOB_LITERAL
|
||||
Tcl_SetVar2(interp, "sqlite_options", "bloblit", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
@ -2869,12 +2875,24 @@ static void set_options(Tcl_Interp *interp){
|
||||
Tcl_SetVar2(interp, "sqlite_options", "integrityck", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_LIKE_OPTIMIZATION
|
||||
Tcl_SetVar2(interp, "sqlite_options", "like_opt", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "like_opt", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_MEMORYDB
|
||||
Tcl_SetVar2(interp, "sqlite_options", "memorydb", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "memorydb", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_OR_OPTIMIZATION
|
||||
Tcl_SetVar2(interp, "sqlite_options", "or_opt", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "or_opt", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_PAGER_PRAGMAS
|
||||
Tcl_SetVar2(interp, "sqlite_options", "pager_pragmas", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
@ -3094,6 +3112,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
extern int sqlite3_memUsed;
|
||||
extern int sqlite3_memMax;
|
||||
extern char sqlite3_query_plan[];
|
||||
extern int sqlite3_like_count;
|
||||
static char *query_plan = sqlite3_query_plan;
|
||||
|
||||
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
|
||||
@ -3107,6 +3126,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
(char*)&sqlite3_search_count, TCL_LINK_INT);
|
||||
Tcl_LinkVar(interp, "sqlite_sort_count",
|
||||
(char*)&sqlite3_sort_count, TCL_LINK_INT);
|
||||
Tcl_LinkVar(interp, "sqlite_like_count",
|
||||
(char*)&sqlite3_like_count, TCL_LINK_INT);
|
||||
Tcl_LinkVar(interp, "sqlite_interrupt_count",
|
||||
(char*)&sqlite3_interrupt_count, TCL_LINK_INT);
|
||||
Tcl_LinkVar(interp, "sqlite_open_file_count",
|
||||
|
@ -109,6 +109,7 @@ int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){
|
||||
pOp->p2 = p2;
|
||||
pOp->p3 = 0;
|
||||
pOp->p3type = P3_NOTUSED;
|
||||
p->expired = 0;
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( sqlite3_vdbe_addop_trace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]);
|
||||
#endif
|
||||
|
41
src/where.c
41
src/where.c
@ -16,7 +16,7 @@
|
||||
** so is applicable. Because this module is responsible for selecting
|
||||
** indices, you might also think of this module as the "query optimizer".
|
||||
**
|
||||
** $Id: where.c,v 1.161 2005/08/13 16:13:05 drh Exp $
|
||||
** $Id: where.c,v 1.162 2005/08/14 01:20:39 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -467,54 +467,35 @@ static void exprAnalyzeAll(
|
||||
** literal that does not begin with a wildcard.
|
||||
*/
|
||||
static int isLikeOrGlob(
|
||||
sqlite3 *db, /* The database */
|
||||
Expr *pExpr, /* Test this expression */
|
||||
int *pnPattern, /* Number of non-wildcard prefix characters */
|
||||
int *pisComplete /* True if the only wildcard is % in the last character */
|
||||
){
|
||||
const char *z;
|
||||
Expr *pRight, *pLeft;
|
||||
ExprList *pList;
|
||||
int c, cnt;
|
||||
char wc1, wc2, wc3;
|
||||
if( pExpr->op!=TK_FUNCTION ){
|
||||
char wc[3];
|
||||
if( !sqlite3IsLikeFunction(db, pExpr, wc) ){
|
||||
return 0;
|
||||
}
|
||||
if( pExpr->pList->nExpr!=2 ){
|
||||
return 0;
|
||||
}
|
||||
if( pExpr->token.n!=4 ){
|
||||
return 0;
|
||||
}
|
||||
z = pExpr->token.z;
|
||||
if( sqlite3StrNICmp(z, "glob", 4)==0 ){
|
||||
wc1 = '*';
|
||||
wc2 = '?';
|
||||
wc3 = '[';
|
||||
}
|
||||
#ifdef SQLITE_CASE_SENSITIVE_LIKE
|
||||
else if( sqlite3StrNICmp(z, "like", 4)==0 ){
|
||||
wc1 = '%';
|
||||
wc2 = '_';
|
||||
wc3 = '_';
|
||||
}
|
||||
#endif
|
||||
else{
|
||||
return 0;
|
||||
}
|
||||
pRight = pExpr->pList->a[0].pExpr;
|
||||
pList = pExpr->pList;
|
||||
pRight = pList->a[0].pExpr;
|
||||
if( pRight->op!=TK_STRING ){
|
||||
return 0;
|
||||
}
|
||||
pLeft = pExpr->pList->a[1].pExpr;
|
||||
pLeft = pList->a[1].pExpr;
|
||||
if( pLeft->op!=TK_COLUMN ){
|
||||
return 0;
|
||||
}
|
||||
sqlite3DequoteExpr(pRight);
|
||||
z = pRight->token.z;
|
||||
for(cnt=0; (c=z[cnt])!=0 && c!=wc1 && c!=wc2 && c!=wc3; cnt++){}
|
||||
for(cnt=0; (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2]; cnt++){}
|
||||
if( cnt==0 || 255==(u8)z[cnt] ){
|
||||
return 0;
|
||||
}
|
||||
*pisComplete = z[cnt]==wc1 && z[cnt+1]==0;
|
||||
*pisComplete = z[cnt]==wc[0] && z[cnt+1]==0;
|
||||
*pnPattern = cnt;
|
||||
return 1;
|
||||
}
|
||||
@ -671,7 +652,7 @@ or_not_possible:
|
||||
/* Add constraints to reduce the search space on a LIKE or GLOB
|
||||
** operator.
|
||||
*/
|
||||
if( isLikeOrGlob(pExpr, &nPattern, &isComplete) ){
|
||||
if( isLikeOrGlob(pTerm->pWC->pParse->db, pExpr, &nPattern, &isComplete) ){
|
||||
Expr *pLeft, *pRight;
|
||||
Expr *pStr1, *pStr2;
|
||||
Expr *pNewExpr1, *pNewExpr2;
|
||||
|
283
test/like.test
Normal file
283
test/like.test
Normal file
@ -0,0 +1,283 @@
|
||||
# 2005 August 13
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing the LIKE and GLOB operators and
|
||||
# in particular the optimizations that occur to help those operators
|
||||
# run faster.
|
||||
#
|
||||
# $Id: like.test,v 1.1 2005/08/14 01:20:40 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# Create some sample data to work with.
|
||||
#
|
||||
do_test like-1.0 {
|
||||
execsql {
|
||||
CREATE TABLE t1(x TEXT);
|
||||
}
|
||||
foreach str {
|
||||
a
|
||||
ab
|
||||
abc
|
||||
abcd
|
||||
|
||||
acd
|
||||
abd
|
||||
bc
|
||||
bcd
|
||||
|
||||
xyz
|
||||
ABC
|
||||
CDE
|
||||
{ABC abc xyz}
|
||||
} {
|
||||
db eval {INSERT INTO t1 VALUES($str)}
|
||||
}
|
||||
execsql {
|
||||
SELECT count(*) FROM t1;
|
||||
}
|
||||
} {12}
|
||||
|
||||
# Test that both case sensitive and insensitive version of LIKE work.
|
||||
#
|
||||
do_test like-1.1 {
|
||||
execsql {
|
||||
SELECT x FROM t1 WHERE x LIKE 'abc' ORDER BY 1;
|
||||
}
|
||||
} {ABC abc}
|
||||
do_test like-1.2 {
|
||||
execsql {
|
||||
SELECT x FROM t1 WHERE x GLOB 'abc' ORDER BY 1;
|
||||
}
|
||||
} {abc}
|
||||
do_test like-1.3 {
|
||||
execsql {
|
||||
SELECT x FROM t1 WHERE x LIKE 'ABC' ORDER BY 1;
|
||||
}
|
||||
} {ABC abc}
|
||||
do_test like-1.4 {
|
||||
execsql {
|
||||
SELECT x FROM t1 WHERE x LIKE 'aBc' ORDER BY 1;
|
||||
}
|
||||
} {ABC abc}
|
||||
do_test like-1.5 {
|
||||
execsql {
|
||||
PRAGMA case_sensitive_like=on;
|
||||
SELECT x FROM t1 WHERE x LIKE 'abc' ORDER BY 1;
|
||||
}
|
||||
} {abc}
|
||||
do_test like-1.6 {
|
||||
execsql {
|
||||
SELECT x FROM t1 WHERE x GLOB 'abc' ORDER BY 1;
|
||||
}
|
||||
} {abc}
|
||||
do_test like-1.7 {
|
||||
execsql {
|
||||
SELECT x FROM t1 WHERE x LIKE 'ABC' ORDER BY 1;
|
||||
}
|
||||
} {ABC}
|
||||
do_test like-1.8 {
|
||||
execsql {
|
||||
SELECT x FROM t1 WHERE x LIKE 'aBc' ORDER BY 1;
|
||||
}
|
||||
} {}
|
||||
do_test like-1.9 {
|
||||
execsql {
|
||||
PRAGMA case_sensitive_like=off;
|
||||
SELECT x FROM t1 WHERE x LIKE 'abc' ORDER BY 1;
|
||||
}
|
||||
} {ABC abc}
|
||||
|
||||
# Tests of the REGEXP operator
|
||||
#
|
||||
do_test like-2.1 {
|
||||
proc test_regexp {a b} {
|
||||
return [regexp $a $b]
|
||||
}
|
||||
db function regexp test_regexp
|
||||
execsql {
|
||||
SELECT x FROM t1 WHERE x REGEXP 'abc' ORDER BY 1;
|
||||
}
|
||||
} {{ABC abc xyz} abc abcd}
|
||||
do_test like-2.2 {
|
||||
execsql {
|
||||
SELECT x FROM t1 WHERE x REGEXP '^abc' ORDER BY 1;
|
||||
}
|
||||
} {abc abcd}
|
||||
|
||||
# For the remaining tests, we need to have the like optimizations
|
||||
# enabled.
|
||||
#
|
||||
ifcapable !like_opt {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# This procedure executes the SQL. Then it appends to the result the
|
||||
# "sort" or "nosort" keyword (as in the cksort procedure above) then
|
||||
# it appends the ::sqlite_query_plan variable.
|
||||
#
|
||||
proc queryplan {sql} {
|
||||
set ::sqlite_sort_count 0
|
||||
set data [execsql $sql]
|
||||
if {$::sqlite_sort_count} {set x sort} {set x nosort}
|
||||
lappend data $x
|
||||
return [concat $data $::sqlite_query_plan]
|
||||
}
|
||||
|
||||
# Perform tests on the like optimization.
|
||||
#
|
||||
# With no index on t1.x and with case sensitivity turned off, no optimization
|
||||
# is performed.
|
||||
#
|
||||
do_test like-3.1 {
|
||||
set sqlite_like_count 0
|
||||
queryplan {
|
||||
SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1;
|
||||
}
|
||||
} {ABC {ABC abc xyz} abc abcd sort t1 {}}
|
||||
do_test like-3.2 {
|
||||
set sqlite_like_count
|
||||
} {12}
|
||||
|
||||
# With an index on t1.x and case sensitivity on, optimize completely.
|
||||
#
|
||||
do_test like-3.3 {
|
||||
set sqlite_like_count 0
|
||||
execsql {
|
||||
PRAGMA case_sensitive_like=on;
|
||||
CREATE INDEX i1 ON t1(x);
|
||||
}
|
||||
queryplan {
|
||||
SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1;
|
||||
}
|
||||
} {abc abcd nosort {} i1}
|
||||
do_test like-3.4 {
|
||||
set sqlite_like_count
|
||||
} 0
|
||||
|
||||
# Partial optimization when the pattern does not end in '%'
|
||||
#
|
||||
do_test like-3.5 {
|
||||
set sqlite_like_count 0
|
||||
queryplan {
|
||||
SELECT x FROM t1 WHERE x LIKE 'a_c' ORDER BY 1;
|
||||
}
|
||||
} {abc nosort {} i1}
|
||||
do_test like-3.6 {
|
||||
set sqlite_like_count
|
||||
} 6
|
||||
do_test like-3.7 {
|
||||
set sqlite_like_count 0
|
||||
queryplan {
|
||||
SELECT x FROM t1 WHERE x LIKE 'ab%d' ORDER BY 1;
|
||||
}
|
||||
} {abcd abd nosort {} i1}
|
||||
do_test like-3.8 {
|
||||
set sqlite_like_count
|
||||
} 4
|
||||
do_test like-3.9 {
|
||||
set sqlite_like_count 0
|
||||
queryplan {
|
||||
SELECT x FROM t1 WHERE x LIKE 'a_c%' ORDER BY 1;
|
||||
}
|
||||
} {abc abcd nosort {} i1}
|
||||
do_test like-3.10 {
|
||||
set sqlite_like_count
|
||||
} 6
|
||||
|
||||
# No optimization when the pattern begins with a wildcard.
|
||||
# Note that the index is still used but only for sorting.
|
||||
#
|
||||
do_test like-3.11 {
|
||||
set sqlite_like_count 0
|
||||
queryplan {
|
||||
SELECT x FROM t1 WHERE x LIKE '%bcd' ORDER BY 1;
|
||||
}
|
||||
} {abcd bcd nosort {} i1}
|
||||
do_test like-3.12 {
|
||||
set sqlite_like_count
|
||||
} 12
|
||||
|
||||
# No optimization for case insensitive LIKE
|
||||
#
|
||||
do_test like-3.13 {
|
||||
set sqlite_like_count 0
|
||||
queryplan {
|
||||
PRAGMA case_sensitive_like=off;
|
||||
SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1;
|
||||
}
|
||||
} {ABC {ABC abc xyz} abc abcd nosort {} i1}
|
||||
do_test like-3.14 {
|
||||
set sqlite_like_count
|
||||
} 12
|
||||
|
||||
# No optimization without an index.
|
||||
#
|
||||
do_test like-3.15 {
|
||||
set sqlite_like_count 0
|
||||
queryplan {
|
||||
PRAGMA case_sensitive_like=on;
|
||||
DROP INDEX i1;
|
||||
SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1;
|
||||
}
|
||||
} {abc abcd sort t1 {}}
|
||||
do_test like-3.16 {
|
||||
set sqlite_like_count
|
||||
} 12
|
||||
|
||||
# No GLOB optimization without an index.
|
||||
#
|
||||
do_test like-3.17 {
|
||||
set sqlite_like_count 0
|
||||
queryplan {
|
||||
SELECT x FROM t1 WHERE x GLOB 'abc*' ORDER BY 1;
|
||||
}
|
||||
} {abc abcd sort t1 {}}
|
||||
do_test like-3.18 {
|
||||
set sqlite_like_count
|
||||
} 12
|
||||
|
||||
# GLOB is optimized regardless of the case_sensitive_like setting.
|
||||
#
|
||||
do_test like-3.19 {
|
||||
set sqlite_like_count 0
|
||||
queryplan {
|
||||
CREATE INDEX i1 ON t1(x);
|
||||
SELECT x FROM t1 WHERE x GLOB 'abc*' ORDER BY 1;
|
||||
}
|
||||
} {abc abcd nosort {} i1}
|
||||
do_test like-3.20 {
|
||||
set sqlite_like_count
|
||||
} 0
|
||||
do_test like-3.21 {
|
||||
set sqlite_like_count 0
|
||||
queryplan {
|
||||
PRAGMA case_sensitive_like=on;
|
||||
SELECT x FROM t1 WHERE x GLOB 'abc*' ORDER BY 1;
|
||||
}
|
||||
} {abc abcd nosort {} i1}
|
||||
do_test like-3.22 {
|
||||
set sqlite_like_count
|
||||
} 0
|
||||
do_test like-3.23 {
|
||||
set sqlite_like_count 0
|
||||
queryplan {
|
||||
PRAGMA case_sensitive_like=off;
|
||||
SELECT x FROM t1 WHERE x GLOB 'a[bc]d' ORDER BY 1;
|
||||
}
|
||||
} {abd acd nosort {} i1}
|
||||
do_test like-3.24 {
|
||||
set sqlite_like_count
|
||||
} 6
|
||||
|
||||
finish_test
|
Loading…
Reference in New Issue
Block a user