diff --git a/manifest b/manifest index ba1735a782..137279ac8c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Work\saround\sa\sname\scollision\sproblem\son\swindows.\s(CVS\s934) -D 2003-04-25T13:28:03 +C Add\stests\sto\sinsure\sVACUUM\sworks\sin\sthe\spresence\sof\sI/O\serrors.\s\sFix\ssome\nproblems\sthat\scame\sto\slight\sby\sthese\stests.\s(CVS\s935) +D 2003-04-25T15:37:58 F Makefile.in 004acec253ecdde985c8ecd5b7c9accdb210378f F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -21,7 +21,7 @@ F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2 F src/attach.c 7ebc7487de43e357a64226f8abef81f2669f2183 F src/auth.c a4afd27964fb9f661147115790c8ae2ee230ebcc -F src/btree.c a9e8aa96c2af6a81e442719d0cbc1a71bb9b3e08 +F src/btree.c 077d75aee4ed63f3628698611ba43c87097d458d F src/btree.h 23c50e00709de16a5dce1fcea9c0429cc955ff0e F src/btree_rb.c 8e00e40be264716e1929987878672e55d9e0e76d F src/build.c d5a26baeffa5bc49b4b7009a7723c6ab7e1b02d9 @@ -37,7 +37,7 @@ F src/main.c 5e4d4d081d82840a743c57269ca3c32640cefc06 F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565 F src/os.c e56853eaea5dab258ab1ccb77b4743b453516e3a F src/os.h 9e5bbddff123187295e3d00d49af06192cd1cd49 -F src/pager.c 18066f5057500dccc2948c258ea5ffd4139bbf7d +F src/pager.c 51fdfda63e2d8c01fff8f7fe0c49f2636d5b1321 F src/pager.h 5da62c83443f26b1792cfd72c96c422f91aadd31 F src/parse.y 15ae47e7dd84304c1c6ae9205558405127977541 F src/pragma.c 118fe400d71b7fdcc03580d5eab6bb5aa00772a5 @@ -58,8 +58,8 @@ F src/tokenize.c 067d1a477a94af7712ca74e09aaa6bd0f7299527 F src/trigger.c e763f4015c96e06b694184ead5754985c1dfdae0 F src/update.c b7fa7c427b74aee6db56ecfa09e5e151e6f9fa6a F src/util.c 87635cfdfffa056a8d3147719357aa442374f78c -F src/vacuum.c 44420de0f02cc66a673469fee1f33b6d08bb717e -F src/vdbe.c f0868ac926d98395d28c2a29119364ff11b77852 +F src/vacuum.c 14ac3073203fa021e01ffe33db56968ad79a8344 +F src/vdbe.c 48098080d2b5d35d4cc28ac2a4855c7730f6ee7b F src/vdbe.h 985c24f312d10f9ef8f9a8b8ea62fcdf68e82f21 F src/where.c f632cd30f013163484a4d60c249d36fe31f5be12 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 @@ -86,7 +86,7 @@ F test/index.test 90ef4c426865f15937858bd433cc82b9c11af913 F test/insert.test 5697ba098e4d8a6f0151f281b7e39dec9c439e05 F test/insert2.test c288375a64dad3295044714f0dfed4a193cf067f F test/intpkey.test 39f49fd993350f7f3ab255e5cfbf9a09d8f8800e -F test/ioerr.test 45c8feebe608d7f456fea27ff27a0aaaf0b9c636 +F test/ioerr.test 5dbaf09f96b56ee01cf3edd762b96eb4ad2c9ca4 F test/join.test c97267c19294bf1fa4e81087edad179828bced88 F test/limit.test 9ffb965a0f5bf7152187ef3d8d1249b96e5620bf F test/lock.test 388a3a10962d2d571c0c1821cc35bf069ee73473 @@ -165,7 +165,7 @@ F www/speed.tcl cb4c10a722614aea76d2c51f32ee43400d5951be F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 -P caa960289f3d1f5e8f35a94e9e4321996c211ed2 -R 6965193ade608332ec748a76df98b36c +P c3b1f84dfce13b2523c9923e4270577862ca0595 +R 40330553c4eb619fb11602a7f62ead1c U drh -Z d6cf94162cb85ee388573561bf7c7da3 +Z 09a1f9c6aa9e8c12d787618e6052f340 diff --git a/manifest.uuid b/manifest.uuid index aab1235d08..0e2dd63f42 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c3b1f84dfce13b2523c9923e4270577862ca0595 \ No newline at end of file +8d3e879349fc9523c72cb46111e0058b57ce9341 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 46a27e7c2a..dccb960594 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 && nPagepPager, nPage); + } if( rc ){ fileBtreeRollback(pBtTo); } diff --git a/src/pager.c b/src/pager.c index 373aceaf79..130043d388 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 35d12c4907..50c7e88eff 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; izErrMsg==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 8c1ee6bda3..3c921d2f8a 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 @@ -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 ){ diff --git a/test/ioerr.test b/test/ioerr.test index 1497b5c50e..06435f7048 100644 --- a/test/ioerr.test +++ b/test/ioerr.test @@ -15,7 +15,7 @@ # The tests in this file use special facilities that are only # available in the SQLite test fixture. # -# $Id: ioerr.test,v 1.2 2003/02/16 22:21:33 drh Exp $ +# $Id: ioerr.test,v 1.3 2003/04/25 15:37:59 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -56,5 +56,65 @@ for {set n 1} {$go} {incr n} { } set ::sqlite_io_error_pending 0 +proc cksum {{db db}} { + set txt [$db eval {SELECT name, type, sql FROM sqlite_master}]\n + foreach tbl [$db eval {SELECT name FROM sqlite_master WHERE type='table'}] { + append txt [$db eval "SELECT * FROM $tbl"]\n + } + foreach prag {default_synchronous default_cache_size} { + append txt $prag-[$db eval "PRAGMA $prag"]\n + } + set cksum [string length $txt]-[md5 $txt] + # puts $cksum-[file size test.db] + return $cksum +} + +set ::go 1 +for {set n 1} {$go} {incr n} { + do_test ioerr-2.$n.1 { + set ::sqlite_io_error_pending 0 + db close + catch {file delete -force test.db} + catch {file delete -force test.db-journal} + sqlite db test.db + execsql { + BEGIN; + CREATE TABLE t1(a, b, c); + INSERT INTO t1 VALUES(1, randstr(5,50), randstr(5,50)); + INSERT INTO t1 SELECT a+2, b||'-'||rowid, c||'-'||rowid FROM t1; + INSERT INTO t1 SELECT a+4, b||'-'||rowid, c||'-'||rowid FROM t1; + INSERT INTO t1 SELECT a+8, b||'-'||rowid, c||'-'||rowid FROM t1; + INSERT INTO t1 SELECT a+16, b||'-'||rowid, c||'-'||rowid FROM t1; + INSERT INTO t1 SELECT a+32, b||'-'||rowid, c||'-'||rowid FROM t1; + INSERT INTO t1 SELECT a+64, b||'-'||rowid, c||'-'||rowid FROM t1; + INSERT INTO t1 SELECT a+128, b||'-'||rowid, c||'-'||rowid FROM t1; + CREATE TABLE t2 AS SELECT * FROM t1; + CREATE TABLE t3 AS SELECT * FROM t1; + COMMIT; + DROP TABLE t2; + } + set ::cksum [cksum] + execsql { + SELECT name FROM sqlite_master WHERE type='table' + } + } {t1 t3} + do_test ioerr-2.$n.2 [subst { + set ::sqlite_io_error_pending $n + }] $n + do_test ioerr-2.$n.3 { + set r [catch {db eval { + VACUUM; + }} msg] + # puts "error_pending=$::sqlite_io_error_pending" + # if {$r} {puts $msg} + set ::go [expr {$::sqlite_io_error_pending<=0}] + expr {$::sqlite_io_error_pending>0 || $r!=0} + set ::sqlite_io_error_pending 0 + db close + sqlite db test.db + cksum + } $cksum +} +set ::sqlite_io_error_pending 0 finish_test