aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2015-03-09 12:11:56 +0000
committerdrh <drh@noemail.net>2015-03-09 12:11:56 +0000
commita40da62dd4712b198fe5579a94a24ccafc4fdf54 (patch)
treea0341ba41c796f29aa939f8adc9e0da82d445a60 /src
parent52fc05ba1c4c297560ec28906b2902e2a3c522c5 (diff)
downloadsqlite-a40da62dd4712b198fe5579a94a24ccafc4fdf54.tar.gz
sqlite-a40da62dd4712b198fe5579a94a24ccafc4fdf54.zip
Always use LIKE optimization range constraints in pairs.
FossilOrigin-Name: 0e02dc94fd1bb891d0edd1e34b57e923b17712a7
Diffstat (limited to 'src')
-rw-r--r--src/where.c38
1 files changed, 28 insertions, 10 deletions
diff --git a/src/where.c b/src/where.c
index 3e2558d00..d6bce65d2 100644
--- a/src/where.c
+++ b/src/where.c
@@ -3013,8 +3013,8 @@ static void addScanStatus(
#endif
/*
-** Look at the last instruction coded. If that instruction is OP_String8
-** and if pLoop->iLikeRepCntr is non-zero, then change the P3 to be
+** If the most recently coded instruction is a constant range contraint
+** that originated from the LIKE optimization, then change the P3 to be
** pLoop->iLikeRepCntr and set P5.
**
** The LIKE optimization trys to evaluate "x LIKE 'abc%'" as a range
@@ -3030,11 +3030,14 @@ static void whereLikeOptimizationStringFixup(
WhereTerm *pTerm /* The upper or lower bound just coded */
){
if( pTerm->wtFlags & TERM_LIKEOPT ){
- VdbeOp *pOp = sqlite3VdbeGetOp(v, -1);
- if( pLevel->iLikeRepCntr && pOp->opcode==OP_String8 ){
- pOp->p3 = pLevel->iLikeRepCntr;
- pOp->p5 = 1;
- }
+ VdbeOp *pOp;
+ assert( pLevel->iLikeRepCntr>0 );
+ pOp = sqlite3VdbeGetOp(v, -1);
+ assert( pOp!=0 );
+ assert( pOp->opcode==OP_String8
+ || pTerm->pWC->pWInfo->pParse->db->mallocFailed );
+ pOp->p3 = pLevel->iLikeRepCntr;
+ pOp->p5 = 1;
}
}
@@ -3370,9 +3373,9 @@ static Bitmask codeOneLoopStart(
if( pLoop->wsFlags & WHERE_TOP_LIMIT ){
pRangeEnd = pLoop->aLTerm[j++];
nExtraReg = 1;
- if( (pRangeStart && (pRangeStart->wtFlags & TERM_LIKEOPT)!=0)
- || (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0
- ){
+ if( (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0 ){
+ assert( pRangeStart!=0 );
+ assert( pRangeStart->wtFlags & TERM_LIKEOPT );
pLevel->iLikeRepCntr = ++pParse->nMem;
testcase( bRev );
testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC );
@@ -4547,6 +4550,10 @@ static int whereLoopAddBtreeIndex(
}
if( pTerm->prereqRight & pNew->maskSelf ) continue;
+ /* Do not allow the upper bound of a LIKE optimization range constraint
+ ** to mix with a lower range bound from some other source */
+ if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue;
+
pNew->wsFlags = saved_wsFlags;
pNew->u.btree.nEq = saved_nEq;
pNew->nLTerm = saved_nLTerm;
@@ -4590,6 +4597,17 @@ static int whereLoopAddBtreeIndex(
pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT;
pBtm = pTerm;
pTop = 0;
+ if( pTerm->wtFlags & TERM_LIKEOPT ){
+ /* Make sure that range contraints that come from the LIKE
+ ** optimization are always used in pairs. */
+ pTop = &pTerm[1];
+ assert( (pTop-(pTerm->pWC->a))<pTerm->pWC->nTerm );
+ assert( pTop->wtFlags & TERM_LIKEOPT );
+ assert( pTop->eOperator==WO_LT );
+ if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
+ pNew->aLTerm[pNew->nLTerm++] = pTop;
+ pNew->wsFlags |= WHERE_TOP_LIMIT;
+ }
}else{
assert( eOp & (WO_LT|WO_LE) );
testcase( eOp & WO_LT );