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:
62
src/where.c
62
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];
|
||||
@@ -1286,12 +1302,11 @@ static void exprAnalyze(
|
||||
sCollSeqName.z = noCase ? "NOCASE" : "BINARY";
|
||||
sCollSeqName.n = 6;
|
||||
pNewExpr1 = sqlite3ExprDup(db, pLeft, 0);
|
||||
pNewExpr1 = sqlite3PExpr(pParse, TK_GE,
|
||||
pNewExpr1 = sqlite3PExpr(pParse, TK_GE,
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user