| OLD | NEW | 
 | (Empty) | 
|    1  |  | 
|    2 # 2007 Aug 13 |  | 
|    3 # |  | 
|    4 # The author disclaims copyright to this source code.  In place of |  | 
|    5 # a legal notice, here is a blessing: |  | 
|    6 # |  | 
|    7 #    May you do good and not evil. |  | 
|    8 #    May you find forgiveness for yourself and forgive others. |  | 
|    9 #    May you share freely, never taking more than you give. |  | 
|   10 # |  | 
|   11 #*********************************************************************** |  | 
|   12 #  |  | 
|   13 # This file tests aspects of recovery from a malloc() failure |  | 
|   14 # in a CREATE INDEX statement. |  | 
|   15 # |  | 
|   16 # $Id: crash5.test,v 1.3 2008/07/12 14:52:20 drh Exp $ |  | 
|   17  |  | 
|   18 set testdir [file dirname $argv0] |  | 
|   19 source $testdir/tester.tcl |  | 
|   20  |  | 
|   21 # Only run these tests if memory debugging is turned on. |  | 
|   22 # |  | 
|   23 ifcapable !memdebug||!crashtest||!memorymanage { |  | 
|   24    puts "Skipping crash5 tests: not compiled with -DSQLITE_MEMDEBUG..." |  | 
|   25    finish_test |  | 
|   26    return |  | 
|   27 } |  | 
|   28  |  | 
|   29 db close |  | 
|   30  |  | 
|   31 for {set ii 0} {$ii < 10} {incr ii} { |  | 
|   32   for {set jj 50} {$jj < 100} {incr jj} { |  | 
|   33  |  | 
|   34     # Set up the database so that it is an auto-vacuum database  |  | 
|   35     # containing a single table (root page 3) with a single row.  |  | 
|   36     # The row has an overflow page (page 4). |  | 
|   37     file delete -force test.db test.db-journal |  | 
|   38     sqlite3 db test.db |  | 
|   39     set c [string repeat 3 1500] |  | 
|   40     db eval { |  | 
|   41       pragma auto_vacuum = 1; |  | 
|   42       CREATE TABLE t1(a, b, c); |  | 
|   43       INSERT INTO t1 VALUES('1111111111', '2222222222', $c); |  | 
|   44     } |  | 
|   45     db close |  | 
|   46  |  | 
|   47     do_test crash5-$ii.$jj.1 { |  | 
|   48       crashsql -delay 1 -file test.db-journal -seed $ii -tclbody [join [list \ |  | 
|   49         [list set iFail $jj] { |  | 
|   50         sqlite3_crashparams 0 [file join [pwd] test.db-journal] |  | 
|   51        |  | 
|   52         # Begin a transaction and evaluate a "CREATE INDEX" statement |  | 
|   53         # with the iFail'th malloc() set to fail. This operation will |  | 
|   54         # have to move the current contents of page 4 (the overflow |  | 
|   55         # page) to make room for the new root page. The bug is that |  | 
|   56         # if malloc() fails at a particular point in sqlite3PagerMovepage(), |  | 
|   57         # sqlite mistakenly thinks that the page being moved (page 4) has  |  | 
|   58         # been safely synced into the journal. If the page is written |  | 
|   59         # to later in the transaction, it may be written out to the database |  | 
|   60         # before the relevant part of the journal has been synced. |  | 
|   61         # |  | 
|   62         db eval BEGIN |  | 
|   63         sqlite3_memdebug_fail $iFail -repeat 0 |  | 
|   64         catch {db eval { CREATE UNIQUE INDEX i1 ON t1(a); }} msg |  | 
|   65         # puts "$n $msg ac=[sqlite3_get_autocommit db]" |  | 
|   66        |  | 
|   67         # If the transaction is still active (it may not be if the malloc() |  | 
|   68         # failure occured in the OS layer), write to the database. Make sure |  | 
|   69         # page 4 is among those written. |  | 
|   70         # |  | 
|   71         if {![sqlite3_get_autocommit db]} { |  | 
|   72           db eval { |  | 
|   73             DELETE FROM t1;  -- This will put page 4 on the free list. |  | 
|   74             INSERT INTO t1 VALUES('111111111', '2222222222', '33333333'); |  | 
|   75             INSERT INTO t1 SELECT * FROM t1;                     -- 2 |  | 
|   76             INSERT INTO t1 SELECT * FROM t1;                     -- 4 |  | 
|   77             INSERT INTO t1 SELECT * FROM t1;                     -- 8 |  | 
|   78             INSERT INTO t1 SELECT * FROM t1;                     -- 16 |  | 
|   79             INSERT INTO t1 SELECT * FROM t1;                     -- 32 |  | 
|   80             INSERT INTO t1 SELECT * FROM t1 WHERE rowid%2;       -- 48 |  | 
|   81           } |  | 
|   82         } |  | 
|   83          |  | 
|   84         # If the right malloc() failed during the 'CREATE INDEX' above and |  | 
|   85         # the transaction was not rolled back, then the sqlite cache now  |  | 
|   86         # has a dirty page 4 that it incorrectly believes is already safely |  | 
|   87         # in the synced part of the journal file. When  |  | 
|   88         # sqlite3_release_memory() is called sqlite tries to free memory |  | 
|   89         # by writing page 4 out to the db file. If it crashes later on, |  | 
|   90         # before syncing the journal... Corruption! |  | 
|   91         # |  | 
|   92         sqlite3_crashparams 1 [file join [pwd] test.db-journal] |  | 
|   93         sqlite3_release_memory 8092 |  | 
|   94       }]] {} |  | 
|   95       expr 1 |  | 
|   96     } {1} |  | 
|   97    |  | 
|   98     sqlite3 db test.db |  | 
|   99     do_test crash5-$ii.$jj.2 { |  | 
|  100       db eval {pragma integrity_check} |  | 
|  101     } {ok} |  | 
|  102     do_test crash5-$ii.$jj.3 { |  | 
|  103       db eval {SELECT * FROM t1} |  | 
|  104     } [list 1111111111 2222222222 $::c] |  | 
|  105     db close |  | 
|  106   } |  | 
|  107 } |  | 
|  108  |  | 
|  109  |  | 
|  110 finish_test |  | 
| OLD | NEW |