From: drh <> Date: Fri, 20 Mar 2026 19:30:58 +0000 (+0000) Subject: If the argument to REINDEX is EXPRESSIONS (with no schema prefix) then it X-Git-Tag: major-release~65^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f163bfba4edf4c574705a0e3c0544e866582b973;p=thirdparty%2Fsqlite.git If the argument to REINDEX is EXPRESSIONS (with no schema prefix) then it updates both expression indexes, and any indexes named "expressions" or all indexes of any tables name "expressions". FossilOrigin-Name: 72650dc152279a6da1937f377b1e16b79f4cd664841e12222dc5459838408d22 --- diff --git a/manifest b/manifest index 73930bf865..d427d530e6 100644 --- 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. diff --git a/manifest.uuid b/manifest.uuid index 19509a7e47..58dad7f5ef 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -df5c5aa26758e0dc00a9ccba29eac83071176d257e121207e0a13c54833b18c0 +72650dc152279a6da1937f377b1e16b79f4cd664841e12222dc5459838408d22 diff --git a/src/build.c b/src/build.c index 94c3f52624..f7e2806175 100644 --- a/src/build.c +++ b/src/build.c @@ -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; inColumn; 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; iDbnDb; 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 -- 2 -** REINDEX ?.? -- 3 -** REINDEX ?.? -- 4 +** REINDEX ?.? -- 3 +** REINDEX ?.? -- 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; iDbnDb; 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; } diff --git a/test/auth.test b/test/auth.test index 1d56f70343..f378b900af 100644 --- a/test/auth.test +++ b/test/auth.test @@ -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 {