1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Support root-page allocation/deallocation in auto-vacuum databases. Still a few problems. (CVS 2054)

FossilOrigin-Name: 1da361fae82d420be63c53f8e3efaccac24f348a
This commit is contained in:
danielk1977
2004-11-04 14:30:04 +00:00
parent 798da52ce7
commit a0bf265269
10 changed files with 358 additions and 144 deletions

View File

@@ -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

View File

@@ -1 +1 @@
c33b3a613751057e8a46fdcd428b8448329d414d
1da361fae82d420be63c53f8e3efaccac24f348a

View 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;
}

View 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);

View 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);
}

View 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;
}
}else{
/* 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);
/* 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{
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",
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);
}
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);
*(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);
}
pPager->stmtNRec++;
assert( pPager->aInStmt!=0 );
pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
}
}else{
pPg->needSync = !pPager->journalStarted && !pPager->noSync;
TRACE4("APPEND %d page %d needSync=%d\n",
pPager->fd.h, pPg->pgno, pPg->needSync);
page_add_to_stmt_list(pPg);
}
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);
}
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);
}
/* Update the database size and return.

View 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

View 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;

View 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;
}

View 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