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