CoolFace
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
crash8.test420 linesDownload Raw Back to test
1# 2009 January 82#3# The author disclaims copyright to this source code.  In place of4# a legal notice, here is a blessing:5#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.9#10#***********************************************************************11#12# This test verifies a couple of specific potential data corruption 13# scenarios involving crashes or power failures.14#15# Later: Also, some other specific scenarios required for coverage16# testing that do not lead to corruption.17#18# $Id: crash8.test,v 1.4 2009/01/11 00:44:48 drh Exp $19 20 21set testdir [file dirname $argv0]22source $testdir/tester.tcl23 24ifcapable !crashtest {25  finish_test26  return27}28do_not_use_codec29 30do_test crash8-1.1 {31  execsql {32    PRAGMA auto_vacuum=OFF;33    CREATE TABLE t1(a, b);34    CREATE INDEX i1 ON t1(a, b);35    INSERT INTO t1 VALUES(1, randstr(1000,1000));36    INSERT INTO t1 VALUES(2, randstr(1000,1000));37    INSERT INTO t1 VALUES(3, randstr(1000,1000));38    INSERT INTO t1 VALUES(4, randstr(1000,1000));39    INSERT INTO t1 VALUES(5, randstr(1000,1000));40    INSERT INTO t1 VALUES(6, randstr(1000,1000));41    CREATE TABLE t2(a, b);42    CREATE TABLE t3(a, b);43    CREATE TABLE t4(a, b);44    CREATE TABLE t5(a, b);45    CREATE TABLE t6(a, b);46    CREATE TABLE t7(a, b);47    CREATE TABLE t8(a, b);48    CREATE TABLE t9(a, b);49    CREATE TABLE t10(a, b);50    PRAGMA integrity_check51  }52} {ok}53 54 55# Potential corruption scenario 1. A second process opens the database 56# and modifies a large portion of it. It then opens a second transaction57# and modifies a small part of the database, but crashes before it commits58# the transaction. 59#60# When the first process accessed the database again, it was rolling back61# the aborted transaction, but was not purging its in-memory cache (which62# was loaded before the second process made its first, successful, 63# modification). Producing an inconsistent cache.64#65do_test crash8-1.2 {66  crashsql -delay 2 -file test.db {67    PRAGMA cache_size = 10;68    UPDATE t1 SET b = randstr(1000,1000);69    INSERT INTO t9 VALUES(1, 2);70  }71} {1 {child process exited abnormally}}72do_test crash8-1.3 {73  execsql {PRAGMA integrity_check}74} {ok}75 76# Potential corruption scenario 2. The second process, operating in77# persistent-journal mode, makes a large change to the database file78# with a small in-memory cache. Such that more than one journal-header79# was written to the file. It then opens a second transaction and makes80# a smaller change that requires only a single journal-header to be81# written to the journal file. The second change is such that the 82# journal content written to the persistent journal file exactly overwrites83# the first journal-header and set of subsequent records written by the84# first, successful, change. The second process crashes before it can85# commit its second change.86#87# When the first process accessed the database again, it was rolling back88# the second aborted transaction, then continuing to rollback the second89# and subsequent journal-headers written by the first, successful, change.90# Database corruption.91#92do_test crash8.2.1 {93  crashsql -delay 2 -file test.db {94    PRAGMA journal_mode = persist;95    PRAGMA cache_size = 10;96    UPDATE t1 SET b = randstr(1000,1000);97    PRAGMA cache_size = 100;98    BEGIN;99      INSERT INTO t2 VALUES('a', 'b');100      INSERT INTO t3 VALUES('a', 'b');101      INSERT INTO t4 VALUES('a', 'b');102      INSERT INTO t5 VALUES('a', 'b');103      INSERT INTO t6 VALUES('a', 'b');104      INSERT INTO t7 VALUES('a', 'b');105      INSERT INTO t8 VALUES('a', 'b');106      INSERT INTO t9 VALUES('a', 'b');107      INSERT INTO t10 VALUES('a', 'b');108    COMMIT;109  }110} {1 {child process exited abnormally}}111 112do_test crash8-2.3 {113  execsql {PRAGMA integrity_check}114} {ok}115 116proc read_file {zFile} {117  set fd [open $zFile]118  fconfigure $fd -translation binary 119  set zData [read $fd]120  close $fd121  return $zData122}123proc write_file {zFile zData} {124  set fd [open $zFile w]125  fconfigure $fd -translation binary 126  puts -nonewline $fd $zData127  close $fd128}129 130# The following tests check that SQLite will not roll back a hot-journal131# file if the sector-size field in the first journal file header is132# suspect. Definition of suspect:133# 134#    a) Not a power of 2, or                (crash8-3.5)135#    b) Greater than 0x01000000 (16MB), or  (crash8-3.6)136#    c) Less than 512.                      (crash8-3.7)137#138# Also test that SQLite will not rollback a hot-journal file with a139# suspect page-size. In this case "suspect" means:140# 141#    a) Not a power of 2, or142#    b) Less than 512, or143#    c) Greater than SQLITE_MAX_PAGE_SIZE144#145if {[atomic_batch_write test.db]==0} {146do_test crash8-3.1 {147  list [file exists test.db-joural] [file exists test.db]148} {0 1}149do_test crash8-3.2 {150  execsql {151    PRAGMA synchronous = off;152    BEGIN;153    DELETE FROM t1;154    SELECT count(*) FROM t1;155  }156} {0}157do_test crash8-3.3 {158  set zJournal [read_file test.db-journal]159  execsql { 160    COMMIT;161    SELECT count(*) FROM t1;162  }163} {0}164do_test crash8-3.4 {165  binary scan [string range $zJournal 20 23] I nSector166  set nSector167} {512}168 169do_test crash8-3.5 {170  set zJournal2 [string replace $zJournal 20 23 [binary format I 513]]171  write_file test.db-journal $zJournal2172 173  execsql { 174    SELECT count(*) FROM t1;175    PRAGMA integrity_check176  }177} {0 ok}178do_test crash8-3.6 {179  set zJournal2 [string replace $zJournal 20 23 [binary format I 0x2000000]]180  write_file test.db-journal $zJournal2181  execsql { 182    SELECT count(*) FROM t1;183    PRAGMA integrity_check184  }185} {0 ok}186do_test crash8-3.7 {187  set zJournal2 [string replace $zJournal 20 23 [binary format I 256]]188  write_file test.db-journal $zJournal2189  execsql { 190    SELECT count(*) FROM t1;191    PRAGMA integrity_check192  }193} {0 ok}194 195do_test crash8-3.8 {196  set zJournal2 [string replace $zJournal 24 27 [binary format I 513]]197  write_file test.db-journal $zJournal2198 199  execsql { 200    SELECT count(*) FROM t1;201    PRAGMA integrity_check202  }203} {0 ok}204do_test crash8-3.9 {205  set big [expr $SQLITE_MAX_PAGE_SIZE * 2]206  set zJournal2 [string replace $zJournal 24 27 [binary format I $big]]207  write_file test.db-journal $zJournal2208  execsql { 209    SELECT count(*) FROM t1;210    PRAGMA integrity_check211  }212} {0 ok}213do_test crash8-3.10 {214  set zJournal2 [string replace $zJournal 24 27 [binary format I 256]]215  write_file test.db-journal $zJournal2216  execsql { 217    SELECT count(*) FROM t1;218    PRAGMA integrity_check219  }220} {0 ok}221 222do_test crash8-3.11 {223  set fd [open test.db-journal w]224  fconfigure $fd -translation binary 225  puts -nonewline $fd $zJournal226  close $fd227  execsql { 228    SELECT count(*) FROM t1;229    PRAGMA integrity_check230  }231} {6 ok}232}233 234 235# If a connection running in persistent-journal mode is part of a 236# multi-file transaction, it must ensure that the master-journal name237# appended to the journal file contents during the commit is located238# at the end of the physical journal file. If there was already a239# large journal file allocated at the start of the transaction, this240# may mean truncating the file so that the master journal name really241# is at the physical end of the file.242#243# This block of tests test that SQLite correctly truncates such244# journal files, and that the results behave correctly if a hot-journal245# rollback occurs.246#247ifcapable pragma {248  reset_db249  forcedelete test2.db250 251  do_test crash8-4.1 {252    execsql {253      PRAGMA journal_mode = persist;254      CREATE TABLE ab(a, b);255      INSERT INTO ab VALUES(0, 'abc');256      INSERT INTO ab VALUES(1, NULL);257      INSERT INTO ab VALUES(2, NULL);258      INSERT INTO ab VALUES(3, NULL);259      INSERT INTO ab VALUES(4, NULL);260      INSERT INTO ab VALUES(5, NULL);261      INSERT INTO ab VALUES(6, NULL);262      UPDATE ab SET b = randstr(1000,1000);263      ATTACH 'test2.db' AS aux;264      PRAGMA aux.journal_mode = persist;265      CREATE TABLE aux.ab(a, b);266      INSERT INTO aux.ab SELECT * FROM main.ab;267 268      UPDATE aux.ab SET b = randstr(1000,1000) WHERE a>=1;269      UPDATE ab SET b = randstr(1000,1000) WHERE a>=1;270    }271  } {persist persist}272  if {[atomic_batch_write test.db]==0} {273    do_test crash8.4.1.1 {274      list [file exists test.db-journal] [file exists test2.db-journal]275    } {1 1}276  }277 278  do_test crash8-4.2 {279    execsql {280      BEGIN;281        UPDATE aux.ab SET b = 'def' WHERE a = 0;282        UPDATE main.ab SET b = 'def' WHERE a = 0;283      COMMIT;284    }285  } {}286 287  do_test crash8-4.3 {288    execsql {289      UPDATE aux.ab SET b = randstr(1000,1000) WHERE a>=1;290      UPDATE ab SET b = randstr(1000,1000) WHERE a>=1;291    }292  } {}293 294  set contents_main [db eval {SELECT b FROM main.ab WHERE a = 1}]295  set contents_aux  [db eval {SELECT b FROM  aux.ab WHERE a = 1}]296 297  do_test crash8-4.4 {298    crashsql -file test2.db -delay 1 {299      ATTACH 'test2.db' AS aux;300      BEGIN;301        UPDATE aux.ab SET b = 'ghi' WHERE a = 0;302        UPDATE main.ab SET b = 'ghi' WHERE a = 0;303      COMMIT;304    }305  } {1 {child process exited abnormally}}306 307  do_test crash8-4.5 {308    list [file exists test.db-journal] [file exists test2.db-journal]309  } {1 1}310 311  do_test crash8-4.6 {312    execsql {313      SELECT b FROM main.ab WHERE a = 0;314      SELECT b FROM aux.ab WHERE a = 0;315    }316  } {def def}317 318  do_test crash8-4.7 {319    crashsql -file test2.db -delay 1 {320      ATTACH 'test2.db' AS aux;321      BEGIN;322        UPDATE aux.ab SET b = 'jkl' WHERE a = 0;323        UPDATE main.ab SET b = 'jkl' WHERE a = 0;324      COMMIT;325    }326  } {1 {child process exited abnormally}}327 328  do_test crash8-4.8 {329    set fd [open test.db-journal]330    fconfigure $fd -translation binary331    seek $fd -16 end332    binary scan [read $fd 4] I len333 334    seek $fd [expr {-1 * ($len + 16)}] end335    set zMasterJournal [read $fd $len]336    close $fd337 338    file exists $zMasterJournal339  } {1}340 341  do_test crash8-4.9 {342    execsql { SELECT b FROM aux.ab WHERE a = 0 }343  } {def}344 345  do_test crash8-4.10 {346    delete_file $zMasterJournal347    execsql { SELECT b FROM main.ab WHERE a = 0 }348  } {jkl}349}350 351#352# Since the following tests (crash8-5.*) rely upon being able353# to copy a file while open, they will not work on Windows.354#355# They also depend on being able to copy the journal file, which356# is not created on F2FS file-systems that support atomic357# write. So do not run these tests in that case either.358#359if {$::tcl_platform(os) ne "Windows NT" && [atomic_batch_write test.db]==0 } {360  for {set i 1} {$i < 10} {incr i} {361    catch { db close }362    forcedelete test.db test.db-journal363    sqlite3 db test.db364    do_test crash8-5.$i.1 {365      execsql {366        CREATE TABLE t1(x PRIMARY KEY);367        INSERT INTO t1 VALUES(randomblob(900));368        INSERT INTO t1 SELECT randomblob(900) FROM t1;369        INSERT INTO t1 SELECT randomblob(900) FROM t1;370        INSERT INTO t1 SELECT randomblob(900) FROM t1;371        INSERT INTO t1 SELECT randomblob(900) FROM t1;372        INSERT INTO t1 SELECT randomblob(900) FROM t1;373        INSERT INTO t1 SELECT randomblob(900) FROM t1;          /* 64 rows */374      }375      crashsql -file test.db -delay [expr ($::i%2) + 1] {376        PRAGMA cache_size = 10;377        BEGIN;378          UPDATE t1 SET x = randomblob(900);379        ROLLBACK;380        INSERT INTO t1 VALUES(randomblob(900));381      }382      execsql { PRAGMA integrity_check }383    } {ok}384  385    catch { db close }386    forcedelete test.db test.db-journal387    sqlite3 db test.db388    do_test crash8-5.$i.2 {389      execsql {390        PRAGMA cache_size = 10;391        CREATE TABLE t1(x PRIMARY KEY);392        INSERT INTO t1 VALUES(randomblob(900));393        INSERT INTO t1 SELECT randomblob(900) FROM t1;394        INSERT INTO t1 SELECT randomblob(900) FROM t1;395        INSERT INTO t1 SELECT randomblob(900) FROM t1;396        INSERT INTO t1 SELECT randomblob(900) FROM t1;397        INSERT INTO t1 SELECT randomblob(900) FROM t1;398        INSERT INTO t1 SELECT randomblob(900) FROM t1;          /* 64 rows */399        BEGIN;400          UPDATE t1 SET x = randomblob(900);401      }402      forcedelete testX.db testX.db-journal testX.db-wal403      forcecopy test.db testX.db404      forcecopy test.db-journal testX.db-journal405      db close406 407      crashsql -file test.db -delay [expr ($::i%2) + 1] {408        SELECT * FROM sqlite_master;409        INSERT INTO t1 VALUES(randomblob(900));410      }411 412      sqlite3 db2 testX.db413      execsql { PRAGMA integrity_check } db2414    } {ok}415  }416  catch {db2 close}417}418 419finish_test420