First cut at a REINDEX command. Basic testing only. No documentation. (CVS 2072)
FossilOrigin-Name: 11dba47e61279bdf3be6f64a6259b877f3bf6155
diff --git a/src/build.c b/src/build.c
index c796cf3..92ddfd7 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 <ctype.h>
@@ -1989,6 +1984,7 @@
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 @@
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 @@
}
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; iDb<db->nDb; 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 f999052..4193ac4 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 @@
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 a0d8ecd..b6e7dfc 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 *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 1dd4a79..02a722e 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 @@
#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
}
/*