xref: /sqlite-3.40.0/test/snapshot_fault.test (revision 6a9e7f16)
17d159794Sdan# 2015 December 10
27d159794Sdan#
37d159794Sdan# The author disclaims copyright to this source code.  In place of
47d159794Sdan# a legal notice, here is a blessing:
57d159794Sdan#
67d159794Sdan#    May you do good and not evil.
77d159794Sdan#    May you find forgiveness for yourself and forgive others.
87d159794Sdan#    May you share freely, never taking more than you give.
97d159794Sdan#
107d159794Sdan#***********************************************************************
117d159794Sdan# This file implements regression tests for SQLite library. The focus
127d159794Sdan# of this file is the sqlite3_snapshot_xxx() APIs.
137d159794Sdan#
147d159794Sdan
157d159794Sdanset testdir [file dirname $argv0]
167d159794Sdansource $testdir/tester.tcl
1768d28ea4Sdrhifcapable !snapshot {finish_test; return}
187d159794Sdanset testprefix snapshot_fault
197d159794Sdan
20*6a9e7f16Sdanif 1 {
21*6a9e7f16Sdan
227d159794Sdan#-------------------------------------------------------------------------
237d159794Sdan# Check that an sqlite3_snapshot_open() client cannot be tricked into
247d159794Sdan# reading a corrupt snapshot even if a second client fails while
257d159794Sdan# checkpointing the db.
267d159794Sdan#
277d159794Sdando_faultsim_test 1.0 -prep {
287d159794Sdan  faultsim_delete_and_reopen
297d159794Sdan  sqlite3 db2 test.db
307d159794Sdan  db2 eval {
317d159794Sdan    CREATE TABLE t1(a, b UNIQUE, c UNIQUE);
327d159794Sdan    INSERT INTO t1 VALUES(1, randomblob(500), randomblob(500));
337d159794Sdan    INSERT INTO t1 VALUES(2, randomblob(500), randomblob(500));
347d159794Sdan    PRAGMA journal_mode = wal;
357d159794Sdan    INSERT INTO t1 VALUES(3, randomblob(500), randomblob(500));
367d159794Sdan    BEGIN;
377d159794Sdan      SELECT a FROM t1;
387d159794Sdan  }
397d159794Sdan  set ::snapshot [sqlite3_snapshot_get db2 main]
407d159794Sdan  db2 eval COMMIT
417d159794Sdan  db2 eval {
427d159794Sdan    UPDATE t1 SET b=randomblob(501), c=randomblob(501) WHERE a=1;
437d159794Sdan    INSERT INTO t1 VALUES(4, randomblob(500), randomblob(500));
447d159794Sdan    INSERT INTO t1 VALUES(5, randomblob(500), randomblob(500));
457d159794Sdan    INSERT INTO t1 VALUES(6, randomblob(500), randomblob(500));
467d159794Sdan  }
477d159794Sdan} -body {
487d159794Sdan  db eval { PRAGMA wal_checkpoint }
497d159794Sdan} -test {
507d159794Sdan  db2 eval BEGIN
517d159794Sdan  if {[catch { sqlite3_snapshot_open db2 main $::snapshot } msg]} {
527d159794Sdan    if {$msg != "SQLITE_BUSY_SNAPSHOT" && $msg != "SQLITE_BUSY"} {
537d159794Sdan      error "error is $msg"
547d159794Sdan    }
557d159794Sdan  } else {
567d159794Sdan    set res [db2 eval {
577d159794Sdan      SELECT a FROM t1;
587d159794Sdan      PRAGMA integrity_check;
597d159794Sdan    }]
607d159794Sdan    if {$res != "1 2 3 ok"} { error "res is $res" }
617d159794Sdan  }
627d159794Sdan
637d159794Sdan  sqlite3_snapshot_free $::snapshot
647d159794Sdan}
657d159794Sdan
667d159794Sdan#-------------------------------------------------------------------------
677d159794Sdan# This test is similar to the previous one. Except, after the
687d159794Sdan# "PRAGMA wal_checkpoint" command fails the db is closed and reopened
697d159794Sdan# so as to require wal file recovery. It should not be possible to open
707d159794Sdan# a snapshot that is part of the body of a recovered wal file.
717d159794Sdan#
727d159794Sdando_faultsim_test 2.0 -prep {
737d159794Sdan  faultsim_delete_and_reopen
747d159794Sdan  db eval {
757d159794Sdan    CREATE TABLE t1(a, b UNIQUE, c UNIQUE);
767d159794Sdan    INSERT INTO t1 VALUES(1, randomblob(500), randomblob(500));
777d159794Sdan    INSERT INTO t1 VALUES(2, randomblob(500), randomblob(500));
787d159794Sdan    PRAGMA journal_mode = wal;
797d159794Sdan    INSERT INTO t1 VALUES(3, randomblob(500), randomblob(500));
807d159794Sdan    BEGIN;
817d159794Sdan      SELECT a FROM t1;
827d159794Sdan  }
837d159794Sdan  set ::snapshot [sqlite3_snapshot_get db main]
847d159794Sdan  db eval COMMIT
857d159794Sdan
867d159794Sdan  db eval {
877d159794Sdan    UPDATE t1 SET b=randomblob(501), c=randomblob(501) WHERE a=1;
887d159794Sdan    INSERT INTO t1 VALUES(4, randomblob(500), randomblob(500));
897d159794Sdan    INSERT INTO t1 VALUES(5, randomblob(500), randomblob(500));
907d159794Sdan    INSERT INTO t1 VALUES(6, randomblob(500), randomblob(500));
917d159794Sdan  }
927d159794Sdan} -body {
937d159794Sdan  db eval { PRAGMA wal_checkpoint }
947d159794Sdan} -test {
957d159794Sdan
967d159794Sdan  db_save
977d159794Sdan  db close
987d159794Sdan  db_restore_and_reopen
997d159794Sdan  db eval { SELECT * FROM t1 }
1007d159794Sdan
1017d159794Sdan  db eval BEGIN
1027d159794Sdan  if {[catch { sqlite3_snapshot_open db main $::snapshot } msg]} {
1037d159794Sdan    if {$msg != "SQLITE_BUSY_SNAPSHOT" && $msg != "SQLITE_BUSY"} {
1047d159794Sdan      error "error is $msg"
1057d159794Sdan    }
1067d159794Sdan  } else {
1077d159794Sdan    # This branch should actually never be taken. But it was useful in
1087d159794Sdan    # determining whether or not this test was actually working (by
1097d159794Sdan    # running a modified version of SQLite that allowed snapshots to be
1107d159794Sdan    # opened following a recovery).
1117d159794Sdan    error "TEST HAS FAILED"
1127d159794Sdan
1137d159794Sdan    set res [db eval {
1147d159794Sdan      SELECT a FROM t1;
1157d159794Sdan      PRAGMA integrity_check;
1167d159794Sdan    }]
1177d159794Sdan    if {$res != "1 2 3 ok"} { error "res is $res" }
1187d159794Sdan  }
1197d159794Sdan
1207d159794Sdan  sqlite3_snapshot_free $::snapshot
1217d159794Sdan}
1227d159794Sdan
1237d159794Sdan#-------------------------------------------------------------------------
1247d159794Sdan# Test the handling of faults that occur within sqlite3_snapshot_open().
1257d159794Sdan#
1267d159794Sdando_faultsim_test 3.0 -prep {
1277d159794Sdan  faultsim_delete_and_reopen
1287d159794Sdan  db eval {
1297d159794Sdan    CREATE TABLE t1(a, b UNIQUE, c UNIQUE);
1307d159794Sdan    INSERT INTO t1 VALUES(1, randomblob(500), randomblob(500));
1317d159794Sdan    INSERT INTO t1 VALUES(2, randomblob(500), randomblob(500));
1327d159794Sdan    PRAGMA journal_mode = wal;
1337d159794Sdan    INSERT INTO t1 VALUES(3, randomblob(500), randomblob(500));
1347d159794Sdan    BEGIN;
1357d159794Sdan      SELECT a FROM t1;
1367d159794Sdan  }
1377d159794Sdan  set ::snapshot [sqlite3_snapshot_get db main]
1387d159794Sdan  db eval COMMIT
1397d159794Sdan  db eval {
1407d159794Sdan    UPDATE t1 SET b=randomblob(501), c=randomblob(501) WHERE a=1;
1417d159794Sdan    INSERT INTO t1 VALUES(4, randomblob(500), randomblob(500));
1427d159794Sdan    INSERT INTO t1 VALUES(5, randomblob(500), randomblob(500));
1437d159794Sdan    INSERT INTO t1 VALUES(6, randomblob(500), randomblob(500));
1447d159794Sdan    BEGIN;
1457d159794Sdan  }
1467d159794Sdan} -body {
1477d159794Sdan  if { [catch { sqlite3_snapshot_open db main $::snapshot } msg] } {
1487d159794Sdan    error $msg
1497d159794Sdan  }
1507d159794Sdan} -test {
151cc47eac0Sdan  faultsim_test_result {0 {}} {1 SQLITE_IOERR} {1 SQLITE_NOMEM} \
1527d159794Sdan                              {1 SQLITE_IOERR_NOMEM} {1 SQLITE_IOERR_READ}
1537d159794Sdan  if {$testrc==0} {
1547d159794Sdan    set res [db eval {
1557d159794Sdan      SELECT a FROM t1;
1567d159794Sdan      PRAGMA integrity_check;
1577d159794Sdan    }]
1587d159794Sdan    if {$res != "1 2 3 ok"} { error "res is $res" }
1597d159794Sdan  }
1607d159794Sdan
1617d159794Sdan  sqlite3_snapshot_free $::snapshot
1627d159794Sdan}
1637d159794Sdan
164*6a9e7f16Sdan}
165*6a9e7f16Sdan
166*6a9e7f16Sdan#-------------------------------------------------------------------------
167*6a9e7f16Sdan# Test the handling of faults that occur within sqlite3_snapshot_recover().
168*6a9e7f16Sdan#
169*6a9e7f16Sdanreset_db
170*6a9e7f16Sdando_execsql_test 4.0 {
171*6a9e7f16Sdan  PRAGMA journal_mode = wal;
172*6a9e7f16Sdan  CREATE TABLE t1(zzz);
173*6a9e7f16Sdan  INSERT INTO t1 VALUES('abc');
174*6a9e7f16Sdan  INSERT INTO t1 VALUES('def');
175*6a9e7f16Sdan} {wal}
176*6a9e7f16Sdanfaultsim_save_and_close
177*6a9e7f16Sdan
178*6a9e7f16Sdando_test 4.1 {
179*6a9e7f16Sdan  faultsim_restore_and_reopen
180*6a9e7f16Sdan  db eval { SELECT * FROM sqlite_master }
181*6a9e7f16Sdan  sqlite3_snapshot_recover db main
182*6a9e7f16Sdan} {}
183*6a9e7f16Sdandb close
184*6a9e7f16Sdan
185*6a9e7f16Sdando_faultsim_test 4 -faults oom* -prep {
186*6a9e7f16Sdan  faultsim_restore_and_reopen
187*6a9e7f16Sdan  db eval { SELECT * FROM sqlite_master }
188*6a9e7f16Sdan} -body {
189*6a9e7f16Sdan  sqlite3_snapshot_recover db main
190*6a9e7f16Sdan} -test {
191*6a9e7f16Sdan  faultsim_test_result {0 {}} {1 SQLITE_NOMEM} {1 SQLITE_IOERR_NOMEM}
192*6a9e7f16Sdan}
1937d159794Sdan
1947d159794Sdan
1957d159794Sdanfinish_test
196