]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
If the argument to REINDEX is EXPRESSIONS (with no schema prefix) then it
authordrh <>
Fri, 20 Mar 2026 19:30:58 +0000 (19:30 +0000)
committerdrh <>
Fri, 20 Mar 2026 19:30:58 +0000 (19:30 +0000)
updates both expression indexes, and any indexes named "expressions" or
all indexes of any tables name "expressions".

FossilOrigin-Name: 72650dc152279a6da1937f377b1e16b79f4cd664841e12222dc5459838408d22

manifest
manifest.uuid
src/build.c
test/auth.test

index 73930bf8655bc71ed346e96079472697d084209e..d427d530e67b367c43cdb3407f7face3f12a8f4d 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C If\sthere\sare\snot\scollating\ssequences,\stables,\sor\sindexes\snamed\s"EXPRESSIONS"\nthen\sthe\s"REINDEX\sEXPRESSIONS"\scommand\srebuilds\sall\sexpression\sindexes.
-D 2026-03-20T14:37:39.310
+C If\sthe\sargument\sto\sREINDEX\sis\sEXPRESSIONS\s(with\sno\sschema\sprefix)\sthen\sit\nupdates\sboth\sexpression\sindexes,\sand\sany\sindexes\snamed\s"expressions"\sor\nall\sindexes\sof\sany\stables\sname\s"expressions".
+D 2026-03-20T19:30:58.886
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -676,7 +676,7 @@ F src/btmutex.c 30dada73a819a1ef5b7583786370dce1842e12e1ad941e4d05ac29695528daea
 F src/btree.c fb350c445316c1cc0529703c0b76450770a1de0ab0440641a56b19f05d6fefbe
 F src/btree.h e823c46d87f63d904d735a24b76146d19f51f04445ea561f71cc3382fd1307f0
 F src/btreeInt.h 9c0f9ea5c9b5f4dcaea18111d43efe95f2ac276cd86d770dce10fd99ccc93886
-F src/build.c beb8069bccb2ddd101b384df95f45b300999e70ab1be4061dd8da7bd27fb3579
+F src/build.c c180fbb25a3c3e02c7eacdf1d5911a0f29bbd4b4c5e1b64fe5d8772096419a69
 F src/callback.c 3605bbf02bd7ed46c79cd48346db4a32fc51d67624400539c0532f4eead804ad
 F src/carray.c 3efe3982d5fb323334c29328a4e189ccaef6b95612a6084ad5fa124fd5db1179
 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
@@ -876,7 +876,7 @@ F test/attach2.test 6d1e3a457ce260d6fc8e5945c07fba6c76dc2aa90e1c701f067b50ee88f7
 F test/attach3.test c59d92791070c59272e00183b7353eeb94915976
 F test/attach4.test 00e754484859998d124d144de6d114d920f2ed6ca2f961e6a7f4183c714f885e
 F test/attachmalloc.test 67309af95c6b765c13e7d2279d7fccbef78e6eb0565d75d51cefd5dc88784549
-F test/auth.test 5b8558a40571ebc55c1581cb7cec3b2348a699542a0a51b83ef21c6a953d95e3
+F test/auth.test 2a01bf5bf3a0f10adf8ae3a3fd2c05af8a8c1b7a52fae227adb4ccd931915b5c
 F test/auth2.test 9eb7fce9f34bf1f50d3f366fb3e606be5a2000a1
 F test/auth3.test 76d20a7fa136d63bcfcf8bcb65c0b1455ed71078d81f22bcd0550d3eb18594ab
 F test/autoanalyze1.test b9cc3f32a990fa56669b668d237c6d53e983554ae80c0604992e18869a0b2dec
@@ -2195,11 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
 F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
 F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
-P 078b3162d0d3d3035f4d3ad88664066d99c218a731ac481b9f1172529e26e4eb
-R fffd90b5bfe8609c91e78fb9093e3446
-T *branch * reindex-expressions
-T *sym-reindex-expressions *
-T -sym-trunk *
+P df5c5aa26758e0dc00a9ccba29eac83071176d257e121207e0a13c54833b18c0
+R fa2d2188fd0c121dfe90e3d57a7a9881
 U drh
-Z 9182359fa4b768364b8403c0c94e4fa6
+Z 99001bf01c3f8b11e63f25852a2515f5
 # Remove this line to create a well-formed Fossil manifest.
index 19509a7e471a132d731a6fa793c093618ff069bf..58dad7f5ef330e0545c884ef4a17dde57eca49d5 100644 (file)
@@ -1 +1 @@
-df5c5aa26758e0dc00a9ccba29eac83071176d257e121207e0a13c54833b18c0
+72650dc152279a6da1937f377b1e16b79f4cd664841e12222dc5459838408d22
index 94c3f52624a95104060542d123d71437fdb51678..f7e280617511d03a31e035be1eb5017cbcc4a844 100644 (file)
@@ -5523,119 +5523,55 @@ void sqlite3RowidConstraint(
 }
 
 /*
-** KEYWORD "expressions".  Identify the magic "expressions" collating
-** sequence name in collationMatch() by pointer comparison to this
-** value.
-*/
-static const char zExpressionsKW[] = "expressions";
-
-/*
-** Check to see if pIndex uses the collating sequence pColl.  Return
-** true if it does and false if it does not.
-**
-** If zColl==zExpressionsKW, then match only if index is an expression
-** index.
+** Return true if any column of pIndex uses the zColl collation
 */
 #ifndef SQLITE_OMIT_REINDEX
 static int collationMatch(const char *zColl, Index *pIndex){
   int i;
   assert( zColl!=0 );
   for(i=0; i<pIndex->nColumn; i++){
-    const char *z;
-    i16 iCol = pIndex->aiColumn[i];
-    if( iCol==XN_ROWID ) continue;
-    if( iCol==XN_EXPR ){
-      if( zColl==zExpressionsKW ){
-        return 1;   /* Index on an expression */
-      }
-      continue;
-    }
-    z = pIndex->azColl[i];
-    assert( z!=0 );
-    if( 0==sqlite3StrICmp(z, zColl) ){
-      assert( zColl!=zExpressionsKW );
-      return 1;   /* Index using collating sequence zColl */
-    }
-    if( zColl==zExpressionsKW
-     && (pIndex->pTable->aCol[iCol].colFlags & COLFLAG_VIRTUAL)!=0
-    ){
-      return 1;   /* Index on a VIRTUAL generated column */
-    }
+    const char *z = pIndex->azColl[i];
+    assert( z!=0 || pIndex->aiColumn[i]<0 );
+    if( z!=0 && 0==sqlite3StrICmp(z, zColl) ) return 1;
   }
   return 0;
 }
 #endif
 
-/*
-** Recompute all indexes of pTab that use the collating sequence pColl.
-** If pColl==0 then recompute all indexes of pTab.
-*/
-#ifndef SQLITE_OMIT_REINDEX
-static void reindexTable(Parse *pParse, Table *pTab, char const *zColl){
-  if( !IsVirtual(pTab) ){
-    Index *pIndex;              /* An index associated with pTab */
-
-    for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){
-      if( zColl==0 || collationMatch(zColl, pIndex) ){
-        int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
-        sqlite3BeginWriteOperation(pParse, 0, iDb);
-        sqlite3RefillIndex(pParse, pIndex, -1);
-      }
-    }
-  }
-}
-#endif
-
-/*
-** Recompute all indexes of all tables in all databases where the
-** indexes use the collating sequence zColl.  If zColl==0 then recompute
-** all indexes everywhere.
-*/
-#ifndef SQLITE_OMIT_REINDEX
-static void reindexDatabases(Parse *pParse, char const *zColl){
-  Db *pDb;                    /* A single database */
-  int iDb;                    /* The database index number */
-  sqlite3 *db = pParse->db;   /* The database connection */
-  HashElem *k;                /* For looping over tables in pDb */
-  Table *pTab;                /* A table in the database */
-
-  assert( sqlite3BtreeHoldsAllMutexes(db) );  /* Needed for schema access */
-  for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){
-    assert( pDb!=0 );
-    for(k=sqliteHashFirst(&pDb->pSchema->tblHash);  k; k=sqliteHashNext(k)){
-      pTab = (Table*)sqliteHashData(k);
-      reindexTable(pParse, pTab, zColl);
-    }
-  }
-}
-#endif
-
 /*
 ** Generate code for the REINDEX command.
 **
 **        REINDEX                            -- 1
 **        REINDEX  <collation>               -- 2
-**        REINDEX  ?<database>.?<tablename>  -- 3
-**        REINDEX  ?<database>.?<indexname>  -- 4
+**        REINDEX  ?<database>.?<indexname>  -- 3
+**        REINDEX  ?<database>.?<tablename>  -- 4
+**        REINDEX  EXPRESSIONS               -- 5
 **
 ** Form 1 causes all indexes in all attached databases to be rebuilt.
 ** Form 2 rebuilds all indexes in all databases that use the named
 ** collating function.  Forms 3 and 4 rebuild the named index or all
-** indexes associated with the named table.
+** indexes associated with the named table, respectively.  Form 5
+** rebuilds all expression indexes in addition to all collations,
+** indexes, or tables named "EXPRESSIONS".
 **
-** If the argument to form 2 does not match any known collation, but
-** it does match "EXPRESSIONS", then all expression indexes are rebuilt.
+** If the name is ambiguous such that it matches two or more of
+** forms 2 through 5, then rebuild the union of all matching indexes,
+** taken care to avoid rebuilding the same index more than once.
 */
 #ifndef SQLITE_OMIT_REINDEX
 void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
   CollSeq *pColl;             /* Collating sequence to be reindexed, or NULL */
-  char *z;                    /* Name of a table or index or collation */
-  const char *zDb;            /* Name of the database */
-  Table *pTab;                /* A table in the database */
-  Index *pIndex;              /* An index associated with pTab */
-  int iDb;                    /* The database index number */
+  char *z = 0;                /* Name of a table or index or collation */
+  const char *zDb = 0;        /* Name of the database */
+  int iReDb = -1;             /* The database index number */
   sqlite3 *db = pParse->db;   /* The database connection */
   Token *pObjName;            /* Name of the table or index to be reindexed */
+  int bMatch = 0;             /* At least one name match */
+  const char *zColl = 0;      /* Rebuild indexes using this collation */
+  Table *pReTab = 0;          /* Rebuild all indexes of this table */
+  Index *pReIndex = 0;        /* Rebuild this index */
+  int isExprIdx = 0;          /* Rebuild all expression indexes */
+  int bAll = 0;               /* Rebuild all indexes */
 
   /* Read the database schema. If an error occurs, leave an error message
   ** and code in pParse and return NULL. */
@@ -5644,43 +5580,64 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
   }
 
   if( pName1==0 ){
-    reindexDatabases(pParse, 0);
-    return;
+    /* rebuild all indexes */
+    bMatch = 1;
+    bAll = 1;
   }else if( NEVER(pName2==0) || pName2->z==0 ){
     assert( pName1->z );
     z = sqlite3NameFromToken(pParse->db, pName1);
     if( z==0 ) return;
-    pColl = sqlite3FindCollSeq(db, ENC(db), z, 0);
-    if( pColl ){
-      reindexDatabases(pParse, z);
-      goto reindex_done;
-    }
-    sqlite3DbFree(db, z);
-  }
-  iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName);
-  if( iDb<0 ) return;
-  z = sqlite3NameFromToken(db, pObjName);
-  if( z==0 ) return;
-  zDb = pName2->n ? db->aDb[iDb].zDbSName : 0;
-  pTab = sqlite3FindTable(db, z, zDb);
-  if( pTab ){
-    reindexTable(pParse, pTab, 0);
-    goto reindex_done;
+  }else{
+    iReDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName);
+    if( iReDb<0 ) return;
+    z = sqlite3NameFromToken(db, pObjName);
+    if( z==0 ) return;
+    zDb = pName2->n ? db->aDb[iReDb].zDbSName : 0;
   }
-  pIndex = sqlite3FindIndex(db, z, zDb);
-  if( pIndex ){
-    iDb = sqlite3SchemaToIndex(db, pIndex->pTable->pSchema);
-    sqlite3BeginWriteOperation(pParse, 0, iDb);
-    sqlite3RefillIndex(pParse, pIndex, -1);
-    goto reindex_done;
+  if( !bAll ){
+    if( zDb==0 && sqlite3StrICmp(z, "expressions")==0 ){
+      isExprIdx = 1;
+      bMatch = 1;
+    }
+    if( zDb==0 && (pColl = sqlite3FindCollSeq(db, ENC(db), z, 0))!=0 ){
+      zColl = z;
+      bMatch = 1;
+    }
+    if( zColl==0 && (pReTab = sqlite3FindTable(db, z, zDb))!=0 ){
+      bMatch = 1; 
+    }
+    if( zColl==0 && (pReIndex = sqlite3FindIndex(db, z, zDb))!=0 ){
+      bMatch = 1;
+    }
   }
-  if( zDb==0 && sqlite3StrICmp(z,zExpressionsKW)==0 ){
-    reindexDatabases(pParse, zExpressionsKW);
-    goto reindex_done;
+  if( bMatch ){
+    int iDb;
+    HashElem *k;
+    Table *pTab;
+    Index *pIdx;
+    Db *pDb;
+    for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){
+      assert( pDb!=0 );
+      if( iReDb>=0 && iReDb!=iDb ) continue;
+      for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){
+        pTab = (Table*)sqliteHashData(k);
+        if( IsVirtual(pTab) ) continue;
+        for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+          if( bAll
+           || pTab==pReTab
+           || pIdx==pReIndex
+           || (isExprIdx && pIdx->bHasExpr)
+           || (zColl!=0 && collationMatch(zColl,pIdx))
+          ){
+            sqlite3BeginWriteOperation(pParse, 0, iDb);
+            sqlite3RefillIndex(pParse, pIdx, -1);
+          }
+        } /* End loop over indexes of pTab */
+      } /* End loop over tables of iDb */
+    } /* End loop over databases */
+  }else{
+    sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed");
   }
-  sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed");
-
-reindex_done:
   sqlite3DbFree(db, z);
   return;
 }
index 1d56f70343563f026fc0d7d87b4ea57f107ed6a1..f378b900af978f8306dfa20de477bab01b9a764f 100644 (file)
@@ -1922,8 +1922,8 @@ do_test auth-1.283 {
   execsql {
     REINDEX BINARY;
   }
-  set ::authargs
-} {t3_idx1 {} main {} sqlite_autoindex_t3_1 {} main {}}
+  lsort -unique $::authargs
+} {{} main sqlite_autoindex_t3_1 t3_idx1 t3_idx2}
 do_test auth-1.284 {
   set ::authargs {}
   execsql {
@@ -1963,8 +1963,8 @@ ifcapable tempdb {
     execsql {
       REINDEX BINARY;
     }
-    set ::authargs
-  } {t3_idx1 {} temp {} sqlite_autoindex_t3_1 {} temp {}}
+    lsort -unique $::authargs
+  } {{} sqlite_autoindex_t3_1 t3_idx1 t3_idx2 temp}
   do_test auth-1.290 {
     set ::authargs {}
     execsql {