🌐 AI搜索 & 代理 主页
Begin transitioning the fixed-length (64-bit) bitmap used to keep track of
the subset of columns of a table that are used by a query into a more general
structure that can work with wide tables.  Experimental.

FossilOrigin-Name: 5dd78588203b38e5782a31944c8f14141f348d4ccc9d378cf81c57b07162b650
diff --git a/manifest b/manifest
index 0c94ebc..37c3400 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sSQLITE_DQS\sto\sthe\scompileoptions_used\slist,\sper\srequest\sin\s[forum\spost\s8b1060122b|forum:8b1060122b].\sForce\sDQS=0\sin\ssqlite3-wasm.c.
-D 2022-10-21T17:48:49.786
+C Begin\stransitioning\sthe\sfixed-length\s(64-bit)\sbitmap\sused\sto\skeep\strack\sof\nthe\ssubset\sof\scolumns\sof\sa\stable\sthat\sare\sused\sby\sa\squery\sinto\sa\smore\sgeneral\nstructure\sthat\scan\swork\swith\swide\stables.\s\sExperimental.
+D 2022-10-21T20:12:24.563
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -557,12 +557,12 @@
 F src/attach.c 4431f82f0247bf3aaf91589acafdff77d1882235c95407b36da1585c765fbbc8
 F src/auth.c f4fa91b6a90bbc8e0d0f738aa284551739c9543a367071f55574681e0f24f8cf
 F src/backup.c a2891172438e385fdbe97c11c9745676bec54f518d4447090af97189fd8e52d7
-F src/bitvec.c 7c849aac407230278445cb069bebc5f89bf2ddd87c5ed9459b070a9175707b3d
+F src/bitvec.c 4915778f09f486e38f5fc43451c67e9b0933cacf23524fef61d7740f1d898588
 F src/btmutex.c 6ffb0a22c19e2f9110be0964d0731d2ef1c67b5f7fabfbaeb7b9dabc4b7740ca
 F src/btree.c 74fc5f6a0577df703d6f98d0c51ee0d8d91d22dbc0ba86e42e056517e2b45576
 F src/btree.h 74d64b8f28cfa4a894d14d4ed64fa432cd697b98b61708d4351482ae15913e22
 F src/btreeInt.h 8ce1332edd89dfd2461d561ac10a0ab5601c8e06200cb5230596c3caaf54482e
-F src/build.c 13bcc04821ad260ef00d87e0704424e0ae4e6cd66c7e384b4cedb379a6cb738b
+F src/build.c df4dbc89b03927c493fb85b8d2500cea58105ee1714ad9725427de4333a6b5b9
 F src/callback.c 4cd7225b26a97f7de5fee5ae10464bed5a78f2adefe19534cc2095b3a8ca484a
 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
 F src/ctime.c 20507cc0b0a6c19cd882fcd0eaeda32ae6a4229fb4b024cfdf3183043d9b703d
@@ -570,7 +570,7 @@
 F src/dbpage.c 5808e91bc27fa3981b028000f8fadfdc10ce9e59a34ce7dc4e035a69be3906ec
 F src/dbstat.c 861e08690fcb0f2ee1165eff0060ea8d4f3e2ea10f80dab7d32ad70443a6ff2d
 F src/delete.c 86573edae75e3d3e9a8b590d87db8e47222103029df4f3e11fa56044459b514e
-F src/expr.c 847f87d9df3ede2b2b0a8db088af0b9c1923b21009f8ea1b9b7b28cb0a383170
+F src/expr.c 304bce440edc89567bed99756771331a8316b6c36c36edee7b0226666eeaef3a
 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
 F src/fkey.c 722f20779f5342a787922deded3628d8c74b5249cab04098cf17ee2f2aaff002
 F src/func.c fe2a795ad647ce42054873ac91c43beb7b5d204892903a67f6e7e314379b9d4a
@@ -618,14 +618,14 @@
 F src/prepare.c 1b02be0441eda4579471fea097f678effcbb77ef0c39ab3f703c837822bcd674
 F src/printf.c e99ee9741e79ae3873458146f59644276657340385ade4e76a5f5d1c25793764
 F src/random.c 546d6feb15ec69c1aafe9bb351a277cbb498fd5410e646add673acb805714960
-F src/resolve.c efea4e5fbecfd6d0a9071b0be0d952620991673391b6ffaaf4c277b0bb674633
+F src/resolve.c 857836c954ad8affa5a71c0cfaf011742346b0e8fc74c2fc3437e32ff102a9d1
 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
-F src/select.c 3f7238ebb3252f4768a8fb46ad95b62700d27baddcab8a21548129f4f9305d52
+F src/select.c 22905c05a1ef7c33f67c2ece75306d228590b4fcd2d00cf7fb1fba026e76d8e7
 F src/shell.c.in 6a9e15cb9fc3cd13d3647d4d9714c0d4d4a65e7f49228c2aafca910ed08d5774
 F src/sqlite.h.in d9c8a6243fc0a1c270d69db33758e34b810af3462f9bc5b4af113b347e07c69d
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 5336beea1868d99d2f62e628dbea55e97267dbff8193291ab175e960c5df9141
-F src/sqliteInt.h ce8bf543210ab4a8a797e6abaf45e15f4cff24570b1043560aa747b3dc1a7935
+F src/sqliteInt.h 449848d59da7b4862bee9a73ff0f8453beebc6689395e3aeaca33d994aa24a89
 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
 F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749
 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@ -685,9 +685,9 @@
 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
 F src/tokenize.c 1305797eab3542a0896b552c6e7669c972c1468e11e92b370533c1f37a37082b
-F src/treeview.c 07787f67cd297a6d09d04b8d70c06769c60c9c1d9080378f93929c16f8fd3298
+F src/treeview.c bb143b907d5ee2f98f8a866eac20a2dd73e41bcfcc34a2360cde0df9720cb817
 F src/trigger.c 4163ada044af89d51caba1cb713a73165347b2ec05fe84a283737c134d61fcd5
-F src/update.c 5b0302c47cf31b533d5dff04c497ca1d8b9d89c39727e633fbe7b882fd5ac5aa
+F src/update.c 932e88c143737695b0afec7be019e960a69d23ad049d2587be85c4ea39c6eb33
 F src/upsert.c 5303dc6c518fa7d4b280ec65170f465c7a70b7ac2b22491598f6d0b4875b3145
 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
 F src/util.c 0be191521ff6d2805995f4910f0b6231b42843678b2efdc1abecaf39929a673f
@@ -707,10 +707,10 @@
 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d
 F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
 F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b
-F src/where.c bccea9a1066c9843ad7bf05f9054b390fe9b5d0fb721ff8af2d11fb93779836a
+F src/where.c d5037ce38cf934151d57440a0e9713efba6c766f6207837169670e105b404782
 F src/whereInt.h e5f5cf1bc32b7d01a6337027478ef6ed90c8c403de4b977198345c8238f0e1b0
 F src/wherecode.c 13b6373af69d484d9b05b9a732d393ce3b7b320cc93275c6528127678650f8cb
-F src/whereexpr.c a1bd9d8faddc946d19ae8b6b3468874794bf54acd13fe46e1680fb428e8d3ea7
+F src/whereexpr.c 793ed333739cc8f9320e9c3cb5b6e95f1b92d773d8cf3fbd739aae125da30002
 F src/window.c 928e215840e2f2d9a2746e018c9643ef42c66c4ab6630ef0df7fa388fa145e86
 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
@@ -2036,8 +2036,11 @@
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 9cf1142b0cdb13347e3f551c862cb4714cadfe5ad637f049cf0a4b8bb6125b32
-R f0d8c3eadf9b3a16756631ad00044092
-U stephan
-Z 4b9ac72991a7e1ed1b8b1873a504bb5c
+P fcd9e0dbe3226f3f7ccc15b11fc3aa3b8058571bef274c25a33e9753e22f7551
+R 90ea3d24eab5cb65c030271a81eb056f
+T *branch * column-set
+T *sym-column-set *
+T -sym-trunk *
+U drh
+Z 9f1ca2bdbb2f4127a8ebcf444d4383b0
 # Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index 16c3bc4..1853bea 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-fcd9e0dbe3226f3f7ccc15b11fc3aa3b8058571bef274c25a33e9753e22f7551
\ No newline at end of file
+5dd78588203b38e5782a31944c8f14141f348d4ccc9d378cf81c57b07162b650
\ No newline at end of file
diff --git a/src/bitvec.c b/src/bitvec.c
index 9393428..4569be1 100644
--- a/src/bitvec.c
+++ b/src/bitvec.c
@@ -9,10 +9,14 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
-** This file implements an object that represents a fixed-length
-** bitmap.  Bits are numbered starting with 1.
+** This file implements two objects:  Bitvec and ColumnSet
 **
-** A bitmap is used to record which pages of a database file have been
+** ## BITVEC
+**
+** The Bitvec object represents a fixed-length bitmap.  Bits are
+** numbered starting with 1.
+**
+** A Bitvec bitmap is used to record which pages of a database file have been
 ** journalled during a transaction, or which pages have the "dont-write"
 ** property.  Usually only a few pages are meet either condition.
 ** So the bitmap is usually sparse and has low cardinality.
@@ -21,7 +25,7 @@
 ** the bitmap becomes dense with high cardinality.  The algorithm needs 
 ** to handle both cases well.
 **
-** The size of the bitmap is fixed when the object is created.
+** The size of a Bitvec bitmap is fixed when the object is created.
 **
 ** All bits are clear when the bitmap is created.  Individual bits
 ** may be set or cleared one at a time.
@@ -33,6 +37,13 @@
 ** Bitvec object is the number of pages in the database file at the
 ** start of a transaction, and is thus usually less than a few thousand,
 ** but can be as large as 2 billion for a really big database.
+**
+** ## COLUMNSET
+**
+** The ColumnSet object represents a subset of the columns of a table that
+** are used by an SQL statement or an index.  This information is used to
+** during query planning, and especially to help determine if an index will
+** be a covering index.
 */
 #include "sqliteInt.h"
 
@@ -409,3 +420,38 @@
   return rc;
 }
 #endif /* SQLITE_UNTESTABLE */
+
+
+/*
+** The pExpr argument is guaranteed to be a non-NULL Expr node of 
+** type TK_COLUMN.  Mark this column as used in pCSet.
+*/
+void sqlite3CSetAddExpr(ColumnSet *pCSet, const Expr *pExpr){
+  int n;
+  Table *pExTab;
+
+  assert( pExpr!=0 );
+  n = pExpr->iColumn;
+  assert( ExprUseYTab(pExpr) );
+  pExTab = pExpr->y.pTab;
+  assert( pExTab!=0 );
+  if( (pExTab->tabFlags & TF_HasGenerated)!=0
+   && (pExTab->aCol[n].colFlags & COLFLAG_GENERATED)!=0 
+  ){
+    testcase( pExTab->nCol==BMS-1 );
+    testcase( pExTab->nCol==BMS );
+    pCSet->m |= (pExTab->nCol>=BMS ? ALLBITS : MASKBIT(pExTab->nCol)-1);
+  }else{
+    testcase( n==BMS-1 );
+    testcase( n==BMS );
+    if( n>=BMS ) n = BMS-1;
+    pCSet->m |= ((Bitmask)1)<<n;
+  }
+}
+
+/*
+** Convert a ColumnSet into a finite-length bitmask.
+*/
+Bitmask sqlite3CSetToMask(const ColumnSet *pCSet){
+  return pCSet->m;
+}
diff --git a/src/build.c b/src/build.c
index 8578a71..c3b61f6 100644
--- a/src/build.c
+++ b/src/build.c
@@ -2303,8 +2303,8 @@
       if( x<BMS-1 ) m |= MASKBIT(x);
     }
   }
-  pIdx->colNotIdxed = ~m;
-  assert( (pIdx->colNotIdxed>>63)==1 );
+  pIdx->colNotIdxed.m = ~m;
+  assert( (pIdx->colNotIdxed.m>>63)==1 );
 }
 
 /*
diff --git a/src/expr.c b/src/expr.c
index 7a4e59f..044d687 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -1694,7 +1694,7 @@
     }else{
       pNewItem->u3.pOn = sqlite3ExprDup(db, pOldItem->u3.pOn, flags);
     }
-    pNewItem->colUsed = pOldItem->colUsed;
+    pNewItem->colUsed.m = pOldItem->colUsed.m;
   }
   return pNew;
 }
diff --git a/src/resolve.c b/src/resolve.c
index 1c3a9d9..ba68971 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -154,32 +154,6 @@
 }
 
 /*
-** The argument is guaranteed to be a non-NULL Expr node of type TK_COLUMN.
-** return the appropriate colUsed mask.
-*/
-Bitmask sqlite3ExprColUsed(Expr *pExpr){
-  int n;
-  Table *pExTab;
-
-  n = pExpr->iColumn;
-  assert( ExprUseYTab(pExpr) );
-  pExTab = pExpr->y.pTab;
-  assert( pExTab!=0 );
-  if( (pExTab->tabFlags & TF_HasGenerated)!=0
-   && (pExTab->aCol[n].colFlags & COLFLAG_GENERATED)!=0 
-  ){
-    testcase( pExTab->nCol==BMS-1 );
-    testcase( pExTab->nCol==BMS );
-    return pExTab->nCol>=BMS ? ALLBITS : MASKBIT(pExTab->nCol)-1;
-  }else{
-    testcase( n==BMS-1 );
-    testcase( n==BMS );
-    if( n>=BMS ) n = BMS-1;
-    return ((Bitmask)1)<<n;
-  }
-}
-
-/*
 ** Create a new expression term for the column specified by pMatch and
 ** iColumn.  Append this new expression term to the FULL JOIN Match set
 ** in *ppList.  Create a new *ppList if this is the first term in the
@@ -714,9 +688,7 @@
   }
 
   /* If a column from a table in pSrcList is referenced, then record
-  ** this fact in the pSrcList.a[].colUsed bitmask.  Column 0 causes
-  ** bit 0 to be set.  Column 1 sets bit 1.  And so forth.  Bit 63 is
-  ** set if the 63rd or any subsequent column is used.
+  ** this fact in pSrcList.a[].colUsed.
   **
   ** The colUsed mask is an optimization used to help determine if an
   ** index is a covering index.  The correct answer is still obtained
@@ -728,7 +700,7 @@
   ** of the table.
   */
   if( pExpr->iColumn>=0 && pMatch!=0 ){
-    pMatch->colUsed |= sqlite3ExprColUsed(pExpr);
+    sqlite3CSetAddExpr(&pMatch->colUsed, pExpr);
   }
 
   pExpr->op = eNewExprOp;
@@ -777,11 +749,11 @@
       ){
         testcase( pTab->nCol==63 );
         testcase( pTab->nCol==64 );
-        pItem->colUsed = pTab->nCol>=64 ? ALLBITS : MASKBIT(pTab->nCol)-1;
+        pItem->colUsed.m = pTab->nCol>=64 ? ALLBITS : MASKBIT(pTab->nCol)-1;
       }else{
         testcase( iCol==BMS );
         testcase( iCol==BMS-1 );
-        pItem->colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol);
+        pItem->colUsed.m |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol);
       }
     }
   }
diff --git a/src/select.c b/src/select.c
index 03d9c42..a44501f 100644
--- a/src/select.c
+++ b/src/select.c
@@ -3920,7 +3920,7 @@
   pItem = pWalker->u.pSrcItem;
   if( pItem->iCursor!=pExpr->iTable ) return WRC_Continue;
   if( pExpr->iColumn<0 ) return WRC_Continue;
-  pItem->colUsed |= sqlite3ExprColUsed(pExpr);
+  sqlite3CSetAddExpr(&pItem->colUsed, pExpr);
   return WRC_Continue;
 }
 static void recomputeColumnsUsed(
@@ -3933,7 +3933,7 @@
   w.xExprCallback = recomputeColumnsUsedExpr;
   w.xSelectCallback = sqlite3SelectWalkNoop;
   w.u.pSrcItem = pSrcItem;
-  pSrcItem->colUsed = 0;
+  pSrcItem->colUsed.m = 0;
   sqlite3WalkSelect(&w, pSelect);
 }
 #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
@@ -6939,7 +6939,7 @@
     ** assume the column name is non-NULL and segfault.  The use of an empty
     ** string for the fake column name seems safer.
     */
-    if( pItem->colUsed==0 && pItem->zName!=0 ){
+    if( pItem->colUsed.m==0 && pItem->zName!=0 ){
       sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase);
     }
 
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 5e4afb1..9d4053b 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1176,6 +1176,7 @@
 typedef struct Bitvec Bitvec;
 typedef struct CollSeq CollSeq;
 typedef struct Column Column;
+typedef struct ColumnSet ColumnSet;
 typedef struct Cte Cte;
 typedef struct CteUse CteUse;
 typedef struct Db Db;
@@ -2556,6 +2557,14 @@
   u8 eqSeen;          /* True if an equality comparison has been seen */
 };
 
+/*
+** A ColumnSet object is used to indicate a subset of the columns in
+** a table that are used in an SQL statement or used by an Index.
+*/
+struct ColumnSet {
+  Bitmask m;
+};
+
 
 /*
 ** Each SQL index is represented in memory by an
@@ -2628,7 +2637,7 @@
   tRowcnt *aiRowEst;       /* Non-logarithmic stat1 data for this index */
   tRowcnt nRowEst0;        /* Non-logarithmic number of rows in the index */
 #endif
-  Bitmask colNotIdxed;     /* 0 for unindexed columns in pTab */
+  ColumnSet colNotIdxed;   /* 0 for unindexed columns in pTab */
 };
 
 /*
@@ -3120,7 +3129,6 @@
     Expr *pOn;        /* fg.isUsing==0 =>  The ON clause of a join */
     IdList *pUsing;   /* fg.isUsing==1 =>  The USING clause of a join */
   } u3;
-  Bitmask colUsed;  /* Bit N (1<<N) set if column N of pTab is used */
   union {
     char *zIndexedBy;    /* Identifier from "INDEXED BY <zIndex>" clause */
     ExprList *pFuncArg;  /* Arguments to table-valued-function */
@@ -3129,6 +3137,7 @@
     Index *pIBIndex;  /* Index structure corresponding to u1.zIndexedBy */
     CteUse *pCteUse;  /* CTE Usage info info fg.isCte is true */
   } u2;
+  ColumnSet colUsed;  /* Bit N (1<<N) set if column N of pTab is used */
 };
 
 /*
@@ -5078,7 +5087,8 @@
   const char*,
   const char*
 );
-Bitmask sqlite3ExprColUsed(Expr*);
+void sqlite3CSetAddExpr(ColumnSet*,const Expr*);
+Bitmask sqlite3CSetToMask(const ColumnSet*);
 u8 sqlite3StrIHash(const char*);
 int sqlite3ResolveExprNames(NameContext*, Expr*);
 int sqlite3ResolveExprListNames(NameContext*, ExprList*);
diff --git a/src/treeview.c b/src/treeview.c
index 89a128d..20a4141 100644
--- a/src/treeview.c
+++ b/src/treeview.c
@@ -195,7 +195,8 @@
     sqlite3_str_appendf(&x, "{%d:*} %!S", pItem->iCursor, pItem);
     if( pItem->pTab ){
       sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx",
-           pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab, pItem->colUsed);
+           pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab,
+           sqlite3CSetToMask(&pItem->colUsed));
     }
     if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))==(JT_LEFT|JT_RIGHT) ){
       sqlite3_str_appendf(&x, " FULL-OUTER-JOIN");
diff --git a/src/update.c b/src/update.c
index 809b306..a21b94e 100644
--- a/src/update.c
+++ b/src/update.c
@@ -560,7 +560,7 @@
   ** case, set all bits of the colUsed mask (to ensure that the virtual
   ** table implementation makes all columns available).
   */
-  pTabList->a[0].colUsed = IsVirtual(pTab) ? ALLBITS : 0;
+  pTabList->a[0].colUsed.m = IsVirtual(pTab) ? ALLBITS : 0;
 
   hasFK = sqlite3FkRequired(pParse, pTab, aXRef, chngKey);
 
diff --git a/src/where.c b/src/where.c
index 8e9290c..771c1f1 100644
--- a/src/where.c
+++ b/src/where.c
@@ -908,14 +908,14 @@
   ** original table changes and the index and table cannot both be used
   ** if they go out of sync.
   */
-  extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1));
+  extraCols = pSrc->colUsed.m & (~idxCols | MASKBIT(BMS-1));
   mxBitCol = MIN(BMS-1,pTable->nCol);
   testcase( pTable->nCol==BMS-1 );
   testcase( pTable->nCol==BMS-2 );
   for(i=0; i<mxBitCol; i++){
     if( extraCols & MASKBIT(i) ) nKeyCol++;
   }
-  if( pSrc->colUsed & MASKBIT(BMS-1) ){
+  if( pSrc->colUsed.m & MASKBIT(BMS-1) ){
     nKeyCol += pTable->nCol - BMS + 1;
   }
 
@@ -958,7 +958,7 @@
       n++;
     }
   }
-  if( pSrc->colUsed & MASKBIT(BMS-1) ){
+  if( pSrc->colUsed.m & MASKBIT(BMS-1) ){
     for(i=BMS-1; i<pTable->nCol; i++){
       pIdx->aiColumn[n] = i;
       pIdx->azColl[n] = sqlite3StrBINARY;
@@ -3463,7 +3463,7 @@
         pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED;
         m = 0;
       }else{
-        m = pSrc->colUsed & pProbe->colNotIdxed;
+        m = pSrc->colUsed.m & pProbe->colNotIdxed.m;
         pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED;
       }
 
@@ -3626,7 +3626,7 @@
   pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2;
   pIdxInfo->estimatedRows = 25;
   pIdxInfo->idxFlags = 0;
-  pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed;
+  pIdxInfo->colUsed = sqlite3CSetToMask(&pSrc->colUsed);
   pHidden->mHandleIn = 0;
 
   /* Invoke the virtual table xBestIndex() method */
@@ -5140,7 +5140,7 @@
       }
       if( j!=pIdx->nKeyCol ) continue;
       pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_ONEROW|WHERE_INDEXED;
-      if( pIdx->isCovering || (pItem->colUsed & pIdx->colNotIdxed)==0 ){
+      if( pIdx->isCovering || (pItem->colUsed.m & pIdx->colNotIdxed.m)==0 ){
         pLoop->wsFlags |= WHERE_IDX_ONLY;
       }
       pLoop->nLTerm = j;
@@ -5937,7 +5937,7 @@
         /* If we know that only a prefix of the record will be used,
         ** it is advantageous to reduce the "column count" field in
         ** the P4 operand of the OP_OpenRead/Write opcode. */
-        Bitmask b = pTabItem->colUsed;
+        Bitmask b = pTabItem->colUsed.m;
         int n = 0;
         for(; b; b=b>>1, n++){}
         sqlite3VdbeChangeP4(v, -1, SQLITE_INT_TO_PTR(n), P4_INT32);
@@ -5953,7 +5953,7 @@
       }
 #ifdef SQLITE_ENABLE_COLUMN_USED_MASK
       sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, pTabItem->iCursor, 0, 0,
-                            (const u8*)&pTabItem->colUsed, P4_INT64);
+                            (const u8*)&pTabItem->colUsed.m, P4_INT64);
 #endif
     }else{
       sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
@@ -6015,7 +6015,7 @@
             jj = pIx->aiColumn[ii];
             if( jj<0 ) continue;
             if( jj>63 ) jj = 63;
-            if( (pTabItem->colUsed & MASKBIT(jj))==0 ) continue;
+            if( (pTabItem->colUsed.m & MASKBIT(jj))==0 ) continue;
             colUsed |= ((u64)1)<<(ii<63 ? ii : 63);
           }
           sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, iIndexCur, 0, 0,
diff --git a/src/whereexpr.c b/src/whereexpr.c
index 9fe7791..5ef12b1 100644
--- a/src/whereexpr.c
+++ b/src/whereexpr.c
@@ -1835,7 +1835,7 @@
     pColRef->iColumn = k++;
     assert( ExprUseYTab(pColRef) );
     pColRef->y.pTab = pTab;
-    pItem->colUsed |= sqlite3ExprColUsed(pColRef);
+    sqlite3CSetAddExpr(&pItem->colUsed, pColRef);
     pRhs = sqlite3PExpr(pParse, TK_UPLUS, 
         sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0);
     pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs);