Proof of concept for the ability to use the expression columns in an index
on expressions in place of equivalent expressions in the result set or in
the WHERE clause.  This check-in compiles but is mostly untested.

FossilOrigin-Name: a52ef2ad7c0e14b78b801f16a1f6ea8d8fa9ae5d7d810e18dd24c600b662a312
diff --git a/src/expr.c b/src/expr.c
index e3db597..afdbbb1 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -3192,6 +3192,10 @@
   int iCol,       /* Index of the column to extract */
   int regOut      /* Extract the value into this register */
 ){
+  if( pTab==0 ){
+    sqlite3VdbeAddOp3(v, OP_Column, iTabCur, iCol, regOut);
+    return;
+  }
   if( iCol<0 || iCol==pTab->iPKey ){
     sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut);
   }else{
diff --git a/src/select.c b/src/select.c
index 334307c..55d2584 100644
--- a/src/select.c
+++ b/src/select.c
@@ -3147,7 +3147,7 @@
 ** This routine is part of the flattening procedure.  A subquery
 ** whose result set is defined by pEList appears as entry in the
 ** FROM clause of a SELECT such that the VDBE cursor assigned to that
-** FORM clause entry is iTable.  This routine make the necessary 
+** FORM clause entry is iTable.  This routine makes the necessary 
 ** changes to pExpr so that it refers directly to the source table
 ** of the subquery rather the result set of the subquery.
 */
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 2b3c934..40660ae 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -3324,6 +3324,7 @@
     struct CCurHint *pCCurHint;                /* Used by codeCursorHint() */
     int *aiCol;                                /* array of column indexes */
     struct IdxCover *pIdxCover;                /* Check for index coverage */
+    struct IdxExprTrans *pIdxTrans;            /* Convert indexed expr to column */
   } u;
 };
 
diff --git a/src/where.c b/src/where.c
index 5a0b35b..38183d6 100644
--- a/src/where.c
+++ b/src/where.c
@@ -4447,6 +4447,7 @@
   pWInfo->pParse = pParse;
   pWInfo->pTabList = pTabList;
   pWInfo->pOrderBy = pOrderBy;
+  pWInfo->pWhere = pWhere;
   pWInfo->pResultSet = pResultSet;
   pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1;
   pWInfo->nLevel = nTabList;
diff --git a/src/whereInt.h b/src/whereInt.h
index f065fae..6bd4aab 100644
--- a/src/whereInt.h
+++ b/src/whereInt.h
@@ -417,6 +417,7 @@
   SrcList *pTabList;        /* List of tables in the join */
   ExprList *pOrderBy;       /* The ORDER BY clause or NULL */
   ExprList *pResultSet;     /* Result set of the query */
+  Expr *pWhere;             /* The complete WHERE clause */
   LogEst iLimit;            /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */
   int aiCurOnePass[2];      /* OP_OpenWrite cursors for the ONEPASS opt */
   int iContinue;            /* Jump here to continue with next record */
diff --git a/src/wherecode.c b/src/wherecode.c
index 4fd5e16..bdf7327 100644
--- a/src/wherecode.c
+++ b/src/wherecode.c
@@ -1039,6 +1039,61 @@
   }
 }
 
+#if 1 /* INDEXEXPRTRANS */
+typedef struct IdxExprTrans {
+  Expr *pIdxExpr;    /* The index expression */
+  int iTabCur;       /* The cursor of the corresponding table */
+  int iIdxCur;       /* The cursor for the index */
+  int iIdxCol;       /* The column for the index */
+} IdxExprTrans;
+
+static int whereIndexExprTransNode(Walker *p, Expr *pExpr){
+  IdxExprTrans *pX = p->u.pIdxTrans;
+  if( sqlite3ExprCompare(pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){
+    pExpr->op = TK_COLUMN;
+    pExpr->iTable = pX->iIdxCur;
+    pExpr->iColumn = pX->iIdxCol;
+    pExpr->pTab = 0;
+    return WRC_Prune;
+  }else{
+    return WRC_Continue;
+  }
+}
+
+/*
+** For an indexes on expression X, locate every instance of expression X in pExpr
+** and change that subexpression into a reference to the appropriate column of
+** the index.
+*/
+static void whereIndexExprTrans(
+  Index *pIdx,      /* The Index */
+  int iTabCur,      /* Cursor of the table that is being indexed */
+  int iIdxCur,      /* Cursor of the index itself */
+  WhereInfo *pWInfo /* Transform expressions in this WHERE clause */
+){
+  int iIdxCol;               /* Column number of the index */
+  ExprList *aColExpr;        /* Expressions that are indexed */
+  Walker w;
+  IdxExprTrans x;
+  aColExpr = pIdx->aColExpr;
+  if( aColExpr==0 ) return;  /* Not an index on expressions */
+  memset(&w, 0, sizeof(w));
+  w.xExprCallback = whereIndexExprTransNode;
+  w.u.pIdxTrans = &x;
+  x.iTabCur = iTabCur;
+  x.iIdxCur = iIdxCur;
+  for(iIdxCol=0; iIdxCol<aColExpr->nExpr; iIdxCol++){
+    if( pIdx->aiColumn[iIdxCol]!=XN_EXPR ) continue;
+    assert( aColExpr->a[iIdxCol].pExpr!=0 );
+    x.iIdxCol = iIdxCol;
+    x.pIdxExpr = aColExpr->a[iIdxCol].pExpr;
+    sqlite3WalkExpr(&w, pWInfo->pWhere);
+    sqlite3WalkExprList(&w, pWInfo->pOrderBy);
+    sqlite3WalkExprList(&w, pWInfo->pResultSet);
+  }
+}
+#endif
+
 /*
 ** Generate code for the start of the iLevel-th loop in the WHERE clause
 ** implementation described by pWInfo.
@@ -1620,6 +1675,10 @@
                            iRowidReg, pPk->nKeyCol); VdbeCoverage(v);
     }
 
+#if 1  /* INDEXEXPRTANS */
+    whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo);
+#endif
+
     /* Record the instruction used to terminate the loop. */
     if( pLoop->wsFlags & WHERE_ONEROW ){
       pLevel->op = OP_Noop;