diff options
author | drh <drh@noemail.net> | 2003-04-25 15:37:57 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2003-04-25 15:37:57 +0000 |
commit | 2e6d11bc07ca73239a49d25fd8313713f6eeb75e (patch) | |
tree | c1c60078b7fc365913d74d9ea1b020610bda7c98 /src | |
parent | 9c05dc6298e529bbdd78726dc99b110f641b0c58 (diff) | |
download | sqlite-2e6d11bc07ca73239a49d25fd8313713f6eeb75e.tar.gz sqlite-2e6d11bc07ca73239a49d25fd8313713f6eeb75e.zip |
Add tests to insure VACUUM works in the presence of I/O errors. Fix some
problems that came to light by these tests. (CVS 935)
FossilOrigin-Name: 8d3e879349fc9523c72cb46111e0058b57ce9341
Diffstat (limited to 'src')
-rw-r--r-- | src/btree.c | 24 | ||||
-rw-r--r-- | src/pager.c | 33 | ||||
-rw-r--r-- | src/vacuum.c | 28 | ||||
-rw-r--r-- | src/vdbe.c | 6 |
4 files changed, 56 insertions, 35 deletions
diff --git a/src/btree.c b/src/btree.c index 46a27e7c2..dccb96059 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.91 2003/04/25 13:22:52 drh Exp $ +** $Id: btree.c,v 1.92 2003/04/25 15:37:58 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -3498,22 +3498,34 @@ static const char *fileBtreeGetFilename(Btree *pBt){ */ static int fileBtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){ int rc = SQLITE_OK; - Pgno i, nPage; + Pgno i, nPage, nToPage; if( !pBtTo->inTrans || !pBtFrom->inTrans ) return SQLITE_ERROR; if( pBtTo->needSwab!=pBtFrom->needSwab ) return SQLITE_ERROR; if( pBtTo->pCursor ) return SQLITE_BUSY; memcpy(pBtTo->page1, pBtFrom->page1, SQLITE_PAGE_SIZE); - sqlitepager_overwrite(pBtTo->pPager, 1, pBtFrom->page1); + rc = sqlitepager_overwrite(pBtTo->pPager, 1, pBtFrom->page1); + nToPage = sqlitepager_pagecount(pBtTo->pPager); nPage = sqlitepager_pagecount(pBtFrom->pPager); - for(i=2; i<=nPage; i++){ + for(i=2; rc==SQLITE_OK && i<=nPage; i++){ void *pPage; rc = sqlitepager_get(pBtFrom->pPager, i, &pPage); if( rc ) break; - sqlitepager_overwrite(pBtTo->pPager, i, pPage); + rc = sqlitepager_overwrite(pBtTo->pPager, i, pPage); + if( rc ) break; sqlitepager_unref(pPage); } - if( !rc ) rc = sqlitepager_truncate(pBtTo->pPager, nPage); + for(i=nPage+1; rc==SQLITE_OK && i<=nToPage; i++){ + void *pPage; + rc = sqlitepager_get(pBtTo->pPager, i, &pPage); + if( rc ) break; + rc = sqlitepager_write(pPage); + sqlitepager_unref(pPage); + sqlitepager_dont_write(pBtTo->pPager, i); + } + if( !rc && nPage<nToPage ){ + rc = sqlitepager_truncate(pBtTo->pPager, nPage); + } if( rc ){ fileBtreeRollback(pBtTo); } diff --git a/src/pager.c b/src/pager.c index 373aceaf7..130043d38 100644 --- a/src/pager.c +++ b/src/pager.c @@ -18,7 +18,7 @@ ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.82 2003/04/25 13:22:53 drh Exp $ +** @(#) $Id: pager.c,v 1.83 2003/04/25 15:37:58 drh Exp $ */ #include "os.h" /* Must be first to enable large file support */ #include "sqliteInt.h" @@ -937,7 +937,13 @@ static int syncAllPages(Pager*); */ int sqlitepager_truncate(Pager *pPager, Pgno nPage){ int rc; - if( pPager->dbSize<0 ) sqlitepager_pagecount(pPager); + if( pPager->dbSize<0 ){ + sqlitepager_pagecount(pPager); + } + if( pPager->errMask!=0 ){ + rc = pager_errcode(pPager); + return rc; + } if( nPage>=pPager->dbSize ){ return SQLITE_OK; } @@ -1197,6 +1203,7 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){ */ assert( pPager!=0 ); assert( pgno!=0 ); + *ppPage = 0; if( pPager->errMask & ~(PAGER_ERR_FULL) ){ return pager_errcode(pPager); } @@ -1207,7 +1214,6 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){ if( pPager->nRef==0 ){ rc = sqliteOsReadLock(&pPager->fd); if( rc!=SQLITE_OK ){ - *ppPage = 0; return rc; } pPager->state = SQLITE_READLOCK; @@ -1225,7 +1231,6 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){ /* This should never happen! */ rc = SQLITE_INTERNAL; } - *ppPage = 0; return rc; } pPager->state = SQLITE_WRITELOCK; @@ -1241,7 +1246,6 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){ if( rc!=SQLITE_OK ){ rc = sqliteOsUnlock(&pPager->fd); assert( rc==SQLITE_OK ); - *ppPage = 0; return SQLITE_BUSY; } pPager->journalOpen = 1; @@ -1269,7 +1273,6 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){ pPg = sqliteMallocRaw( sizeof(*pPg) + SQLITE_PAGE_SIZE + sizeof(u32) + pPager->nExtra ); if( pPg==0 ){ - *ppPage = 0; pager_unwritelock(pPager); pPager->errMask |= PAGER_ERR_MEM; return SQLITE_NOMEM; @@ -1298,7 +1301,6 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){ int rc = syncAllPages(pPager); if( rc!=0 ){ sqlitepager_rollback(pPager); - *ppPage = 0; return SQLITE_IOERR; } pPg = pPager->pFirst; @@ -1313,7 +1315,6 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){ rc = pager_write_pagelist( pPg ); if( rc!=SQLITE_OK ){ sqlitepager_rollback(pPager); - *ppPage = 0; return SQLITE_IOERR; } } @@ -1391,7 +1392,15 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){ assert( pPg->pNextHash->pPrevHash==0 ); pPg->pNextHash->pPrevHash = pPg; } + if( pPager->nExtra>0 ){ + memset(PGHDR_TO_EXTRA(pPg), 0, pPager->nExtra); + } if( pPager->dbSize<0 ) sqlitepager_pagecount(pPager); + if( pPager->errMask!=0 ){ + sqlitepager_unref(PGHDR_TO_DATA(pPg)); + rc = pager_errcode(pPager); + return rc; + } if( pPager->dbSize<(int)pgno ){ memset(PGHDR_TO_DATA(pPg), 0, SQLITE_PAGE_SIZE); }else{ @@ -1402,15 +1411,13 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){ off_t fileSize; if( sqliteOsFileSize(&pPager->fd,&fileSize)!=SQLITE_OK || fileSize>=pgno*SQLITE_PAGE_SIZE ){ + sqlitepager_unref(PGHDR_TO_DATA(pPg)); return rc; }else{ memset(PGHDR_TO_DATA(pPg), 0, SQLITE_PAGE_SIZE); } } } - if( pPager->nExtra>0 ){ - memset(PGHDR_TO_EXTRA(pPg), 0, pPager->nExtra); - } }else{ /* The requested page is in the page cache. */ pPager->nHit++; @@ -1532,6 +1539,10 @@ static int pager_open_journal(Pager *pPager){ pPager->alwaysRollback = 0; pPager->nRec = 0; sqlitepager_pagecount(pPager); + if( pPager->errMask!=0 ){ + rc = pager_errcode(pPager); + return rc; + } pPager->origDbSize = pPager->dbSize; if( journal_format==JOURNAL_FORMAT_3 ){ rc = sqliteOsWrite(&pPager->jfd, aJournalMagic3, sizeof(aJournalMagic3)); diff --git a/src/vacuum.c b/src/vacuum.c index 35d12c490..50c7e88ef 100644 --- a/src/vacuum.c +++ b/src/vacuum.c @@ -14,7 +14,7 @@ ** Most of the code in this file may be omitted by defining the ** SQLITE_OMIT_VACUUM macro. ** -** $Id: vacuum.c,v 1.5 2003/04/25 13:22:53 drh Exp $ +** $Id: vacuum.c,v 1.6 2003/04/25 15:37:58 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -280,31 +280,31 @@ void sqliteVacuum(Parse *pParse, Token *pTableName){ sVac.dbOld = db; sVac.dbNew = dbNew; sVac.pParse = pParse; - for(i=0; i<sizeof(zPragma)/sizeof(zPragma[0]); i++){ + for(i=0; rc==SQLITE_OK && i<sizeof(zPragma)/sizeof(zPragma[0]); i++){ char zBuf[200]; assert( strlen(zPragma[i])<100 ); sprintf(zBuf, "PRAGMA %s;", zPragma[i]); sVac.zPragma = zPragma[i]; rc = sqlite_exec(db, zBuf, vacuumCallback3, &sVac, &zErrMsg); - if( rc ) goto vacuum_error; } - if( rc==SQLITE_OK ){ + if( !rc ){ rc = sqlite_exec(db, "SELECT type, name, sql FROM sqlite_master " "WHERE sql NOT NULL", vacuumCallback1, &sVac, &zErrMsg); } - if( rc ){ - if( pParse->zErrMsg==0 ){ - sqliteErrorMsg(pParse, "unable to vacuum database - %s", zErrMsg); - } - goto end_of_vacuum; + if( !rc ){ + rc = sqliteBtreeCopyFile(db->aDb[0].pBt, dbNew->aDb[0].pBt); + sqlite_exec(db, "COMMIT", 0, 0, 0); + sqlite_exec(db, "ROLLBACK", 0, 0, 0); /* In case the COMMIT failed */ + sqliteResetInternalSchema(db, 0); } - rc = sqliteBtreeCopyFile(db->aDb[0].pBt, dbNew->aDb[0].pBt); - sqlite_exec(db, "COMMIT", 0, 0, 0); - sqliteResetInternalSchema(db, 0); end_of_vacuum: - sqlite_exec(db, "COMMIT", 0, 0, 0); + if( rc && pParse->zErrMsg==0 && zErrMsg!=0 ){ + sqliteErrorMsg(pParse, "unable to vacuum database - %s", zErrMsg); + } if( safety ) { + sqlite_exec(db, "COMMIT", 0, 0, 0); + sqlite_exec(db, "ROLLBACK", 0, 0, 0); /* In case the COMMIT failed */ sqliteSafetyOn(db); } if( dbNew ) sqlite_close(dbNew); @@ -314,7 +314,5 @@ end_of_vacuum: sqliteFree(sVac.s2.z); if( zErrMsg ) sqlite_freemem(zErrMsg); return; - -vacuum_error: #endif } diff --git a/src/vdbe.c b/src/vdbe.c index 8c1ee6bda..3c921d2f8 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -36,7 +36,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.219 2003/04/23 12:25:25 drh Exp $ +** $Id: vdbe.c,v 1.220 2003/04/25 15:37:58 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -4317,7 +4317,7 @@ case OP_Last: { pC = &p->aCsr[i]; if( (pCrsr = pC->pCursor)!=0 ){ int res; - sqliteBtreeLast(pCrsr, &res); + rc = sqliteBtreeLast(pCrsr, &res); p->aCsr[i].nullRow = res; if( res && pOp->p2>0 ){ pc = pOp->p2 - 1; @@ -4345,7 +4345,7 @@ case OP_Rewind: { pC = &p->aCsr[i]; if( (pCrsr = pC->pCursor)!=0 ){ int res; - sqliteBtreeFirst(pCrsr, &res); + rc = sqliteBtreeFirst(pCrsr, &res); pC->atFirst = res==0; pC->nullRow = res; if( res && pOp->p2>0 ){ |