1
0
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:
drh
2015-03-06 19:47:38 +00:00
parent f07cf6e2a5
commit 8f1a7ed33f
4 changed files with 61 additions and 24 deletions

View File

@@ -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. C Fix\sthe\sLIKE\soptimization\seven\swhen\scomparing\smixed-case\sBLOBs.
D 2015-03-06T16:45:16.543 D 2015-03-06T19:47:38.505
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 2f643d6968dfc0b82d2e546a0525a39079f9e928 F Makefile.in 2f643d6968dfc0b82d2e546a0525a39079f9e928
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -307,8 +307,8 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb
F src/wal.c 39303f2c9db02a4e422cd8eb2c8760420c6a51fe F src/wal.c 39303f2c9db02a4e422cd8eb2c8760420c6a51fe
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804
F src/where.c b7e82341d2570ac8a051e133cfc44c7eec79a30e F src/where.c cace7eef1838ea22f549e824236eaaa4195b83e6
F src/whereInt.h 0ba6257f2a44acd6262f259d5147cd01c52cc45b F src/whereInt.h cbe4aa57326998d89e7698ca65bb7c28541d483c
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7 F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7
@@ -1240,10 +1240,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 8c1e85aab9e0d90726057e25e2ea0663341c070f P 5757e803cb5759b476bbc6453c58340089611420
R db06eec232964b57030b876196612d14 R 1a18426c5e280ce5513288eef4bf379e
T *branch * like-opt-fix
T *sym-like-opt-fix *
T -sym-trunk *
U drh U drh
Z 9b71822fa0ca3d1b398ae4d623871060 Z 4902bd060fa099614e1fc5278ee9e5b6

View File

@@ -1 +1 @@
5757e803cb5759b476bbc6453c58340089611420 a58aafdb4e1422b6a8ffc07a67984928bbedf919

View File

@@ -1264,9 +1264,25 @@ static void exprAnalyze(
int idxNew1; int idxNew1;
int idxNew2; int idxNew2;
Token sCollSeqName; /* Name of collating sequence */ 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; pLeft = pExpr->x.pList->a[1].pExpr;
pStr2 = sqlite3ExprDup(db, pStr1, 0); 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 ){ if( !db->mallocFailed ){
u8 c, *pC; /* Last character before the first wildcard */ u8 c, *pC; /* Last character before the first wildcard */
pC = (u8*)&pStr2->u.zToken[sqlite3Strlen30(pStr2->u.zToken)-1]; pC = (u8*)&pStr2->u.zToken[sqlite3Strlen30(pStr2->u.zToken)-1];
@@ -1290,8 +1306,7 @@ static void exprAnalyze(
sqlite3ExprAddCollateToken(pParse,pNewExpr1,&sCollSeqName), sqlite3ExprAddCollateToken(pParse,pNewExpr1,&sCollSeqName),
pStr1, 0); pStr1, 0);
transferJoinMarkings(pNewExpr1, pExpr); transferJoinMarkings(pNewExpr1, pExpr);
idxNew1 = whereClauseInsert(pWC, pNewExpr1, idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags);
TERM_LIKEOPT|TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew1==0 ); testcase( idxNew1==0 );
exprAnalyze(pSrc, pWC, idxNew1); exprAnalyze(pSrc, pWC, idxNew1);
pNewExpr2 = sqlite3ExprDup(db, pLeft, 0); pNewExpr2 = sqlite3ExprDup(db, pLeft, 0);
@@ -1299,8 +1314,7 @@ static void exprAnalyze(
sqlite3ExprAddCollateToken(pParse,pNewExpr2,&sCollSeqName), sqlite3ExprAddCollateToken(pParse,pNewExpr2,&sCollSeqName),
pStr2, 0); pStr2, 0);
transferJoinMarkings(pNewExpr2, pExpr); transferJoinMarkings(pNewExpr2, pExpr);
idxNew2 = whereClauseInsert(pWC, pNewExpr2, idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags);
TERM_LIKEOPT|TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew2==0 ); testcase( idxNew2==0 );
exprAnalyze(pSrc, pWC, idxNew2); exprAnalyze(pSrc, pWC, idxNew2);
pTerm = &pWC->a[idxTerm]; 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 ** 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 ** as we can without disabling too much. If we disabled in (1), we'd get
** the wrong answer. See ticket #813. ** 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){ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
if( pTerm int nLoop = 0;
while( pTerm
&& (pTerm->wtFlags & TERM_CODED)==0 && (pTerm->wtFlags & TERM_CODED)==0
&& (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin)) && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
&& (pLevel->notReady & pTerm->prereqAll)==0 && (pLevel->notReady & pTerm->prereqAll)==0
){ ){
pTerm->wtFlags |= TERM_CODED; if( nLoop && (pTerm->wtFlags & TERM_LIKE)!=0 ){
if( pTerm->iParent>=0 ){ pTerm->wtFlags |= TERM_LIKECOND;
WhereTerm *pOther = &pTerm->pWC->a[pTerm->iParent]; }else{
if( (--pOther->nChild)==0 ){ pTerm->wtFlags |= TERM_CODED;
disableTerm(pLevel, pOther);
}
} }
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++){ for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
Expr *pE; Expr *pE;
int skipLikeAddr = 0;
testcase( pTerm->wtFlags & TERM_VIRTUAL ); testcase( pTerm->wtFlags & TERM_VIRTUAL );
testcase( pTerm->wtFlags & TERM_CODED ); testcase( pTerm->wtFlags & TERM_CODED );
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
@@ -3821,7 +3853,13 @@ static Bitmask codeOneLoopStart(
if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){ if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
continue; 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); sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr);
pTerm->wtFlags |= TERM_CODED; pTerm->wtFlags |= TERM_CODED;
} }

View File

@@ -277,7 +277,9 @@ struct WhereTerm {
#else #else
# define TERM_VNULL 0x00 /* Disabled if not using stat3 */ # define TERM_VNULL 0x00 /* Disabled if not using stat3 */
#endif #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 ** An instance of the WhereScan object is used as an iterator for locating