]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add a version number to the wal-index header. If SQLite encounters a version number...
authordan <dan@noemail.net>
Wed, 23 Jun 2010 15:55:43 +0000 (15:55 +0000)
committerdan <dan@noemail.net>
Wed, 23 Jun 2010 15:55:43 +0000 (15:55 +0000)
FossilOrigin-Name: 8d0f8a7f70d6fb42369411a934b30f8c8ca8322f

13 files changed:
manifest
manifest.uuid
src/wal.c
test/backup2.test
test/date.test
test/pager1.test
test/wal.test
test/wal2.test
test/wal_common.tcl
test/walbak.test
test/walcksum.test
test/walcrash2.test
test/walhook.test

index 6243eaeeb90bdd28d25647d1aebf39d45458e6bc..7df261b1515565aa23bb1cbf014798e4ed7c275d 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,8 +1,5 @@
------BEGIN PGP SIGNED MESSAGE-----
-Hash: SHA1
-
-C Fix\sthe\sxCurrentTimeInt64\sinterface\son\swindows.\s\sIt\swas\soff\sby\sa\sfactor\sof\s10.
-D 2010-06-23T15:18:12
+C Add\sa\sversion\snumber\sto\sthe\swal-index\sheader.\sIf\sSQLite\sencounters\sa\sversion\snumber\sin\seither\sthe\swal\sor\swal-index\sfiles\sthat\sit\sdoes\snot\sunderstand,\sthe\soperation\sis\sabandoned\sand\sSQLITE_CANTOPEN\sreturned.
+D 2010-06-23T15:55:43
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -229,7 +226,7 @@ F src/vdbeblob.c 258a6010ba7a82b72b327fb24c55790655689256
 F src/vdbemem.c 2a82f455f6ca6f78b59fb312f96054c04ae0ead1
 F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
 F src/vtab.c a0f8a40274e4261696ef57aa806de2776ab72cda
-F src/wal.c 70ffd43c93adb3c28c175f7ac5e63db3b5469821
+F src/wal.c 563b7030efc55fe1ef105bd865876f2bf74f281b
 F src/wal.h 4ace25262452d17e7d3ec970c89ee17794004008
 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
 F src/where.c 1c895bef33d0dfc7ed90fb1f74120435d210ea56
@@ -262,7 +259,7 @@ F test/autovacuum.test 25f891bc343a8bf5d9229e2e9ddab9f31a9ab5ec
 F test/autovacuum_ioerr2.test 598b0663074d3673a9c1bc9a16e80971313bafe6
 F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85
 F test/backup.test 200e64bd91244b73ca8094bc1e03dfc83cc94c2e
-F test/backup2.test 159419073d9769fdb1780ed7e5b391a046f898d5
+F test/backup2.test b7c69f937c912e85ac8a5dbd1e1cf290302b2d49
 F test/backup_ioerr.test 1f012e692f42c0442ae652443258f70e9f20fa38
 F test/backup_malloc.test 1e063c6d75143d0d6e0ae77971dd690070369387
 F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f
@@ -331,7 +328,7 @@ F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2
 F test/createtab.test 199cf68f44e5d9e87a0b8afc7130fdeb4def3272
 F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
 F test/ctime.test f5040beef89c1b2bdb6a9edb7358a519213ff80c
-F test/date.test 30269d897df4e2e8064aca5d36bc78c5fa265ce3
+F test/date.test 6354b883f922c38046a8efbad187cc95df6da023
 F test/dbstatus.test 838447a0ecca1232675b025c0a518a9ef0f8057e
 F test/default.test 6faf23ccb300114924353007795aa9a8ec0aa9dc
 F test/delete.test f7629d9eb245dfca170169cc5c7a735dec34aeb4
@@ -537,7 +534,7 @@ F test/notify2.test 195a467e021f74197be2c4fb02d6dee644b8d8db
 F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347
 F test/null.test a8b09b8ed87852742343b33441a9240022108993
 F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec
-F test/pager1.test c3ec08550a4b6beb1c26976e6f7eca9762427259
+F test/pager1.test 31478e94375cb3725a2ffe8b84196520a8248c36
 F test/pager2.test f5c757c271ce642d36a393ecbfb3aef1c240dcef
 F test/pagerfault.test e67e9c18bf7b4bb8cc8d458d3a5ecc980f18a225
 F test/pageropt.test 8146bf448cf09e87bb1867c2217b921fb5857806
@@ -772,16 +769,16 @@ F test/vtabE.test 7c4693638d7797ce2eda17af74292b97e705cc61
 F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
 F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
 F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
-F test/wal.test 55c3fae8a03437d52518e61ef115544fac108582
-F test/wal2.test 7ea1426f71fd29566ec8be818f3c2681125dd462
+F test/wal.test 1891e6f72dd437a1c2a48091aa9182ba17a8f780
+F test/wal2.test 9f2c2a00358b1466bc38feda85f105a4fb52f251
 F test/wal3.test bb3bc0be06411c2d147c1d1d636b6208fbe0349d
-F test/wal_common.tcl 3e953ae60919281688ea73e4d0aa0e1bc94becd9
-F test/walbak.test e7650a26eb4b8abeca9b145b1af1e63026dde432
-F test/walcksum.test 4efa8fb88c32bed8288ea4385a9cc113a5c8f0bf
+F test/wal_common.tcl 875ee2118cd7b292ba22fb9bfa66a984b5226b13
+F test/walbak.test e5632adde03fbb0533b9928a89468566ef78a710
+F test/walcksum.test a37b36375c595e61bdb7e1ec49b5f0979b6fc7ce
 F test/walcrash.test f6d5fb2bb108876f04848720a488065d9deef69f
-F test/walcrash2.test 14585ad1a2c85da2de721caa3b4deeea55213008
+F test/walcrash2.test 019d60b89d96c1937adb2b30b850ac7e86e5a142
 F test/walfault.test c2b524299dede269282a0795e11396cc446ca9af
-F test/walhook.test 67e675127f4acb72f061a12667ce6e5460b06b78
+F test/walhook.test ed00a40ba7255da22d6b66433ab61fab16a63483
 F test/walmode.test b54e2f91f34179c65cab02a6916578617a33eef0
 F test/walslow.test d21625e2e99e11c032ce949e8a94661576548933
 F test/walthread.test a25a393c068a2b42b44333fa3fdaae9072f1617c
@@ -828,14 +825,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 8bfbdec647d29f0eb103ba7deb9116c44193f2e1
-R 09a8767bbb752bc5b889ee5ad34b2188
-U drh
-Z d3f0906bc523ad7c3782958b2021769c
------BEGIN PGP SIGNATURE-----
-Version: GnuPG v1.4.6 (GNU/Linux)
-
-iD8DBQFMIiW3oxKgR168RlERAv0qAJ0YNJBoEwyIMC3xoABroYp+XV2k5wCcCG9Z
-gBb3bOdo5LzCqETOgEv1j3o=
-=bpAb
------END PGP SIGNATURE-----
+P 51ef43b9f7db8fabf73d9c8a76dae6c275e50d58
+R e307cca35ebca5b482c8b5d8cba99105
+U dan
+Z a33770995e057029bfccdeb012e41a17
index d575526182e23513bd6fb2a2c5183512d32c4f5c..7640e952a63a1df1f9fc0ef175dd498a0c496db4 100644 (file)
@@ -1 +1 @@
-51ef43b9f7db8fabf73d9c8a76dae6c275e50d58
\ No newline at end of file
+8d0f8a7f70d6fb42369411a934b30f8c8ca8322f
\ No newline at end of file
index 0175c852ca24d130ff407431c48acf8821f1b187..83dd758378cef9ddf8a7040aa0e5e8d107698b56 100644 (file)
--- a/src/wal.c
+++ b/src/wal.c
@@ -40,6 +40,8 @@
 **    12: Checkpoint sequence number
 **    16: Salt-1, random integer incremented with each checkpoint
 **    20: Salt-2, a different random integer changing with each ckpt
+**    24: Checksum-1 (first part of checksum for first 24 bytes of header).
+**    28: Checksum-2 (second part of checksum for first 24 bytes of header).
 **
 ** Immediately following the wal-header are zero or more frames. Each
 ** frame consists of a 24-byte frame-header followed by a <page-size> bytes
@@ -246,6 +248,21 @@ int sqlite3WalTrace = 0;
 # define WALTRACE(X)
 #endif
 
+/*
+** The maximum (and only) versions of the wal and wal-index formats
+** that may be interpreted by this version of SQLite.
+**
+** If a client begins recovering a WAL file and finds that (a) the checksum
+** values in the wal-header are correct and (b) the version field is not
+** WAL_MAX_VERSION, recovery fails and SQLite returns SQLITE_CANTOPEN.
+**
+** Similarly, if a client successfully reads a wal-index header (i.e. the 
+** checksum test is successful) and finds that the version field is not
+** WALINDEX_MAX_VERSION, then no read-transaction is opened and SQLite
+** returns SQLITE_CANTOPEN.
+*/
+#define WAL_MAX_VERSION      3007000
+#define WALINDEX_MAX_VERSION 3007000
 
 /*
 ** Indices of various locking bytes.   WAL_NREADER is the number
@@ -272,6 +289,8 @@ typedef struct WalCkptInfo WalCkptInfo;
 ** object.
 */
 struct WalIndexHdr {
+  u32 iVersion;                   /* Wal-index version */
+  u32 unused;                     /* Unused (padding) field */
   u32 iChange;                    /* Counter incremented each transaction */
   u8 isInit;                      /* 1 when initialized */
   u8 bigEndCksum;                 /* True if checksums in WAL are big-endian */
@@ -351,8 +370,9 @@ struct WalCkptInfo {
 /* Size of header before each frame in wal */
 #define WAL_FRAME_HDRSIZE 24
 
-/* Size of write ahead log header */
-#define WAL_HDRSIZE 24
+/* Size of write ahead log header, including checksum. */
+/* #define WAL_HDRSIZE 24 */
+#define WAL_HDRSIZE 32
 
 /* WAL magic value. Either this value, or the same value with the least
 ** significant bit also set (WAL_MAGIC | 0x00000001) is stored in 32-bit
@@ -580,6 +600,7 @@ static void walIndexWriteHdr(Wal *pWal){
 
   assert( pWal->writeLock );
   pWal->hdr.isInit = 1;
+  pWal->hdr.iVersion = WALINDEX_MAX_VERSION;
   walChecksumBytes(1, (u8*)&pWal->hdr, nCksum, 0, pWal->hdr.aCksum);
   memcpy((void *)&aHdr[1], (void *)&pWal->hdr, sizeof(WalIndexHdr));
   sqlite3OsShmBarrier(pWal->pDbFd);
@@ -1029,6 +1050,7 @@ static int walIndexRecover(Wal *pWal){
     i64 iOffset;                  /* Next offset to read from log file */
     int szPage;                   /* Page size according to the log */
     u32 magic;                    /* Magic value read from WAL header */
+    u32 version;                  /* Magic value read from WAL header */
 
     /* Read in the WAL header. */
     rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
@@ -1055,9 +1077,21 @@ static int walIndexRecover(Wal *pWal){
     pWal->nCkpt = sqlite3Get4byte(&aBuf[12]);
     memcpy(&pWal->hdr.aSalt, &aBuf[16], 8);
     walChecksumBytes(pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN, 
-        aBuf, WAL_HDRSIZE, 0, pWal->hdr.aFrameCksum
+        aBuf, WAL_HDRSIZE-2*4, 0, pWal->hdr.aFrameCksum
     );
 
+    if( pWal->hdr.aFrameCksum[0]!=sqlite3Get4byte(&aBuf[24])
+     || pWal->hdr.aFrameCksum[1]!=sqlite3Get4byte(&aBuf[28])
+    ){
+      goto finished;
+    }
+
+    version = sqlite3Get4byte(&aBuf[4]);
+    if( version!=WAL_MAX_VERSION ){
+      rc = SQLITE_CANTOPEN_BKPT;
+      goto finished;
+    }
+
     /* Malloc a buffer to read frames into. */
     szFrame = szPage + WAL_FRAME_HDRSIZE;
     aFrame = (u8 *)sqlite3_malloc(szFrame);
@@ -1658,6 +1692,9 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
   ** being modified by another user.
   */
   badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1);
+  if( badHdr==0 && pWal->hdr.iVersion!=WALINDEX_MAX_VERSION ){
+    rc = SQLITE_CANTOPEN_BKPT;
+  }
 
   /* If the first attempt failed, it might have been due to a race
   ** with a writer.  So get a WRITE lock and try again.
@@ -2265,20 +2302,28 @@ int sqlite3WalFrames(
   */
   iFrame = pWal->hdr.mxFrame;
   if( iFrame==0 ){
-    u8 aWalHdr[WAL_HDRSIZE];        /* Buffer to assembly wal-header in */
+    u8 aWalHdr[WAL_HDRSIZE];      /* Buffer to assemble wal-header in */
+    u32 aCksum[2];                /* Checksum for wal-header */
+
     sqlite3Put4byte(&aWalHdr[0], (WAL_MAGIC | SQLITE_BIGENDIAN));
-    sqlite3Put4byte(&aWalHdr[4], 3007000);
+    sqlite3Put4byte(&aWalHdr[4], WAL_MAX_VERSION);
     sqlite3Put4byte(&aWalHdr[8], szPage);
-    pWal->szPage = szPage;
-    pWal->hdr.bigEndCksum = SQLITE_BIGENDIAN;
     sqlite3Put4byte(&aWalHdr[12], pWal->nCkpt);
     memcpy(&aWalHdr[16], pWal->hdr.aSalt, 8);
+    walChecksumBytes(1, aWalHdr, WAL_HDRSIZE-2*4, 0, aCksum);
+    sqlite3Put4byte(&aWalHdr[24], aCksum[0]);
+    sqlite3Put4byte(&aWalHdr[28], aCksum[1]);
+    
+    pWal->szPage = szPage;
+    pWal->hdr.bigEndCksum = SQLITE_BIGENDIAN;
+    pWal->hdr.aFrameCksum[0] = aCksum[0];
+    pWal->hdr.aFrameCksum[1] = aCksum[1];
+
     rc = sqlite3OsWrite(pWal->pWalFd, aWalHdr, sizeof(aWalHdr), 0);
     WALTRACE(("WAL%p: wal-header write %s\n", pWal, rc ? "failed" : "ok"));
     if( rc!=SQLITE_OK ){
       return rc;
     }
-    walChecksumBytes(1, aWalHdr, sizeof(aWalHdr), 0, pWal->hdr.aFrameCksum);
   }
   assert( pWal->szPage==szPage );
 
index 17b5f6de19cab82eaccd754e2988d5d4db13360e..749c460e4a401b8cbda7d2261e8d05d1aa73c889 100644 (file)
@@ -18,6 +18,8 @@
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
 
+do_not_use_codec
+
 ifcapable !trigger||!view { finish_test ; return }
 
 # Fill a database with test data.
index 1e29187f87573223f22135b4a412648136c14d4c..29b5ed4d1d5d6a273ed8a0681db64072510c8e5b 100644 (file)
@@ -500,30 +500,32 @@ datetest 13.34 {date('2001-01-01','-1.5 years')} {1999-07-02}
 # Put a floating point number in the database so that we can manipulate
 # raw bits using the hexio interface.
 #
-do_test date-14.1 {
-  execsql {
-    PRAGMA auto_vacuum=OFF;
-    PRAGMA page_size = 1024;
-    CREATE TABLE t1(x);
-    INSERT INTO t1 VALUES(1.1);
+if {0==[sqlite3 -has-codec]} {
+  do_test date-14.1 {
+    execsql {
+      PRAGMA auto_vacuum=OFF;
+      PRAGMA page_size = 1024;
+      CREATE TABLE t1(x);
+      INSERT INTO t1 VALUES(1.1);
+    }
+    db close
+    hexio_write test.db 2040 4142ba32bffffff9
+    sqlite3 db test.db
+    db eval {SELECT * FROM t1}
+  } {2454629.5}
+  
+  # Changing the least significant byte of the floating point value between
+  # 00 and FF should always generate a time of either 23:59:59 or 00:00:00,
+  # never 24:00:00
+  #
+  for {set i 0} {$i<=255} {incr i} {
+    db close
+    hexio_write test.db 2047 [format %02x $i]
+    sqlite3 db test.db
+    do_test date-14.2.$i {
+      set date [db one {SELECT datetime(x) FROM t1}]
+      expr {$date eq "2008-06-12 00:00:00" || $date eq "2008-06-11 23:59:59"}
+    } {1}
   }
-  db close
-  hexio_write test.db 2040 4142ba32bffffff9
-  sqlite3 db test.db
-  db eval {SELECT * FROM t1}
-} {2454629.5}
-
-# Changing the least significant byte of the floating point value between
-# 00 and FF should always generate a time of either 23:59:59 or 00:00:00,
-# never 24:00:00
-#
-for {set i 0} {$i<=255} {incr i} {
-  db close
-  hexio_write test.db 2047 [format %02x $i]
-  sqlite3 db test.db
-  do_test date-14.2.$i {
-    set date [db one {SELECT datetime(x) FROM t1}]
-    expr {$date eq "2008-06-12 00:00:00" || $date eq "2008-06-11 23:59:59"}
-  } {1}
 }
 finish_test
index a9481e853bf013f562d711bbd6b508d9b1d9e174..332fb1ff80b29af4141e9379aa8a318ddeaaa95a 100644 (file)
@@ -556,6 +556,10 @@ do_execsql_test pager1.4.5.2 {
 #                journal. Check that the first record in the transaction is 
 #                played back, but not the second.
 #
+#  pager1-4.5.6: Restore the file-system. Try to open the database with a
+#                readonly connection. This should fail, as a read-only
+#                connection cannot roll back the database file.
+#
 faultsim_restore_and_reopen
 do_execsql_test pager1.4.5.3 {
   SELECT * FROM t1;
@@ -574,6 +578,14 @@ do_execsql_test pager1.4.5.5 {
   SELECT * FROM t2;
 } {I II III IV 3 4}
 
+faultsim_restore_and_reopen
+db close
+sqlite3 db test.db -readonly 1
+do_catchsql_test pager1.4.5.6 {
+  SELECT * FROM t1;
+  SELECT * FROM t2;
+} {1 {disk I/O error}}
+
 db close
 tv delete
 
index b7a026efe26d70222b4ec4a7c391fd0f93a5499d..59097dc740f89a7b014c6785c4c52a0acaeeb813 100644 (file)
@@ -17,6 +17,7 @@ set testdir [file dirname $argv0]
 source $testdir/tester.tcl
 source $testdir/lock_common.tcl
 source $testdir/malloc_common.tcl
+source $testdir/wal_common.tcl
 
 ifcapable !wal {finish_test ; return }
 
@@ -41,10 +42,6 @@ proc sqlite3_wal {args} {
   [lindex $args 0] function blob blob
 }
 
-proc log_file_size {nFrame pgsz} {
-  expr {24 + ($pgsz+24)*$nFrame}
-}
-
 proc log_deleted {logfile} {
   return [expr [file exists $logfile]==0]
 }
@@ -87,7 +84,7 @@ do_test wal-1.1 {
 do_test wal-1.2 {
   # There are now two pages in the log.
   file size test.db-wal
-} [log_file_size 2 1024]
+} [wal_file_size 2 1024]
 
 do_test wal-1.3 {
   execsql { SELECT * FROM sqlite_master }
@@ -366,11 +363,11 @@ do_test wal-7.1 {
     INSERT INTO t1 VALUES(1, 2);
   }
   list [file size test.db] [file size test.db-wal]
-} [list 1024 [log_file_size 3 1024]]
+} [list 1024 [wal_file_size 3 1024]]
 do_test wal-7.2 {
   execsql { PRAGMA wal_checkpoint }
   list [file size test.db] [file size test.db-wal]
-} [list 2048 [log_file_size 3 1024]]
+} [list 2048 [wal_file_size 3 1024]]
 
 # Execute some transactions in auto-vacuum mode to test database file
 # truncation.
@@ -685,11 +682,11 @@ do_test wal-11.1 {
 do_test wal-11.2 {
   execsql { PRAGMA wal_checkpoint }
   list [expr [file size test.db]/1024] [file size test.db-wal]
-} [list 3 [log_file_size 3 1024]]
+} [list 3 [wal_file_size 3 1024]]
 do_test wal-11.3 {
   execsql { INSERT INTO t1 VALUES( blob(900) ) }
   list [expr [file size test.db]/1024] [file size test.db-wal]
-} [list 3 [log_file_size 4 1024]]
+} [list 3 [wal_file_size 4 1024]]
 
 do_test wal-11.4 {
   execsql { 
@@ -700,7 +697,7 @@ do_test wal-11.4 {
       INSERT INTO t1 SELECT blob(900) FROM t1;   -- 16
   }
   list [expr [file size test.db]/1024] [file size test.db-wal]
-} [list 3 [log_file_size 32 1024]]
+} [list 3 [wal_file_size 32 1024]]
 do_test wal-11.5 {
   execsql { 
     SELECT count(*) FROM t1;
@@ -710,7 +707,7 @@ do_test wal-11.5 {
 do_test wal-11.6 {
   execsql COMMIT
   list [expr [file size test.db]/1024] [file size test.db-wal]
-} [list 3 [log_file_size 41 1024]]
+} [list 3 [wal_file_size 41 1024]]
 do_test wal-11.7 {
   execsql { 
     SELECT count(*) FROM t1;
@@ -720,7 +717,7 @@ do_test wal-11.7 {
 do_test wal-11.8 {
   execsql { PRAGMA wal_checkpoint }
   list [expr [file size test.db]/1024] [file size test.db-wal]
-} [list 37 [log_file_size 41 1024]]
+} [list 37 [wal_file_size 41 1024]]
 do_test wal-11.9 {
   db close
   list [expr [file size test.db]/1024] [log_deleted test.db-wal]
@@ -734,7 +731,7 @@ do_test wal-11.10 {
       SELECT count(*) FROM t1;
   }
   list [expr [file size test.db]/1024] [file size test.db-wal]
-} [list 37 [log_file_size 37 1024]]
+} [list 37 [wal_file_size 37 1024]]
 do_test wal-11.11 {
   execsql {
       SELECT count(*) FROM t1;
@@ -744,7 +741,7 @@ do_test wal-11.11 {
 } {32 16}
 do_test wal-11.12 {
   list [expr [file size test.db]/1024] [file size test.db-wal]
-} [list 37 [log_file_size 37 1024]]
+} [list 37 [wal_file_size 37 1024]]
 do_test wal-11.13 {
   execsql {
     INSERT INTO t1 VALUES( blob(900) );
@@ -754,7 +751,7 @@ do_test wal-11.13 {
 } {17 ok}
 do_test wal-11.14 {
   list [expr [file size test.db]/1024] [file size test.db-wal]
-} [list 37 [log_file_size 37 1024]]
+} [list 37 [wal_file_size 37 1024]]
 
 
 #-------------------------------------------------------------------------
@@ -771,7 +768,7 @@ do_test wal-12.1 {
     INSERT INTO t1 VALUES('A', 1);
   }
   list [expr [file size test.db]/1024] [file size test.db-wal]
-} [list 1 [log_file_size 5 1024]]
+} [list 1 [wal_file_size 5 1024]]
 do_test wal-12.2 {
   db close
   sqlite3 db test.db
@@ -865,7 +862,7 @@ do_test wal-13.2.2 {
   execsql { SELECT count(*) FROM t2 }
 } [expr int(pow(2, 16))]
 do_test wal-13.2.3 {
-  expr [file size test.db-wal] > [log_file_size 33000 1024]
+  expr [file size test.db-wal] > [wal_file_size 33000 1024]
 } 1
 
 do_multiclient_test tn {
@@ -1067,20 +1064,20 @@ foreach {tn ckpt_cmd ckpt_res ckpt_main ckpt_aux} {
     }
   
     list [file size test.db] [file size test.db-wal]
-  } [list [expr 1*1024] [log_file_size 10 1024]]
+  } [list [expr 1*1024] [wal_file_size 10 1024]]
   do_test wal-16.$tn.3 {
     list [file size test2.db] [file size test2.db-wal]
-  } [list [expr 1*1024] [log_file_size 16 1024]]
+  } [list [expr 1*1024] [wal_file_size 16 1024]]
   
   do_test wal-16.$tn.4 [list eval $ckpt_cmd] $ckpt_res
   
   do_test wal-16.$tn.5 {
     list [file size test.db] [file size test.db-wal]
-  } [list [expr ($ckpt_main ? 7 : 1)*1024] [log_file_size 10 1024]]
+  } [list [expr ($ckpt_main ? 7 : 1)*1024] [wal_file_size 10 1024]]
 
   do_test wal-16.$tn.6 {
     list [file size test2.db] [file size test2.db-wal]
-  } [list [expr ($ckpt_aux ? 7 : 1)*1024] [log_file_size 16 1024]]
+  } [list [expr ($ckpt_aux ? 7 : 1)*1024] [wal_file_size 16 1024]]
 
   catch { db close }
 }
@@ -1094,7 +1091,7 @@ foreach {tn ckpt_cmd ckpt_res ckpt_main ckpt_aux} {
 # a transaction that modifies 171 pages. In synchronous=NORMAL mode, this
 # produces a log file of:
 #
-#   24 + (24+512)*171 = 90312 bytes.
+#   32 + (24+512)*171 = 90312 bytes.
 #
 # Slightly larger than 11*8192 = 90112 bytes.
 #
@@ -1106,15 +1103,15 @@ foreach {tn ckpt_cmd ckpt_res ckpt_main ckpt_aux} {
 #
 set old_pending_byte [sqlite3_test_control_pending_byte 0x10000000]
 catch { db close }
-foreach {tn sectorsize logsize} {
-  1   128  92216
-  2   256  92216
-  3   512  92216 
-  4  1024  92216
-  5  2048  92216
-  6  4096  94360
-  7  8192  98648
-} {
+foreach {tn sectorsize logsize} "
+  1   128  [wal_file_size 172 512]
+  2   256  [wal_file_size 172 512]
+  3   512  [wal_file_size 172 512] 
+  4  1024  [wal_file_size 172 512]
+  5  2048  [wal_file_size 172 512]
+  6  4096  [wal_file_size 176 512]
+  7  8192  [wal_file_size 184 512]
+" {
   file delete -force test.db test.db-wal test.db-journal
   sqlite3_simulate_device -sectorsize $sectorsize
   sqlite3 db test.db -vfs devsym
@@ -1181,7 +1178,7 @@ do_test wal-18.0 {
   file copy -force test.db-wal testX.db-wal
   db close
   list [file size testX.db] [file size testX.db-wal]
-} [list [expr 3*1024] [log_file_size 6 1024]]
+} [list [expr 3*1024] [wal_file_size 6 1024]]
 
 unset -nocomplain nFrame result
 foreach {nFrame result} {
@@ -1280,6 +1277,8 @@ foreach {tn pgsz works} {
       set c1 0
       set c2 0
       logcksum c1 c2 $walhdr
+
+      append walhdr [binary format II $c1 $c2]
       logcksum c1 c2 [string range $framehdr 0 7]
       logcksum c1 c2 $framebody
       set framehdr [binary format IIIIII $pg 5 22 23 $c1 $c2]
@@ -1292,7 +1291,7 @@ foreach {tn pgsz works} {
       close $fd
   
       file size test.db-wal
-    } [log_file_size 1 $pgsz]
+    } [wal_file_size 1 $pgsz]
   
     do_test wal-18.2.$tn.$pg.5 {
       sqlite3 db test.db
@@ -1414,10 +1413,9 @@ integrity_check wal-20.5
 
 catch { db2 close }
 catch { db close }
-file delete -force test.db test.db-wal test.db-journal
 
 do_test wal-21.1 {
-  sqlite3 db test.db
+  faultsim_delete_and_reopen
   execsql { 
     PRAGMA journal_mode = WAL;
     CREATE TABLE t1(a, b);
index 447ac109a4bf77906286dc81cc1ca211c34d4ae4..dbfcfc467af6e635730ef0631555debd3f1e61a4 100644 (file)
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
 source $testdir/lock_common.tcl
+source $testdir/malloc_common.tcl
+source $testdir/wal_common.tcl
+
 ifcapable !wal {finish_test ; return }
 
 proc set_tvfs_hdr {file args} {
 
   # Set $nHdr to the number of bytes in the wal-index header:
-  set nHdr 40
+  set nHdr 48
   set nInt [expr {$nHdr/4}]
 
   if {[llength $args]>2} {
@@ -880,7 +883,7 @@ foreach {tn hdr1 hdr2 res} [list                                            \
   5  $wih(2)                $wih(1)                {Barton Deakin Watson}   \
   6  $wih(2)                $wih(2)                {Barton Deakin Watson}   \
   7  $wih(1)                $wih(1)                {Barton Deakin}          \
-  8  {0 0 0 0 0 0 0 0 0 0} {0 0 0 0 0 0 0 0 0 0}   {Barton Deakin Watson}   \
+  8  {0 0 0 0 0 0 0 0 0 0 0 0} {0 0 0 0 0 0 0 0 0 0 0 0} {Barton Deakin Watson}
 ] {
   do_test wal2-9.$tn {
     set_tvfs_hdr $::filename $hdr1 $hdr2
@@ -891,4 +894,62 @@ foreach {tn hdr1 hdr2 res} [list                                            \
 db2 close
 db close
 
+#-------------------------------------------------------------------------
+# This block of tests - wal2-10.* - focus on the libraries response to
+# new versions of the wal or wal-index formats. 
+#
+#   wal2-10.1.*: Test that the library refuses to "recover" a new WAL 
+#                format.
+#
+#   wal2-10.2.*: Test that the library refuses to read or write a database
+#                if the wal-index version is newer than it understands.
+#
+# At time of writing, the only versions of the wal and wal-index formats
+# that exist are versions 3007000 (corresponding to SQLite version 3.7.0,
+# the first version of SQLite to feature wal mode).
+#
+do_test wal2-10.1.1 {
+  faultsim_delete_and_reopen
+  execsql {
+    PRAGMA journal_mode = WAL;
+    CREATE TABLE t1(a, b);
+    PRAGMA wal_checkpoint;
+    INSERT INTO t1 VALUES(1, 2);
+    INSERT INTO t1 VALUES(3, 4);
+  }
+  faultsim_save_and_close
+} {}
+do_test wal2-10.1.2 {
+  faultsim_restore_and_reopen
+  execsql { SELECT * FROM t1 }
+} {1 2 3 4}
+do_test wal2-10.1.3 {
+  faultsim_restore_and_reopen
+  set hdr [wal_set_walhdr test.db-wal]
+  lindex $hdr 1
+} {3007000}
+do_test wal2-10.1.4 {
+  lset hdr 1 3007001
+  wal_set_walhdr test.db-wal $hdr
+  catchsql { SELECT * FROM t1 }
+} {1 {unable to open database file}}
+
+testvfs tvfs -default 1
+do_test wal2-10.2.1 {
+  faultsim_restore_and_reopen
+  execsql { SELECT * FROM t1 }
+} {1 2 3 4}
+do_test wal2-10.2.2 { 
+  set hdr [set_tvfs_hdr $::filename] 
+  lindex $hdr 0 
+} {3007000}
+breakpoint
+do_test wal2-10.2.3 { 
+  lset hdr 0 3007001
+  wal_fix_walindex_cksum hdr 
+  set_tvfs_hdr $::filename $hdr
+  catchsql { SELECT * FROM t1 }
+} {1 {unable to open database file}}
+
 finish_test
+
index cbea99949a335100b55cdb5509af685c6f7f457e..6e42c447b1b082954fade8b15476c3dbdc5970b9 100644 (file)
 #
 
 proc wal_file_size {nFrame pgsz} {
-  expr {24 + ($pgsz+24)*$nFrame}
+  expr {32 + ($pgsz+24)*$nFrame}
 }
 
 proc wal_frame_count {zFile pgsz} {
   set f [file size $zFile]
-  expr {($f - 24) / ($pgsz+24)}
+  expr {($f - 32) / ($pgsz+24)}
 }
 
+proc wal_cksum_intlist {ckv1 ckv2 intlist} {
+  upvar $ckv1 c1
+  upvar $ckv2 c2
+  foreach {v1 v2} $intlist {
+    set c1 [expr {($c1 + $v1 + $c2)&0xFFFFFFFF}]
+    set c2 [expr {($c2 + $v2 + $c1)&0xFFFFFFFF}]
+  }
+}
+
+
+# This proc calculates checksums in the same way as those used by SQLite 
+# in WAL files. If the $endian argument is "big", then checksums are
+# calculated by interpreting data as an array of big-endian integers. If
+# it is "little", data is interpreted as an array of little-endian integers.
+#
+proc wal_cksum {endian ckv1 ckv2 blob} {
+  upvar $ckv1 c1
+  upvar $ckv2 c2
+
+  if {$endian!="big" && $endian!="little"} {
+    return -error "Bad value \"$endian\" - must be \"big\" or \"little\""
+  }
+  set scanpattern I*
+  if {$endian == "little"} { set scanpattern i* }
+
+  binary scan $blob $scanpattern values
+  wal_cksum_intlist c1 c2 $values
+}
+
+proc wal_set_walhdr {filename {intlist {}}} {
+  if {[llength $intlist]==6} {
+    set blob [binary format I6 $intlist]
+    set endian little
+    if {[lindex $intlist 0] & 0x00000001} { set endian big }
+    set c1 0
+    set c2 0
+    wal_cksum $endian c1 c2 $blob
+    append blob [binary format II $c1 $c2]
+
+    set fd [open $filename r+]
+    fconfigure $fd -translation binary
+    fconfigure $fd -encoding binary
+    seek $fd 0
+    puts -nonewline $fd $blob
+    close $fd
+  }
+
+  set fd [open $filename]
+  fconfigure $fd -translation binary
+  fconfigure $fd -encoding binary
+  set blob [read $fd 24]
+
+  binary scan $blob I6 ints
+  set ints
+}
+
+proc wal_fix_walindex_cksum {hdrvar} {
+  upvar $hdrvar hdr
+  set c1 0
+  set c2 0
+  wal_cksum_intlist c1 c2 [lrange $hdr 0 9]
+  lset hdr 10 $c1
+  lset hdr 11 $c2
+}
 
 
index 79d26eafc0be8ad01b2751210c550fd601093659..4988cfd52c1e21b1834f21483d87acc1dcf9d11a 100644 (file)
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
+source $testdir/wal_common.tcl
+
+do_not_use_codec
 
 ifcapable !wal {finish_test ; return }
 
-proc log_file_size {nFrame pgsz} {
-  expr {24 + ($pgsz+24)*$nFrame}
-}
 
 # Test organization:
 # 
@@ -69,11 +69,11 @@ do_test walbak-1.4 {
 } {wal}
 do_test walbak-1.5 {
   list [file size test.db] [file size test.db-wal]
-} [list 1024 [log_file_size 6 1024]]
+} [list 1024 [wal_file_size 6 1024]]
 do_test walbak-1.6 {
   execsql { PRAGMA wal_checkpoint }
   list [file size test.db] [file size test.db-wal]
-} [list [expr 3*1024] [log_file_size 6 1024]]
+} [list [expr 3*1024] [wal_file_size 6 1024]]
 do_test walbak-1.7 {
   execsql { 
     CREATE TABLE t2(a, b);
@@ -81,15 +81,15 @@ do_test walbak-1.7 {
     DROP TABLE t1;
   }
   list [file size test.db] [file size test.db-wal]
-} [list [expr 3*1024] [log_file_size 6 1024]]
+} [list [expr 3*1024] [wal_file_size 6 1024]]
 do_test walbak-1.8 {
   execsql { VACUUM }
   list [file size test.db] [file size test.db-wal]
-} [list [expr 3*1024] [log_file_size 8 1024]]
+} [list [expr 3*1024] [wal_file_size 8 1024]]
 do_test walbak-1.9 {
   execsql { PRAGMA wal_checkpoint }
   list [file size test.db] [file size test.db-wal]
-} [list [expr 2*1024] [log_file_size 8 1024]]
+} [list [expr 2*1024] [wal_file_size 8 1024]]
 
 #-------------------------------------------------------------------------
 # Backups when the source db is modified mid-backup.
index 0d15bc050e22f37013fa2c0350410a7391f4b8f2..b2c4a90530159c1a2680d45f01b689e1442ee488 100644 (file)
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
 source $testdir/lock_common.tcl
+source $testdir/wal_common.tcl
 
 ifcapable !wal {finish_test ; return }
 
-# This proc calculates checksums in the same way as those used by SQLite 
-# in WAL files. If the $endian argument is "big", then checksums are
-# calculated by interpreting data as an array of big-endian integers. If
-# it is "little", data is interpreted as an array of little-endian integers.
-#
-proc log_cksum {endian ckv1 ckv2 blob} {
-  upvar $ckv1 c1
-  upvar $ckv2 c2
-
-  if {$endian!="big" && $endian!="little"} {
-    return -error "Bad value \"$endian\" - must be \"big\" or \"little\""
-  }
-  set scanpattern I*
-  if {$endian == "little"} { set scanpattern i* }
-
-  binary scan $blob $scanpattern values
-  foreach {v1 v2} $values {
-    set c1 [expr {($c1 + $v1 + $c2)&0xFFFFFFFF}]
-    set c2 [expr {($c2 + $v2 + $c1)&0xFFFFFFFF}]
-  }
-}
-
-proc log_file_size {nFrame pgsz} {
-  expr {24 + ($pgsz+24)*$nFrame}
-}
-
 # Read and return the contents of file $filename. Treat the content as
 # binary data.
 #
@@ -72,7 +47,6 @@ proc log_checksum_verify {filename iFrame endian} {
   expr {$c1==$expect1 && $c2==$expect2}
 }
 
-#
 # File $filename must be a WAL file on disk. Compute the checksum for frame
 # $iFrame in the file by interpreting data as $endian-endian integers 
 # ($endian must be either "big" or "little"). Then write the computed 
@@ -92,21 +66,38 @@ proc log_checksum_write {filename iFrame endian} {
   close $fd
 }
 
+# Calculate and return the checksum for a particular frame in a WAL.
+#
+# Arguments are:
+#
+#   $data         Blob containing the entire contents of a WAL.
+#
+#   $iFrame       Frame number within the $data WAL. Frames are numbered 
+#                 starting at 1.
+#
+#   $endian       One of "big" or "little".
+#
+# Returns a list of three elements, as follows:
+#
+#   * The byte offset of the checksum belonging to frame $iFrame in the WAL.
+#   * The first integer in the calculated version of the checksum.
+#   * The second integer in the calculated version of the checksum.
+#
 proc log_checksum_calc {data iFrame endian} {
   
   binary scan [string range $data 8 11] I pgsz
   if {$iFrame > 1} {
-    set n [log_file_size [expr $iFrame-2] $pgsz]
+    set n [wal_file_size [expr $iFrame-2] $pgsz]
     binary scan [string range $data [expr $n+16] [expr $n+23]] II c1 c2
   } else {
     set c1 0
     set c2 0
-    log_cksum $endian c1 c2 [string range $data 0 23]
+    wal_cksum $endian c1 c2 [string range $data 0 23]
   }
 
-  set n [log_file_size [expr $iFrame-1] $pgsz]
-  log_cksum $endian c1 c2 [string range $data $n [expr $n+7]]
-  log_cksum $endian c1 c2 [string range $data [expr $n+24] [expr $n+24+$pgsz-1]]
+  set n [wal_file_size [expr $iFrame-1] $pgsz]
+  wal_cksum $endian c1 c2 [string range $data $n [expr $n+7]]
+  wal_cksum $endian c1 c2 [string range $data [expr $n+24] [expr $n+24+$pgsz-1]]
 
   list [expr $n+16] $c1 $c2
 }
@@ -116,6 +107,9 @@ proc log_checksum_calc {data iFrame endian} {
 # WAL header to indicate that checksums are $endian-endian ($endian must be
 # either "big" or "little").
 #
+# Also update the wal header checksum (since the wal header contents may
+# have changed).
+#
 proc log_checksum_writemagic {filename endian} {
   set val [expr {0x377f0682 | ($endian == "big" ? 1 : 0)}]
   set bin [binary format I $val]
@@ -123,6 +117,15 @@ proc log_checksum_writemagic {filename endian} {
   fconfigure $fd -encoding binary
   fconfigure $fd -translation binary
   puts -nonewline $fd $bin
+
+  seek $fd 0
+  set blob [read $fd 24]
+  set c1 0
+  set c2 0
+  wal_cksum $endian c1 c2 $blob 
+  seek $fd 24
+  puts -nonewline $fd [binary format II $c1 $c2]
+
   close $fd
 }
 
@@ -174,7 +177,7 @@ foreach endian {big little} {
     db close
 
     list [file size test2.db] [file size test2.db-wal]
-  } [list [expr 1024*3] [log_file_size 6 1024]]
+  } [list [expr 1024*3] [wal_file_size 6 1024]]
 
   # Verify that the checksums are valid for all frames and that they
   # are calculated by interpreting data in native byte-order.
@@ -211,7 +214,7 @@ foreach endian {big little} {
       INSERT INTO t1 VALUES(34, 'thirtyfour');
     }
     list [file size test.db] [file size test.db-wal]
-  } [list [expr 1024*3] [log_file_size 8 1024]]
+  } [list [expr 1024*3] [wal_file_size 8 1024]]
   for {set f 1} {$f <= 8} {incr f} {
     do_test walcksum-1.$endian.5.$f {
       log_checksum_verify test.db-wal $f $endian
@@ -235,7 +238,7 @@ foreach endian {big little} {
       INSERT INTO t1 VALUES(55, 'fiftyfive');
     } db2
     list [file size test.db] [file size test.db-wal]
-  } [list [expr 1024*3] [log_file_size 10 1024]]
+  } [list [expr 1024*3] [wal_file_size 10 1024]]
   for {set f 1} {$f <= 10} {incr f} {
     do_test walcksum-1.$endian.7.$f {
       log_checksum_verify test.db-wal $f $endian
@@ -351,7 +354,7 @@ do_test walcksum-3.1 {
   }
 
   file size test.db-wal
-} [log_file_size 1 1024]
+} [wal_file_size 1 1024]
 do_test walcksum-3.2 {
   file copy -force test.db-wal test2.db-wal
   file copy -force test.db test2.db
@@ -365,7 +368,7 @@ file copy -force test.db test2.db
 foreach incr {1 2 3 20 40 60 80 100 120 140 160 180 200 220 240 253 254 255} {
   do_test walcksum-3.3.$incr {
     set FAIL 0
-    for {set iOff 0} {$iOff < [log_file_size 1 1024]} {incr iOff} {
+    for {set iOff 0} {$iOff < [wal_file_size 1 1024]} {incr iOff} {
 
       file copy -force test.db-wal test2.db-wal
       set fd [open test2.db-wal r+]
index 417fe144d7bce4baba75da30bd42664b9b50104b..7116281c2d8c67a347033c4211aec96b9b893400 100644 (file)
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
 source $testdir/lock_common.tcl
+source $testdir/wal_common.tcl
 ifcapable !wal {finish_test ; return }
 
-proc wal_file_size {nFrame pgsz} { 
-  expr {24 + ($pgsz+24)*$nFrame} 
-}
 
 #-------------------------------------------------------------------------
 # This test case demonstrates a flaw in the wal-index manipulation that
index dbda082cb845c4de795bd7e89c708fee5345a245..631ec834e3873b57421cf6eb548ff5e929b6486e 100644 (file)
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
+source $testdir/wal_common.tcl
 
 ifcapable !wal {finish_test ; return }
 
-proc log_file_size {nFrame pgsz} {
-  expr {24 + ($pgsz+24)*$nFrame}
-}
-
 set ::wal_hook [list]
 proc wal_hook {zDb nEntry} {
   lappend ::wal_hook $zDb $nEntry
@@ -104,7 +101,7 @@ foreach {tn sql dbpages logpages} {
   do_test walhook-2.$tn {
     execsql $sql
     list [file size test.db] [file size test.db-wal]
-  } [list [expr $dbpages*1024] [log_file_size $logpages 1024]]
+  } [list [expr $dbpages*1024] [wal_file_size $logpages 1024]]
 }
 
 catch { db2 close }