Index: third_party/sqlite/src/src/wherecode.c |
diff --git a/third_party/sqlite/src/src/wherecode.c b/third_party/sqlite/src/src/wherecode.c |
index bc72e0ac7d2819e416d7866fa16b6fa99ce7d802..58e040628ae8752a98dafdd2472e776dee3977f3 100644 |
--- a/third_party/sqlite/src/src/wherecode.c |
+++ b/third_party/sqlite/src/src/wherecode.c |
@@ -21,6 +21,17 @@ |
#include "whereInt.h" |
#ifndef SQLITE_OMIT_EXPLAIN |
+ |
+/* |
+** Return the name of the i-th column of the pIdx index. |
+*/ |
+static const char *explainIndexColumnName(Index *pIdx, int i){ |
+ i = pIdx->aiColumn[i]; |
+ if( i==XN_EXPR ) return "<expr>"; |
+ if( i==XN_ROWID ) return "rowid"; |
+ return pIdx->pTable->aCol[i].zName; |
+} |
+ |
/* |
** This routine is a helper for explainIndexRange() below |
** |
@@ -31,24 +42,32 @@ |
*/ |
static void explainAppendTerm( |
StrAccum *pStr, /* The text expression being built */ |
- int iTerm, /* Index of this term. First is zero */ |
- const char *zColumn, /* Name of the column */ |
+ Index *pIdx, /* Index to read column names from */ |
+ int nTerm, /* Number of terms */ |
+ int iTerm, /* Zero-based index of first term. */ |
+ int bAnd, /* Non-zero to append " AND " */ |
const char *zOp /* Name of the operator */ |
){ |
- if( iTerm ) sqlite3StrAccumAppend(pStr, " AND ", 5); |
- sqlite3StrAccumAppendAll(pStr, zColumn); |
+ int i; |
+ |
+ assert( nTerm>=1 ); |
+ if( bAnd ) sqlite3StrAccumAppend(pStr, " AND ", 5); |
+ |
+ if( nTerm>1 ) sqlite3StrAccumAppend(pStr, "(", 1); |
+ for(i=0; i<nTerm; i++){ |
+ if( i ) sqlite3StrAccumAppend(pStr, ",", 1); |
+ sqlite3StrAccumAppendAll(pStr, explainIndexColumnName(pIdx, iTerm+i)); |
+ } |
+ if( nTerm>1 ) sqlite3StrAccumAppend(pStr, ")", 1); |
+ |
sqlite3StrAccumAppend(pStr, zOp, 1); |
- sqlite3StrAccumAppend(pStr, "?", 1); |
-} |
-/* |
-** Return the name of the i-th column of the pIdx index. |
-*/ |
-static const char *explainIndexColumnName(Index *pIdx, int i){ |
- i = pIdx->aiColumn[i]; |
- if( i==XN_EXPR ) return "<expr>"; |
- if( i==XN_ROWID ) return "rowid"; |
- return pIdx->pTable->aCol[i].zName; |
+ if( nTerm>1 ) sqlite3StrAccumAppend(pStr, "(", 1); |
+ for(i=0; i<nTerm; i++){ |
+ if( i ) sqlite3StrAccumAppend(pStr, ",", 1); |
+ sqlite3StrAccumAppend(pStr, "?", 1); |
+ } |
+ if( nTerm>1 ) sqlite3StrAccumAppend(pStr, ")", 1); |
} |
/* |
@@ -76,17 +95,16 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){ |
for(i=0; i<nEq; i++){ |
const char *z = explainIndexColumnName(pIndex, i); |
if( i ) sqlite3StrAccumAppend(pStr, " AND ", 5); |
- sqlite3XPrintf(pStr, 0, i>=nSkip ? "%s=?" : "ANY(%s)", z); |
+ sqlite3XPrintf(pStr, i>=nSkip ? "%s=?" : "ANY(%s)", z); |
} |
j = i; |
if( pLoop->wsFlags&WHERE_BTM_LIMIT ){ |
- const char *z = explainIndexColumnName(pIndex, i); |
- explainAppendTerm(pStr, i++, z, ">"); |
+ explainAppendTerm(pStr, pIndex, pLoop->u.btree.nBtm, j, i, ">"); |
+ i = 1; |
} |
if( pLoop->wsFlags&WHERE_TOP_LIMIT ){ |
- const char *z = explainIndexColumnName(pIndex, j); |
- explainAppendTerm(pStr, i, z, "<"); |
+ explainAppendTerm(pStr, pIndex, pLoop->u.btree.nTop, j, i, "<"); |
} |
sqlite3StrAccumAppend(pStr, ")", 1); |
} |
@@ -126,7 +144,7 @@ int sqlite3WhereExplainOneScan( |
pLoop = pLevel->pWLoop; |
flags = pLoop->wsFlags; |
- if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return 0; |
+ if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_OR_SUBCLAUSE) ) return 0; |
isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 |
|| ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0)) |
@@ -135,13 +153,13 @@ int sqlite3WhereExplainOneScan( |
sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); |
sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN"); |
if( pItem->pSelect ){ |
- sqlite3XPrintf(&str, 0, " SUBQUERY %d", pItem->iSelectId); |
+ sqlite3XPrintf(&str, " SUBQUERY %d", pItem->iSelectId); |
}else{ |
- sqlite3XPrintf(&str, 0, " TABLE %s", pItem->zName); |
+ sqlite3XPrintf(&str, " TABLE %s", pItem->zName); |
} |
if( pItem->zAlias ){ |
- sqlite3XPrintf(&str, 0, " AS %s", pItem->zAlias); |
+ sqlite3XPrintf(&str, " AS %s", pItem->zAlias); |
} |
if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){ |
const char *zFmt = 0; |
@@ -165,7 +183,7 @@ int sqlite3WhereExplainOneScan( |
} |
if( zFmt ){ |
sqlite3StrAccumAppend(&str, " USING ", 7); |
- sqlite3XPrintf(&str, 0, zFmt, pIdx->zName); |
+ sqlite3XPrintf(&str, zFmt, pIdx->zName); |
explainIndexRange(&str, pLoop); |
} |
}else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){ |
@@ -180,17 +198,17 @@ int sqlite3WhereExplainOneScan( |
assert( flags&WHERE_TOP_LIMIT); |
zRangeOp = "<"; |
} |
- sqlite3XPrintf(&str, 0, " USING INTEGER PRIMARY KEY (rowid%s?)",zRangeOp); |
+ sqlite3XPrintf(&str, " USING INTEGER PRIMARY KEY (rowid%s?)",zRangeOp); |
} |
#ifndef SQLITE_OMIT_VIRTUALTABLE |
else if( (flags & WHERE_VIRTUALTABLE)!=0 ){ |
- sqlite3XPrintf(&str, 0, " VIRTUAL TABLE INDEX %d:%s", |
+ sqlite3XPrintf(&str, " VIRTUAL TABLE INDEX %d:%s", |
pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr); |
} |
#endif |
#ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS |
if( pLoop->nOut>=10 ){ |
- sqlite3XPrintf(&str, 0, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut)); |
+ sqlite3XPrintf(&str, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut)); |
}else{ |
sqlite3StrAccumAppend(&str, " (~1 row)", 9); |
} |
@@ -276,7 +294,7 @@ void sqlite3WhereAddScanStatus( |
*/ |
static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ |
int nLoop = 0; |
- while( pTerm |
+ while( ALWAYS(pTerm!=0) |
&& (pTerm->wtFlags & TERM_CODED)==0 |
&& (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin)) |
&& (pLevel->notReady & pTerm->prereqAll)==0 |
@@ -327,22 +345,50 @@ static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){ |
/* Code the OP_Affinity opcode if there is anything left to do. */ |
if( n>0 ){ |
- sqlite3VdbeAddOp2(v, OP_Affinity, base, n); |
- sqlite3VdbeChangeP4(v, -1, zAff, n); |
+ sqlite3VdbeAddOp4(v, OP_Affinity, base, n, 0, zAff, n); |
sqlite3ExprCacheAffinityChange(pParse, base, n); |
} |
} |
+/* |
+** Expression pRight, which is the RHS of a comparison operation, is |
+** either a vector of n elements or, if n==1, a scalar expression. |
+** Before the comparison operation, affinity zAff is to be applied |
+** to the pRight values. This function modifies characters within the |
+** affinity string to SQLITE_AFF_BLOB if either: |
+** |
+** * the comparison will be performed with no affinity, or |
+** * the affinity change in zAff is guaranteed not to change the value. |
+*/ |
+static void updateRangeAffinityStr( |
+ Expr *pRight, /* RHS of comparison */ |
+ int n, /* Number of vector elements in comparison */ |
+ char *zAff /* Affinity string to modify */ |
+){ |
+ int i; |
+ for(i=0; i<n; i++){ |
+ Expr *p = sqlite3VectorFieldSubexpr(pRight, i); |
+ if( sqlite3CompareAffinity(p, zAff[i])==SQLITE_AFF_BLOB |
+ || sqlite3ExprNeedsNoAffinityChange(p, zAff[i]) |
+ ){ |
+ zAff[i] = SQLITE_AFF_BLOB; |
+ } |
+ } |
+} |
/* |
** Generate code for a single equality term of the WHERE clause. An equality |
** term can be either X=expr or X IN (...). pTerm is the term to be |
** coded. |
** |
-** The current value for the constraint is left in register iReg. |
+** The current value for the constraint is left in a register, the index |
+** of which is returned. An attempt is made store the result in iTarget but |
+** this is only guaranteed for TK_ISNULL and TK_IN constraints. If the |
+** constraint is a TK_EQ or TK_IS, then the current value might be left in |
+** some other register and it is the caller's responsibility to compensate. |
** |
-** For a constraint of the form X=expr, the expression is evaluated and its |
-** result is left on the stack. For constraints of the form X IN (...) |
+** For a constraint of the form X=expr, the expression is evaluated in |
+** straight-line code. For constraints of the form X IN (...) |
** this routine sets up a loop that will iterate over all values of X. |
*/ |
static int codeEqualityTerm( |
@@ -357,6 +403,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); |
@@ -365,10 +412,13 @@ static int codeEqualityTerm( |
sqlite3VdbeAddOp2(v, OP_Null, 0, iReg); |
#ifndef SQLITE_OMIT_SUBQUERY |
}else{ |
- int eType; |
+ int eType = IN_INDEX_NOOP; |
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 |
@@ -380,7 +430,78 @@ 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( ALWAYS(pLoop->aLTerm[i]) && pLoop->aLTerm[i]->pExpr==pX ) nEq++; |
+ } |
+ |
+ if( (pX->flags & EP_xIsSelect)==0 || pX->x.pSelect->pEList->nExpr==1 ){ |
+ eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0); |
+ }else{ |
+ Select *pSelect = pX->x.pSelect; |
+ sqlite3 *db = pParse->db; |
+ u16 savedDbOptFlags = db->dbOptFlags; |
+ ExprList *pOrigRhs = 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); |
+ } |
+ } |
+ if( !db->mallocFailed ){ |
+ Expr *pLeft = pX->pLeft; |
+ |
+ if( pSelect->pOrderBy ){ |
+ /* If the SELECT statement has an ORDER BY clause, zero the |
+ ** iOrderByCol variables. These are set to non-zero when an |
+ ** ORDER BY term exactly matches one of the terms of the |
+ ** result-set. Since the result-set of the SELECT statement may |
+ ** have been modified or reordered, these variables are no longer |
+ ** set correctly. Since setting them is just an optimization, |
+ ** it's easiest just to zero them here. */ |
+ ExprList *pOrderBy = pSelect->pOrderBy; |
+ for(i=0; i<pOrderBy->nExpr; i++){ |
+ pOrderBy->a[i].u.x.iOrderByCol = 0; |
+ } |
+ } |
+ |
+ /* Take care here not to generate a TK_VECTOR containing only a |
+ ** single value. Since the parser never creates such a vector, some |
+ ** of the subroutines do not handle this case. */ |
+ if( pLhs->nExpr==1 ){ |
+ pX->pLeft = pLhs->a[0].pExpr; |
+ }else{ |
+ pLeft->x.pList = pLhs; |
+ aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int) * nEq); |
+ testcase( aiMap==0 ); |
+ } |
+ pSelect->pEList = pRhs; |
+ db->dbOptFlags |= SQLITE_QueryFlattener; |
+ eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap); |
+ db->dbOptFlags = savedDbOptFlags; |
+ testcase( aiMap!=0 && aiMap[0]!=0 ); |
+ pSelect->pEList = pOrigRhs; |
+ pLeft->x.pList = pOrigLhs; |
+ pX->pLeft = pLeft; |
+ } |
+ sqlite3ExprListDelete(pParse->db, pLhs); |
+ sqlite3ExprListDelete(pParse->db, pRhs); |
+ } |
+ |
if( eType==IN_INDEX_INDEX_DESC ){ |
testcase( bRev ); |
bRev = !bRev; |
@@ -390,28 +511,45 @@ 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++){ |
+ if( pLoop->aLTerm[i]->pExpr==pX ){ |
+ int iOut = iReg + i - iEq; |
+ if( eType==IN_INDEX_ROWID ){ |
+ testcase( nEq>1 ); /* Happens with a UNIQUE index on ROWID */ |
+ pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iOut); |
+ }else{ |
+ int iCol = aiMap ? aiMap[iMap++] : 0; |
+ pIn->addrInTop = sqlite3VdbeAddOp3(v,OP_Column,iTab, iCol, iOut); |
+ } |
+ sqlite3VdbeAddOp1(v, OP_IsNull, iOut); VdbeCoverage(v); |
+ if( i==iEq ){ |
+ pIn->iCur = iTab; |
+ pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen; |
+ }else{ |
+ pIn->eEndLoopOp = OP_Noop; |
+ } |
+ pIn++; |
+ } |
} |
- 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); |
@@ -496,9 +634,7 @@ static int codeAllEqualityTerms( |
pParse->nMem += nReg; |
zAff = sqlite3DbStrDup(pParse->db,sqlite3IndexAffinityStr(pParse->db,pIdx)); |
- if( !zAff ){ |
- pParse->db->mallocFailed = 1; |
- } |
+ assert( zAff!=0 || pParse->db->mallocFailed ); |
if( nSkip ){ |
int iIdxCur = pLevel->iIdxCur; |
@@ -539,9 +675,15 @@ static int codeAllEqualityTerms( |
sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j); |
} |
} |
- testcase( pTerm->eOperator & WO_ISNULL ); |
- testcase( pTerm->eOperator & WO_IN ); |
- if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){ |
+ if( pTerm->eOperator & WO_IN ){ |
+ if( pTerm->pExpr->flags & EP_xIsSelect ){ |
+ /* No affinity ever needs to be (or should be) applied to a value |
+ ** from the RHS of an "? IN (SELECT ...)" expression. The |
+ ** sqlite3FindInIndex() routine has already ensured that the |
+ ** affinity of the comparison has been applied to the value. */ |
+ if( zAff ) zAff[j] = SQLITE_AFF_BLOB; |
+ } |
+ }else if( (pTerm->eOperator & WO_ISNULL)==0 ){ |
Expr *pRight = pTerm->pExpr->pRight; |
if( (pTerm->wtFlags & TERM_IS)==0 && sqlite3ExprCanBeNull(pRight) ){ |
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk); |
@@ -563,15 +705,16 @@ static int codeAllEqualityTerms( |
#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS |
/* |
-** 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. |
+** If the most recently coded instruction is a constant range constraint |
+** (a string literal) that originated from the LIKE optimization, then |
+** set P3 and P5 on the OP_String opcode so that the string will be cast |
+** to a BLOB at appropriate times. |
** |
** The LIKE optimization trys to evaluate "x LIKE 'abc%'" as a range |
** expression: "x>='ABC' AND x<'abd'". But this requires that the range |
** scan loop run twice, once for strings and a second time for BLOBs. |
** The OP_String opcodes on the second pass convert the upper and lower |
-** bound string contants to blobs. This routine makes the necessary changes |
+** bound string constants to blobs. This routine makes the necessary changes |
** to the OP_String opcodes for that to happen. |
** |
** Except, of course, if SQLITE_LIKE_DOESNT_MATCH_BLOBS is defined, then |
@@ -590,8 +733,8 @@ static void whereLikeOptimizationStringFixup( |
assert( pOp!=0 ); |
assert( pOp->opcode==OP_String8 |
|| pTerm->pWC->pWInfo->pParse->db->mallocFailed ); |
- pOp->p3 = pLevel->iLikeRepCntr; |
- pOp->p5 = 1; |
+ pOp->p3 = (int)(pLevel->iLikeRepCntr>>1); /* Register holding counter */ |
+ pOp->p5 = (u8)(pLevel->iLikeRepCntr&1); /* ASC or DESC */ |
} |
} |
#else |
@@ -628,6 +771,38 @@ static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){ |
return WRC_Continue; |
} |
+/* |
+** Test whether or not expression pExpr, which was part of a WHERE clause, |
+** should be included in the cursor-hint for a table that is on the rhs |
+** of a LEFT JOIN. Set Walker.eCode to non-zero before returning if the |
+** expression is not suitable. |
+** |
+** An expression is unsuitable if it might evaluate to non NULL even if |
+** a TK_COLUMN node that does affect the value of the expression is set |
+** to NULL. For example: |
+** |
+** col IS NULL |
+** col IS NOT NULL |
+** coalesce(col, 1) |
+** CASE WHEN col THEN 0 ELSE 1 END |
+*/ |
+static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){ |
+ if( pExpr->op==TK_IS |
+ || pExpr->op==TK_ISNULL || pExpr->op==TK_ISNOT |
+ || pExpr->op==TK_NOTNULL || pExpr->op==TK_CASE |
+ ){ |
+ pWalker->eCode = 1; |
+ }else if( pExpr->op==TK_FUNCTION ){ |
+ int d1; |
+ char d2[3]; |
+ if( 0==sqlite3IsLikeFunction(pWalker->pParse->db, pExpr, &d1, d2) ){ |
+ pWalker->eCode = 1; |
+ } |
+ } |
+ |
+ return WRC_Continue; |
+} |
+ |
/* |
** This function is called on every node of an expression tree used as an |
@@ -680,6 +855,7 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){ |
** Insert an OP_CursorHint instruction if it is appropriate to do so. |
*/ |
static void codeCursorHint( |
+ struct SrcList_item *pTabItem, /* FROM clause item */ |
WhereInfo *pWInfo, /* The where clause */ |
WhereLevel *pLevel, /* Which loop to provide hints for */ |
WhereTerm *pEndRange /* Hint this end-of-scan boundary term if not NULL */ |
@@ -710,7 +886,42 @@ static void codeCursorHint( |
pTerm = &pWC->a[i]; |
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; |
if( pTerm->prereqAll & pLevel->notReady ) continue; |
- if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue; |
+ |
+ /* Any terms specified as part of the ON(...) clause for any LEFT |
+ ** JOIN for which the current table is not the rhs are omitted |
+ ** from the cursor-hint. |
+ ** |
+ ** If this table is the rhs of a LEFT JOIN, "IS" or "IS NULL" terms |
+ ** that were specified as part of the WHERE clause must be excluded. |
+ ** This is to address the following: |
+ ** |
+ ** SELECT ... t1 LEFT JOIN t2 ON (t1.a=t2.b) WHERE t2.c IS NULL; |
+ ** |
+ ** Say there is a single row in t2 that matches (t1.a=t2.b), but its |
+ ** t2.c values is not NULL. If the (t2.c IS NULL) constraint is |
+ ** pushed down to the cursor, this row is filtered out, causing |
+ ** SQLite to synthesize a row of NULL values. Which does match the |
+ ** WHERE clause, and so the query returns a row. Which is incorrect. |
+ ** |
+ ** For the same reason, WHERE terms such as: |
+ ** |
+ ** WHERE 1 = (t2.c IS NULL) |
+ ** |
+ ** are also excluded. See codeCursorHintIsOrFunction() for details. |
+ */ |
+ if( pTabItem->fg.jointype & JT_LEFT ){ |
+ Expr *pExpr = pTerm->pExpr; |
+ if( !ExprHasProperty(pExpr, EP_FromJoin) |
+ || pExpr->iRightJoinTable!=pTabItem->iCursor |
+ ){ |
+ sWalker.eCode = 0; |
+ sWalker.xExprCallback = codeCursorHintIsOrFunction; |
+ sqlite3WalkExpr(&sWalker, pTerm->pExpr); |
+ if( sWalker.eCode ) continue; |
+ } |
+ }else{ |
+ if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue; |
+ } |
/* All terms in pWLoop->aLTerm[] except pEndRange are used to initialize |
** the cursor. These terms are not needed as hints for a pure range |
@@ -744,10 +955,91 @@ static void codeCursorHint( |
} |
} |
#else |
-# define codeCursorHint(A,B,C) /* No-op */ |
+# define codeCursorHint(A,B,C,D) /* No-op */ |
#endif /* SQLITE_ENABLE_CURSOR_HINTS */ |
/* |
+** Cursor iCur is open on an intkey b-tree (a table). Register iRowid contains |
+** a rowid value just read from cursor iIdxCur, open on index pIdx. This |
+** function generates code to do a deferred seek of cursor iCur to the |
+** rowid stored in register iRowid. |
+** |
+** Normally, this is just: |
+** |
+** OP_Seek $iCur $iRowid |
+** |
+** However, if the scan currently being coded is a branch of an OR-loop and |
+** the statement currently being coded is a SELECT, then P3 of the OP_Seek |
+** is set to iIdxCur and P4 is set to point to an array of integers |
+** containing one entry for each column of the table cursor iCur is open |
+** on. For each table column, if the column is the i'th column of the |
+** index, then the corresponding array entry is set to (i+1). If the column |
+** does not appear in the index at all, the array entry is set to 0. |
+*/ |
+static void codeDeferredSeek( |
+ WhereInfo *pWInfo, /* Where clause context */ |
+ Index *pIdx, /* Index scan is using */ |
+ int iCur, /* Cursor for IPK b-tree */ |
+ int iIdxCur /* Index cursor */ |
+){ |
+ Parse *pParse = pWInfo->pParse; /* Parse context */ |
+ Vdbe *v = pParse->pVdbe; /* Vdbe to generate code within */ |
+ |
+ assert( iIdxCur>0 ); |
+ assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 ); |
+ |
+ sqlite3VdbeAddOp3(v, OP_Seek, iIdxCur, 0, iCur); |
+ if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE) |
+ && DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask) |
+ ){ |
+ int i; |
+ Table *pTab = pIdx->pTable; |
+ int *ai = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*(pTab->nCol+1)); |
+ if( ai ){ |
+ ai[0] = pTab->nCol; |
+ for(i=0; i<pIdx->nColumn-1; i++){ |
+ assert( pIdx->aiColumn[i]<pTab->nCol ); |
+ if( pIdx->aiColumn[i]>=0 ) ai[pIdx->aiColumn[i]+1] = i+1; |
+ } |
+ sqlite3VdbeChangeP4(v, -1, (char*)ai, P4_INTARRAY); |
+ } |
+ } |
+} |
+ |
+/* |
+** If the expression passed as the second argument is a vector, generate |
+** code to write the first nReg elements of the vector into an array |
+** of registers starting with iReg. |
+** |
+** If the expression is not a vector, then nReg must be passed 1. In |
+** this case, generate code to evaluate the expression and leave the |
+** result in register iReg. |
+*/ |
+static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){ |
+ assert( nReg>0 ); |
+ if( sqlite3ExprIsVector(p) ){ |
+#ifndef SQLITE_OMIT_SUBQUERY |
+ if( (p->flags & EP_xIsSelect) ){ |
+ Vdbe *v = pParse->pVdbe; |
+ int iSelect = sqlite3CodeSubselect(pParse, p, 0, 0); |
+ sqlite3VdbeAddOp3(v, OP_Copy, iSelect, iReg, nReg-1); |
+ }else |
+#endif |
+ { |
+ int i; |
+ ExprList *pList = p->x.pList; |
+ assert( nReg<=pList->nExpr ); |
+ for(i=0; i<nReg; i++){ |
+ sqlite3ExprCode(pParse, pList->a[i].pExpr, iReg+i); |
+ } |
+ } |
+ }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. |
*/ |
@@ -785,7 +1077,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( |
pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); |
bRev = (pWInfo->revMask>>iLevel)&1; |
omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0 |
- && (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)==0; |
+ && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0; |
VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName)); |
/* Create labels for the "break" and "continue" instructions |
@@ -829,6 +1121,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( |
int iReg; /* P3 Value for OP_VFilter */ |
int addrNotFound; |
int nConstraint = pLoop->nLTerm; |
+ int iIn; /* Counter for IN constraints */ |
sqlite3ExprCachePush(pParse); |
iReg = sqlite3GetTempRange(pParse, nConstraint+2); |
@@ -836,30 +1129,73 @@ Bitmask sqlite3WhereCodeOneLoopStart( |
for(j=0; j<nConstraint; j++){ |
int iTarget = iReg+j+2; |
pTerm = pLoop->aLTerm[j]; |
- if( pTerm==0 ) continue; |
+ if( NEVER(pTerm==0) ) continue; |
if( pTerm->eOperator & WO_IN ){ |
codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget); |
addrNotFound = pLevel->addrNxt; |
}else{ |
- sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget); |
+ Expr *pRight = pTerm->pExpr->pRight; |
+ codeExprOrVector(pParse, pRight, iTarget, 1); |
} |
} |
sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg); |
sqlite3VdbeAddOp2(v, OP_Integer, nConstraint, iReg+1); |
sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg, |
pLoop->u.vtab.idxStr, |
- pLoop->u.vtab.needFree ? P4_MPRINTF : P4_STATIC); |
+ pLoop->u.vtab.needFree ? P4_DYNAMIC : P4_STATIC); |
VdbeCoverage(v); |
pLoop->u.vtab.needFree = 0; |
- for(j=0; j<nConstraint && j<16; j++){ |
- if( (pLoop->u.vtab.omitMask>>j)&1 ){ |
- disableTerm(pLevel, pLoop->aLTerm[j]); |
- } |
- } |
pLevel->p1 = iCur; |
pLevel->op = pWInfo->eOnePass ? OP_Noop : OP_VNext; |
pLevel->p2 = sqlite3VdbeCurrentAddr(v); |
- sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2); |
+ iIn = pLevel->u.in.nIn; |
+ for(j=nConstraint-1; j>=0; j--){ |
+ pTerm = pLoop->aLTerm[j]; |
+ if( j<16 && (pLoop->u.vtab.omitMask>>j)&1 ){ |
+ disableTerm(pLevel, pTerm); |
+ }else if( (pTerm->eOperator & WO_IN)!=0 ){ |
+ Expr *pCompare; /* The comparison operator */ |
+ Expr *pRight; /* RHS of the comparison */ |
+ VdbeOp *pOp; /* Opcode to access the value of the IN constraint */ |
+ |
+ /* Reload the constraint value into reg[iReg+j+2]. The same value |
+ ** was loaded into the same register prior to the OP_VFilter, but |
+ ** the xFilter implementation might have changed the datatype or |
+ ** encoding of the value in the register, so it *must* be reloaded. */ |
+ assert( pLevel->u.in.aInLoop!=0 || db->mallocFailed ); |
+ if( !db->mallocFailed ){ |
+ assert( iIn>0 ); |
+ pOp = sqlite3VdbeGetOp(v, pLevel->u.in.aInLoop[--iIn].addrInTop); |
+ assert( pOp->opcode==OP_Column || pOp->opcode==OP_Rowid ); |
+ assert( pOp->opcode!=OP_Column || pOp->p3==iReg+j+2 ); |
+ assert( pOp->opcode!=OP_Rowid || pOp->p2==iReg+j+2 ); |
+ testcase( pOp->opcode==OP_Rowid ); |
+ sqlite3VdbeAddOp3(v, pOp->opcode, pOp->p1, pOp->p2, pOp->p3); |
+ } |
+ |
+ /* Generate code that will continue to the next row if |
+ ** the IN constraint is not satisfied */ |
+ pCompare = sqlite3PExpr(pParse, TK_EQ, 0, 0); |
+ assert( pCompare!=0 || db->mallocFailed ); |
+ if( pCompare ){ |
+ pCompare->pLeft = pTerm->pExpr->pLeft; |
+ pCompare->pRight = pRight = sqlite3Expr(db, TK_REGISTER, 0); |
+ if( pRight ){ |
+ pRight->iTable = iReg+j+2; |
+ sqlite3ExprIfFalse(pParse, pCompare, pLevel->addrCont, 0); |
+ } |
+ pCompare->pLeft = 0; |
+ sqlite3ExprDelete(db, pCompare); |
+ } |
+ } |
+ } |
+ /* These registers need to be preserved in case there is an IN operator |
+ ** loop. So we could deallocate the registers here (and potentially |
+ ** reuse them later) if (pLoop->wsFlags & WHERE_IN_ABLE)==0. But it seems |
+ ** simpler and safer to simply not reuse the registers. |
+ ** |
+ ** sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2); |
+ */ |
sqlite3ExprCachePop(pParse); |
}else |
#endif /* SQLITE_OMIT_VIRTUALTABLE */ |
@@ -882,8 +1218,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( |
iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg); |
if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg); |
addrNxt = pLevel->addrNxt; |
- sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt); VdbeCoverage(v); |
- sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg); |
+ sqlite3VdbeAddOp3(v, OP_SeekRowid, iCur, addrNxt, iRowidReg); |
VdbeCoverage(v); |
sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1); |
sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); |
@@ -910,10 +1245,11 @@ Bitmask sqlite3WhereCodeOneLoopStart( |
pStart = pEnd; |
pEnd = pTerm; |
} |
- codeCursorHint(pWInfo, pLevel, pEnd); |
+ codeCursorHint(pTabItem, pWInfo, pLevel, pEnd); |
if( pStart ){ |
Expr *pX; /* The expression that defines the start bound */ |
int r1, rTemp; /* Registers for holding the start boundary */ |
+ int op; /* Cursor seek operation */ |
/* The following constant maps TK_xx codes into corresponding |
** seek opcodes. It depends on a particular ordering of TK_xx |
@@ -933,8 +1269,16 @@ Bitmask sqlite3WhereCodeOneLoopStart( |
pX = pStart->pExpr; |
assert( pX!=0 ); |
testcase( pStart->leftCursor!=iCur ); /* transitive constraints */ |
- r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp); |
- sqlite3VdbeAddOp3(v, aMoveOp[pX->op-TK_GT], iCur, addrBrk, r1); |
+ if( sqlite3ExprIsVector(pX->pRight) ){ |
+ r1 = rTemp = sqlite3GetTempReg(pParse); |
+ codeExprOrVector(pParse, pX->pRight, r1, 1); |
+ op = aMoveOp[(pX->op - TK_GT) | 0x0001]; |
+ }else{ |
+ r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp); |
+ disableTerm(pLevel, pStart); |
+ op = aMoveOp[(pX->op - TK_GT)]; |
+ } |
+ sqlite3VdbeAddOp3(v, op, iCur, addrBrk, r1); |
VdbeComment((v, "pk")); |
VdbeCoverageIf(v, pX->op==TK_GT); |
VdbeCoverageIf(v, pX->op==TK_LE); |
@@ -942,7 +1286,6 @@ Bitmask sqlite3WhereCodeOneLoopStart( |
VdbeCoverageIf(v, pX->op==TK_GE); |
sqlite3ExprCacheAffinityChange(pParse, r1, 1); |
sqlite3ReleaseTempReg(pParse, rTemp); |
- disableTerm(pLevel, pStart); |
}else{ |
sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrBrk); |
VdbeCoverageIf(v, bRev==0); |
@@ -956,13 +1299,17 @@ Bitmask sqlite3WhereCodeOneLoopStart( |
testcase( pEnd->leftCursor!=iCur ); /* Transitive constraints */ |
testcase( pEnd->wtFlags & TERM_VIRTUAL ); |
memEndValue = ++pParse->nMem; |
- sqlite3ExprCode(pParse, pX->pRight, memEndValue); |
- if( pX->op==TK_LT || pX->op==TK_GT ){ |
+ codeExprOrVector(pParse, pX->pRight, memEndValue, 1); |
+ if( 0==sqlite3ExprIsVector(pX->pRight) |
+ && (pX->op==TK_LT || pX->op==TK_GT) |
+ ){ |
testOp = bRev ? OP_Le : OP_Ge; |
}else{ |
testOp = bRev ? OP_Lt : OP_Gt; |
} |
- disableTerm(pLevel, pEnd); |
+ if( 0==sqlite3ExprIsVector(pX->pRight) ){ |
+ disableTerm(pLevel, pEnd); |
+ } |
} |
start = sqlite3VdbeCurrentAddr(v); |
pLevel->op = bRev ? OP_Prev : OP_Next; |
@@ -1029,6 +1376,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 */ |
@@ -1041,7 +1390,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( |
int nExtraReg = 0; /* Number of extra registers needed */ |
int op; /* Instruction opcode */ |
char *zStartAff; /* Affinity for start of range constraint */ |
- char cEndAff = 0; /* Affinity for end of range constraint */ |
+ char *zEndAff = 0; /* Affinity for end of range constraint */ |
u8 bSeekPastNull = 0; /* True to seek past initial nulls */ |
u8 bStopAtNull = 0; /* Add condition to terminate at NULLs */ |
@@ -1075,33 +1424,36 @@ 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 */ |
assert( pRangeStart->wtFlags & TERM_LIKEOPT ); /* occur in pairs */ |
- pLevel->iLikeRepCntr = ++pParse->nMem; |
- testcase( bRev ); |
- testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC ); |
- sqlite3VdbeAddOp2(v, OP_Integer, |
- bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC), |
- pLevel->iLikeRepCntr); |
+ pLevel->iLikeRepCntr = (u32)++pParse->nMem; |
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, (int)pLevel->iLikeRepCntr); |
VdbeComment((v, "LIKE loop counter")); |
pLevel->addrLikeRep = sqlite3VdbeCurrentAddr(v); |
+ /* iLikeRepCntr actually stores 2x the counter register number. The |
+ ** bottom bit indicates whether the search order is ASC or DESC. */ |
+ testcase( bRev ); |
+ testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC ); |
+ assert( (bRev & ~1)==0 ); |
+ pLevel->iLikeRepCntr <<=1; |
+ pLevel->iLikeRepCntr |= bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC); |
} |
#endif |
- if( pRangeStart==0 |
- && (j = pIdx->aiColumn[nEq])>=0 |
- && pIdx->pTable->aCol[j].notNull==0 |
- ){ |
- bSeekPastNull = 1; |
+ if( pRangeStart==0 ){ |
+ j = pIdx->aiColumn[nEq]; |
+ if( (j>=0 && pIdx->pTable->aCol[j].notNull==0) || j==XN_EXPR ){ |
+ bSeekPastNull = 1; |
+ } |
} |
} |
assert( pRangeEnd==0 || (pRangeEnd->wtFlags & TERM_VNULL)==0 ); |
@@ -1115,16 +1467,19 @@ Bitmask sqlite3WhereCodeOneLoopStart( |
){ |
SWAP(WhereTerm *, pRangeEnd, pRangeStart); |
SWAP(u8, bSeekPastNull, bStopAtNull); |
+ SWAP(u8, nBtm, nTop); |
} |
/* Generate code to evaluate all constraint terms using == or IN |
** and store the values of those terms in an array of registers |
** starting at regBase. |
*/ |
- codeCursorHint(pWInfo, pLevel, pRangeEnd); |
+ codeCursorHint(pTabItem, pWInfo, pLevel, pRangeEnd); |
regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff); |
assert( zStartAff==0 || sqlite3Strlen30(zStartAff)>=nEq ); |
- if( zStartAff ) cEndAff = zStartAff[nEq]; |
+ if( zStartAff && nTop ){ |
+ zEndAff = sqlite3DbStrDup(db, &zStartAff[nEq]); |
+ } |
addrNxt = pLevel->addrNxt; |
testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 ); |
@@ -1139,7 +1494,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) |
@@ -1148,18 +1503,16 @@ Bitmask sqlite3WhereCodeOneLoopStart( |
VdbeCoverage(v); |
} |
if( zStartAff ){ |
- if( sqlite3CompareAffinity(pRight, zStartAff[nEq])==SQLITE_AFF_BLOB){ |
- /* Since the comparison is to be performed with no conversions |
- ** applied to the operands, set the affinity to apply to pRight to |
- ** SQLITE_AFF_BLOB. */ |
- zStartAff[nEq] = SQLITE_AFF_BLOB; |
- } |
- if( sqlite3ExprNeedsNoAffinityChange(pRight, zStartAff[nEq]) ){ |
- zStartAff[nEq] = SQLITE_AFF_BLOB; |
- } |
+ updateRangeAffinityStr(pRight, nBtm, &zStartAff[nEq]); |
} |
- nConstraint++; |
+ nConstraint += nBtm; |
testcase( pRangeStart->wtFlags & TERM_VIRTUAL ); |
+ if( sqlite3ExprIsVector(pRight)==0 ){ |
+ disableTerm(pLevel, pRangeStart); |
+ }else{ |
+ startEq = 1; |
+ } |
+ bSeekPastNull = 0; |
}else if( bSeekPastNull ){ |
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); |
nConstraint++; |
@@ -1167,16 +1520,22 @@ Bitmask sqlite3WhereCodeOneLoopStart( |
start_constraints = 1; |
} |
codeApplyAffinity(pParse, regBase, nConstraint - bSeekPastNull, zStartAff); |
- op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev]; |
- assert( op!=0 ); |
- sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); |
- VdbeCoverage(v); |
- VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind ); |
- VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last ); |
- VdbeCoverageIf(v, op==OP_SeekGT); testcase( op==OP_SeekGT ); |
- VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE ); |
- VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE ); |
- VdbeCoverageIf(v, op==OP_SeekLT); testcase( op==OP_SeekLT ); |
+ if( pLoop->nSkip>0 && nConstraint==pLoop->nSkip ){ |
+ /* The skip-scan logic inside the call to codeAllEqualityConstraints() |
+ ** above has already left the cursor sitting on the correct row, |
+ ** so no further seeking is needed */ |
+ }else{ |
+ op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev]; |
+ assert( op!=0 ); |
+ sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); |
+ VdbeCoverage(v); |
+ VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind ); |
+ VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last ); |
+ VdbeCoverageIf(v, op==OP_SeekGT); testcase( op==OP_SeekGT ); |
+ VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE ); |
+ VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE ); |
+ VdbeCoverageIf(v, op==OP_SeekLT); testcase( op==OP_SeekLT ); |
+ } |
/* Load the value for the inequality constraint at the end of the |
** range (if any). |
@@ -1185,7 +1544,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) |
@@ -1193,19 +1552,27 @@ Bitmask sqlite3WhereCodeOneLoopStart( |
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); |
VdbeCoverage(v); |
} |
- if( sqlite3CompareAffinity(pRight, cEndAff)!=SQLITE_AFF_BLOB |
- && !sqlite3ExprNeedsNoAffinityChange(pRight, cEndAff) |
- ){ |
- codeApplyAffinity(pParse, regBase+nEq, 1, &cEndAff); |
+ if( zEndAff ){ |
+ updateRangeAffinityStr(pRight, nTop, zEndAff); |
+ codeApplyAffinity(pParse, regBase+nEq, nTop, zEndAff); |
+ }else{ |
+ assert( pParse->db->mallocFailed ); |
} |
- nConstraint++; |
+ nConstraint += nTop; |
testcase( pRangeEnd->wtFlags & TERM_VIRTUAL ); |
+ |
+ if( sqlite3ExprIsVector(pRight)==0 ){ |
+ disableTerm(pLevel, pRangeEnd); |
+ }else{ |
+ endEq = 1; |
+ } |
}else if( bStopAtNull ){ |
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); |
endEq = 0; |
nConstraint++; |
} |
sqlite3DbFree(db, zStartAff); |
+ sqlite3DbFree(db, zEndAff); |
/* Top of the loop body */ |
pLevel->p2 = sqlite3VdbeCurrentAddr(v); |
@@ -1221,19 +1588,20 @@ Bitmask sqlite3WhereCodeOneLoopStart( |
} |
/* 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) ){ |
- iRowidReg = ++pParse->nMem; |
- sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg); |
- sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); |
- if( pWInfo->eOnePass!=ONEPASS_OFF ){ |
+ if( (pWInfo->wctrlFlags & WHERE_SEEK_TABLE) || ( |
+ (pWInfo->wctrlFlags & WHERE_SEEK_UNIQ_TABLE) |
+ && (pWInfo->eOnePass==ONEPASS_SINGLE) |
+ )){ |
+ iRowidReg = ++pParse->nMem; |
+ sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg); |
+ sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); |
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowidReg); |
VdbeCoverage(v); |
}else{ |
- sqlite3VdbeAddOp2(v, OP_Seek, iCur, iRowidReg); /* Deferred seek */ |
+ codeDeferredSeek(pWInfo, pIdx, iCur, iIdxCur); |
} |
}else if( iCur!=iIdxCur ){ |
Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable); |
@@ -1246,9 +1614,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 ){ |
@@ -1325,7 +1691,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( |
u16 wctrlFlags; /* Flags for sub-WHERE clause */ |
Expr *pAndExpr = 0; /* An ".. AND (...)" expression */ |
Table *pTab = pTabItem->pTab; |
- |
+ |
pTerm = pLoop->aLTerm[0]; |
assert( pTerm!=0 ); |
assert( pTerm->eOperator & WO_OR ); |
@@ -1402,14 +1768,16 @@ Bitmask sqlite3WhereCodeOneLoopStart( |
Expr *pExpr = pWC->a[iTerm].pExpr; |
if( &pWC->a[iTerm] == pTerm ) continue; |
if( ExprHasProperty(pExpr, EP_FromJoin) ) continue; |
- if( (pWC->a[iTerm].wtFlags & TERM_VIRTUAL)!=0 ) continue; |
+ testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL ); |
+ testcase( pWC->a[iTerm].wtFlags & TERM_CODED ); |
+ if( (pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_CODED))!=0 ) continue; |
if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue; |
testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO ); |
pExpr = sqlite3ExprDup(db, pExpr, 0); |
pAndExpr = sqlite3ExprAnd(db, pAndExpr, pExpr); |
} |
if( pAndExpr ){ |
- pAndExpr = sqlite3PExpr(pParse, TK_AND|TKFLG_DONTFOLD, 0, pAndExpr, 0); |
+ pAndExpr = sqlite3PExpr(pParse, TK_AND|TKFLG_DONTFOLD, 0, pAndExpr); |
} |
} |
@@ -1417,10 +1785,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( |
** eliminating duplicates from other WHERE clauses, the action for each |
** sub-WHERE clause is to to invoke the main loop body as a subroutine. |
*/ |
- wctrlFlags = WHERE_OMIT_OPEN_CLOSE |
- | WHERE_FORCE_TABLE |
- | WHERE_ONETABLE_ONLY |
- | WHERE_NO_AUTOINDEX; |
+ wctrlFlags = WHERE_OR_SUBCLAUSE | (pWInfo->wctrlFlags & WHERE_SEEK_TABLE); |
for(ii=0; ii<pOrWc->nTerm; ii++){ |
WhereTerm *pOrTerm = &pOrWc->a[ii]; |
if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){ |
@@ -1485,7 +1850,8 @@ Bitmask sqlite3WhereCodeOneLoopStart( |
} |
if( iSet>=0 ){ |
sqlite3VdbeAddOp3(v, OP_MakeRecord, r, nPk, regRowid); |
- sqlite3VdbeAddOp3(v, OP_IdxInsert, regRowset, regRowid, 0); |
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, regRowset, regRowid, |
+ r, nPk); |
if( iSet ) sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); |
} |
@@ -1528,7 +1894,6 @@ Bitmask sqlite3WhereCodeOneLoopStart( |
){ |
assert( pSubWInfo->a[0].iIdxCur==iCovCur ); |
pCov = pSubLoop->u.btree.pIndex; |
- wctrlFlags |= WHERE_REOPEN_IDX; |
}else{ |
pCov = 0; |
} |
@@ -1565,7 +1930,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( |
** a pseudo-cursor. No need to Rewind or Next such cursors. */ |
pLevel->op = OP_Noop; |
}else{ |
- codeCursorHint(pWInfo, pLevel, 0); |
+ codeCursorHint(pTabItem, pWInfo, pLevel, 0); |
pLevel->op = aStep[bRev]; |
pLevel->p1 = iCur; |
pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk); |
@@ -1590,7 +1955,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( |
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; |
if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ |
testcase( pWInfo->untestedTerms==0 |
- && (pWInfo->wctrlFlags & WHERE_ONETABLE_ONLY)!=0 ); |
+ && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ); |
pWInfo->untestedTerms = 1; |
continue; |
} |
@@ -1600,11 +1965,17 @@ Bitmask sqlite3WhereCodeOneLoopStart( |
continue; |
} |
if( pTerm->wtFlags & TERM_LIKECOND ){ |
+ /* If the TERM_LIKECOND flag is set, that means that the range search |
+ ** is sufficient to guarantee that the LIKE operator is true, so we |
+ ** can skip the call to the like(A,B) function. But this only works |
+ ** for strings. So do not skip the call to the function on the pass |
+ ** that compares BLOBs. */ |
#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS |
continue; |
#else |
- assert( pLevel->iLikeRepCntr>0 ); |
- skipLikeAddr = sqlite3VdbeAddOp1(v, OP_IfNot, pLevel->iLikeRepCntr); |
+ u32 x = pLevel->iLikeRepCntr; |
+ assert( x>0 ); |
+ skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)? OP_IfNot : OP_If, (int)(x>>1)); |
VdbeCoverage(v); |
#endif |
} |
@@ -1622,7 +1993,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( |
** the implied "t1.a=123" constraint. |
*/ |
for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ |
- Expr *pE, *pEAlt; |
+ Expr *pE, sEAlt; |
WhereTerm *pAlt; |
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; |
if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue; |
@@ -1640,13 +2011,9 @@ Bitmask sqlite3WhereCodeOneLoopStart( |
testcase( pAlt->eOperator & WO_IS ); |
testcase( pAlt->eOperator & WO_IN ); |
VdbeModuleComment((v, "begin transitive constraint")); |
- pEAlt = sqlite3StackAllocRaw(db, sizeof(*pEAlt)); |
- if( pEAlt ){ |
- *pEAlt = *pAlt->pExpr; |
- pEAlt->pLeft = pE->pLeft; |
- sqlite3ExprIfFalse(pParse, pEAlt, addrCont, SQLITE_JUMPIFNULL); |
- sqlite3StackFree(db, pEAlt); |
- } |
+ sEAlt = *pAlt->pExpr; |
+ sEAlt.pLeft = pE->pLeft; |
+ sqlite3ExprIfFalse(pParse, &sEAlt, addrCont, SQLITE_JUMPIFNULL); |
} |
/* For a LEFT OUTER JOIN, generate code that will record the fact that |