aboutsummaryrefslogtreecommitdiff
path: root/src/wherecode.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/wherecode.c')
-rw-r--r--src/wherecode.c145
1 files changed, 124 insertions, 21 deletions
diff --git a/src/wherecode.c b/src/wherecode.c
index d78982f5b..892831d82 100644
--- a/src/wherecode.c
+++ b/src/wherecode.c
@@ -356,6 +356,7 @@ static int codeEqualityTerm(
Vdbe *v = pParse->pVdbe;
int iReg; /* Register holding results */
+ assert( pLevel->pWLoop->aLTerm[iEq]==pTerm );
assert( iTarget>0 );
if( pX->op==TK_EQ || pX->op==TK_IS ){
iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget);
@@ -368,6 +369,9 @@ static int codeEqualityTerm(
int iTab;
struct InLoop *pIn;
WhereLoop *pLoop = pLevel->pWLoop;
+ int i;
+ int nEq = 0;
+ int *aiMap = 0;
if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0
&& pLoop->u.btree.pIndex!=0
@@ -379,7 +383,52 @@ static int codeEqualityTerm(
}
assert( pX->op==TK_IN );
iReg = iTarget;
- eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0);
+
+ for(i=0; i<iEq; i++){
+ if( pLoop->aLTerm[i] && pLoop->aLTerm[i]->pExpr==pX ){
+ disableTerm(pLevel, pTerm);
+ return iTarget;
+ }
+ }
+ for(i=iEq;i<pLoop->nLTerm; i++){
+ if( pLoop->aLTerm[i] && pLoop->aLTerm[i]->pExpr==pX ) nEq++;
+ }
+
+ if( nEq>1 ){
+ aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int) * nEq);
+ if( !aiMap ) return 0;
+ }
+
+ if( (pX->flags & EP_xIsSelect)==0 || pX->x.pSelect->pEList->nExpr==1 ){
+ eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0);
+ }else{
+ sqlite3 *db = pParse->db;
+ ExprList *pOrigRhs = pX->x.pSelect->pEList;
+ ExprList *pOrigLhs = pX->pLeft->x.pList;
+ ExprList *pRhs = 0; /* New Select.pEList for RHS */
+ ExprList *pLhs = 0; /* New pX->pLeft vector */
+
+ for(i=iEq;i<pLoop->nLTerm; i++){
+ if( pLoop->aLTerm[i]->pExpr==pX ){
+ int iField = pLoop->aLTerm[i]->iField - 1;
+ Expr *pNewRhs = sqlite3ExprDup(db, pOrigRhs->a[iField].pExpr, 0);
+ Expr *pNewLhs = sqlite3ExprDup(db, pOrigLhs->a[iField].pExpr, 0);
+
+ pRhs = sqlite3ExprListAppend(pParse, pRhs, pNewRhs);
+ pLhs = sqlite3ExprListAppend(pParse, pLhs, pNewLhs);
+ }
+ }
+
+ pX->x.pSelect->pEList = pRhs;
+ pX->pLeft->x.pList = pLhs;
+
+ eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap);
+ pX->x.pSelect->pEList = pOrigRhs;
+ pX->pLeft->x.pList = pOrigLhs;
+ sqlite3ExprListDelete(pParse->db, pLhs);
+ sqlite3ExprListDelete(pParse->db, pRhs);
+ }
+
if( eType==IN_INDEX_INDEX_DESC ){
testcase( bRev );
bRev = !bRev;
@@ -389,28 +438,44 @@ static int codeEqualityTerm(
VdbeCoverageIf(v, bRev);
VdbeCoverageIf(v, !bRev);
assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 );
+
pLoop->wsFlags |= WHERE_IN_ABLE;
if( pLevel->u.in.nIn==0 ){
pLevel->addrNxt = sqlite3VdbeMakeLabel(v);
}
- pLevel->u.in.nIn++;
+
+ i = pLevel->u.in.nIn;
+ pLevel->u.in.nIn += nEq;
pLevel->u.in.aInLoop =
sqlite3DbReallocOrFree(pParse->db, pLevel->u.in.aInLoop,
sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn);
pIn = pLevel->u.in.aInLoop;
if( pIn ){
- pIn += pLevel->u.in.nIn - 1;
- pIn->iCur = iTab;
- if( eType==IN_INDEX_ROWID ){
- pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg);
- }else{
- pIn->addrInTop = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg);
+ int iMap = 0; /* Index in aiMap[] */
+ pIn += i;
+ for(i=iEq;i<pLoop->nLTerm; i++, pIn++){
+ if( pLoop->aLTerm[i]->pExpr==pX ){
+ if( eType==IN_INDEX_ROWID ){
+ assert( nEq==1 && i==iEq );
+ pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg);
+ }else{
+ int iCol = aiMap ? aiMap[iMap++] : 0;
+ int iOut = iReg + i - iEq;
+ pIn->addrInTop = sqlite3VdbeAddOp3(v,OP_Column,iTab, iCol, iOut);
+ }
+ if( i==iEq ){
+ pIn->iCur = iTab;
+ pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen;
+ }else{
+ pIn->eEndLoopOp = OP_Noop;
+ }
+ }
+ sqlite3VdbeAddOp1(v, OP_IsNull, iReg); VdbeCoverage(v);
}
- pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen;
- sqlite3VdbeAddOp1(v, OP_IsNull, iReg); VdbeCoverage(v);
}else{
pLevel->u.in.nIn = 0;
}
+ sqlite3DbFree(pParse->db, aiMap);
#endif
}
disableTerm(pLevel, pTerm);
@@ -861,6 +926,30 @@ static void codeDeferredSeek(
}
}
+static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){
+ assert( nReg>0 );
+ if( p->flags & EP_Vector ){
+ int i;
+ if( (p->flags & EP_xIsSelect)==0 ){
+ ExprList *pList = p->x.pList;
+ assert( nReg<=pList->nExpr );
+ for(i=0; i<nReg; i++){
+ sqlite3ExprCode(pParse, pList->a[i].pExpr, iReg+i);
+ }
+ }else{
+ Vdbe *v = pParse->pVdbe;
+ int iSelect = sqlite3CodeSubselect(pParse, p, 0, 0);
+ sqlite3VdbeAddOp3(v, OP_Copy, iSelect, iReg, nReg-1);
+ p->op2 = p->op;
+ p->op = TK_REGISTER;
+ p->iTable = iSelect;
+ }
+ }else{
+ assert( nReg==1 );
+ sqlite3ExprCode(pParse, p, iReg);
+ }
+}
+
/*
** Generate code for the start of the iLevel-th loop in the WHERE clause
** implementation described by pWInfo.
@@ -1185,6 +1274,8 @@ Bitmask sqlite3WhereCodeOneLoopStart(
OP_IdxLT, /* 3: (end_constraints && bRev && endEq) */
};
u16 nEq = pLoop->u.btree.nEq; /* Number of == or IN terms */
+ u16 nBtm = pLoop->u.btree.nBtm; /* Length of BTM vector */
+ u16 nTop = pLoop->u.btree.nTop; /* Length of TOP vector */
int regBase; /* Base register holding constraint values */
WhereTerm *pRangeStart = 0; /* Inequality constraint at range start */
WhereTerm *pRangeEnd = 0; /* Inequality constraint at range end */
@@ -1231,14 +1322,14 @@ Bitmask sqlite3WhereCodeOneLoopStart(
j = nEq;
if( pLoop->wsFlags & WHERE_BTM_LIMIT ){
pRangeStart = pLoop->aLTerm[j++];
- nExtraReg = 1;
+ nExtraReg = MAX(nExtraReg, pLoop->u.btree.nBtm);
/* Like optimization range constraints always occur in pairs */
assert( (pRangeStart->wtFlags & TERM_LIKEOPT)==0 ||
(pLoop->wsFlags & WHERE_TOP_LIMIT)!=0 );
}
if( pLoop->wsFlags & WHERE_TOP_LIMIT ){
pRangeEnd = pLoop->aLTerm[j++];
- nExtraReg = 1;
+ nExtraReg = MAX(nExtraReg, pLoop->u.btree.nTop);
#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
if( (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0 ){
assert( pRangeStart!=0 ); /* LIKE opt constraints */
@@ -1274,6 +1365,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
){
SWAP(WhereTerm *, pRangeEnd, pRangeStart);
SWAP(u8, bSeekPastNull, bStopAtNull);
+ SWAP(u8, nBtm, nTop);
}
/* Generate code to evaluate all constraint terms using == or IN
@@ -1298,7 +1390,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
nConstraint = nEq;
if( pRangeStart ){
Expr *pRight = pRangeStart->pExpr->pRight;
- sqlite3ExprCode(pParse, pRight, regBase+nEq);
+ codeExprOrVector(pParse, pRight, regBase+nEq, nBtm);
whereLikeOptimizationStringFixup(v, pLevel, pRangeStart);
if( (pRangeStart->wtFlags & TERM_VNULL)==0
&& sqlite3ExprCanBeNull(pRight)
@@ -1317,8 +1409,13 @@ Bitmask sqlite3WhereCodeOneLoopStart(
zStartAff[nEq] = SQLITE_AFF_BLOB;
}
}
- nConstraint++;
+ nConstraint += nBtm;
testcase( pRangeStart->wtFlags & TERM_VIRTUAL );
+ if( (pRight->flags & EP_Vector)==0 ){
+ disableTerm(pLevel, pRangeStart);
+ }else{
+ startEq = 1;
+ }
bSeekPastNull = 0;
}else if( bSeekPastNull ){
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
@@ -1351,7 +1448,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
if( pRangeEnd ){
Expr *pRight = pRangeEnd->pExpr->pRight;
sqlite3ExprCacheRemove(pParse, regBase+nEq, 1);
- sqlite3ExprCode(pParse, pRight, regBase+nEq);
+ codeExprOrVector(pParse, pRight, regBase+nEq, nTop);
whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd);
if( (pRangeEnd->wtFlags & TERM_VNULL)==0
&& sqlite3ExprCanBeNull(pRight)
@@ -1364,8 +1461,14 @@ Bitmask sqlite3WhereCodeOneLoopStart(
){
codeApplyAffinity(pParse, regBase+nEq, 1, &cEndAff);
}
- nConstraint++;
+ nConstraint += nTop;
testcase( pRangeEnd->wtFlags & TERM_VIRTUAL );
+
+ if( (pRight->flags & EP_Vector)==0 ){
+ disableTerm(pLevel, pRangeEnd);
+ }else{
+ endEq = 1;
+ }
}else if( bStopAtNull ){
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
endEq = 0;
@@ -1386,9 +1489,11 @@ Bitmask sqlite3WhereCodeOneLoopStart(
testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE );
}
+ /* Disable the start and end range terms if possible */
+ /* disableTerm(pLevel, pRangeStart); */
+ /* disableTerm(pLevel, pRangeEnd); */
+
/* Seek the table cursor, if required */
- disableTerm(pLevel, pRangeStart);
- disableTerm(pLevel, pRangeEnd);
if( omitTable ){
/* pIdx is a covering index. No need to access the main table. */
}else if( HasRowid(pIdx->pTable) ){
@@ -1412,9 +1517,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
iRowidReg, pPk->nKeyCol); VdbeCoverage(v);
}
- /* Record the instruction used to terminate the loop. Disable
- ** WHERE clause terms made redundant by the index range scan.
- */
+ /* Record the instruction used to terminate the loop. */
if( pLoop->wsFlags & WHERE_ONEROW ){
pLevel->op = OP_Noop;
}else if( bRev ){