os/persistentdata/persistentstorage/sqlite3api/TEST/TclScript/crash5.test
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/persistentdata/persistentstorage/sqlite3api/TEST/TclScript/crash5.test	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,110 @@
     1.4 +
     1.5 +# 2007 Aug 13
     1.6 +#
     1.7 +# The author disclaims copyright to this source code.  In place of
     1.8 +# a legal notice, here is a blessing:
     1.9 +#
    1.10 +#    May you do good and not evil.
    1.11 +#    May you find forgiveness for yourself and forgive others.
    1.12 +#    May you share freely, never taking more than you give.
    1.13 +#
    1.14 +#***********************************************************************
    1.15 +# 
    1.16 +# This file tests aspects of recovery from a malloc() failure
    1.17 +# in a CREATE INDEX statement.
    1.18 +#
    1.19 +# $Id: crash5.test,v 1.3 2008/07/12 14:52:20 drh Exp $
    1.20 +
    1.21 +set testdir [file dirname $argv0]
    1.22 +source $testdir/tester.tcl
    1.23 +
    1.24 +# Only run these tests if memory debugging is turned on.
    1.25 +#
    1.26 +ifcapable !memdebug||!crashtest||!memorymanage {
    1.27 +   puts "Skipping crash5 tests: not compiled with -DSQLITE_MEMDEBUG..."
    1.28 +   finish_test
    1.29 +   return
    1.30 +}
    1.31 +
    1.32 +db close
    1.33 +
    1.34 +for {set ii 0} {$ii < 10} {incr ii} {
    1.35 +  for {set jj 50} {$jj < 100} {incr jj} {
    1.36 +
    1.37 +    # Set up the database so that it is an auto-vacuum database 
    1.38 +    # containing a single table (root page 3) with a single row. 
    1.39 +    # The row has an overflow page (page 4).
    1.40 +    file delete -force test.db test.db-journal
    1.41 +    sqlite3 db test.db
    1.42 +    set c [string repeat 3 1500]
    1.43 +    db eval {
    1.44 +      pragma auto_vacuum = 1;
    1.45 +      CREATE TABLE t1(a, b, c);
    1.46 +      INSERT INTO t1 VALUES('1111111111', '2222222222', $c);
    1.47 +    }
    1.48 +    db close
    1.49 +
    1.50 +    do_test crash5-$ii.$jj.1 {
    1.51 +      crashsql -delay 1 -file test.db-journal -seed $ii -tclbody [join [list \
    1.52 +        [list set iFail $jj] {
    1.53 +        sqlite3_crashparams 0 [file join [pwd] test.db-journal]
    1.54 +      
    1.55 +        # Begin a transaction and evaluate a "CREATE INDEX" statement
    1.56 +        # with the iFail'th malloc() set to fail. This operation will
    1.57 +        # have to move the current contents of page 4 (the overflow
    1.58 +        # page) to make room for the new root page. The bug is that
    1.59 +        # if malloc() fails at a particular point in sqlite3PagerMovepage(),
    1.60 +        # sqlite mistakenly thinks that the page being moved (page 4) has 
    1.61 +        # been safely synced into the journal. If the page is written
    1.62 +        # to later in the transaction, it may be written out to the database
    1.63 +        # before the relevant part of the journal has been synced.
    1.64 +        #
    1.65 +        db eval BEGIN
    1.66 +        sqlite3_memdebug_fail $iFail -repeat 0
    1.67 +        catch {db eval { CREATE UNIQUE INDEX i1 ON t1(a); }} msg
    1.68 +        # puts "$n $msg ac=[sqlite3_get_autocommit db]"
    1.69 +      
    1.70 +        # If the transaction is still active (it may not be if the malloc()
    1.71 +        # failure occured in the OS layer), write to the database. Make sure
    1.72 +        # page 4 is among those written.
    1.73 +        #
    1.74 +        if {![sqlite3_get_autocommit db]} {
    1.75 +          db eval {
    1.76 +            DELETE FROM t1;  -- This will put page 4 on the free list.
    1.77 +            INSERT INTO t1 VALUES('111111111', '2222222222', '33333333');
    1.78 +            INSERT INTO t1 SELECT * FROM t1;                     -- 2
    1.79 +            INSERT INTO t1 SELECT * FROM t1;                     -- 4
    1.80 +            INSERT INTO t1 SELECT * FROM t1;                     -- 8
    1.81 +            INSERT INTO t1 SELECT * FROM t1;                     -- 16
    1.82 +            INSERT INTO t1 SELECT * FROM t1;                     -- 32
    1.83 +            INSERT INTO t1 SELECT * FROM t1 WHERE rowid%2;       -- 48
    1.84 +          }
    1.85 +        }
    1.86 +        
    1.87 +        # If the right malloc() failed during the 'CREATE INDEX' above and
    1.88 +        # the transaction was not rolled back, then the sqlite cache now 
    1.89 +        # has a dirty page 4 that it incorrectly believes is already safely
    1.90 +        # in the synced part of the journal file. When 
    1.91 +        # sqlite3_release_memory() is called sqlite tries to free memory
    1.92 +        # by writing page 4 out to the db file. If it crashes later on,
    1.93 +        # before syncing the journal... Corruption!
    1.94 +        #
    1.95 +        sqlite3_crashparams 1 [file join [pwd] test.db-journal]
    1.96 +        sqlite3_release_memory 8092
    1.97 +      }]] {}
    1.98 +      expr 1
    1.99 +    } {1}
   1.100 +  
   1.101 +    sqlite3 db test.db
   1.102 +    do_test crash5-$ii.$jj.2 {
   1.103 +      db eval {pragma integrity_check}
   1.104 +    } {ok}
   1.105 +    do_test crash5-$ii.$jj.3 {
   1.106 +      db eval {SELECT * FROM t1}
   1.107 +    } [list 1111111111 2222222222 $::c]
   1.108 +    db close
   1.109 +  }
   1.110 +}
   1.111 +
   1.112 +
   1.113 +finish_test