]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add some savepoint related test cases and fix a few problems. (CVS 6116)
authordanielk1977 <danielk1977@noemail.net>
Tue, 6 Jan 2009 13:40:08 +0000 (13:40 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Tue, 6 Jan 2009 13:40:08 +0000 (13:40 +0000)
FossilOrigin-Name: 8c62ea4fded2251e9daf16f2a050f94359299d76

manifest
manifest.uuid
src/pager.c
test/permutations.test
test/savepoint.test
test/savepoint6.test

index 52ab79a2249c5d509cc7bc963146ead711a5145d..44619fdb04929e4b8b58351c1a755de55bdee991 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Remove\sleftover\s"breakpoint"\sfrom\sthe\sfuzz.test\sscript.\s(CVS\s6115)
-D 2009-01-06T00:11:26
+C Add\ssome\ssavepoint\srelated\stest\scases\sand\sfix\sa\sfew\sproblems.\s(CVS\s6116)
+D 2009-01-06T13:40:08
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in 05461a9b5803d5ad10c79f989801e9fd2cc3e592
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -142,7 +142,7 @@ F src/os_common.h 24525d8b7bce66c374dfc1810a6c9043f3359b60
 F src/os_os2.c bed77dc26e3a95ce4a204936b9a1ca6fe612fcc5
 F src/os_unix.c e6eacc7ec735ded605fefcbaf250058baa8feb12
 F src/os_win.c 496e3ceb499aedc63622a89ef76f7af2dd902709
-F src/pager.c b12dbe7e6c561d1675ddcc9c50b997c0692212e0
+F src/pager.c 9c9bc48765cb8d6c4445d3628bed52a0e0af762c
 F src/pager.h 75396879910768a0af03a4af8413e798d84c096f
 F src/parse.y 4d0e33a702dc3ea7b69d8ae1914b3fbd32e46057
 F src/pcache.c 16dc8da6e6ba6250f8dfd9ee46036db1cbceedc6
@@ -477,7 +477,7 @@ F test/pageropt.test 3ee6578891baaca967f0bd349e4abfa736229e1a
 F test/pagesize.test 0d9ff3fedfce6e5ffe8fa7aca9b6d3433a2e843b
 F test/pcache.test 515b4c26e9f57660357dfff5b6b697acac1abc5f
 F test/pcache2.test 46efd980a89f737847b99327bda19e08fe11e402
-F test/permutations.test dccfc24254ab8d9cb9098e790c12fae52865f65f
+F test/permutations.test 9e667c6b027856fc9b1d3d82cb51f0744885d010
 F test/pragma.test 325aa0833d483b8e0c98e8196f1cc49fa5d8c336
 F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
 F test/printf.test 262a5acd3158f788e9bdf7f18d718f3af32ff6ef
@@ -493,12 +493,12 @@ F test/rollback.test 1f70ab4301d8d105d41438a436cad1fc8897f5e5
 F test/rowid.test 1c8fc43c60d273e6ea44dfb992db587f3164312c
 F test/rtree.test b85fd4f0861a40ca366ac195e363be2528dcfadf
 F test/safety.test b69e2b2dd5d52a3f78e216967086884bbc1a09c6
-F test/savepoint.test 154001ac2863714eadd9c79865fa07faeda3d3a4
+F test/savepoint.test 7c743ac26268b042f8e16797c755644240c724e5
 F test/savepoint2.test 18f6c75d5c133b93838019df8988b8cdf379d3de
 F test/savepoint3.test 1a0b1c0f59c6ae4402bfbca7cec29d4b1b272ff0
 F test/savepoint4.test fd8850063e3c40565545f5c291e7f79a30591670
 F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd
-F test/savepoint6.test 4808a41d2426d96d2fd742573c374f1d3ba90c61
+F test/savepoint6.test 7d584a665cb6e4f0c24d7a8ae7f8985461c683b1
 F test/schema.test a8b000723375fd42c68d310091bdbd744fde647c
 F test/schema2.test 35e1c9696443d6694c8980c411497c2b5190d32e
 F test/select1.test d0a4cad954fd41c030ec16ffbd2d08a4c0548742
@@ -692,7 +692,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
-P a7015625610624be1645e918d0a62cf85bec86ce
-R f82e1e4aa3ea5aea66445267a01cdb30
-U drh
-Z b753d108e96492fb67c6923669f55766
+P c2482d8877a5f9e387b288377e410ae1b8267f3c
+R 99d979f1a5afc6b0e70e7af446024426
+U danielk1977
+Z 76e17593f6a27ee09beef4dfa4478a92
index fb3293e5b475d0a3e3f3d466fbeb36f91a686393..00fa21adca5c7ea90fc768bd2a4444d6acfad6c4 100644 (file)
@@ -1 +1 @@
-c2482d8877a5f9e387b288377e410ae1b8267f3c
\ No newline at end of file
+8c62ea4fded2251e9daf16f2a050f94359299d76
\ No newline at end of file
index 9b669376df1b5cb27c492ca9da8abda885a6d97c..c7904613e67f0847499b35609eceeee3ce10090f 100644 (file)
@@ -18,7 +18,7 @@
 ** file simultaneously, or one process from reading the database while
 ** another is writing.
 **
-** @(#) $Id: pager.c,v 1.529 2009/01/03 12:55:18 drh Exp $
+** @(#) $Id: pager.c,v 1.530 2009/01/06 13:40:08 danielk1977 Exp $
 */
 #ifndef SQLITE_OMIT_DISKIO
 #include "sqliteInt.h"
 ** Macros for troubleshooting.  Normally turned off
 */
 #if 0
+int sqlite3PagerTrace=1;  /* True to enable tracing */
 #define sqlite3DebugPrintf printf
-#define PAGERTRACE1(X)       sqlite3DebugPrintf(X)
-#define PAGERTRACE2(X,Y)     sqlite3DebugPrintf(X,Y)
-#define PAGERTRACE3(X,Y,Z)   sqlite3DebugPrintf(X,Y,Z)
-#define PAGERTRACE4(X,Y,Z,W) sqlite3DebugPrintf(X,Y,Z,W)
-#define PAGERTRACE5(X,Y,Z,W,V) sqlite3DebugPrintf(X,Y,Z,W,V)
+#define PAGERTRACE1(X)       if( sqlite3PagerTrace ) sqlite3DebugPrintf(X)
+#define PAGERTRACE2(X,Y)     if( sqlite3PagerTrace ) sqlite3DebugPrintf(X,Y)
+#define PAGERTRACE3(X,Y,Z)   if( sqlite3PagerTrace ) sqlite3DebugPrintf(X,Y,Z)
+#define PAGERTRACE4(X,Y,Z,W) if( sqlite3PagerTrace ) sqlite3DebugPrintf(X,Y,Z,W)
+#define PAGERTRACE5(X,Y,Z,W,V) if( sqlite3PagerTrace ) sqlite3DebugPrintf(X,Y,Z,W,V)
 #else
 #define PAGERTRACE1(X)
 #define PAGERTRACE2(X,Y)
@@ -1178,7 +1179,7 @@ static int pager_playback_one_page(
   if( rc!=SQLITE_OK ) return rc;
   rc = sqlite3OsRead(jfd, aData, pPager->pageSize, offset+4);
   if( rc!=SQLITE_OK ) return rc;
-  pPager->journalOff += pPager->pageSize + 4;
+  pPager->journalOff += pPager->pageSize + 4 + (isMainJrnl?4:0);
 
   /* Sanity checking on the page.  This is more important that I originally
   ** thought.  If a power failure occurs while the journal is being written,
@@ -1194,7 +1195,6 @@ static int pager_playback_one_page(
   if( isMainJrnl ){
     rc = read32bits(jfd, offset+pPager->pageSize+4, &cksum);
     if( rc ) return rc;
-    pPager->journalOff += 4;
     if( !isSavepnt && pager_cksum(pPager, aData)!=cksum ){
       return SQLITE_DONE;
     }
@@ -1251,6 +1251,29 @@ static int pager_playback_one_page(
     if( pgno>pPager->dbFileSize ){
       pPager->dbFileSize = pgno;
     }
+  }else if( !isMainJrnl && pPg==0 ){
+    /* If this is a rollback of a savepoint and data was not written to
+    ** the database and the page is not in-memory, there is a potential
+    ** problem. When the page is next fetched by the b-tree layer, it 
+    ** will be read from the database file, which may or may not be 
+    ** current. 
+    **
+    ** There are a couple of different ways this can happen. All are quite
+    ** obscure. When not running in synchronous mode, this can only happen 
+    ** if the page is on the free-list at the start of the transaction, then
+    ** populated, then moved using sqlite3PagerMovepage().
+    **
+    ** The solution is to add an in-memory page to the cache containing
+    ** the data just read from the sub-journal. Mark the page as dirty 
+    ** and if the pager requires a journal-sync, then mark the page as 
+    ** requiring a journal-sync before it is written.
+    */
+    assert( isSavepnt );
+    if( (rc = sqlite3PagerAcquire(pPager, pgno, &pPg, 1)) ){
+      return rc;
+    }
+    pPg->flags &= ~PGHDR_NEED_READ;
+    sqlite3PcacheMakeDirty(pPg);
   }
   if( pPg ){
     /* No page should ever be explicitly rolled back that is in use, except
@@ -1662,7 +1685,7 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
   i64 szJ;                 /* Size of the full journal */
   i64 iHdrOff;             /* End of first segment of main-journal records */
   Pgno ii;                 /* Loop counter */
-  int rc;                  /* Return code */
+  int rc = SQLITE_OK;      /* Return code */
   Bitvec *pDone = 0;       /* Bitvec to ensure pages played back only once */
 
   /* Allocate a bitvec to use to store the set of pages rolled back */
@@ -1676,7 +1699,7 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
   /* Truncate the database back to the size it was before the 
   ** savepoint being reverted was opened.
   */
-  rc = pager_truncate(pPager, pSavepoint?pSavepoint->nOrig:pPager->dbOrigSize);
+  pPager->dbSize = pSavepoint?pSavepoint->nOrig:pPager->dbOrigSize;
   assert( pPager->state>=PAGER_SHARED );
 
   /* Now roll back all main journal file records that occur after byte
@@ -2350,6 +2373,13 @@ int sqlite3PagerClose(Pager *pPager){
   pPager->exclusiveMode = 0;
   pager_reset(pPager);
   if( !MEMDB ){
+    /* Set Pager.journalHdr to -1 for the benefit of the pager_playback() 
+    ** call which may be made from within pagerUnlockAndRollback(). If it
+    ** is not -1, then the unsynced portion of an open journal file may
+    ** be played back into the database. If a power failure occurs while
+    ** this is happening, the database may become corrupt.
+    */
+    pPager->journalHdr = -1;
     pagerUnlockAndRollback(pPager);
   }
   enable_simulated_io_errors();
@@ -2556,6 +2586,34 @@ static int pager_write_pagelist(PgHdr *pList){
   return SQLITE_OK;
 }
 
+/*
+** Add the page to the sub-journal. It is the callers responsibility to
+** use subjRequiresPage() to check that it is really required before 
+** calling this function.
+*/
+static int subjournalPage(PgHdr *pPg){
+  int rc;
+  void *pData = pPg->pData;
+  Pager *pPager = pPg->pPager;
+  i64 offset = pPager->stmtNRec*(4+pPager->pageSize);
+  char *pData2 = CODEC2(pPager, pData, pPg->pgno, 7);
+
+  PAGERTRACE3("STMT-JOURNAL %d page %d @ %d\n", PAGERID(pPager), pPg->pgno);
+
+  assert( pageInJournal(pPg) || pPg->pgno>pPager->dbOrigSize );
+  rc = write32bits(pPager->sjfd, offset, pPg->pgno);
+  if( rc==SQLITE_OK ){
+    rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4);
+  }
+  if( rc==SQLITE_OK ){
+    pPager->stmtNRec++;
+    assert( pPager->nSavepoint>0 );
+    rc = addToSavepointBitvecs(pPager, pPg->pgno);
+  }
+  return rc;
+}
+
+
 /*
 ** This function is called by the pcache layer when it has reached some
 ** soft memory limit. The argument is a pointer to a purgeable Pager 
@@ -2585,7 +2643,12 @@ static int pagerStress(void *p, PgHdr *pPg){
     }
     if( rc==SQLITE_OK ){
       pPg->pDirty = 0;
-      rc = pager_write_pagelist(pPg);
+      if( pPg->pgno>pPager->dbSize && subjRequiresPage(pPg) ){
+        rc = subjournalPage(pPg);
+      }
+      if( rc==SQLITE_OK ){
+        rc = pager_write_pagelist(pPg);
+      }
     }
     if( rc!=SQLITE_OK ){
       pager_error(pPager, rc);
@@ -2593,6 +2656,7 @@ static int pagerStress(void *p, PgHdr *pPg){
   }
 
   if( rc==SQLITE_OK ){
+    PAGERTRACE3("STRESS %d page %d\n", PAGERID(pPager), pPg->pgno);
     sqlite3PcacheMakeClean(pPg);
   }
   return rc;
@@ -3387,24 +3451,7 @@ static int pager_write(PgHdr *pPg){
     ** in that it omits the checksums and the header.
     */
     if( subjRequiresPage(pPg) ){
-      i64 offset = pPager->stmtNRec*(4+pPager->pageSize);
-      char *pData2 = CODEC2(pPager, pData, pPg->pgno, 7);
-      assert( pageInJournal(pPg) || pPg->pgno>pPager->dbOrigSize );
-      rc = write32bits(pPager->sjfd, offset, pPg->pgno);
-      if( rc==SQLITE_OK ){
-        rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4);
-      }
-      PAGERTRACE3("STMT-JOURNAL %d page %d @ %d\n", PAGERID(pPager), pPg->pgno);
-      if( rc!=SQLITE_OK ){
-        return rc;
-      }
-      pPager->stmtNRec++;
-      assert( pPager->nSavepoint>0 );
-      rc = addToSavepointBitvecs(pPager, pPg->pgno);
-      if( rc!=SQLITE_OK ){
-        assert( rc==SQLITE_NOMEM );
-        return rc;
-      }
+      rc = subjournalPage(pPg);
     }
   }
 
index 2599c2d586641e19b4a7340716394de8aef58bc7..bd92896d5af24deeb6ce30da0c50a010519be29a 100644 (file)
@@ -9,7 +9,7 @@
 #
 #***********************************************************************
 #
-# $Id: permutations.test,v 1.42 2009/01/03 15:06:38 danielk1977 Exp $
+# $Id: permutations.test,v 1.43 2009/01/06 13:40:08 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -712,7 +712,9 @@ run_tests "journaltest" -description {
   set ISQUICK 1
   catch {db close}
   register_jt_vfs -default ""
+  #sqlite3_instvfs binarylog -default binarylog ostrace.bin
 } -shutdown {
+  #sqlite3_instvfs destroy binarylog
   unregister_jt_vfs
 } -include [concat $::ALLTESTS savepoint6.test
 ] -exclude {
index b79c87f572474c79fc152e5ba1f6adcbd9eec883..6ccb07762d5d144e19cdf97d0b648db1f80820ce 100644 (file)
@@ -9,7 +9,7 @@
 #
 #***********************************************************************
 #
-# $Id: savepoint.test,v 1.7 2009/01/03 15:06:38 danielk1977 Exp $
+# $Id: savepoint.test,v 1.8 2009/01/06 13:40:08 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -467,6 +467,35 @@ do_test savepoint-7.4.1 {
   execsql { PRAGMA integrity_check }
 } {ok}
 
+do_test savepoint-7.5.1 {
+  execsql {
+    PRAGMA incremental_vacuum;
+    CREATE TABLE t5(x, y);
+    INSERT INTO t5 VALUES(1, randstr(1000,1000));
+    INSERT INTO t5 VALUES(2, randstr(1000,1000));
+    INSERT INTO t5 VALUES(3, randstr(1000,1000));
+
+    BEGIN;
+      INSERT INTO t5 VALUES(4, randstr(1000,1000));
+      INSERT INTO t5 VALUES(5, randstr(1000,1000));
+      DELETE FROM t5 WHERE x=1 OR x=2;
+      SAVEPOINT one;
+        PRAGMA incremental_vacuum;
+        SAVEPOINT two;
+          INSERT INTO t5 VALUES(1, randstr(1000,1000));
+          INSERT INTO t5 VALUES(2, randstr(1000,1000));
+        ROLLBACK TO two;
+      ROLLBACK TO one;
+    COMMIT;
+    PRAGMA integrity_check;
+  }
+} {ok}
+do_test savepoint-7.5.2 {
+  execsql {
+    DROP TABLE t5;
+  }
+} {}
+
 # Test oddly named and quoted savepoints.
 #
 do_test savepoint-8-1 {
index 96d95fc2f05b9d587d13afaff44a83654df677d0..474d1051fcd99767adf058b21e04b1f1350cf5a4 100644 (file)
@@ -9,19 +9,22 @@
 #
 #***********************************************************************
 #
-# $Id: savepoint6.test,v 1.1 2009/01/03 10:41:29 danielk1977 Exp $
+# $Id: savepoint6.test,v 1.2 2009/01/06 13:40:08 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
 
-do_test savepoint6-1.1 {
-  execsql {
+proc sql {zSql} {
+  uplevel db eval [list $zSql]
+  #puts stderr "$zSql ;"
+}
+
+set DATABASE_SCHEMA {
     PRAGMA auto_vacuum = incremental;
     CREATE TABLE t1(x, y);
     CREATE UNIQUE INDEX i1 ON t1(x);
     CREATE INDEX i2 ON t1(y);
-  }
-} {}
+}
 
 #--------------------------------------------------------------------------
 # In memory database state.
@@ -60,12 +63,12 @@ proc x_to_y {x} {
 #   delete_rows XVALUES
 #
 proc savepoint {zName} {
-  catch { db eval "SAVEPOINT $zName" }
+  catch { sql "SAVEPOINT $zName" }
   lappend ::lSavepoint [list $zName [array get ::aEntry]]
 }
 
 proc rollback {zName} {
-  catch { db eval "ROLLBACK TO $zName" }
+  catch { sql "ROLLBACK TO $zName" }
   for {set i [expr {[llength $::lSavepoint]-1}]} {$i>=0} {incr i -1} {
     set zSavepoint [lindex $::lSavepoint $i 0]
     if {$zSavepoint eq $zName} {
@@ -82,7 +85,7 @@ proc rollback {zName} {
 }
 
 proc release {zName} {
-  catch { db eval "RELEASE $zName" }
+  catch { sql "RELEASE $zName" }
   for {set i [expr {[llength $::lSavepoint]-1}]} {$i>=0} {incr i -1} {
     set zSavepoint [lindex $::lSavepoint $i 0]
     if {$zSavepoint eq $zName} {
@@ -90,6 +93,10 @@ proc release {zName} {
       break
     }
   }
+
+  if {[llength $::lSavepoint] == 0} {
+    #puts stderr "-- End of transaction!!!!!!!!!!!!!"
+  }
 }
 
 proc insert_rows {lX} {
@@ -97,7 +104,7 @@ proc insert_rows {lX} {
     set y [x_to_y $x]
 
     # Update database [db]
-    db eval {INSERT OR REPLACE INTO t1 VALUES($x, $y)}
+    sql "INSERT OR REPLACE INTO t1 VALUES($x, '$y')"
 
     # Update the Tcl database.
     set ::aEntry($x) $y
@@ -107,7 +114,7 @@ proc insert_rows {lX} {
 proc delete_rows {lX} {
   foreach x $lX {
     # Update database [db]
-    db eval {DELETE FROM t1 WHERE x = $x}
+    sql "DELETE FROM t1 WHERE x = $x"
 
     # Update the Tcl database.
     unset -nocomplain ::aEntry($x)
@@ -153,9 +160,6 @@ proc random_integers {nRes nRange} {
 } 
 #-------------------------------------------------------------------------
 
-db eval { PRAGMA cache_size = 10 }
-expr srand(0)
-
 proc database_op {} {
   set i [expr int(rand()*2)] 
   if {$i==0} {
@@ -165,7 +169,7 @@ proc database_op {} {
     delete_rows [random_integers 100 1000]
     set i [expr int(rand()*3)] 
     if {$i==0} {
-      db eval {PRAGMA incremental_vacuum}
+      sql {PRAGMA incremental_vacuum}
     }
   }
 }
@@ -177,27 +181,82 @@ proc savepoint_op {} {
   set C [lindex $cmds [expr int(rand()*6)]]
   set N [lindex $names [expr int(rand()*5)]]
 
+  #puts stderr "   $C $N ;  "
+  #flush stderr
+
   $C $N
   return ok
 }
 
-do_test savepoint6-2.1 {
+expr srand(0)
+
+############################################################################
+############################################################################
+# Start of test cases.
+
+do_test savepoint6-1.1 {
+  sql $DATABASE_SCHEMA
+} {}
+do_test savepoint6-1.2 {
+  insert_rows {
+    497 166 230 355 779 588 394 317 290 475 362 193 805 851 564 
+    763 44 930 389 819 765 760 966 280 538 414 500 18 25 287 320 
+    30 382 751 87 283 981 429 630 974 421 270 810 405 
+  }
+
   savepoint one
-  insert_rows [random_integers 100 1000]
+  insert_rows 858
+  delete_rows 930
+  savepoint two
+    execsql {PRAGMA incremental_vacuum}
+    savepoint three
+      insert_rows 144
+     rollback three
+    rollback two
   release one
-  checkdb
-} {ok}
 
-for {set i 0} {$i < 1000} {incr i} {
-  do_test savepoint6-3.$i.1 {
-    savepoint_op
-  } {ok}
+  execsql {SELECT count(*) FROM t1}
+} {44}
+
+foreach zSetup [list {
+  set testname normal
+  sqlite3 db test.db
+} {
+  set testname tempdb
+  sqlite3 db ""
+} {
+  set testname smallcache
+  sqlite3 db test.db
+  sql { PRAGMA cache_size = 10 }
+}] {
+
+  unset -nocomplain ::lSavepoint
+  unset -nocomplain ::aEntry
 
-  do_test savepoint6-3.$i.2 {
-    database_op
-    database_op
+  db close
+  file delete -force test.db
+  eval $zSetup
+  sql $DATABASE_SCHEMA
+
+  do_test savepoint6-$testname.setup {
+    savepoint one
+    insert_rows [random_integers 100 1000]
+    release one
     checkdb
   } {ok}
+  
+  for {set i 0} {$i < 1000} {incr i} {
+    do_test savepoint6-$testname.$i.1 {
+      savepoint_op
+      checkdb
+    } {ok}
+  
+    do_test savepoint6-$testname.$i.2 {
+      database_op
+      database_op
+      checkdb
+    } {ok}
+  }
 }
 
 unset -nocomplain ::lSavepoint