]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add tests to insure VACUUM works in the presence of I/O errors. Fix some
authordrh <drh@noemail.net>
Fri, 25 Apr 2003 15:37:57 +0000 (15:37 +0000)
committerdrh <drh@noemail.net>
Fri, 25 Apr 2003 15:37:57 +0000 (15:37 +0000)
problems that came to light by these tests. (CVS 935)

FossilOrigin-Name: 8d3e879349fc9523c72cb46111e0058b57ce9341

manifest
manifest.uuid
src/btree.c
src/pager.c
src/vacuum.c
src/vdbe.c
test/ioerr.test

index ba1735a78268d4c53d18117a705928f8572bbc65..137279ac8c9f91828a8f832c7aee518f0a941362 100644 (file)
--- 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
index aab1235d087f6136d3b5d314f3f18b11a686afa7..0e2dd63f429baf6650be269fd088d2a660c96545 100644 (file)
@@ -1 +1 @@
-c3b1f84dfce13b2523c9923e4270577862ca0595
\ No newline at end of file
+8d3e879349fc9523c72cb46111e0058b57ce9341
\ No newline at end of file
index 46a27e7c2ab59c24bce5268c65023f0974d19846..dccb96059411402b0af7f2cdb58a3815aafe4f21 100644 (file)
@@ -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);
   }
index 373aceaf79d1ab1204a0fc791827c4a26e3e69f3..130043d3883387b17a25432bab8ad4535a13a21c 100644 (file)
@@ -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));
index 35d12c490759edeb208c5a91839a3391da4f57e6..50c7e88eff03066dcc934d2913ce55862620762c 100644 (file)
@@ -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
 }
index 8c1ee6bda37116e9922b2b75a99b45e05b6322c9..3c921d2f8a257f5b641beb80d538199ab174def5 100644 (file)
@@ -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 ){
index 1497b5c50ee7bff86505a21df027eb6f14417ae1..06435f7048848bf9ddd37704b0714d0d29fa0592 100644 (file)
@@ -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