Experimental changes that try to identify indexes as covering when they contain
expressions which do cover all data uses.  This check-in does not work, because
the AggInfo object might still refer to individual columns.  The purpose of
this check-in is to preserve the idea.  I might come back to it later.

FossilOrigin-Name: 018914a5a1dbf09307db3f85627f136fa011ab58641796471f5700937bd69bb6
diff --git a/manifest b/manifest
index 2443057..e015f63 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Minor\sbuild\scleanups\sand\sfix\sa\sharmless\srace\scondition\sin\sthe\sOPFS\spart\sof\stester1.js.
-D 2022-11-02T14:08:59.340
+C Experimental\schanges\sthat\stry\sto\sidentify\sindexes\sas\scovering\swhen\sthey\scontain\nexpressions\swhich\sdo\scover\sall\sdata\suses.\s\sThis\scheck-in\sdoes\snot\swork,\sbecause\nthe\sAggInfo\sobject\smight\sstill\srefer\sto\sindividual\scolumns.\s\sThe\spurpose\sof\nthis\scheck-in\sis\sto\spreserve\sthe\sidea.\s\sI\smight\scome\sback\sto\sit\slater.
+D 2022-11-03T21:08:56.993
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -723,7 +723,7 @@
 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d
 F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
 F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b
-F src/where.c 1ef5aae7fac877057b9f360f06b26d4275888460d8fb6e92bbb9e70e07afe946
+F src/where.c 5188da8bcc2fd5988d64c37eb69e0a0ae44d4b9798c4c7d31074434961f907a6
 F src/whereInt.h df0c79388c0b71b4a91f480d02791679fe0345d40410435c541c8893e95a4d3f
 F src/wherecode.c 133a94f82858787217d073143617df19e4a6a7d0b771a1519f957608109ad5a5
 F src/whereexpr.c 05295b44b54eea76d1ba766f0908928d0e20e990c249344c9521454d3d09c7ae
@@ -2054,8 +2054,11 @@
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P f6fa0cffa921ccde8910e7fa4a63c2e4ef8ddb376c8ce99e436b27ac332c4498
-R 49cc6fc37416a3ba7fdfd0b20ce15895
-U stephan
-Z b66cc4ccdf23cf485ede2fda7e429a86
+P 70ee6ee014bc4e2c1daa9b4a8909cf76ccecf32de1eb39055f20d3d0b1daa1bd
+R 1dc6261e5b309b19594c2d2789301577
+T *branch * indexed-expr-exp
+T *sym-indexed-expr-exp *
+T -sym-trunk *
+U drh
+Z 39e597a6456d4496ffa146482c09b77b
 # Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index f545a72..64c1e62 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-70ee6ee014bc4e2c1daa9b4a8909cf76ccecf32de1eb39055f20d3d0b1daa1bd
\ No newline at end of file
+018914a5a1dbf09307db3f85627f136fa011ab58641796471f5700937bd69bb6
\ No newline at end of file
diff --git a/src/where.c b/src/where.c
index 7ba72d2..8991b5b 100644
--- a/src/where.c
+++ b/src/where.c
@@ -3274,29 +3274,51 @@
   const Index *pIdx;      /* The index of interest */
   const i16 *aiColumn;    /* Columns contained in the index */
   u16 nColumn;            /* Number of columns in the index */
-  if( pExpr->op!=TK_COLUMN && pExpr->op!=TK_AGG_COLUMN ) return WRC_Continue;
-  if( pExpr->iColumn<(BMS-1) ) return WRC_Continue;
-  if( pExpr->iTable!=pWalk->u.pCovIdxCk->iTabCur ) return WRC_Continue;
-  pIdx = pWalk->u.pCovIdxCk->pIdx;
-  aiColumn = pIdx->aiColumn;
-  nColumn = pIdx->nColumn;
-  for(i=0; i<nColumn; i++){
-    if( aiColumn[i]==pExpr->iColumn ) return WRC_Continue;
+  if( pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN ){
+    if( pExpr->iTable!=pWalk->u.pCovIdxCk->iTabCur ){
+      return WRC_Prune;
+    }
+    pIdx = pWalk->u.pCovIdxCk->pIdx;
+    aiColumn = pIdx->aiColumn;
+    nColumn = pIdx->nColumn;
+    for(i=0; i<nColumn; i++){
+      if( aiColumn[i]==pExpr->iColumn ){
+        return WRC_Prune;
+      }
+    }
+    pWalk->eCode = 0;  /* Not a covering index */
+    return WRC_Abort;
+  }else if( pWalk->eCode==2 ){
+    int iCur = pWalk->u.pCovIdxCk->iTabCur;
+    pIdx = pWalk->u.pCovIdxCk->pIdx;
+    assert( pIdx->aColExpr!=0 );
+    aiColumn = pIdx->aiColumn;
+    nColumn = pIdx->nColumn;
+    for(i=0; i<nColumn; i++){
+      if( aiColumn[i]==XN_EXPR
+       && sqlite3ExprCompare(0, pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0
+      ){
+        return WRC_Prune;
+      }
+    }
   }
-  pWalk->eCode = 1;
-  return WRC_Abort;
+  return WRC_Continue;
 }
 
 
 /*
-** pIdx is an index that covers all of the low-number columns used by
-** pWInfo->pSelect (columns from 0 through 62).  But there are columns
-** in pWInfo->pSelect beyond 62.  This routine tries to answer the question
-** of whether pIdx covers *all* columns in the query.
+** pIdx is an index for which we cannot determine is covering using
+** the SrcItem.colUsed bitmask.  We can't use colUsed to make the
+** determination for either of these reasons:
 **
-** Return 0 if pIdx is a covering index.   Return non-zero if pIdx is
-** not a covering index or if we are unable to determine if pIdx is a
-** covering index.
+**   *   pIdx might contains indexed expressions.
+**   *   SrcItem.colUsed indicates that columns beyond the 63rd column
+**       are used in the query, making bitmap tests ineffective.
+**
+** This routine does extra work to try to make a more accurate determination
+** of whether or not pIdx is covering.  Return 0 if we know that pIdx is
+** covering.  Return non-zero if pIdx is not covering or if unable to
+** complete the analysis.
 **
 ** This routine is an optimization.  It is always safe to return non-zero.
 ** But returning zero when non-zero should have been returned can lead to
@@ -3310,18 +3332,20 @@
   int i;
   struct CoveringIndexCheck ck;
   Walker w;
+  int bHasHigh = 0;
+  int bHasExpr = 0;
   if( pWInfo->pSelect==0 ){
     /* We don't have access to the full query, so we cannot check to see
     ** if pIdx is covering.  Assume it is not. */
     return 1;
   }
   for(i=0; i<pIdx->nColumn; i++){
-    if( pIdx->aiColumn[i]>=BMS-1 ) break;
+    if( pIdx->aiColumn[i]>=BMS-1 ) bHasHigh = 1;
+    if( pIdx->aiColumn[i]==XN_EXPR ) bHasExpr = 1;
   }
-  if( i>=pIdx->nColumn ){
-    /* pIdx does not index any columns greater than 62, but we know from
-    ** colMask that columns greater than 62 are used, so this is not a
-    ** covering index */
+  if( bHasHigh==0 && bHasExpr==0 ){
+    /* pIdx does not index any columns greater than 62 nor any expression
+    ** columns.  The colMask analysis must have been correct.  Not covering. */
     return 1;
   }
   ck.pIdx = pIdx;
@@ -3330,9 +3354,9 @@
   w.xExprCallback = whereIsCoveringIndexWalkCallback;
   w.xSelectCallback = sqlite3SelectWalkNoop;
   w.u.pCovIdxCk = &ck;
-  w.eCode = 0;
+  w.eCode = 1 + bHasExpr;
   sqlite3WalkSelect(&w, pWInfo->pSelect);
-  return w.eCode;
+  return w.eCode==0;
 }
 
 /*
@@ -3552,7 +3576,7 @@
         m = 0;
       }else{
         m = pSrc->colUsed & pProbe->colNotIdxed;
-        if( m==TOPBIT ){
+        if( m==TOPBIT || (pProbe->bHasExpr && m!=0) ){
           m = whereIsCoveringIndex(pWInfo, pProbe, pSrc->iCursor);
         }
         pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED;