Add assert() statements to validate access to the SrcItem.u1.nRow union member.
[sqlite.git] / test / snapshot_fault.test
blob10c5094594494516ff88b4651e6f066fca378ad7
1 # 2015 December 10
3 # The author disclaims copyright to this source code.  In place of
4 # a legal notice, here is a blessing:
6 #    May you do good and not evil.
7 #    May you find forgiveness for yourself and forgive others.
8 #    May you share freely, never taking more than you give.
10 #***********************************************************************
11 # This file implements regression tests for SQLite library. The focus
12 # of this file is the sqlite3_snapshot_xxx() APIs.
15 set testdir [file dirname $argv0]
16 source $testdir/tester.tcl
17 ifcapable !snapshot {finish_test; return}
18 set testprefix snapshot_fault
20 #-------------------------------------------------------------------------
21 # Check that an sqlite3_snapshot_open() client cannot be tricked into
22 # reading a corrupt snapshot even if a second client fails while 
23 # checkpointing the db.
25 do_faultsim_test 1.0 -prep {
26   catch { db2 close }
27   faultsim_delete_and_reopen
28   sqlite3 db2 test.db
29   db2 eval { 
30     CREATE TABLE t1(a, b UNIQUE, c UNIQUE);
31     INSERT INTO t1 VALUES(1, randomblob(500), randomblob(500));
32     INSERT INTO t1 VALUES(2, randomblob(500), randomblob(500));
33     PRAGMA journal_mode = wal;
34     INSERT INTO t1 VALUES(3, randomblob(500), randomblob(500));
35     BEGIN;
36       SELECT a FROM t1;
37   }
38   set ::snapshot [sqlite3_snapshot_get db2 main] 
39   db2 eval COMMIT
40   db2 eval {
41     UPDATE t1 SET b=randomblob(501), c=randomblob(501) WHERE a=1;
42     INSERT INTO t1 VALUES(4, randomblob(500), randomblob(500));
43     INSERT INTO t1 VALUES(5, randomblob(500), randomblob(500));
44     INSERT INTO t1 VALUES(6, randomblob(500), randomblob(500));
45   }
46 } -body {
47   db eval { PRAGMA wal_checkpoint }
48 } -test {
49   db2 eval BEGIN
50   if {[catch { sqlite3_snapshot_open db2 main $::snapshot } msg]} {
51     if {$msg != "SQLITE_ERROR_SNAPSHOT" && $msg != "SQLITE_BUSY"} {
52       error "error is $msg" 
53     }
54   } else {
55     set res [db2 eval { 
56       SELECT a FROM t1;
57       PRAGMA integrity_check;
58     }]
59     if {$res != "1 2 3 ok"} { error "res is $res" }
60   }
62   sqlite3_snapshot_free $::snapshot
65 #-------------------------------------------------------------------------
66 # This test is similar to the previous one. Except, after the 
67 # "PRAGMA wal_checkpoint" command fails the db is closed and reopened
68 # so as to require wal file recovery. It should not be possible to open
69 # a snapshot that is part of the body of a recovered wal file.
71 do_faultsim_test 2.0 -prep {
72   faultsim_delete_and_reopen
73   db eval { 
74     CREATE TABLE t1(a, b UNIQUE, c UNIQUE);
75     INSERT INTO t1 VALUES(1, randomblob(500), randomblob(500));
76     INSERT INTO t1 VALUES(2, randomblob(500), randomblob(500));
77     PRAGMA journal_mode = wal;
78     INSERT INTO t1 VALUES(3, randomblob(500), randomblob(500));
79     BEGIN;
80       SELECT a FROM t1;
81   }
82   set ::snapshot [sqlite3_snapshot_get db main] 
83   db eval COMMIT
85   db eval {
86     UPDATE t1 SET b=randomblob(501), c=randomblob(501) WHERE a=1;
87     INSERT INTO t1 VALUES(4, randomblob(500), randomblob(500));
88     INSERT INTO t1 VALUES(5, randomblob(500), randomblob(500));
89     INSERT INTO t1 VALUES(6, randomblob(500), randomblob(500));
90   }
91 } -body {
92   db eval { PRAGMA wal_checkpoint }
93 } -test {
95   db_save
96   db close
97   db_restore_and_reopen
98   db eval { SELECT * FROM t1 }
99   
100   db eval BEGIN
101   if {[catch { sqlite3_snapshot_open db main $::snapshot } msg]} {
102     if {$msg != "SQLITE_ERROR_SNAPSHOT" && $msg != "SQLITE_BUSY"} {
103       error "error is $msg" 
104     }
105   } else {
106     # This branch should actually never be taken. But it was useful in
107     # determining whether or not this test was actually working (by 
108     # running a modified version of SQLite that allowed snapshots to be
109     # opened following a recovery).
110     error "TEST HAS FAILED"
112     set res [db eval { 
113       SELECT a FROM t1;
114       PRAGMA integrity_check;
115     }]
116     if {$res != "1 2 3 ok"} { error "res is $res" }
117   }
119   sqlite3_snapshot_free $::snapshot
122 #-------------------------------------------------------------------------
123 # Test the handling of faults that occur within sqlite3_snapshot_open().
125 do_faultsim_test 3.0 -prep {
126   faultsim_delete_and_reopen
127   db eval { 
128     CREATE TABLE t1(a, b UNIQUE, c UNIQUE);
129     INSERT INTO t1 VALUES(1, randomblob(500), randomblob(500));
130     INSERT INTO t1 VALUES(2, randomblob(500), randomblob(500));
131     PRAGMA journal_mode = wal;
132     INSERT INTO t1 VALUES(3, randomblob(500), randomblob(500));
133     BEGIN;
134       SELECT a FROM t1;
135   }
136   set ::snapshot [sqlite3_snapshot_get db main] 
137   db eval COMMIT
138   db eval {
139     UPDATE t1 SET b=randomblob(501), c=randomblob(501) WHERE a=1;
140     INSERT INTO t1 VALUES(4, randomblob(500), randomblob(500));
141     INSERT INTO t1 VALUES(5, randomblob(500), randomblob(500));
142     INSERT INTO t1 VALUES(6, randomblob(500), randomblob(500));
143     BEGIN;
144   }
145 } -body {
146   if { [catch { sqlite3_snapshot_open db main $::snapshot } msg] } {
147     error $msg
148   }
149 } -test {
150   faultsim_test_result {0 {}} {1 SQLITE_IOERR} {1 SQLITE_NOMEM} \
151                               {1 SQLITE_IOERR_NOMEM} {1 SQLITE_IOERR_READ}
152   if {$testrc==0} {
153     set res [db eval { 
154       SELECT a FROM t1;
155       PRAGMA integrity_check;
156     }]
157     if {$res != "1 2 3 ok"} { error "res is $res" }
158   }
160   sqlite3_snapshot_free $::snapshot
163 #-------------------------------------------------------------------------
164 # Test the handling of faults that occur within sqlite3_snapshot_recover().
166 reset_db
167 do_execsql_test 4.0 {
168   PRAGMA journal_mode = wal;
169   CREATE TABLE t1(zzz);
170   INSERT INTO t1 VALUES('abc');
171   INSERT INTO t1 VALUES('def');
172 } {wal}
173 faultsim_save_and_close
175 do_test 4.0.1 {
176   faultsim_restore_and_reopen
177   db eval { SELECT * FROM sqlite_master } 
178   sqlite3_snapshot_recover db main
179 } {}
180 db close
182 do_faultsim_test 4.0 -faults oom* -prep {
183   faultsim_restore_and_reopen
184   db eval { SELECT * FROM sqlite_master } 
185 } -body {
186   sqlite3_snapshot_recover db main
187 } -test {
188   faultsim_test_result {0 {}} {1 SQLITE_NOMEM} {1 SQLITE_IOERR_NOMEM}
191 # The following test cases contrive to call sqlite3_snapshot_recover()
192 # before all pages of the *-shm file have been mapped. This tests an
193 # extra branch of error handling logic in snapshot_recover().
195 reset_db
196 do_execsql_test 4.1.0 {
197   PRAGMA page_size = 512;
198   PRAGMA journal_mode = wal;
199   PRAGMA wal_autocheckpoint = 0;
200   CREATE TABLE t1(zzz);
201   INSERT INTO t1 VALUES(randomblob( 500 * 9500 ));
202   PRAGMA user_version = 211;
203 } {wal 0}
205 do_test 4.1.1 {
206   list [file size test.db-shm] [file size test.db]
207 } {98304 512}
209 faultsim_save_and_close
210 do_faultsim_test 4.1 -faults shm* -prep {
211   catch { db2 close } 
212   catch { db close } 
213   faultsim_restore_and_reopen
214   sqlite3 db2 test.db
215   db2 eval { SELECT * FROM sqlite_master } 
216   db eval BEGIN
217   sqlite3_snapshot_get_blob db main
218   db eval COMMIT
219 } -body {
220   sqlite3_snapshot_recover db main
221 } -test {
222   faultsim_test_result {0 {}} {1 SQLITE_IOERR}
225 #-------------------------------------------------------------------------
226 # Test the handling of faults that occur within sqlite3_snapshot_get().
228 reset_db
229 do_execsql_test 5.0 {
230   PRAGMA page_size = 512;
231   PRAGMA journal_mode = wal;
232   PRAGMA wal_autocheckpoint = 0;
233   CREATE TABLE t1(zzz);
234   INSERT INTO t1 VALUES(randomblob( 5000 ));
235   PRAGMA user_version = 211;
236 } {wal 0}
237 faultsim_save_and_close
239 do_faultsim_test 5 -prep {
240   faultsim_restore_and_reopen
241   execsql { SELECT count(*) FROM sqlite_master }
242   execsql BEGIN
243 } -body {
244   sqlite3_snapshot_get_blob db main
245   set {} {}
246 } -test {
247   execsql END
248   faultsim_test_result {0 {}} {1 SQLITE_IOERR} {1 SQLITE_NOMEM}
252 finish_test