mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-18 10:21:03 +03:00
Fix the LIKE optimization even when comparing mixed-case BLOBs.
FossilOrigin-Name: a58aafdb4e1422b6a8ffc07a67984928bbedf919
This commit is contained in:
17
manifest
17
manifest
@@ -1,5 +1,5 @@
|
||||
C The\sLIKE\soptimization\smust\sbe\sapplied\stwice,\sonce\sfor\sstrings\sand\sa\ssecond\ntime\sfor\sBLOBs.\s\sTicket\s[05f43be8fdda9f].\s\sThis\scheck-in\sis\sa\sproof-of-concept\nof\show\sthat\smight\sbe\sdone.
|
||||
D 2015-03-06T16:45:16.543
|
||||
C Fix\sthe\sLIKE\soptimization\seven\swhen\scomparing\smixed-case\sBLOBs.
|
||||
D 2015-03-06T19:47:38.505
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 2f643d6968dfc0b82d2e546a0525a39079f9e928
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@@ -307,8 +307,8 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb
|
||||
F src/wal.c 39303f2c9db02a4e422cd8eb2c8760420c6a51fe
|
||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||
F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804
|
||||
F src/where.c b7e82341d2570ac8a051e133cfc44c7eec79a30e
|
||||
F src/whereInt.h 0ba6257f2a44acd6262f259d5147cd01c52cc45b
|
||||
F src/where.c cace7eef1838ea22f549e824236eaaa4195b83e6
|
||||
F src/whereInt.h cbe4aa57326998d89e7698ca65bb7c28541d483c
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7
|
||||
@@ -1240,10 +1240,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P 8c1e85aab9e0d90726057e25e2ea0663341c070f
|
||||
R db06eec232964b57030b876196612d14
|
||||
T *branch * like-opt-fix
|
||||
T *sym-like-opt-fix *
|
||||
T -sym-trunk *
|
||||
P 5757e803cb5759b476bbc6453c58340089611420
|
||||
R 1a18426c5e280ce5513288eef4bf379e
|
||||
U drh
|
||||
Z 9b71822fa0ca3d1b398ae4d623871060
|
||||
Z 4902bd060fa099614e1fc5278ee9e5b6
|
||||
|
||||
@@ -1 +1 @@
|
||||
5757e803cb5759b476bbc6453c58340089611420
|
||||
a58aafdb4e1422b6a8ffc07a67984928bbedf919
|
||||
60
src/where.c
60
src/where.c
@@ -1264,9 +1264,25 @@ static void exprAnalyze(
|
||||
int idxNew1;
|
||||
int idxNew2;
|
||||
Token sCollSeqName; /* Name of collating sequence */
|
||||
const u16 wtFlags = TERM_LIKEOPT | TERM_VIRTUAL | TERM_DYNAMIC;
|
||||
|
||||
pTerm->wtFlags |= TERM_LIKE;
|
||||
pLeft = pExpr->x.pList->a[1].pExpr;
|
||||
pStr2 = sqlite3ExprDup(db, pStr1, 0);
|
||||
|
||||
/* Convert the lower bound to upper-case and the upper bound to
|
||||
** lower-case (upper-case is less than lower-case in ASCII) so that
|
||||
** the range constraints also work for BLOBs
|
||||
*/
|
||||
if( noCase && !pParse->db->mallocFailed ){
|
||||
int i;
|
||||
char c;
|
||||
for(i=0; (c = pStr1->u.zToken[i])!=0; i++){
|
||||
pStr1->u.zToken[i] = sqlite3Toupper(c);
|
||||
pStr2->u.zToken[i] = sqlite3Tolower(c);
|
||||
}
|
||||
}
|
||||
|
||||
if( !db->mallocFailed ){
|
||||
u8 c, *pC; /* Last character before the first wildcard */
|
||||
pC = (u8*)&pStr2->u.zToken[sqlite3Strlen30(pStr2->u.zToken)-1];
|
||||
@@ -1290,8 +1306,7 @@ static void exprAnalyze(
|
||||
sqlite3ExprAddCollateToken(pParse,pNewExpr1,&sCollSeqName),
|
||||
pStr1, 0);
|
||||
transferJoinMarkings(pNewExpr1, pExpr);
|
||||
idxNew1 = whereClauseInsert(pWC, pNewExpr1,
|
||||
TERM_LIKEOPT|TERM_VIRTUAL|TERM_DYNAMIC);
|
||||
idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags);
|
||||
testcase( idxNew1==0 );
|
||||
exprAnalyze(pSrc, pWC, idxNew1);
|
||||
pNewExpr2 = sqlite3ExprDup(db, pLeft, 0);
|
||||
@@ -1299,8 +1314,7 @@ static void exprAnalyze(
|
||||
sqlite3ExprAddCollateToken(pParse,pNewExpr2,&sCollSeqName),
|
||||
pStr2, 0);
|
||||
transferJoinMarkings(pNewExpr2, pExpr);
|
||||
idxNew2 = whereClauseInsert(pWC, pNewExpr2,
|
||||
TERM_LIKEOPT|TERM_VIRTUAL|TERM_DYNAMIC);
|
||||
idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags);
|
||||
testcase( idxNew2==0 );
|
||||
exprAnalyze(pSrc, pWC, idxNew2);
|
||||
pTerm = &pWC->a[idxTerm];
|
||||
@@ -2475,20 +2489,37 @@ static int whereInScanEst(
|
||||
** but joins might run a little slower. The trick is to disable as much
|
||||
** as we can without disabling too much. If we disabled in (1), we'd get
|
||||
** the wrong answer. See ticket #813.
|
||||
**
|
||||
** If all the children of a term are disabled, then that term is also
|
||||
** automatically disabled. In this way, terms get disabled if derived
|
||||
** virtual terms are tested first. For example:
|
||||
**
|
||||
** x GLOB 'abc*' AND x>='abc' AND x<'acd'
|
||||
** \___________/ \______/ \_____/
|
||||
** parent child1 child2
|
||||
**
|
||||
** Only the parent term was in the original WHERE clause. The child1
|
||||
** and child2 terms were added by the LIKE optimization. If both of
|
||||
** the virtual child terms are valid, then testing of the parent can be
|
||||
** skipped.
|
||||
*/
|
||||
static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
|
||||
if( pTerm
|
||||
int nLoop = 0;
|
||||
while( pTerm
|
||||
&& (pTerm->wtFlags & TERM_CODED)==0
|
||||
&& (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
|
||||
&& (pLevel->notReady & pTerm->prereqAll)==0
|
||||
){
|
||||
pTerm->wtFlags |= TERM_CODED;
|
||||
if( pTerm->iParent>=0 ){
|
||||
WhereTerm *pOther = &pTerm->pWC->a[pTerm->iParent];
|
||||
if( (--pOther->nChild)==0 ){
|
||||
disableTerm(pLevel, pOther);
|
||||
}
|
||||
if( nLoop && (pTerm->wtFlags & TERM_LIKE)!=0 ){
|
||||
pTerm->wtFlags |= TERM_LIKECOND;
|
||||
}else{
|
||||
pTerm->wtFlags |= TERM_CODED;
|
||||
}
|
||||
if( pTerm->iParent<0 ) break;
|
||||
pTerm = &pTerm->pWC->a[pTerm->iParent];
|
||||
pTerm->nChild--;
|
||||
if( pTerm->nChild!=0 ) break;
|
||||
nLoop++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3807,6 +3838,7 @@ static Bitmask codeOneLoopStart(
|
||||
*/
|
||||
for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
|
||||
Expr *pE;
|
||||
int skipLikeAddr = 0;
|
||||
testcase( pTerm->wtFlags & TERM_VIRTUAL );
|
||||
testcase( pTerm->wtFlags & TERM_CODED );
|
||||
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
|
||||
@@ -3821,7 +3853,13 @@ static Bitmask codeOneLoopStart(
|
||||
if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
|
||||
continue;
|
||||
}
|
||||
if( pTerm->wtFlags & TERM_LIKECOND ){
|
||||
assert( pLevel->iLikeRepCntr>0 );
|
||||
skipLikeAddr = sqlite3VdbeAddOp1(v, OP_IfZero, pLevel->iLikeRepCntr);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
|
||||
if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr);
|
||||
pTerm->wtFlags |= TERM_CODED;
|
||||
}
|
||||
|
||||
|
||||
@@ -277,7 +277,9 @@ struct WhereTerm {
|
||||
#else
|
||||
# define TERM_VNULL 0x00 /* Disabled if not using stat3 */
|
||||
#endif
|
||||
#define TERM_LIKEOPT 0x100 /* Used by the LIKE optimization */
|
||||
#define TERM_LIKEOPT 0x100 /* Virtual terms from the LIKE optimization */
|
||||
#define TERM_LIKECOND 0x200 /* Conditionally this LIKE operator term */
|
||||
#define TERM_LIKE 0x400 /* The original LIKE operator */
|
||||
|
||||
/*
|
||||
** An instance of the WhereScan object is used as an iterator for locating
|
||||
|
||||
Reference in New Issue
Block a user