aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2003-04-25 15:37:57 +0000
committerdrh <drh@noemail.net>2003-04-25 15:37:57 +0000
commit2e6d11bc07ca73239a49d25fd8313713f6eeb75e (patch)
treec1c60078b7fc365913d74d9ea1b020610bda7c98 /src
parent9c05dc6298e529bbdd78726dc99b110f641b0c58 (diff)
downloadsqlite-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.c24
-rw-r--r--src/pager.c33
-rw-r--r--src/vacuum.c28
-rw-r--r--src/vdbe.c6
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 ){