summaryrefslogtreecommitdiff
path: root/test/crash3.test
blob: 7958af992ed76aa9053824cd64e801a85e534c9f (plain)
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