mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-19 21:43:15 +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.
|
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
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
5757e803cb5759b476bbc6453c58340089611420
|
a58aafdb4e1422b6a8ffc07a67984928bbedf919
|
||||||
58
src/where.c
58
src/where.c
@@ -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
|
||||||
){
|
){
|
||||||
|
if( nLoop && (pTerm->wtFlags & TERM_LIKE)!=0 ){
|
||||||
|
pTerm->wtFlags |= TERM_LIKECOND;
|
||||||
|
}else{
|
||||||
pTerm->wtFlags |= TERM_CODED;
|
pTerm->wtFlags |= TERM_CODED;
|
||||||
if( pTerm->iParent>=0 ){
|
|
||||||
WhereTerm *pOther = &pTerm->pWC->a[pTerm->iParent];
|
|
||||||
if( (--pOther->nChild)==0 ){
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user