diff --git a/manifest b/manifest index 5adb28c094..14f12d8ea4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Use\ssqlite3NestedParse\sto\simplement\sDROP\sINDEX.\s(CVS\s2071) -D 2004-11-05T22:18:49 +C First\scut\sat\sa\sREINDEX\scommand.\s\sBasic\stesting\sonly.\s\sNo\sdocumentation.\s(CVS\s2072) +D 2004-11-05T23:46:15 F Makefile.in c4d2416860f472a1e3393714d0372074197565df F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1 @@ -31,7 +31,7 @@ F src/attach.c e49d09dad9f5f9fb10b4b0c1be5a70ae4c45e689 F src/auth.c 3b81f2a42f48a62c2c9c9b0eda31a157c681edea F src/btree.c bf0d3d59ec076f0a37378f8ac6090d157d925c24 F src/btree.h 861e40b759a195ba63819740e484390012cf81ab -F src/build.c e498f958ebb4678e103224edd3a5c2ebcc42d18f +F src/build.c 154e7a666a7b36da04c739a6af87d5e9bdcd0cda F src/date.c 34bdb0082db7ec2a83ef00063f7b44e61ee19dad F src/delete.c f0af21a1ede15524a5edd59fe10ef486283a1ee9 F src/expr.c be18081d2959a2cc53846d0fbedfec40fbfa1d6e @@ -54,17 +54,17 @@ F src/os_win.c 9482dfc92f289b68205bb2c9315757c7e3946bfb F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b F src/pager.c 868c67e4ff8a1785c06caaf483fddb5a95013af0 F src/pager.h 9eba8c53dd91eae7f3f90743b2ee242da02a9862 -F src/parse.y 97247c0a89ca1667729db5035f1ee60140960984 +F src/parse.y 8456726833755ecd6dac9bcd8af205c8dc419d01 F src/pragma.c 6a0ae7721e614c5a921e918ab5206d5e654f1a6f F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 F src/select.c 156990c636102bb6b8de85e7ff3396a62568476b F src/shell.c 55adda3cf3c1cc2f6c1919aac17b2318f9c2a96f F src/sqlite.h.in 4f97b5907acfd2a5068cb0cec9d5178816734db7 -F src/sqliteInt.h 5d26b41b2ab7eeab1bd9db330ed7b7929d2ae875 +F src/sqliteInt.h 9f846c4b752b9a1237e8250f8f8b3ecd1347a086 F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9 F src/tclsqlite.c 0302e3f42f015d132d1291f3388c06e86c24a008 -F src/test1.c df1d1ca2c40cafefb9a29860f072c4d0fee1a7b5 +F src/test1.c 91345097d94b4ad71f88776c2764e18c7955502a F src/test2.c b11fa244fff02190707dd0879987c37c75e61fc8 F src/test3.c de9edf178c02707cd37fd80b54e4c2ea77251cc0 F src/test4.c 7c6b9fc33dd1f3f93c7f1ee6e5e6d016afa6c1df @@ -160,6 +160,7 @@ F test/printf.test 92ba4c510b4fc61120ffa4a01820446ed917ae57 F test/progress.test 5ddba78cb6011fba36093973cfb3ac473b8fb96a x F test/quick.test 2dca186ebd5c418a7699944ba3b5e437d765eddd F test/quote.test 6d75cf635d93ba2484dc9cb378d88cbae9dc2c62 +F test/reindex.test 1d579cdb942c5f9c26c7f8c94cdc3024cabf2644 F test/rollback.test 4097328d44510277244ef4fa51b22b2f11d7ef4c F test/rowid.test 1ce3f1520d2082b0363e7d9bdef904cb72b9efe8 F test/select1.test 0e459a8066259445d707cc4f64ea00459441e29f @@ -252,7 +253,7 @@ F www/tclsqlite.tcl 560ecd6a916b320e59f2917317398f3d59b7cc25 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0 F www/whentouse.tcl fdacb0ba2d39831e8a6240d05a490026ad4c4e4c -P 47d8ebdaaddcb7a05e1917dd1dee2029c34228a4 -R d45e3580de79d7367f59fbd57af5e6a1 +P 0f81aa5b057eab908b46b70ea9e9a42bc2ee8c21 +R 877c89049e39a4d803a0375d417e1d42 U drh -Z 4c43f2f11733856473822a7670e21c59 +Z 82c5d66bdd823220be3997a2e30a2b5d diff --git a/manifest.uuid b/manifest.uuid index cc9caa8dd0..0a6ff8bac4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0f81aa5b057eab908b46b70ea9e9a42bc2ee8c21 \ No newline at end of file +11dba47e61279bdf3be6f64a6259b877f3bf6155 \ No newline at end of file diff --git a/src/build.c b/src/build.c index c796cf3a94..92ddfd702b 100644 --- a/src/build.c +++ b/src/build.c @@ -21,13 +21,8 @@ ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK -** PRAGMA ** -<<<<<<< build.c -** $Id: build.c,v 1.270 2004/11/05 22:18:49 drh Exp $ -======= -** $Id: build.c,v 1.270 2004/11/05 22:18:49 drh Exp $ ->>>>>>> 1.262 +** $Id: build.c,v 1.271 2004/11/05 23:46:15 drh Exp $ */ #include "sqliteInt.h" #include @@ -1989,6 +1984,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ int addr1; /* Address of top of loop */ int tnum; /* Root page of index */ Vdbe *v; /* Generate code into this virtual machine */ + int isUnique; /* True for a unique index */ v = sqlite3GetVdbe(pParse); if( v==0 ) return; @@ -2007,8 +2003,11 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ sqlite3VdbeAddOp(v, OP_SetNumColumns, iTab, pTab->nCol); addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0); sqlite3GenerateIndexKey(v, pIndex, iTab); - sqlite3VdbeOp3(v, OP_IdxPut, iIdx, pIndex->onError!=OE_None, - "indexed columns are not unique", P3_STATIC); + isUnique = pIndex->onError!=OE_None; + sqlite3VdbeAddOp(v, OP_IdxPut, iIdx, isUnique); + if( isUnique ){ + sqlite3VdbeChangeP3(v, -1, "indexed columns are not unique", P3_STATIC); + } sqlite3VdbeAddOp(v, OP_Next, iTab, addr1+1); sqlite3VdbeChangeP2(v, addr1, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeAddOp(v, OP_Close, iTab, 0); @@ -2760,3 +2759,107 @@ sqlite3_value *sqlite3GetTransientValue(sqlite3 *db){ } return db->pValue; } + +/* +** Check to see if pIndex uses the collating sequence pColl. Return +** true if it does and false if it does not. +*/ +#ifndef SQLITE_OMIT_REINDEX +static int collationMatch(CollSeq *pColl, Index *pIndex){ + int n = pIndex->keyInfo.nField; + CollSeq **pp = pIndex->keyInfo.aColl; + while( n-- ){ + if( *pp==pColl ) return 1; + pp++; + } + return 0; +} +#endif + +/* +** Recompute all indices of pTab that use the collating sequence pColl. +** If pColl==0 then recompute all indices of pTab. +*/ +#ifndef SQLITE_OMIT_REINDEX +void reindexTable(Parse *pParse, Table *pTab, CollSeq *pColl){ + Index *pIndex; /* An index associated with pTab */ + + for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){ + if( pColl==0 || collationMatch(pColl,pIndex) ){ + sqlite3BeginWriteOperation(pParse, 0, pTab->iDb); + sqlite3RefillIndex(pParse, pIndex, -1); + } + } +} +#endif + +/* +** Recompute all indices of all tables in all databases where the +** indices use the collating sequence pColl. If pColl==0 then recompute +** all indices everywhere. +*/ +#ifndef SQLITE_OMIT_REINDEX +void reindexDatabases(Parse *pParse, CollSeq *pColl){ + 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 */ + + for(iDb=0, pDb=db->aDb; iDbnDb; iDb++, pDb++){ + if( pDb==0 ) continue; + for(k=sqliteHashFirst(&pDb->tblHash); k; k=sqliteHashNext(k)){ + pTab = (Table*)sqliteHashData(k); + reindexTable(pParse, pTab, pColl); + } + } +} +#endif + +/* +** Generate code for a REINDEX command. If the argument is present it +** is the name of a collating sequence and all indices that use that +** collating sequence should be reindexed. If no argument is present, +** then rebuild all indices +*/ +#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 */ + 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 */ + sqlite3 *db = pParse->db; /* The database connection */ + Token *pObjName; /* Name of the table or index to be reindexed */ + + if( pName1==0 ){ + reindexDatabases(pParse, 0); + return; + }else if( pName2==0 ){ + pColl = sqlite3FindCollSeq(db, db->enc, pName1->z, pName1->n, 0); + if( pColl ){ + reindexDatabases(pParse, pColl); + return; + } + } + iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName); + if( iDb<0 ) return; + z = sqlite3NameFromToken(pObjName); + zDb = db->aDb[iDb].zName; + pTab = sqlite3FindTable(db, z, zDb); + if( pTab ){ + reindexTable(pParse, pTab, 0); + sqliteFree(z); + return; + } + pIndex = sqlite3FindIndex(db, z, zDb); + sqliteFree(z); + if( pIndex ){ + sqlite3BeginWriteOperation(pParse, 0, iDb); + sqlite3RefillIndex(pParse, pIndex, -1); + return; + } + sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed"); +} +#endif diff --git a/src/parse.y b/src/parse.y index f9990525dd..4193ac4c95 100644 --- a/src/parse.y +++ b/src/parse.y @@ -14,7 +14,7 @@ ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.149 2004/11/05 05:10:29 drh Exp $ +** @(#) $Id: parse.y,v 1.150 2004/11/05 23:46:15 drh Exp $ */ %token_prefix TK_ %token_type {Token} @@ -920,3 +920,9 @@ database_kw_opt ::= . cmd ::= DETACH database_kw_opt nm(D). { sqlite3Detach(pParse, &D); } + +////////////////////////// REINDEX collation ////////////////////////////////// +%ifndef SQLITE_OMIT_REINDEX +cmd ::= REINDEX. {sqlite3Reindex(pParse, 0, 0);} +cmd ::= REINDEX nm(X) dbnm(Y). {sqlite3Reindex(pParse, &X, &Y);} +%endif diff --git a/src/sqliteInt.h b/src/sqliteInt.h index a0d8ecddcb..b6e7dfcf81 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.334 2004/11/05 17:17:50 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.335 2004/11/05 23:46:15 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1455,5 +1455,6 @@ sqlite3_value *sqlite3ValueNew(); sqlite3_value *sqlite3GetTransientValue(sqlite3*db); extern const unsigned char sqlite3UpperToLower[]; void sqlite3RootPageMoved(Db*, int, int); +void sqlite3Reindex(Parse*, Token*, Token*); #endif diff --git a/src/test1.c b/src/test1.c index 1dd4a793d0..02a722e835 100644 --- a/src/test1.c +++ b/src/test1.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test1.c,v 1.107 2004/11/03 16:27:01 drh Exp $ +** $Id: test1.c,v 1.108 2004/11/05 23:46:15 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -2558,6 +2558,11 @@ static void set_options(Tcl_Interp *interp){ #else Tcl_SetVar2(interp, "sqlite_options", "bloblit", "1", TCL_GLOBAL_ONLY); #endif +#ifdef SQLITE_OMIT_REINDEX + Tcl_SetVar2(interp, "sqlite_options", "reindex", "0", TCL_GLOBAL_ONLY); +#else + Tcl_SetVar2(interp, "sqlite_options", "reindex", "1", TCL_GLOBAL_ONLY); +#endif } /* diff --git a/test/reindex.test b/test/reindex.test new file mode 100644 index 0000000000..1dc7956329 --- /dev/null +++ b/test/reindex.test @@ -0,0 +1,66 @@ +# 2004 November 5 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# This file implements tests for the REINDEX command. +# +# $Id: reindex.test,v 1.1 2004/11/05 23:46:15 drh Exp $ + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# There is nothing to test if REINDEX is disable for this build. +# +ifcapable {!reindex} { + finish_test + return +} + +# Basic sanity checks. +# +do_test reindex-1.1 { + execsql { + CREATE TABLE t1(a,b); + INSERT INTO t1 VALUES(1,2); + INSERT INTO t1 VALUES(3,4); + CREATE INDEX i1 ON t1(a); + REINDEX; + } +} {} +integrity_check reindex-1.2 +do_test reindex-1.3 { + execsql { + REINDEX t1; + } +} {} +integrity_check reindex-1.4 +do_test reindex-1.5 { + execsql { + REINDEX i1; + } +} {} +integrity_check reindex-1.6 +do_test reindex-1.7 { + execsql { + REINDEX main.t1; + } +} {} +do_test reindex-1.8 { + execsql { + REINDEX main.i1; + } +} {} +do_test reindex-1.9 { + catchsql { + REINDEX bogus + } +} {1 {unable to identify the object to be reindexed}} + +finish_test