191 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			191 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| # 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
 | 
