]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Refactoring of the query optimizer in advance of adding better optimization. (CVS...
authordrh <drh@noemail.net>
Tue, 19 Jul 2005 17:38:22 +0000 (17:38 +0000)
committerdrh <drh@noemail.net>
Tue, 19 Jul 2005 17:38:22 +0000 (17:38 +0000)
FossilOrigin-Name: 57c6bd3760163c174be4a2ece58f414e82b55938

manifest
manifest.uuid
src/sqliteInt.h
src/where.c

index 7fd4c71e6cd3cb8a6183cf5db4eb201dd266f9a6..388983af7bd78ba81ff0c28ce58c3f0be232fae1 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Allow\san\sunlimited\snumber\sof\sterms\sin\sthe\sWHERE\sclause.\s\sThe\sold\slimit\swas\s100.\s(CVS\s2550)
-D 2005-07-16T13:33:21
+C Refactoring\sof\sthe\squery\soptimizer\sin\sadvance\sof\sadding\sbetter\soptimization.\s(CVS\s2551)
+D 2005-07-19T17:38:23
 F Makefile.in 22ea9c0fe748f591712d8fe3c6d972c6c173a165
 F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -64,7 +64,7 @@ F src/random.c 90adff4e73a3b249eb4f1fc2a6ff9cf78c7233a4
 F src/select.c c611471052773b94af771693686bd5bcdbbb0dba
 F src/shell.c 25b3217d7c64e6497225439d261a253a23efff26
 F src/sqlite.h.in 838382ed6b48d392366a55e07f49d9d71263e1fe
-F src/sqliteInt.h af65e8fac1fe8f6f78a65551081bafd49f6e0650
+F src/sqliteInt.h 97d50f5714a5f5a8190b871305e33a96c4638a8a
 F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9
 F src/tclsqlite.c cccaf6b78c290d824cf8ea089b8b27377e545830
 F src/test1.c 1dea8df4abb846cb3a2ce8a6e13d8b32dbd31b16
@@ -85,7 +85,7 @@ F src/vdbeapi.c 7f392f0792d1258c958083d7de9eae7c3530c9a6
 F src/vdbeaux.c 3732a86566a6be4da4c606e9334baf3fd98667af
 F src/vdbefifo.c b8805850afe13b43f1de78d58088cb5d66f88e1e
 F src/vdbemem.c da8e8d6f29dd1323f782f000d7cd120027c9ff03
-F src/where.c 9b02e75ef86f057cee5e93150b10cbc1092d7de6
+F src/where.c 1da2268f5e37257276dff46ebbc1cc596a9efaa1
 F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42
 F test/all.test 7f0988442ab811dfa41793b5b550f5828ce316f3
 F test/alter.test 9d6837a3d946b73df692b7cef2a7644d2e2f6bc6
@@ -286,7 +286,7 @@ F www/tclsqlite.tcl 425be741b8ae664f55cb1ef2371aab0a75109cf9
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
 F www/whentouse.tcl 528299b8316726dbcc5548e9aa0648c8b1bd055b
-P 578490c91331a386f84652db0b3bfd74c82046e1
-R 544e009ea316e2cccd816cc597a10aab
+P ca69f36832d57775e73ac5cdbe0a32d7b759432b
+R 9a4258be8ecf1889fef260cdd1d2d34b
 U drh
-Z 0b48c3e07c6ac902e7fb79f1e0cbf3a1
+Z a631f1b7791a9c3a4f6bac427d47518f
index 694044a09539bdb02a7081390fae1388746c0e82..872d65ac524a73e74ed06a26493a36275c7fb6b6 100644 (file)
@@ -1 +1 @@
-ca69f36832d57775e73ac5cdbe0a32d7b759432b
\ No newline at end of file
+57c6bd3760163c174be4a2ece58f414e82b55938
\ No newline at end of file
index a7a6cd2354afa6471d6e8ea5f14a3331be4b5716..7af55d5b97aed900f2ad9fa3dc15bf2b6af7aaa6 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.393 2005/07/09 02:16:03 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.394 2005/07/19 17:38:23 drh Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -845,7 +845,6 @@ struct Expr {
 #define EP_Error        0x08  /* Expression contains one or more errors */
 #define EP_Not          0x10  /* Operator preceeded by NOT */
 #define EP_VarSelect    0x20  /* pSelect is correlated, not constant */
-#define EP_OptOnly      0x40  /* A constraint used by the optimizer only */
 
 /*
 ** These macros can be used to test, set, or clear bits in the 
index b30a70ae9a3292ac48c52bf625af0cf445caee4c..d9cf7c07635bbcd88c28de6a30847b3cbe901a28 100644 (file)
@@ -16,7 +16,7 @@
 ** so is applicable.  Because this module is responsible for selecting
 ** indices, you might also think of this module as the "query optimizer".
 **
-** $Id: where.c,v 1.145 2005/07/16 13:33:21 drh Exp $
+** $Id: where.c,v 1.146 2005/07/19 17:38:23 drh Exp $
 */
 #include "sqliteInt.h"
 
 */
 #define ARRAYSIZE(X)  (sizeof(X)/sizeof(X[0]))
 
+/* Forward reference
+*/
+typedef struct WhereClause WhereClause;
 
 /*
 ** The query generator uses an array of instances of this structure to
 ** help it analyze the subexpressions of the WHERE clause.  Each WHERE
 ** clause subexpression is separated from the others by an AND operator.
 **
-** The idxLeft and idxRight fields are the VDBE cursor numbers for the
-** table that contains the column that appears on the left-hand and
-** right-hand side of WhereTerm.p.  If either side of WhereTerm.p is
-** something other than a simple column reference, then idxLeft or
-** idxRight are -1.  
+** All WhereTerms are collected into a single WhereClause structure.  
+** The following identity holds:
+**
+**        WhereTerm.pWC->a[WhereTerm.idx] == WhereTerm
+**
+** When a term is of the form:
 **
-** It is the VDBE cursor number is the value stored in Expr.iTable
-** when Expr.op==TK_COLUMN and the value stored in SrcList.a[].iCursor.
+**              X <op> <expr>
 **
-** prereqLeft, prereqRight, and prereqAll record sets of cursor numbers,
+** where X is a column name and <op> is one of certain operators,
+** then WhereTerm.leftCursor and WhereTerm.leftColumn record the
+** cursor number and column number for X.  
+**
+** prereqRight and prereqAll record sets of cursor numbers,
 ** but they do so indirectly.  A single ExprMaskSet structure translates
 ** cursor number into bits and the translated bit is stored in the prereq
 ** fields.  The translation is used in order to maximize the number of
 ** beginning with 0 in order to make the best possible use of the available
 ** bits in the Bitmask.  So, in the example above, the cursor numbers
 ** would be mapped into integers 0 through 7.
-**
-** prereqLeft tells us every VDBE cursor that is referenced on the
-** left-hand side of WhereTerm.p.  prereqRight does the same for the
-** right-hand side of the expression.  The following identity always
-** holds:
-**
-**       prereqAll = prereqLeft | prereqRight
-**
-** The WhereTerm.indexable field is true if the WhereTerm.p expression
-** is of a form that might control an index.  Indexable expressions
-** look like this:
-**
-**              <column> <op> <expr>
-**
-** Where <column> is a simple column name and <op> is on of the operators
-** that allowedOp() recognizes.  
 */
 typedef struct WhereTerm WhereTerm;
 struct WhereTerm {
-  Expr *p;                /* Pointer to the subexpression */
+  Expr *pExpr;            /* Pointer to the subexpression */
+  u16 idx;                /* Index of this term in pWC->a[] */
+  i16 iPartner;           /* Disable pWC->a[iPartner] when this term disabled */
   u16 flags;              /* Bit flags.  See below */
-  u8 indexable;           /* True if this subexprssion is usable by an index */
-  short int idxLeft;      /* p->pLeft is a column in this table number. -1 if
-                          ** p->pLeft is not a column of any table */
-  short int idxRight;     /* p->pRight is a column in this table number. -1 if
-                          ** p->pRight is not a column of any table */
-  Bitmask prereqLeft;     /* Bitmask of tables referenced by p->pLeft */
-  Bitmask prereqRight;    /* Bitmask of tables referenced by p->pRight */
+  i16 leftCursor;         /* Cursor number of X in "X <op> <expr>" */
+  i16 leftColumn;         /* Column number of X in "X <op> <expr>" */
+  WhereClause *pWC;       /* The clause this term is part of */
+  Bitmask prereqRight;    /* Bitmask of tables used by pRight */
   Bitmask prereqAll;      /* Bitmask of tables referenced by p */
 };
 
@@ -92,12 +82,12 @@ struct WhereTerm {
 */
 #define TERM_DYNAMIC    0x0001   /* Need to call sqlite3ExprDelete(p) */
 #define TERM_VIRTUAL    0x0002   /* Added by the optimizer.  Do not code */
+#define TERM_CODED      0x0004   /* This term is already coded */
 
 /*
 ** An instance of the following structure holds all information about a
 ** WHERE clause.  Mostly this is a container for one or more WhereTerms.
 */
-typedef struct WhereClause WhereClause;
 struct WhereClause {
   int nTerm;               /* Number of terms */
   int nSlot;               /* Number of entries in a[] */
@@ -156,7 +146,7 @@ static void whereClauseClear(WhereClause *pWC){
   WhereTerm *a;
   for(i=pWC->nTerm-1, a=pWC->a; i>=0; i--, a++){
     if( a->flags & TERM_DYNAMIC ){
-      sqlite3ExprDelete(a->p);
+      sqlite3ExprDelete(a->pExpr);
     }
   }
   if( pWC->a!=pWC->aStatic ){
@@ -168,21 +158,26 @@ static void whereClauseClear(WhereClause *pWC){
 ** Add a new entries to the WhereClause structure.  Increase the allocated
 ** space as necessary.
 */
-static void whereClauseInsert(WhereClause *pWC, Expr *p, int flags){
+static WhereTerm *whereClauseInsert(WhereClause *pWC, Expr *p, int flags){
   WhereTerm *pTerm;
   if( pWC->nTerm>=pWC->nSlot ){
     WhereTerm *pOld = pWC->a;
     pWC->a = sqliteMalloc( sizeof(pWC->a[0])*pWC->nSlot*2 );
-    if( pWC->a==0 ) return;
+    if( pWC->a==0 ) return 0;
     memcpy(pWC->a, pOld, sizeof(pWC->a[0])*pWC->nTerm);
     if( pOld!=pWC->aStatic ){
       sqliteFree(pOld);
     }
     pWC->nSlot *= 2;
   }
-  pTerm = &pWC->a[pWC->nTerm++];
-  pTerm->p = p;
+  pTerm = &pWC->a[pWC->nTerm];
+  pTerm->idx = pWC->nTerm;
+  pWC->nTerm++;
+  pTerm->pExpr = p;
   pTerm->flags = flags;
+  pTerm->pWC = pWC;
+  pTerm->iPartner = -1;
+  return pTerm;
 }
 
 /*
@@ -233,11 +228,15 @@ static Bitmask getMask(ExprMaskSet *pMaskSet, int iCursor){
 
 /*
 ** Create a new mask for cursor iCursor.
+**
+** There is one cursor per table in the FROM clause.  The number of
+** tables in the FROM clause is limited by a test early in the
+** sqlite3WhereBegin() routien.  So we know that the pMaskSet->ix[]
+** array will never overflow.
 */
 static void createMask(ExprMaskSet *pMaskSet, int iCursor){
-  if( pMaskSet->n<ARRAYSIZE(pMaskSet->ix) ){
-    pMaskSet->ix[pMaskSet->n++] = iCursor;
-  }
+  assert( pMaskSet->n < ARRAYSIZE(pMaskSet->ix) );
+  pMaskSet->ix[pMaskSet->n++] = iCursor;
 }
 
 /*
@@ -305,21 +304,28 @@ static int allowedOp(int op){
 #define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;}
 
 /*
-** Return the index in the SrcList that uses cursor iCur.  If iCur is
-** used by the first entry in SrcList return 0.  If iCur is used by
-** the second entry return 1.  And so forth.
-**
-** SrcList is the set of tables in the FROM clause in the order that
-** they will be processed.  The value returned here gives us an index
-** of which tables will be processed first.
+** Commute a comparision operator.  Expressions of the form "X op Y"
+** are converted into "Y op X".
 */
-static int tableOrder(SrcList *pList, int iCur){
-  int i;
-  struct SrcList_item *pItem;
-  for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
-    if( pItem->iCursor==iCur ) return i;
+static void exprCommute(Expr *pExpr){
+  assert(
+     pExpr->op==TK_EQ ||
+     pExpr->op==TK_NE ||
+     pExpr->op==TK_LT ||
+     pExpr->op==TK_LE ||
+     pExpr->op==TK_GT ||
+     pExpr->op==TK_GE
+  );
+  SWAP(CollSeq*,pExpr->pRight->pColl,pExpr->pLeft->pColl);
+  SWAP(Expr*,pExpr->pRight,pExpr->pLeft);
+  if( pExpr->op>=TK_GT ){
+    assert( TK_LT==TK_GT+2 );
+    assert( TK_GE==TK_LE+2 );
+    assert( TK_GT>TK_EQ );
+    assert( TK_GT<TK_LE );
+    assert( pExpr->op>=TK_GT && pExpr->op<=TK_GE );
+    pExpr->op = ((pExpr->op-TK_GT)^2)+TK_GT;
   }
-  return -1;
 }
 
 /*
@@ -328,53 +334,52 @@ static int tableOrder(SrcList *pList, int iCur){
 ** subexpression and populate all the other fields of the WhereTerm
 ** structure.
 */
-static void exprAnalyze(SrcList *pSrc, ExprMaskSet *pMaskSet, WhereTerm *pInfo){
-  Expr *pExpr = pInfo->p;
-  pInfo->prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
-  pInfo->prereqRight = exprTableUsage(pMaskSet, pExpr->pRight);
-  pInfo->prereqAll = exprTableUsage(pMaskSet, pExpr);
-  pInfo->indexable = 0;
-  pInfo->idxLeft = -1;
-  pInfo->idxRight = -1;
-  if( allowedOp(pExpr->op) && (pInfo->prereqRight & pInfo->prereqLeft)==0 ){
-    if( pExpr->pRight && pExpr->pRight->op==TK_COLUMN ){
-      pInfo->idxRight = pExpr->pRight->iTable;
-      pInfo->indexable = 1;
-    }
-    if( pExpr->pLeft->op==TK_COLUMN ){
-      pInfo->idxLeft = pExpr->pLeft->iTable;
-      pInfo->indexable = 1;
+static void exprAnalyze(
+  SrcList *pSrc,            /* the FROM clause */
+  ExprMaskSet *pMaskSet,    /* table masks */
+  WhereTerm *pTerm          /* the WHERE clause term to be analyzed */
+){
+  Expr *pExpr = pTerm->pExpr;
+  Bitmask prereqLeft;
+  Bitmask prereqAll;
+  int idxRight;
+
+  prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
+  pTerm->prereqRight = exprTableUsage(pMaskSet, pExpr->pRight);
+  pTerm->prereqAll = prereqAll = exprTableUsage(pMaskSet, pExpr);
+  pTerm->leftCursor = -1;
+  pTerm->iPartner = -1;
+  idxRight = -1;
+  if( allowedOp(pExpr->op) && (pTerm->prereqRight & prereqLeft)==0 ){
+    Expr *pLeft = pExpr->pLeft;
+    Expr *pRight = pExpr->pRight;
+    if( pLeft->op==TK_COLUMN ){
+      pTerm->leftCursor = pLeft->iTable;
+      pTerm->leftColumn = pLeft->iColumn;
     }
-  }
-  if( pInfo->indexable ){
-    assert( pInfo->idxLeft!=pInfo->idxRight );
-
-    /* We want the expression to be of the form "X = expr", not "expr = X".
-    ** So flip it over if necessary.  If the expression is "X = Y", then
-    ** we want Y to come from an earlier table than X.
-    **
-    ** The collating sequence rule is to always choose the left expression.
-    ** So if we do a flip, we also have to move the collating sequence.
-    */
-    if( tableOrder(pSrc,pInfo->idxLeft)<tableOrder(pSrc,pInfo->idxRight) ){
-      assert( pExpr->op!=TK_IN );
-      SWAP(CollSeq*,pExpr->pRight->pColl,pExpr->pLeft->pColl);
-      SWAP(Expr*,pExpr->pRight,pExpr->pLeft);
-      if( pExpr->op>=TK_GT ){
-        assert( TK_LT==TK_GT+2 );
-        assert( TK_GE==TK_LE+2 );
-        assert( TK_GT>TK_EQ );
-        assert( TK_GT<TK_LE );
-        assert( pExpr->op>=TK_GT && pExpr->op<=TK_GE );
-        pExpr->op = ((pExpr->op-TK_GT)^2)+TK_GT;
+    if( pRight && pRight->op==TK_COLUMN ){
+      WhereTerm *pNew;
+      Expr *pDup;
+      if( pTerm->leftCursor>=0 ){
+        pDup = sqlite3ExprDup(pExpr);
+        pNew = whereClauseInsert(pTerm->pWC, pDup, TERM_VIRTUAL|TERM_DYNAMIC);
+        if( pNew==0 ) return;
+        pNew->iPartner = pTerm->idx;
+      }else{
+        pDup = pExpr;
+        pNew = pTerm;
       }
-      SWAP(unsigned, pInfo->prereqLeft, pInfo->prereqRight);
-      SWAP(short int, pInfo->idxLeft, pInfo->idxRight);
+      exprCommute(pDup);
+      pLeft = pDup->pLeft;
+      pNew->leftCursor = pLeft->iTable;
+      pNew->leftColumn = pLeft->iColumn;
+      pNew->prereqRight = prereqLeft;
+      pNew->prereqAll = prereqAll;
     }
-  }      
-
+  }
 }
 
+
 /*
 ** This routine decides if pIdx can be used to satisfy the ORDER BY
 ** clause.  If it can, it returns 1.  If pIdx cannot satisfy the
@@ -515,10 +520,15 @@ static int sortableByRowid(
 ** too much.  If we disabled in (1), we'd get the wrong answer.
 ** See ticket #813.
 */
-static void disableTerm(WhereLevel *pLevel, Expr **ppExpr){
-  Expr *pExpr = *ppExpr;
-  if( pLevel->iLeftJoin==0 || ExprHasProperty(pExpr, EP_FromJoin) ){
-    *ppExpr = 0;
+static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
+  if( pTerm
+      && (pTerm->flags & TERM_CODED)==0
+      && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
+  ){
+    pTerm->flags |= TERM_CODED;
+    if( pTerm->iPartner>=0 ){
+      disableTerm(pLevel, &pTerm->pWC->a[pTerm->iPartner]);
+    }
   }
 }
 
@@ -551,7 +561,7 @@ static void codeEqualityTerm(
   int brk,            /* Jump here to abandon the loop */
   WhereLevel *pLevel  /* When level of the FROM clause we are working on */
 ){
-  Expr *pX = pTerm->p;
+  Expr *pX = pTerm->pExpr;
   if( pX->op!=TK_IN ){
     assert( pX->op==TK_EQ );
     sqlite3ExprCode(pParse, pX->pRight);
@@ -569,7 +579,7 @@ static void codeEqualityTerm(
     pLevel->inP1 = iTab;
 #endif
   }
-  disableTerm(pLevel, &pTerm->p);
+  disableTerm(pLevel, pTerm);
 }
 
 #ifdef SQLITE_TEST
@@ -678,7 +688,7 @@ WhereInfo *sqlite3WhereBegin(
   WhereInfo *pWInfo;         /* Will become the return value of this function */
   Vdbe *v = pParse->pVdbe;   /* The virtual database engine */
   int brk, cont = 0;         /* Addresses used during code generation */
-  Bitmask loopMask;          /* One bit set for each outer loop */
+  Bitmask loopMask;          /* One bit cleared for each outer loop */
   WhereTerm *pTerm;          /* A single term in the WHERE clause */
   ExprMaskSet maskSet;       /* The expression mask set */
   int iDirectEq[BMS];        /* Term of the form ROWID==X for the N-th table */
@@ -732,8 +742,8 @@ WhereInfo *sqlite3WhereBegin(
   for(i=0; i<pTabList->nSrc; i++){
     createMask(&maskSet, pTabList->a[i].iCursor);
   }
-  for(pTerm=wc.a, i=0; i<wc.nTerm; i++, pTerm++){
-    exprAnalyze(pTabList, &maskSet, pTerm);
+  for(i=wc.nTerm-1; i>=0; i--){
+    exprAnalyze(pTabList, &maskSet, &wc.a[i]);
   }
 
   /* Figure out what index to use (if any) for each nested loop.
@@ -752,7 +762,7 @@ WhereInfo *sqlite3WhereBegin(
   ** first 32 tables are candidates for indices.  This is (again) due
   ** to the limit of 32 bits in an integer bitmask.
   */
-  loopMask = 0;
+  loopMask = ~(Bitmask)0;
   pTabItem = pTabList->a;
   pLevel = pWInfo->a;
   for(i=0; i<pTabList->nSrc && i<ARRAYSIZE(iDirectEq); i++,pTabItem++,pLevel++){
@@ -778,10 +788,9 @@ WhereInfo *sqlite3WhereBegin(
     iDirectLt[i] = -1;
     iDirectGt[i] = -1;
     for(pTerm=wc.a, j=0; j<wc.nTerm; j++, pTerm++){
-      Expr *pX = pTerm->p;
-      if( pTerm->idxLeft==iCur && pX->pLeft->iColumn<0
-            && (pTerm->prereqRight & loopMask)==pTerm->prereqRight ){
-        switch( pX->op ){
+      if( pTerm->leftCursor==iCur && pTerm->leftColumn<0
+            && (pTerm->prereqRight & loopMask)==0 ){
+        switch( pTerm->pExpr->op ){
           case TK_IN:
           case TK_EQ: iDirectEq[i] = j; break;
           case TK_LE:
@@ -798,7 +807,7 @@ WhereInfo *sqlite3WhereBegin(
     ** an index.  We will always use the ROWID over an index.
     */
     if( iDirectEq[i]>=0 ){
-      loopMask |= mask;
+      loopMask &= ~mask;
       pLevel->pIdx = 0;
       continue;
     }
@@ -849,7 +858,7 @@ WhereInfo *sqlite3WhereBegin(
         continue;  /* Ignore indices with too many columns to analyze */
       }
       for(pTerm=wc.a, j=0; j<wc.nTerm; j++, pTerm++){
-        Expr *pX = pTerm->p;
+        Expr *pX = pTerm->pExpr;
         CollSeq *pColl = sqlite3ExprCollSeq(pParse, pX->pLeft);
         if( !pColl && pX->pRight ){
           pColl = sqlite3ExprCollSeq(pParse, pX->pRight);
@@ -857,9 +866,8 @@ WhereInfo *sqlite3WhereBegin(
         if( !pColl ){
           pColl = pParse->db->pDfltColl;
         }
-        if( pTerm->idxLeft==iCur 
-             && (pTerm->prereqRight & loopMask)==pTerm->prereqRight ){
-          int iColumn = pX->pLeft->iColumn;
+        if( pTerm->leftCursor==iCur && (pTerm->prereqRight & loopMask)==0 ){
+          int iColumn = pTerm->leftColumn;
           int k;
           char idxaff = iColumn>=0 ? pIdx->pTable->aCol[iColumn].affinity : 0; 
           for(k=0; k<pIdx->nColumn; k++){
@@ -952,7 +960,7 @@ WhereInfo *sqlite3WhereBegin(
     pLevel->pIdx = pBestIdx;
     pLevel->score = bestScore;
     pLevel->bRev = bestRev;
-    loopMask |= mask;
+    loopMask &= ~mask;
     if( pBestIdx ){
       pLevel->iIdxCur = pParse->nTab++;
     }
@@ -1070,7 +1078,7 @@ WhereInfo *sqlite3WhereBegin(
 
   /* Generate the code to do the search
   */
-  loopMask = 0;
+  loopMask = ~(Bitmask)0;
   pLevel = pWInfo->a;
   pTabItem = pTabList->a;
   for(i=0; i<pTabList->nSrc; i++, pTabItem++, pLevel++){
@@ -1109,8 +1117,8 @@ WhereInfo *sqlite3WhereBegin(
       */
       assert( k<wc.nTerm );
       pTerm = &wc.a[k];
-      assert( pTerm->p!=0 );
-      assert( pTerm->idxLeft==iCur );
+      assert( pTerm->pExpr!=0 );
+      assert( pTerm->leftCursor==iCur );
       assert( omitTable==0 );
       brk = pLevel->brk = sqlite3VdbeMakeLabel(v);
       codeEqualityTerm(pParse, pTerm, brk, pLevel);
@@ -1132,14 +1140,15 @@ WhereInfo *sqlite3WhereBegin(
       ** generate code to evaluate expr and leave the result on the stack */
       for(j=0; j<nColumn; j++){
         for(pTerm=wc.a, k=0; k<wc.nTerm; k++, pTerm++){
-          Expr *pX = pTerm->p;
-          if( pX==0 ) continue;
-          if( pTerm->idxLeft==iCur
-             && (pTerm->prereqRight & loopMask)==pTerm->prereqRight 
-             && pX->pLeft->iColumn==pIdx->aiColumn[j]
+          Expr *pX = pTerm->pExpr;
+          assert( pX );
+          if( pTerm->leftCursor==iCur
+             && (pTerm->prereqRight & loopMask)==0
+             && pTerm->leftColumn==pIdx->aiColumn[j]
              && (pX->op==TK_EQ || pX->op==TK_IN)
           ){
-            char idxaff = pIdx->pTable->aCol[pX->pLeft->iColumn].affinity;
+            char idxaff = pIdx->pTable->aCol[pTerm->leftColumn].affinity;
+            assert( (pTerm->flags & TERM_CODED)==0 );
             if( sqlite3IndexAffinityOk(pX, idxaff) ){
               codeEqualityTerm(pParse, pTerm, brk, pLevel);
               break;
@@ -1198,14 +1207,14 @@ WhereInfo *sqlite3WhereBegin(
         k = iDirectGt[i];
         assert( k<wc.nTerm );
         pTerm = &wc.a[k];
-        pX = pTerm->p;
+        pX = pTerm->pExpr;
         assert( pX!=0 );
-        assert( pTerm->idxLeft==iCur );
+        assert( pTerm->leftCursor==iCur );
         sqlite3ExprCode(pParse, pX->pRight);
         sqlite3VdbeAddOp(v, OP_ForceInt, pX->op==TK_LE || pX->op==TK_GT, brk);
         sqlite3VdbeAddOp(v, bRev ? OP_MoveLt : OP_MoveGe, iCur, brk);
         VdbeComment((v, "pk"));
-        disableTerm(pLevel, &pTerm->p);
+        disableTerm(pLevel, pTerm);
       }else{
         sqlite3VdbeAddOp(v, bRev ? OP_Last : OP_Rewind, iCur, brk);
       }
@@ -1214,9 +1223,9 @@ WhereInfo *sqlite3WhereBegin(
         k = iDirectLt[i];
         assert( k<wc.nTerm );
         pTerm = &wc.a[k];
-        pX = pTerm->p;
+        pX = pTerm->pExpr;
         assert( pX!=0 );
-        assert( pTerm->idxLeft==iCur );
+        assert( pTerm->leftCursor==iCur );
         sqlite3ExprCode(pParse, pX->pRight);
         pLevel->iMem = pParse->nMem++;
         sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
@@ -1225,7 +1234,7 @@ WhereInfo *sqlite3WhereBegin(
         }else{
           testOp = bRev ? OP_Lt : OP_Gt;
         }
-        disableTerm(pLevel, &pTerm->p);
+        disableTerm(pLevel, pTerm);
       }
       start = sqlite3VdbeCurrentAddr(v);
       pLevel->op = bRev ? OP_Prev : OP_Next;
@@ -1280,18 +1289,19 @@ WhereInfo *sqlite3WhereBegin(
       for(j=0; j<nEqColumn; j++){
         int iIdxCol = pIdx->aiColumn[j];
         for(pTerm=wc.a, k=0; k<wc.nTerm; k++, pTerm++){
-          Expr *pX = pTerm->p;
-          if( pX==0 ) continue;
-          if( pTerm->idxLeft==iCur
-             && pX->op==TK_EQ
-             && (pTerm->prereqRight & loopMask)==pTerm->prereqRight 
-             && pX->pLeft->iColumn==iIdxCol
+          Expr *pX;
+          if( pTerm->leftCursor==iCur
+             && pTerm->leftColumn==iIdxCol
+             && (pX = pTerm->pExpr)->op==TK_EQ
+             && (pTerm->prereqRight & loopMask)==0
           ){
+            assert( (pTerm->flags & TERM_CODED)==0 );
             sqlite3ExprCode(pParse, pX->pRight);
-            disableTerm(pLevel, &pTerm->p);
+            disableTerm(pLevel, pTerm);
             break;
           }
         }
+        assert( k<wc.nTerm );
       }
 
       /* Duplicate the equality term values because they will all be
@@ -1316,19 +1326,21 @@ WhereInfo *sqlite3WhereBegin(
       */
       if( (score & 4)!=0 ){
         for(pTerm=wc.a, k=0; k<wc.nTerm; k++, pTerm++){
-          Expr *pX = pTerm->p;
-          if( pX==0 ) continue;
-          if( pTerm->idxLeft==iCur
+          Expr *pX = pTerm->pExpr;
+          assert( pX );
+          if( pTerm->leftCursor==iCur
              && (pX->op==TK_LT || pX->op==TK_LE)
-             && (pTerm->prereqRight & loopMask)==pTerm->prereqRight 
-             && pX->pLeft->iColumn==pIdx->aiColumn[j]
+             && (pTerm->prereqRight & loopMask)==0
+             && pTerm->leftColumn==pIdx->aiColumn[j]
           ){
+            assert( (pTerm->flags & TERM_CODED)==0 );
             sqlite3ExprCode(pParse, pX->pRight);
             leFlag = pX->op==TK_LE;
-            disableTerm(pLevel, &pTerm->p);
+            disableTerm(pLevel, pTerm);
             break;
           }
         }
+        assert( k<wc.nTerm );
         testOp = OP_IdxGE;
       }else{
         testOp = nEqColumn>0 ? OP_IdxGE : OP_Noop;
@@ -1359,16 +1371,17 @@ WhereInfo *sqlite3WhereBegin(
       */
       if( (score & 8)!=0 ){
         for(pTerm=wc.a, k=0; k<wc.nTerm; k++, pTerm++){
-          Expr *pX = pTerm->p;
-          if( pX==0 ) continue;
-          if( pTerm->idxLeft==iCur
+          Expr *pX = pTerm->pExpr;
+          assert( pX );
+          if( pTerm->leftCursor==iCur
              && (pX->op==TK_GT || pX->op==TK_GE)
-             && (pTerm->prereqRight & loopMask)==pTerm->prereqRight 
-             && pX->pLeft->iColumn==pIdx->aiColumn[j]
+             && (pTerm->prereqRight & loopMask)==0
+             && pTerm->leftColumn==pIdx->aiColumn[j]
           ){
+            assert( (pTerm->flags & TERM_CODED)==0 );
             sqlite3ExprCode(pParse, pX->pRight);
             geFlag = pX->op==TK_GE;
-            disableTerm(pLevel, &pTerm->p);
+            disableTerm(pLevel, pTerm);
             break;
           }
         }
@@ -1417,20 +1430,22 @@ WhereInfo *sqlite3WhereBegin(
       pLevel->p1 = iIdxCur;
       pLevel->p2 = start;
     }
-    loopMask |= getMask(&maskSet, iCur);
+    loopMask &= ~getMask(&maskSet, iCur);
 
     /* Insert code to test every subexpression that can be completely
     ** computed using the current set of tables.
     */
-    for(pTerm=wc.a, j=0; j<wc.nTerm; j++, pTerm++){
-      Expr *pE = pTerm->p;
-      if( pE==0 || ExprHasProperty(pE, EP_OptOnly) ) continue;
-      if( (pTerm->prereqAll & loopMask)!=pTerm->prereqAll ) continue;
+    for(pTerm=wc.a, j=wc.nTerm; j>0; j--, pTerm++){
+      Expr *pE;
+      if( pTerm->flags & (TERM_VIRTUAL|TERM_CODED) ) continue;
+      if( (pTerm->prereqAll & loopMask)!=0 ) continue;
+      pE = pTerm->pExpr;
+      assert( pE!=0 );
       if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
         continue;
       }
       sqlite3ExprIfFalse(pParse, pE, cont, 1);
-      pTerm->p = 0;
+      pTerm->flags |= TERM_CODED;
     }
     brk = cont;
 
@@ -1443,11 +1458,11 @@ WhereInfo *sqlite3WhereBegin(
       sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iLeftJoin, 1);
       VdbeComment((v, "# record LEFT JOIN hit"));
       for(pTerm=wc.a, j=0; j<wc.nTerm; j++, pTerm++){
-        Expr *pE = pTerm->p;
-        if( pE==0 || ExprHasProperty(pE, EP_OptOnly) ) continue;
-        if( (pTerm->prereqAll & loopMask)!=pTerm->prereqAll ) continue;
-        sqlite3ExprIfFalse(pParse, pE, cont, 1);
-        pTerm->p = 0;
+        if( pTerm->flags & (TERM_VIRTUAL|TERM_CODED) ) continue;
+        if( (pTerm->prereqAll & loopMask)!=0 ) continue;
+        assert( pTerm->pExpr );
+        sqlite3ExprIfFalse(pParse, pTerm->pExpr, cont, 1);
+        pTerm->flags |= TERM_CODED;
       }
     }
   }