| 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
|
|
|