]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Support root-page allocation/deallocation in auto-vacuum databases. Still a few probl...
authordanielk1977 <danielk1977@noemail.net>
Thu, 4 Nov 2004 14:30:04 +0000 (14:30 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Thu, 4 Nov 2004 14:30:04 +0000 (14:30 +0000)
FossilOrigin-Name: 1da361fae82d420be63c53f8e3efaccac24f348a

manifest
manifest.uuid
src/btree.c
src/btree.h
src/build.c
src/pager.c
src/sqliteInt.h
src/test3.c
src/vdbe.c
test/autovacuum.test

index d4f99325ab1df9bca06a02dcc3cbc9decf8baf0d..3539df3f2f106610945a6a0031f43e2bdf9b2159 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C All\stests\spass\seven\sif\sOMIT_TRIGGER\sis\sdefined.\s(CVS\s2053)
-D 2004-11-04T04:42:28
+C Support\sroot-page\sallocation/deallocation\sin\sauto-vacuum\sdatabases.\sStill\sa\sfew\sproblems.\s(CVS\s2054)
+D 2004-11-04T14:30:05
 F Makefile.in c4d2416860f472a1e3393714d0372074197565df
 F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
 F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1
@@ -29,9 +29,9 @@ F sqlite3.def dbaeb20c153e1d366e8f421b55a573f5dfc00863
 F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a
 F src/attach.c e49d09dad9f5f9fb10b4b0c1be5a70ae4c45e689
 F src/auth.c 3b81f2a42f48a62c2c9c9b0eda31a157c681edea
-F src/btree.c 93163198e6fb666b92c893fba5edb3ef6f335c0f
-F src/btree.h 94dfec0a1722d33359b23e7e310f2b64ffedf029
-F src/build.c bb896c5f85ab749d17ae5d730235134c12c08033
+F src/btree.c a3e45d54eb1a81698f609693c22df382dfbf9151
+F src/btree.h 3166388fa58c5594d8064d38b43440d79da38fb6
+F src/build.c 89d1ace10837e61d11cf9818750d8782369ac3f5
 F src/date.c 34bdb0082db7ec2a83ef00063f7b44e61ee19dad
 F src/delete.c 52980e594e69e80374fb928fe611d5f75ca4e390
 F src/expr.c 3a43e508a3dc213703808bbcbb17633b88b57d17
@@ -52,7 +52,7 @@ F src/os_unix.c 5824b22ba41fe9d514ef9169aac1b5fde73af229
 F src/os_unix.h f3097815e041e82e24d92505e1ff61ba24172d13
 F src/os_win.c 9482dfc92f289b68205bb2c9315757c7e3946bfb
 F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
-F src/pager.c 9ce238f9540eb56b21fef085dc038dffca75835b
+F src/pager.c a43e2a392be51966129e9afb18b81551c9f222b8
 F src/pager.h cbe4ba356d9dd3f30260f322b3dc77408164df14
 F src/parse.y 4a27450611ed2b8c359078e04daf93c50b1d22dd
 F src/pragma.c 44e192eb5928157bdb015926f858a7c6e3ef6c98
@@ -61,12 +61,12 @@ 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 84d5ca7b02793697641a74fb125fcee3995ea2ff
+F src/sqliteInt.h 8b93c9d7b7343b9013ffb73cbd2cb6ea4f546c62
 F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9
 F src/tclsqlite.c 0302e3f42f015d132d1291f3388c06e86c24a008
 F src/test1.c df1d1ca2c40cafefb9a29860f072c4d0fee1a7b5
 F src/test2.c b11fa244fff02190707dd0879987c37c75e61fc8
-F src/test3.c f423597e220b3d446a65c9cc0c49cb4eb00c0215
+F src/test3.c b6aece10ee51579d0f75d09137b3c94c80b3c278
 F src/test4.c 7c6b9fc33dd1f3f93c7f1ee6e5e6d016afa6c1df
 F src/test5.c b001fa7f1b9e2dc5c2331de62fc641b5ab2bd7a1
 F src/tokenize.c bf9de9689b3bb813d65784bf54472804bf9595e6
@@ -75,7 +75,7 @@ F src/update.c 7b17b281d600bf3e220b3c5718e0883442dee722
 F src/utf.c f4f83acd73389090e32d6589d307fc55d794c7ed
 F src/util.c 005fdf2d008f3429d081766ad6098fdd86d8d8e6
 F src/vacuum.c ecb4a2c6f1ac5cc9b394dc64d3bb14ca650c4f60
-F src/vdbe.c a156e1a2f324e5e11d82af3fbbf41df7a174c860
+F src/vdbe.c cf7eb35b5a649c11345c5f85ad7b1511253431cc
 F src/vdbe.h 067ca8d6750ba4f69a50284765e5883dee860181
 F src/vdbeInt.h 6017100adff362b8dfa37a69e3f1431f084bfa5b
 F src/vdbeapi.c 3965bf4678ae32c05f73550c1b5be3268f9f3006
@@ -87,7 +87,7 @@ F test/attach.test ff7fc16b4518a448fed47dfb3694bf57f522d552
 F test/attach2.test f7795123d3051ace1672b6d23973da6435de3745
 F test/attach3.test 742c932d7130e0e699a5d9f265cb831e0a824633
 F test/auth.test 1cc252d9e7b3bdc1314199cbf3a0d3c5ed026c21
-F test/autovacuum.test 9211914801ad35ad8f0fc15711b12461850ef2ac
+F test/autovacuum.test a5b11269daac313bea6694b04473fdd0e16e439a
 F test/bigfile.test d3744a8821ce9abb8697f2826a3e3d22b719e89f
 F test/bigrow.test f0aeb7573dcb8caaafea76454be3ade29b7fc747
 F test/bind.test fa74f98417cd313f28272acff832a8a7d04a0916
@@ -252,7 +252,7 @@ F www/tclsqlite.tcl 560ecd6a916b320e59f2917317398f3d59b7cc25
 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9
 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
 F www/whentouse.tcl fdacb0ba2d39831e8a6240d05a490026ad4c4e4c
-P da045bd183335a112f9a6c805c12efe12d0a25ca
-R 3020d6f48bce04fcef7f5133e21d3db2
-U drh
-Z 625b1d515abab0cebf7c5f6337f4ff8c
+P c33b3a613751057e8a46fdcd428b8448329d414d
+R 904dc0805c4ad385b004eaf63c77188e
+U danielk1977
+Z d7dc31bf4e5f4e3f4969266ba871dca0
index bfcf2e9e7ae66e7d89e5f934d2d49750db8328e3..780cdb4cdbccc16f92ff8a51d5a94ac904a4c325 100644 (file)
@@ -1 +1 @@
-c33b3a613751057e8a46fdcd428b8448329d414d
\ No newline at end of file
+1da361fae82d420be63c53f8e3efaccac24f348a
\ No newline at end of file
index 218ad74d43839b7488c3b9b3c805487754ec3540..a91b234f8fa2705e235ccbb4b6ad6a00c5b99d49 100644 (file)
@@ -9,7 +9,7 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
-** $Id: btree.c,v 1.203 2004/11/04 02:57:34 danielk1977 Exp $
+** $Id: btree.c,v 1.204 2004/11/04 14:30:05 danielk1977 Exp $
 **
 ** This file implements a external (disk-based) database using BTrees.
 ** For a detailed discussion of BTrees, refer to
@@ -1624,8 +1624,8 @@ static int relocatePage(
   Pager *pPager = pBt->pPager;
   int rc;
 
-  assert( eType==PTRMAP_OVERFLOW2 
-      || eType==PTRMAP_OVERFLOW1 || eType==PTRMAP_BTREE );
+  assert( eType==PTRMAP_OVERFLOW2 || eType==PTRMAP_OVERFLOW1 || 
+      eType==PTRMAP_BTREE || eType==PTRMAP_ROOTPAGE );
 
   /* Move page iDbPage from it's current location to page number iFreePage */
   TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n", 
@@ -1644,7 +1644,7 @@ static int relocatePage(
   ** pointer to a subsequent overflow page. If this is the case, then
   ** the pointer map needs to be updated for the subsequent overflow page.
   */
-  if( eType==PTRMAP_BTREE ){
+  if( eType==PTRMAP_BTREE || eType==PTRMAP_ROOTPAGE ){
     rc = setChildPtrmaps(pDbPage);
     if( rc!=SQLITE_OK ){
       return rc;
@@ -1664,18 +1664,20 @@ static int relocatePage(
   ** that it points at iFreePage. Also fix the pointer map entry for
   ** iPtrPage.
   */
-  rc = getPage(pBt, iPtrPage, &pPtrPage);
-  if( rc!=SQLITE_OK ){
-    return rc;
-  }
-  rc = sqlite3pager_write(pPtrPage->aData);
-  if( rc!=SQLITE_OK ){
+  if( eType!=PTRMAP_ROOTPAGE ){
+    rc = getPage(pBt, iPtrPage, &pPtrPage);
+    if( rc!=SQLITE_OK ){
+      return rc;
+    }
+    rc = sqlite3pager_write(pPtrPage->aData);
+    if( rc!=SQLITE_OK ){
+      releasePage(pPtrPage);
+      return rc;
+    }
+    modifyPagePointer(pPtrPage, iDbPage, iFreePage, eType);
+    rc = ptrmapPut(pBt, iFreePage, eType, iPtrPage);
     releasePage(pPtrPage);
-    return rc;
   }
-  modifyPagePointer(pPtrPage, iDbPage, iFreePage, eType);
-  rc = ptrmapPut(pBt, iFreePage, eType, iPtrPage);
-  releasePage(pPtrPage);
   return rc;
 }
 
@@ -1723,6 +1725,7 @@ static int autoVacuumCommit(Btree *pBt){
 
   TRACE(("AUTOVACUUM: Begin (db size %d->%d)\n", origSize, finSize));
 
+#if 0
   /* Note: This is temporary code for use during development of auto-vacuum. 
   **
   ** Inspect the pointer map to make sure there are no root pages with a
@@ -1738,6 +1741,7 @@ static int autoVacuumCommit(Btree *pBt){
       return SQLITE_OK;
     }
   }
+#endif
 
   /* Variable 'finSize' will be the size of the file in pages after
   ** the auto-vacuum has completed (the current file size minus the number
@@ -4287,6 +4291,7 @@ int sqlite3BtreeCreateTable(Btree *pBt, int *piTable, int flags){
         return rc;
       }
       rc = ptrmapGet(pBt, pgnoRoot, &eType, &iPtrPage);
+      assert( eType!=PTRMAP_ROOTPAGE );
       if( rc!=SQLITE_OK ){
         releasePage(pRoot);
         return rc;
@@ -4408,29 +4413,90 @@ int sqlite3BtreeClearTable(Btree *pBt, int iTable){
 ** This routine will fail with SQLITE_LOCKED if there are any open
 ** cursors on the table.
 */
-int sqlite3BtreeDropTable(Btree *pBt, int iTable){
+int sqlite3BtreeDropTable(Btree *pBt, int iTable, int *piMoved){
   int rc;
-  MemPage *pPage;
+  MemPage *pPage = 0;
   BtCursor *pCur;
-/* TODO: Disallow schema modifications if there are open cursors */
+
   if( pBt->inTrans!=TRANS_WRITE ){
     return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
   }
+
+/* TODO: Disallow schema modifications if there are open cursors */
   for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
     if( pCur->pgnoRoot==(Pgno)iTable ){
       return SQLITE_LOCKED;  /* Cannot drop a table that has a cursor */
     }
   }
+
   rc = getPage(pBt, (Pgno)iTable, &pPage);
   if( rc ) return rc;
   rc = sqlite3BtreeClearTable(pBt, iTable);
   if( rc ) return rc;
+
+  if( piMoved ) *piMoved = 0;
+
   if( iTable>1 ){
+#ifdef SQLITE_OMIT_AUTOVACUUM
     rc = freePage(pPage);
+    releasePage(pPage);
+#else
+    if( pBt->autoVacuum ){
+      Pgno maxRootPgno;
+      rc = sqlite3BtreeGetMeta(pBt, 4, &maxRootPgno);
+      if( rc!=SQLITE_OK ){
+        releasePage(pPage);
+        return rc;
+      }
+
+      if( iTable==maxRootPgno ){
+        /* If the table being dropped is the table with the largest root-page
+        ** number in the database, put the root page on the free list. 
+        */
+        rc = freePage(pPage);
+        releasePage(pPage);
+        if( rc!=SQLITE_OK ){
+          return rc;
+        }
+      }else{
+        /* The table being dropped does not have the largest root-page
+        ** number in the database. So move the page that does into the 
+        ** gap left by the deleted root-page.
+        */
+        MemPage *pMove;
+        releasePage(pPage);
+        rc = getPage(pBt, maxRootPgno, &pMove);
+        if( rc!=SQLITE_OK ){
+          return rc;
+        }
+        rc = relocatePage(pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable);
+        releasePage(pMove);
+        if( rc!=SQLITE_OK ){
+          return rc;
+        }
+        rc = getPage(pBt, maxRootPgno, &pMove);
+        if( rc!=SQLITE_OK ){
+          return rc;
+        }
+        rc = freePage(pMove);
+        releasePage(pMove);
+        if( rc!=SQLITE_OK ){
+          return rc;
+        }
+        *piMoved = maxRootPgno;
+      }
+
+      rc = sqlite3BtreeUpdateMeta(pBt, 4, maxRootPgno-1);
+    }else{
+      rc = freePage(pPage);
+      releasePage(pPage);
+    }
+#endif
   }else{
+    /* If sqlite3BtreeDropTable was called on page 1. */
     zeroPage(pPage, PTF_INTKEY|PTF_LEAF );
+    releasePage(pPage);
   }
-  releasePage(pPage);
   return rc;  
 }
 
index 3f247b77ae8250b3ea783418545a00ab37ce932a..8df9871f2109ddeb7c9598dd7eb9fcb1b2af278f 100644 (file)
@@ -13,7 +13,7 @@
 ** subsystem.  See comments in the source code for a detailed description
 ** of what each interface routine does.
 **
-** @(#) $Id: btree.h,v 1.58 2004/07/23 00:01:39 drh Exp $
+** @(#) $Id: btree.h,v 1.59 2004/11/04 14:30:05 danielk1977 Exp $
 */
 #ifndef _BTREE_H_
 #define _BTREE_H_
@@ -72,7 +72,7 @@ int sqlite3BtreeCopyFile(Btree *, Btree *);
 #define BTREE_ZERODATA   2    /* Table has keys only - no data */
 #define BTREE_LEAFDATA   4    /* Data stored in leaves only.  Implies INTKEY */
 
-int sqlite3BtreeDropTable(Btree*, int);
+int sqlite3BtreeDropTable(Btree*, int, int*);
 int sqlite3BtreeClearTable(Btree*, int);
 int sqlite3BtreeGetMeta(Btree*, int idx, u32 *pValue);
 int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
index 250ca28338b9aebe53d5dae791c0d136c4605fb8..027ae58c073c78db0ebdfd3e0c77e492544a4ed1 100644 (file)
@@ -23,7 +23,7 @@
 **     ROLLBACK
 **     PRAGMA
 **
-** $Id: build.c,v 1.258 2004/10/31 02:22:49 drh Exp $
+** $Id: build.c,v 1.259 2004/11/04 14:30:05 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -1554,6 +1554,141 @@ static void sqliteViewResetAll(sqlite3 *db, int idx){
 # define sqliteViewResetAll(A,B)
 #endif /* SQLITE_OMIT_VIEW */
 
+/*
+** This function is called by the VDBE to adjust the internal schema
+** used by SQLite when the btree layer moves a table root page. The
+** root-page of a table or index in database iDb has changed from iFrom
+** to iTo.
+*/
+#ifndef SQLITE_OMIT_AUTOVACUUM
+void sqlite3RootPageMoved(Db *pDb, int iFrom, int iTo){
+  HashElem *pElem;
+  
+  for(pElem=sqliteHashFirst(&pDb->tblHash); pElem; pElem=sqliteHashNext(pElem)){
+    Table *pTab = sqliteHashData(pElem);
+    if( pTab->tnum==iFrom ){
+      pTab->tnum = iTo;
+      return;
+    }
+  }
+  for(pElem=sqliteHashFirst(&pDb->idxHash); pElem; pElem=sqliteHashNext(pElem)){
+    Index *pIdx = sqliteHashData(pElem);
+    if( pIdx->tnum==iFrom ){
+      pIdx->tnum = iTo;
+      return;
+    }
+  }
+  assert(0);
+}
+#endif
+
+/*
+** Write code to erase the table with root-page iTable from database iDb.
+** Also write code to modify the sqlite_master table and internal schema
+** if a root-page of another table is moved by the btree-layer whilst
+** erasing iTable (this can happen with an auto-vacuum database).
+*/ 
+static void destroyRootPage(Vdbe *v, int iTable, int iDb){
+#ifndef SQLITE_OMIT_AUTOVACUUM
+  int base;
+#endif
+  sqlite3VdbeAddOp(v, OP_Destroy, iTable, iDb);
+#ifndef SQLITE_OMIT_AUTOVACUUM
+  /* If SQLITE_OMIT_AUTOVACUUM is not defined, then OP_Destroy pushes
+  ** an integer onto the stack. If this integer is non-zero, then it is
+  ** the root page number of a table moved to location iTable. The 
+  ** following writes VDBE code to modify the sqlite_master table to
+  ** reflect this. It is assumed that cursor number 0 is a write-cursor
+  ** opened on the sqlite_master table.
+  */
+  static const VdbeOpList updateMaster[] = {
+    /* If the Op_Destroy pushed a 0 onto the stack, then skip the following
+    ** code. sqlite_master does not need updating in this case.
+    */
+    { OP_Dup,        0, 0,        0},
+    { OP_Integer,    0, 0,        0},
+    { OP_Eq,         0, ADDR(17), 0},
+
+    /* Search for the sqlite_master row containing root-page iTable. */
+    { OP_Rewind,     0, ADDR(8), 0}, 
+    { OP_Dup,        0, 0,       0}, /* 4 */
+    { OP_Column,     0, 3,       0}, /* 5 */
+    { OP_Eq,         0, ADDR(9), 0},
+    { OP_Next,       0, ADDR(4), 0},
+    { OP_Halt,       SQLITE_CORRUPT, OE_Fail, 0}, /* 8 */
+    { OP_Recno,      0, 0,       0}, /* 9 */
+
+    /* Cursor 0 now points at the row that will be updated. The top of
+    ** the stack is the rowid of that row. The next value on the stack is 
+    ** the new value for the root-page field.
+    */
+    { OP_Column,     0, 0,       0}, /* 10 */
+    { OP_Column,     0, 1,       0},
+    { OP_Column,     0, 2,       0},
+    { OP_Integer,    4, 0,       0}, /* 13 */
+    { OP_Column,     0, 4,       0},
+    { OP_MakeRecord, 5, 0,       0},
+    { OP_PutIntKey,  0, 0,       0}  /* 16 */
+  };
+
+  base = sqlite3VdbeAddOpList(v, ArraySize(updateMaster), updateMaster);
+  sqlite3VdbeChangeP1(v, base+13, iTable);
+#endif
+}
+
+/*
+** Write VDBE code to erase table pTab and all associated indices on disk.
+** Code to update the sqlite_master tables and internal schema definitions
+** in case a root-page belonging to another table is moved by the btree layer
+** is also added (this can happen with an auto-vacuum database).
+*/
+static void destroyTable(Vdbe *v, Table *pTab){
+#ifdef SQLITE_OMIT_AUTOVACUUM
+  destroyRootPage(v, pTab->tnum, pTab->iDb);
+  for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+    destroyRootPage(v, pIdx->tnum, pIdx->iDb);
+  }
+#else
+  /* If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM
+  ** is not defined), then it is important to call OP_Destroy on the
+  ** table and index root-pages in order, starting with the numerically 
+  ** largest root-page number. This guarantees that none of the root-pages
+  ** to be destroyed is relocated by an earlier OP_Destroy. i.e. if the
+  ** following were coded:
+  **
+  ** OP_Destroy 4 0
+  ** ...
+  ** OP_Destroy 5 0
+  **
+  ** and root page 5 happened to be the largest root-page number in the
+  ** database, then root page 5 would be moved to page 4 by the 
+  ** "OP_Destroy 4 0" opcode. The subsequent "OP_Destroy 5 0" would hit
+  ** a free-list page.
+  */
+  int iTab = pTab->tnum;
+  int iDestroyed = 0;
+
+  while( 1 ){
+    Index *pIdx;
+    int iLargest = 0;
+
+    if( iDestroyed==0 || iTab<iDestroyed ){
+      iLargest = iTab;
+    }
+    for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+      int iIdx = pIdx->tnum;
+      assert( pIdx->iDb==pTab->iDb );
+      if( (iDestroyed==0 || (iIdx<iDestroyed)) && iIdx>iLargest ){
+        iLargest = iIdx;
+      }
+    }
+    if( iLargest==0 ) return;
+    destroyRootPage(v, iLargest, pTab->iDb);
+    iDestroyed = iLargest;
+  }
+#endif
+}
+
 /*
 ** This routine is called to do the work of a DROP TABLE statement.
 ** pName is the name of the table to be dropped.
@@ -1635,7 +1770,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){
       { OP_Goto,       0, ADDR(3),  0},
       { OP_Next,       0, ADDR(3),  0}, /* 12 */
     };
-    Index *pIdx;
+    /* Index *pIdx; */
     Trigger *pTrigger;
     sqlite3BeginWriteOperation(pParse, 0, pTab->iDb);
 
@@ -1661,13 +1796,16 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){
     base = sqlite3VdbeAddOpList(v, ArraySize(dropTable), dropTable);
     sqlite3VdbeChangeP3(v, base+1, pTab->zName, 0);
     sqlite3ChangeCookie(db, v, pTab->iDb);
-    sqlite3VdbeAddOp(v, OP_Close, 0, 0);
     if( !isView ){
+/*
       sqlite3VdbeAddOp(v, OP_Destroy, pTab->tnum, pTab->iDb);
       for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
         sqlite3VdbeAddOp(v, OP_Destroy, pIdx->tnum, pIdx->iDb);
       }
+*/
+      destroyTable(v, pTab);
     }
+    sqlite3VdbeAddOp(v, OP_Close, 0, 0);
     sqlite3VdbeOp3(v, OP_DropTable, pTab->iDb, 0, pTab->zName, 0);
   }
   sqliteViewResetAll(db, iDb);
@@ -2237,8 +2375,9 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName){
     base = sqlite3VdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
     sqlite3VdbeChangeP3(v, base+1, pIndex->zName, 0);
     sqlite3ChangeCookie(db, v, pIndex->iDb);
+    /* sqlite3VdbeAddOp(v, OP_Destroy, pIndex->tnum, pIndex->iDb); */
+    destroyRootPage(v, pIndex->tnum, pIndex->iDb);
     sqlite3VdbeAddOp(v, OP_Close, 0, 0);
-    sqlite3VdbeAddOp(v, OP_Destroy, pIndex->tnum, pIndex->iDb);
     sqlite3VdbeOp3(v, OP_DropIndex, pIndex->iDb, 0, pIndex->zName, 0);
   }
 
index fcbd407c3567a595c506aafa6d150ce899d06be8..0a5249ed6eae0ffe81480b5087a00b80f7303f9a 100644 (file)
@@ -18,7 +18,7 @@
 ** file simultaneously, or one process from reading the database while
 ** another is writing.
 **
-** @(#) $Id: pager.c,v 1.171 2004/11/03 08:44:06 danielk1977 Exp $
+** @(#) $Id: pager.c,v 1.172 2004/11/04 14:30:05 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -2588,115 +2588,115 @@ int sqlite3pager_write(void *pData){
   pPg->dirty = 1;
   if( pPg->inJournal && (pPg->inStmt || pPager->stmtInUse==0) ){
     pPager->dirtyCache = 1;
-    return SQLITE_OK;
-  }
-
-  /* If we get this far, it means that the page needs to be
-  ** written to the transaction journal or the ckeckpoint journal
-  ** or both.
-  **
-  ** First check to see that the transaction journal exists and
-  ** create it if it does not.
-  */
-  assert( pPager->state!=PAGER_UNLOCK );
-  rc = sqlite3pager_begin(pData, 0);
-  if( rc!=SQLITE_OK ){
-    return rc;
-  }
-  assert( pPager->state>=PAGER_RESERVED );
-  if( !pPager->journalOpen && pPager->useJournal ){
-    rc = pager_open_journal(pPager);
-    if( rc!=SQLITE_OK ) return rc;
-  }
-  assert( pPager->journalOpen || !pPager->useJournal );
-  pPager->dirtyCache = 1;
+  }else{
 
-  /* The transaction journal now exists and we have a RESERVED or an
-  ** EXCLUSIVE lock on the main database file.  Write the current page to
-  ** the transaction journal if it is not there already.
-  */
-  if( !pPg->inJournal && (pPager->useJournal || MEMDB) ){
-    if( (int)pPg->pgno <= pPager->origDbSize ){
-      int szPg;
-      u32 saved;
+    /* If we get this far, it means that the page needs to be
+    ** written to the transaction journal or the ckeckpoint journal
+    ** or both.
+    **
+    ** First check to see that the transaction journal exists and
+    ** create it if it does not.
+    */
+    assert( pPager->state!=PAGER_UNLOCK );
+    rc = sqlite3pager_begin(pData, 0);
+    if( rc!=SQLITE_OK ){
+      return rc;
+    }
+    assert( pPager->state>=PAGER_RESERVED );
+    if( !pPager->journalOpen && pPager->useJournal ){
+      rc = pager_open_journal(pPager);
+      if( rc!=SQLITE_OK ) return rc;
+    }
+    assert( pPager->journalOpen || !pPager->useJournal );
+    pPager->dirtyCache = 1;
+  
+    /* The transaction journal now exists and we have a RESERVED or an
+    ** EXCLUSIVE lock on the main database file.  Write the current page to
+    ** the transaction journal if it is not there already.
+    */
+    if( !pPg->inJournal && (pPager->useJournal || MEMDB) ){
+      if( (int)pPg->pgno <= pPager->origDbSize ){
+        int szPg;
+        u32 saved;
+        if( MEMDB ){
+          PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
+          TRACE3("JOURNAL %d page %d\n", pPager->fd.h, pPg->pgno);
+          assert( pHist->pOrig==0 );
+          pHist->pOrig = sqliteMallocRaw( pPager->pageSize );
+          if( pHist->pOrig ){
+            memcpy(pHist->pOrig, PGHDR_TO_DATA(pPg), pPager->pageSize);
+          }
+        }else{
+          u32 cksum;
+          CODEC(pPager, pData, pPg->pgno, 7);
+          cksum = pager_cksum(pPager, pPg->pgno, pData);
+          saved = *(u32*)PGHDR_TO_EXTRA(pPg, pPager);
+          store32bits(cksum, pPg, pPager->pageSize);
+          szPg = pPager->pageSize+8;
+          store32bits(pPg->pgno, pPg, -4);
+          rc = sqlite3OsWrite(&pPager->jfd, &((char*)pData)[-4], szPg);
+          pPager->journalOff += szPg;
+          TRACE4("JOURNAL %d page %d needSync=%d\n",
+                  pPager->fd.h, pPg->pgno, pPg->needSync);
+          CODEC(pPager, pData, pPg->pgno, 0);
+          *(u32*)PGHDR_TO_EXTRA(pPg, pPager) = saved;
+          if( rc!=SQLITE_OK ){
+            sqlite3pager_rollback(pPager);
+            pPager->errMask |= PAGER_ERR_FULL;
+            return rc;
+          }
+          pPager->nRec++;
+          assert( pPager->aInJournal!=0 );
+          pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7);
+          pPg->needSync = !pPager->noSync;
+          if( pPager->stmtInUse ){
+            pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
+            page_add_to_stmt_list(pPg);
+          }
+        }
+      }else{
+        pPg->needSync = !pPager->journalStarted && !pPager->noSync;
+        TRACE4("APPEND %d page %d needSync=%d\n",
+                pPager->fd.h, pPg->pgno, pPg->needSync);
+      }
+      if( pPg->needSync ){
+        pPager->needSync = 1;
+      }
+      pPg->inJournal = 1;
+    }
+  
+    /* If the statement journal is open and the page is not in it,
+    ** then write the current page to the statement journal.  Note that
+    ** the statement journal format differs from the standard journal format
+    ** in that it omits the checksums and the header.
+    */
+    if( pPager->stmtInUse && !pPg->inStmt && (int)pPg->pgno<=pPager->stmtSize ){
+      assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize );
       if( MEMDB ){
         PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
-        TRACE3("JOURNAL %d page %d\n", pPager->fd.h, pPg->pgno);
-        assert( pHist->pOrig==0 );
-        pHist->pOrig = sqliteMallocRaw( pPager->pageSize );
-        if( pHist->pOrig ){
-          memcpy(pHist->pOrig, PGHDR_TO_DATA(pPg), pPager->pageSize);
+        assert( pHist->pStmt==0 );
+        pHist->pStmt = sqliteMallocRaw( pPager->pageSize );
+        if( pHist->pStmt ){
+          memcpy(pHist->pStmt, PGHDR_TO_DATA(pPg), pPager->pageSize);
         }
+        TRACE3("STMT-JOURNAL %d page %d\n", pPager->fd.h, pPg->pgno);
       }else{
-        u32 cksum;
-        CODEC(pPager, pData, pPg->pgno, 7);
-        cksum = pager_cksum(pPager, pPg->pgno, pData);
-        saved = *(u32*)PGHDR_TO_EXTRA(pPg, pPager);
-        store32bits(cksum, pPg, pPager->pageSize);
-        szPg = pPager->pageSize+8;
         store32bits(pPg->pgno, pPg, -4);
-        rc = sqlite3OsWrite(&pPager->jfd, &((char*)pData)[-4], szPg);
-        pPager->journalOff += szPg;
-        TRACE4("JOURNAL %d page %d needSync=%d\n",
-                pPager->fd.h, pPg->pgno, pPg->needSync);
+        CODEC(pPager, pData, pPg->pgno, 7);
+        rc = sqlite3OsWrite(&pPager->stfd,((char*)pData)-4, pPager->pageSize+4);
+        TRACE3("STMT-JOURNAL %d page %d\n", pPager->fd.h, pPg->pgno);
         CODEC(pPager, pData, pPg->pgno, 0);
-        *(u32*)PGHDR_TO_EXTRA(pPg, pPager) = saved;
         if( rc!=SQLITE_OK ){
           sqlite3pager_rollback(pPager);
           pPager->errMask |= PAGER_ERR_FULL;
           return rc;
         }
-        pPager->nRec++;
-        assert( pPager->aInJournal!=0 );
-        pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7);
-        pPg->needSync = !pPager->noSync;
-        if( pPager->stmtInUse ){
-          pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
-          page_add_to_stmt_list(pPg);
-        }
-      }
-    }else{
-      pPg->needSync = !pPager->journalStarted && !pPager->noSync;
-      TRACE4("APPEND %d page %d needSync=%d\n",
-              pPager->fd.h, pPg->pgno, pPg->needSync);
-    }
-    if( pPg->needSync ){
-      pPager->needSync = 1;
-    }
-    pPg->inJournal = 1;
-  }
-
-  /* If the statement journal is open and the page is not in it,
-  ** then write the current page to the statement journal.  Note that
-  ** the statement journal format differs from the standard journal format
-  ** in that it omits the checksums and the header.
-  */
-  if( pPager->stmtInUse && !pPg->inStmt && (int)pPg->pgno<=pPager->stmtSize ){
-    assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize );
-    if( MEMDB ){
-      PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
-      assert( pHist->pStmt==0 );
-      pHist->pStmt = sqliteMallocRaw( pPager->pageSize );
-      if( pHist->pStmt ){
-        memcpy(pHist->pStmt, PGHDR_TO_DATA(pPg), pPager->pageSize);
+        pPager->stmtNRec++;
+        assert( pPager->aInStmt!=0 );
+        pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
       }
-      TRACE3("STMT-JOURNAL %d page %d\n", pPager->fd.h, pPg->pgno);
-    }else{
-      store32bits(pPg->pgno, pPg, -4);
-      CODEC(pPager, pData, pPg->pgno, 7);
-      rc = sqlite3OsWrite(&pPager->stfd, ((char*)pData)-4, pPager->pageSize+4);
-      TRACE3("STMT-JOURNAL %d page %d\n", pPager->fd.h, pPg->pgno);
-      CODEC(pPager, pData, pPg->pgno, 0);
-      if( rc!=SQLITE_OK ){
-        sqlite3pager_rollback(pPager);
-        pPager->errMask |= PAGER_ERR_FULL;
-        return rc;
-      }
-      pPager->stmtNRec++;
-      assert( pPager->aInStmt!=0 );
-      pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
+      page_add_to_stmt_list(pPg);
     }
-    page_add_to_stmt_list(pPg);
   }
 
   /* Update the database size and return.
index 6e2bf58904e2e4411866043b6d7e2f635be0c61b..9244476c82a1a724e82dcbac88b7d16293824f4c 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.329 2004/10/31 02:22:49 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.330 2004/11/04 14:30:05 danielk1977 Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -1432,5 +1432,6 @@ void sqlite3ValueFree(sqlite3_value*);
 sqlite3_value *sqlite3ValueNew();
 sqlite3_value *sqlite3GetTransientValue(sqlite3*db);
 extern const unsigned char sqlite3UpperToLower[];
+void sqlite3RootPageMoved(Db*, int, int);
 
 #endif
index cc62b8c23af36c0e8786e043c052d5d59bccb136..fc443e63f93c4d20558fcc12445e1a7220577c54 100644 (file)
@@ -13,7 +13,7 @@
 ** is not included in the SQLite library.  It is used for automated
 ** testing of the SQLite library.
 **
-** $Id: test3.c,v 1.53 2004/10/31 02:22:49 drh Exp $
+** $Id: test3.c,v 1.54 2004/11/04 14:30:06 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "pager.h"
@@ -322,7 +322,7 @@ static int btree_drop_table(
   }
   pBt = sqlite3TextToPtr(argv[1]);
   if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
-  rc = sqlite3BtreeDropTable(pBt, iTable);
+  rc = sqlite3BtreeDropTable(pBt, iTable, 0);
   if( rc!=SQLITE_OK ){
     Tcl_AppendResult(interp, errorName(rc), 0);
     return TCL_ERROR;
index 95e6bd38a6cb51d3235575c938cce0dfd829e2f1..9e4ef43b4e2650b2fdd1d9376d1fcc15d748629f 100644 (file)
@@ -43,7 +43,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** commenting and indentation practices when changing or adding code.
 **
-** $Id: vdbe.c,v 1.422 2004/11/03 16:27:01 drh Exp $
+** $Id: vdbe.c,v 1.423 2004/11/04 14:30:06 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -3610,7 +3610,16 @@ case OP_IdxIsNull: {
 ** See also: Clear
 */
 case OP_Destroy: {
-  rc = sqlite3BtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1);
+  int iMoved;
+  rc = sqlite3BtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1, &iMoved);
+#ifndef SQLITE_OMIT_AUTOVACUUM
+  pTos++;
+  pTos->flags = MEM_Int;
+  pTos->i = iMoved;
+  if( iMoved!=0 ){
+    sqlite3RootPageMoved(&db->aDb[pOp->p2], iMoved, pOp->p1);
+  }
+#endif
   break;
 }
 
index 9af1ab6522ad1cda02a793a9680c69abf8e7c448..6b80173b5d0eac8a06901093e908715eb4d17fa8 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this file is testing the SELECT statement.
 #
-# $Id: autovacuum.test,v 1.5 2004/11/04 02:57:35 danielk1977 Exp $
+# $Id: autovacuum.test,v 1.6 2004/11/04 14:30:06 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -144,6 +144,5 @@ for {set i 5} {$i < 15} {incr i} {
   } {ok}
 }
 
-
 finish_test