mirror of
https://github.com/status-im/sqlcipher.git
synced 2026-09-01 15:01:08 +00:00
Snapshot of upstream SQLite 3.15.2
This commit is contained in:
+448
-132
@@ -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);
|
||||
sqlite3StrAccumAppend(pStr, zOp, 1);
|
||||
sqlite3StrAccumAppend(pStr, "?", 1);
|
||||
}
|
||||
int i;
|
||||
|
||||
/*
|
||||
** 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;
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -81,12 +100,11 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){
|
||||
|
||||
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))
|
||||
@@ -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
|
||||
@@ -332,16 +350,45 @@ static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** 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(
|
||||
@@ -356,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);
|
||||
@@ -364,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
|
||||
@@ -379,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;
|
||||
@@ -389,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);
|
||||
@@ -536,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);
|
||||
@@ -560,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
|
||||
@@ -587,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
|
||||
@@ -625,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
|
||||
@@ -677,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 */
|
||||
@@ -707,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
|
||||
@@ -741,7 +955,7 @@ static void codeCursorHint(
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define codeCursorHint(A,B,C) /* No-op */
|
||||
# define codeCursorHint(A,B,C,D) /* No-op */
|
||||
#endif /* SQLITE_ENABLE_CURSOR_HINTS */
|
||||
|
||||
/*
|
||||
@@ -775,7 +989,7 @@ static void codeDeferredSeek(
|
||||
assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 );
|
||||
|
||||
sqlite3VdbeAddOp3(v, OP_Seek, iIdxCur, 0, iCur);
|
||||
if( (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)
|
||||
if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)
|
||||
&& DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask)
|
||||
){
|
||||
int i;
|
||||
@@ -792,6 +1006,39 @@ static void codeDeferredSeek(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** 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.
|
||||
@@ -830,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
|
||||
@@ -874,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);
|
||||
@@ -881,12 +1129,13 @@ 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);
|
||||
@@ -896,15 +1145,57 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
pLoop->u.vtab.needFree ? P4_MPRINTF : 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, 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 */
|
||||
@@ -927,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);
|
||||
@@ -955,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
|
||||
@@ -978,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);
|
||||
@@ -987,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);
|
||||
@@ -1001,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;
|
||||
@@ -1074,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 */
|
||||
@@ -1086,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 */
|
||||
|
||||
@@ -1120,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 );
|
||||
@@ -1160,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 );
|
||||
@@ -1184,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)
|
||||
@@ -1193,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++;
|
||||
@@ -1212,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).
|
||||
@@ -1230,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)
|
||||
@@ -1238,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);
|
||||
@@ -1266,12 +1588,10 @@ 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) ){
|
||||
if( pWInfo->eOnePass!=ONEPASS_OFF ){
|
||||
if( (pWInfo->wctrlFlags & WHERE_SEEK_TABLE)!=0 ){
|
||||
iRowidReg = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
|
||||
sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
|
||||
@@ -1291,9 +1611,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 ){
|
||||
@@ -1370,7 +1688,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 );
|
||||
@@ -1464,10 +1782,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 ){
|
||||
@@ -1575,7 +1890,6 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
){
|
||||
assert( pSubWInfo->a[0].iIdxCur==iCovCur );
|
||||
pCov = pSubLoop->u.btree.pIndex;
|
||||
wctrlFlags |= WHERE_REOPEN_IDX;
|
||||
}else{
|
||||
pCov = 0;
|
||||
}
|
||||
@@ -1612,7 +1926,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);
|
||||
@@ -1637,7 +1951,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;
|
||||
}
|
||||
@@ -1647,11 +1961,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
|
||||
}
|
||||
@@ -1669,7 +1989,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;
|
||||
@@ -1687,13 +2007,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
|
||||
|
||||
Reference in New Issue
Block a user