1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
|
# 2007 August 23
#
# 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 contains tests that verify that SQLite can correctly rollback
# databases after crashes when using the special IO modes triggered
# by device IOCAP flags.
#
# $Id: crash3.test,v 1.4 2008/07/12 14:52:20 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !crashtest {
finish_test
return
}
proc do_test2 {name tcl res1 res2} {
set script [subst -nocommands {
do_test $name {
set res1 {$res1}
set res2 {$res2}
set res [eval {$tcl}]
if {[set res] eq [set res1] || [set res] eq [set res2]} {
set res "{[set res1]} or {[set res2]}"
}
set res
} {{$res1} or {$res2}}
}]
uplevel $script
}
# This block tests crash-recovery when the IOCAP_ATOMIC flags is set.
#
# Each iteration of the following loop sets up the database to contain
# the following schema and data:
#
# CREATE TABLE abc(a, b, c);
# INSERT INTO abc VALUES(1, 2, 3);
#
# Then execute the SQL statement, scheduling a crash for part-way through
# the first sync() of either the database file or the journal file (often
# the journal file is not required - meaning no crash occurs).
#
# After the crash (or absence of a crash), open the database and
# verify that:
#
# * The integrity check passes, and
# * The contents of table abc is either {1 2 3} or the value specified
# to the right of the SQL statement below.
#
# The procedure is repeated 10 times for each SQL statement. Five times
# with the crash scheduled for midway through the first journal sync (if
# any), and five times with the crash midway through the database sync.
#
set tn 1
foreach {sql res2} [list \
{INSERT INTO abc VALUES(4, 5, 6)} {1 2 3 4 5 6} \
{DELETE FROM abc} {} \
{INSERT INTO abc SELECT * FROM abc} {1 2 3 1 2 3} \
{UPDATE abc SET a = 2} {2 2 3} \
{INSERT INTO abc VALUES(4, 5, randstr(1000,1000))} {n/a} \
{CREATE TABLE def(d, e, f)} {n/a} \
] {
for {set ii 0} {$ii < 10} {incr ii} {
db close
forcedelete test.db test.db-journal
sqlite3 db test.db
do_test crash3-1.$tn.1 {
execsql {
PRAGMA page_size = 1024;
BEGIN;
CREATE TABLE abc(a, b, c);
INSERT INTO abc VALUES(1, 2, 3);
COMMIT;
}
} {}
db close
set crashfile test.db
if {($ii%2)==0} { append crashfile -journal }
set rand "SELECT randstr($tn,$tn);"
do_test crash3-1.$tn.2 [subst {
crashsql -file $crashfile -char atomic {$rand $sql}
sqlite3 db test.db
execsql { PRAGMA integrity_check; }
}] {ok}
do_test2 crash3-1.$tn.3 {
execsql { SELECT * FROM abc }
} {1 2 3} $res2
incr tn
}
}
# This block tests both the IOCAP_SEQUENTIAL and IOCAP_SAFE_APPEND flags.
#
db close
forcedelete test.db test.db-journal
sqlite3 db test.db
do_test crash3-2.0 {
execsql {
BEGIN;
CREATE TABLE abc(a PRIMARY KEY, b, c);
CREATE TABLE def(d PRIMARY KEY, e, f);
PRAGMA default_cache_size = 10;
INSERT INTO abc VALUES(randstr(10,1000),randstr(10,1000),randstr(10,1000));
INSERT INTO abc
SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc;
INSERT INTO abc
SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc;
INSERT INTO abc
SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc;
INSERT INTO abc
SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc;
INSERT INTO abc
SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc;
INSERT INTO abc
SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc;
COMMIT;
}
} {}
set tn 1
foreach {::crashfile ::delay ::char} {
test.db 1 sequential
test.db 1 safe_append
test.db-journal 1 sequential
test.db-journal 1 safe_append
test.db-journal 2 safe_append
test.db-journal 2 sequential
test.db-journal 3 sequential
test.db-journal 3 safe_append
} {
for {set ii 0} {$ii < 100} {incr ii} {
set ::SQL [subst {
SELECT randstr($ii,$ii+10);
BEGIN;
DELETE FROM abc WHERE random()%5;
INSERT INTO abc
SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000)
FROM abc
WHERE (random()%5)==0;
DELETE FROM def WHERE random()%5;
INSERT INTO def
SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000)
FROM def
WHERE (random()%5)==0;
COMMIT;
}]
do_test crash3-2.$tn.$ii {
crashsql -file $::crashfile -delay $::delay -char $::char $::SQL
db close
sqlite3 db test.db
execsql {PRAGMA integrity_check}
} {ok}
}
incr tn
}
# The following block tests an interaction between IOCAP_ATOMIC and
# IOCAP_SEQUENTIAL. At one point, if both flags were set, small
# journal files that contained only a single page, but were required
# for some other reason (i.e. nTrunk) were not being written to
# disk.
#
for {set ii 0} {$ii < 10} {incr ii} {
db close
forcedelete test.db test.db-journal
crashsql -file test.db -char {sequential atomic} {
CREATE TABLE abc(a, b, c);
}
sqlite3 db test.db
do_test crash3-3.$ii {
execsql {PRAGMA integrity_check}
} {ok}
}
finish_test
|