- C Merge\sfix\s[f80c3f922a]\swith\sexperimental\schanges.
- D 2010-06-17T06:19:53
-C Do\snot\sdelete\sthe\sjournal\sfile\sin\s"PRAGMA\sjournal_mode"\scommands.\sThis\sfixes\s[fc62af4523].
-D 2010-06-17T10:42:07
++C Merge\strunk\supdates\swith\sexperimental\sbranch.
++D 2010-06-17T10:52:07
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
F src/os_os2.c 665876d5eec7585226b0a1cf5e18098de2b2da19
F src/os_unix.c ae173c9f6afaa58b2833a1c95c6cd32021755c42
F src/os_win.c dfde7d33c446e89dd9a277c036f2c4cc564b3138
- F src/pager.c 3b2527d9d65a43880a98546ea84559271bb6d970
-F src/pager.c b5584c5e75e463b4a136e26858d555e83ca97b44
++F src/pager.c 658e5063d2d1661336a1e269e1cc324dfa8a683a
F src/pager.h ca1f23c0cf137ac26f8908df2427c8b308361efd
F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e
F src/pcache.c 1e9aa2dbc0845b52e1b51cc39753b6d1e041cb07
F test/join5.test 86675fc2919269aa923c84dd00ee4249b97990fe
F test/join6.test bf82cf3f979e9eade83ad0d056a66c5ed71d1901
F test/journal1.test 36f2d1bb9bf03f790f43fbdb439e44c0657fab19
- F test/journal2.test 0f867f26c7f30bda2b69dc0e6451caa8fed18ef1
- F test/jrnlmode.test 76f94d61528c5ff32102a12f8cf34f4cc36f7849
++F test/journal2.test 92653f42868b32272a9913c767324b0b3992a60b
+ F test/jrnlmode.test cd0c9c5b2555f3d5bb72ed8aa8d0ad16ecf77e7c
F test/jrnlmode2.test fe79ea1f0375c926b8de0362ddf94f34a64135fd
F test/jrnlmode3.test cfcdb12b90e640a23b92785a002d96c0624c8710
F test/keyword1.test a2400977a2e4fde43bf33754c2929fda34dbca05
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
- P bede8c8a148fb9be5ffbf38df7fa733e35cc68c3 f80c3f922a114e738613955a939db46cf0847038
- R 99e9ca5d85226de77fd66a29f7003e5a
-P cccd32c692057beb08a994102c6a10126ddeb937
-R cc967c249a884e7c285bdbc1b3f00097
++P 20133e9ca98f5e6c42051ed3d65e4eb71d5366a5 1ec74591a93e8b27ad3ac739914a48a91972e82c
++R 4f7b82137af7b10bc7d2278f04c82c2f
U dan
- Z b12621360876a83980ead5d940279e1b
-Z 4ebb4fa39dfc135851bcdd3d6648050e
++Z 03dc90f484cb38d112214ba72ea54330
--- /dev/null
-
+# 2010 June 16
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+source $testdir/lock_common.tcl
+source $testdir/malloc_common.tcl
+db close
+
+set a_string_counter 1
+proc a_string {n} {
+ global a_string_counter
+ incr a_string_counter
+ string range [string repeat "${a_string_counter}." $n] 1 $n
+}
+
+# Create a [testvfs] and install it as the default VFS. Set the device
+# characteristics flags to "SAFE_DELETE".
+#
+testvfs tvfs -default 1
+tvfs devchar safe_delete
+
+# Set up a hook so that each time a journal file is opened, closed or
+# deleted, the method name ("xOpen", "xClose" or "xDelete") and the final
+# segment of the journal file-name (i.e. "test.db-journal") are appended to
+# global list variable $::oplog.
+#
+tvfs filter {xOpen xClose xDelete}
+tvfs script journal_op_catcher
- if {$method == "xDelete" || $method == "xWrite" || $method == "xTruncate"} {
+proc journal_op_catcher {method filename args} {
+
+ # If global variable ::tvfs_error_on_write is defined, then return an
+ # IO error to every attempt to modify the file-system. Otherwise, return
+ # SQLITE_OK.
+ #
+ if {[info exists ::tvfs_error_on_write]} {
- if {[string match *journal* $filename]==0} return
-
++ if {[lsearch {xDelete xWrite xTruncate} $method]>=0} {
+ return SQLITE_IOERR
+ }
+ return SQLITE_OK
+ }
+
- xOpen {
- incr ::open_journals($f) +1
- }
- xClose {
- incr ::open_journals($f) -1
- }
- xDelete {
- if {$::open_journals($f)>0} { return SQLITE_IOERR }
- }
++ # The rest of this command only deals with xOpen(), xClose() and xDelete()
++ # operations on journal files. If this invocation does not represent such
++ # an operation, return with no further ado.
++ #
+ set f [file tail $filename]
++ if {[string match *journal $f]==0} return
++ if {[lsearch {xOpen xDelete xClose} $method]<0} return
++
++ # Append a record of this operation to global list variable $::oplog.
++ #
+ lappend ::oplog $method $f
+
++ # If this is an attempt to delete a journal file for which there exists
++ # one ore more open handles, return an error. The code in test_vfs.c
++ # will not invoke the xDelete method of the "real" VFS in this case.
++ #
+ if {[info exists ::open_journals($f)]==0} { set ::open_journals($f) 0 }
+ switch -- $method {
- return
++ xOpen { incr ::open_journals($f) +1 }
++ xClose { incr ::open_journals($f) -1 }
++ xDelete { if {$::open_journals($f)>0} { puts EEE;return SQLITE_IOERR } }
+ }
+
- # Grow the database until it is reasonably large. Then, from a
- # journal_mode=DELETE connection, attempt to commit a large transaction (one
- # that involves upgrading to an exclusive lock and writing the database
- # before the transaction is committed).
++ return ""
+}
+
+
+do_test journal2-1.1 {
+ set ::oplog [list]
+ sqlite3 db test.db
+ execsql { CREATE TABLE t1(a, b) }
+ set ::oplog
+} {xOpen test.db-journal xClose test.db-journal xDelete test.db-journal}
+do_test journal2-1.2 {
+ set ::oplog [list]
+ execsql {
+ PRAGMA journal_mode = truncate;
+ INSERT INTO t1 VALUES(1, 2);
+ }
+ set ::oplog
+} {xOpen test.db-journal}
+do_test journal2-1.3 {
+ set ::oplog [list]
+ execsql { INSERT INTO t1 VALUES(3, 4) }
+ set ::oplog
+} {}
+do_test journal2-1.4 { execsql { SELECT * FROM t1 } } {1 2 3 4}
+
+# Add a second connection. This connection attempts to commit data in
+# journal_mode=DELETE mode. When it tries to delete the journal file,
+# the VFS layer returns an IO error.
+#
+do_test journal2-1.5 {
+ set ::oplog [list]
+ sqlite3 db2 test.db
+ execsql { PRAGMA journal_mode = delete } db2
+ catchsql { INSERT INTO t1 VALUES(5, 6) } db2
+} {1 {disk I/O error}}
+do_test journal2-1.6 { file exists test.db-journal } 1
+do_test journal2-1.7 { execsql { SELECT * FROM t1 } } {1 2 3 4}
+do_test journal2-1.8 {
+ execsql { PRAGMA journal_mode = truncate } db2
+ execsql { INSERT INTO t1 VALUES(5, 6) } db2
+} {}
+do_test journal2-1.9 { execsql { SELECT * FROM t1 } } {1 2 3 4 5 6}
+
-
++# Grow the database until it is reasonably large.
+#
+do_test journal2-1.10 {
+ db2 close
+ db func a_string a_string
+ execsql {
+ CREATE TABLE t2(a UNIQUE, b UNIQUE);
+ INSERT INTO t2 VALUES(a_string(200), a_string(300));
+ INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 2
+ INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 4
+ INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 8
+ INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 16
+ INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 32
+ INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 64
+ }
+ file size test.db-journal
+} {0}
+do_test journal2-1.11 {
+ set sz [expr [file size test.db] / 1024]
+ expr {$sz>120 && $sz<200}
+} 1
+
++# Using new connection [db2] (with journal_mode=DELETE), write a lot of
++# data to the database. So that many pages within the database file are
++# modified before the transaction is committed.
++#
++# Then, enable simulated IO errors in all calls to xDelete, xWrite
++# and xTruncate before committing the transaction and closing the
++# database file. From the point of view of other file-system users, it
++# appears as if the process hosting [db2] unexpectedly exited.
++#
+do_test journal2-1.12 {
+ sqlite3 db2 test.db
+ execsql {
+ PRAGMA cache_size = 10;
+ BEGIN;
+ INSERT INTO t2 SELECT randomblob(200), randomblob(300) FROM t2; -- 128
+ } db2
+} {}
+do_test journal2-1.13 {
+ tvfs filter {xOpen xClose xDelete xWrite xTruncate}
+ set ::tvfs_error_on_write 1
+ catchsql { COMMIT } db2
+} {1 {disk I/O error}}
+db2 close
+unset ::tvfs_error_on_write
+file copy -force test.db testX.db
+
+do_test journal2-1.14 { file exists test.db-journal } 1
+do_test journal2-1.15 {
+ execsql {
+ SELECT count(*) FROM t2;
+ PRAGMA integrity_check;
+ }
+} {64 ok}
+
+# This block checks that in the test case above, connection [db2] really
+# did begin writing to the database file before it hit IO errors. If
+# this is true, then the copy of the database file made before [db]
+# rolled back the hot journal should fail the integrity-check.
+#
+do_test journal2-1.16 {
+ set sz [expr [file size testX.db] / 1024]
+ expr {$sz>240 && $sz<400}
+} 1
+do_test journal2-1.17 {
+ expr {[catchsql { PRAGMA integrity_check } db] == "0 ok"}
+} {1}
+do_test journal2-1.20 {
+ sqlite3 db2 testX.db
+ expr {[catchsql { PRAGMA integrity_check } db2] == "0 ok"}
+} {0}
+do_test journal2-1.21 {
+ db2 close
+} {}
+db close
++
++#-------------------------------------------------------------------------
++# Test that it is possible to switch from journal_mode=truncate to
++# journal_mode=WAL on a SAFE_DELETE file-system. SQLite should close and
++# delete the journal file when committing the transaction that switches
++# the system to WAL mode.
++#
++ifcapable wal {
++ do_test journal2-2.1 {
++ faultsim_delete_and_reopen
++ set ::oplog [list]
++ execsql { PRAGMA journal_mode = persist }
++ set ::oplog
++ } {}
++ do_test journal2-2.2 {
++ execsql {
++ CREATE TABLE t1(x);
++ INSERT INTO t1 VALUES(3.14159);
++ }
++ set ::oplog
++ } {xOpen test.db-journal}
++ do_test journal2-2.3 {
++ expr {[file size test.db-journal] > 512}
++ } {1}
++ do_test journal2-2.3 {
++ set ::oplog [list]
++ execsql { PRAGMA journal_mode = WAL }
++ set ::oplog
++ } {xClose test.db-journal xDelete test.db-journal}
++ db close
++}
++
+tvfs delete
+finish_test
+