xref: /sqlite-3.40.0/test/corrupt.test (revision 4dcbdbff)
1# 2004 August 30
2#
3# The author disclaims copyright to this source code.  In place of
4# 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# This file implements regression tests for SQLite library.
12#
13# This file implements tests to make sure SQLite does not crash or
14# segfault if it sees a corrupt database file.
15#
16# $Id: corrupt.test,v 1.8 2005/02/19 08:18:06 danielk1977 Exp $
17
18catch {file delete -force test.db}
19catch {file delete -force test.db-journal}
20
21set testdir [file dirname $argv0]
22source $testdir/tester.tcl
23
24# Construct a large database for testing.
25#
26do_test corrupt-1.1 {
27  execsql {
28    BEGIN;
29    CREATE TABLE t1(x);
30    INSERT INTO t1 VALUES(randstr(100,100));
31    INSERT INTO t1 VALUES(randstr(90,90));
32    INSERT INTO t1 VALUES(randstr(80,80));
33    INSERT INTO t1 SELECT x || randstr(5,5) FROM t1;
34    INSERT INTO t1 SELECT x || randstr(6,6) FROM t1;
35    INSERT INTO t1 SELECT x || randstr(7,7) FROM t1;
36    INSERT INTO t1 SELECT x || randstr(8,8) FROM t1;
37    INSERT INTO t1 VALUES(randstr(3000,3000));
38    INSERT INTO t1 SELECT x || randstr(9,9) FROM t1;
39    INSERT INTO t1 SELECT x || randstr(10,10) FROM t1;
40    INSERT INTO t1 SELECT x || randstr(11,11) FROM t1;
41    INSERT INTO t1 SELECT x || randstr(12,12) FROM t1;
42    CREATE INDEX t1i1 ON t1(x);
43    CREATE TABLE t2 AS SELECT * FROM t1;
44    DELETE FROM t2 WHERE rowid%5!=0;
45    COMMIT;
46  }
47} {}
48integrity_check corrupt-1.2
49
50# Copy file $from into $to
51#
52proc copy_file {from to} {
53  set f [open $from]
54  fconfigure $f -translation binary
55  set t [open $to w]
56  fconfigure $t -translation binary
57  puts -nonewline $t [read $f [file size $from]]
58  close $t
59  close $f
60}
61
62# Setup for the tests.  Make a backup copy of the good database in test.bu.
63# Create a string of garbage data that is 256 bytes long.
64#
65copy_file test.db test.bu
66set fsize [file size test.db]
67set junk "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
68while {[string length $junk]<256} {append junk $junk}
69set junk [string range $junk 0 255]
70
71# Go through the database and write garbage data into each 256 segment
72# of the file.  Then do various operations on the file to make sure that
73# the database engine can recover gracefully from the corruption.
74#
75for {set i [expr {1*256}]} {$i<$fsize-256} {incr i 256} {
76  set tn [expr {$i/256}]
77  db close
78  copy_file test.bu test.db
79  set fd [open test.db r+]
80  fconfigure $fd -translation binary
81  seek $fd $i
82  puts -nonewline $fd $junk
83  close $fd
84  do_test corrupt-2.$tn.1 {
85    sqlite3 db test.db
86    catchsql {SELECT count(*) FROM sqlite_master}
87    set x {}
88  } {}
89  do_test corrupt-2.$tn.2 {
90    catchsql {SELECT count(*) FROM t1}
91    set x {}
92  } {}
93  do_test corrupt-2.$tn.3 {
94    catchsql {SELECT count(*) FROM t1 WHERE x>'abcdef'}
95    set x {}
96  } {}
97  do_test corrupt-2.$tn.4 {
98    catchsql {SELECT count(*) FROM t2}
99    set x {}
100  } {}
101  do_test corrupt-2.$tn.5 {
102    catchsql {CREATE TABLE t3 AS SELECT * FROM t1}
103    set x {}
104  } {}
105  do_test corrupt-2.$tn.6 {
106    catchsql {DROP TABLE t1}
107    set x {}
108  } {}
109  do_test corrupt-2.$tn.7 {
110    catchsql {PRAGMA integrity_check}
111    set x {}
112  } {}
113}
114
115#------------------------------------------------------------------------
116# For these tests, swap the rootpage entries of t1 (a table) and t1i1 (an
117# index on t1) in sqlite_master. Then perform a few different queries
118# and make sure this is detected as corruption.
119#
120do_test corrupt-3.1 {
121  db close
122  copy_file test.bu test.db
123  sqlite3 db test.db
124  list
125} {}
126do_test corrupt-3.2 {
127  set t1_r [execsql {SELECT rootpage FROM sqlite_master WHERE name = 't1i1'}]
128  set t1i1_r [execsql {SELECT rootpage FROM sqlite_master WHERE name = 't1'}]
129  set cookie [expr [execsql {PRAGMA schema_version}] + 1]
130  execsql "
131    PRAGMA writable_schema = 1;
132    UPDATE sqlite_master SET rootpage = $t1_r WHERE name = 't1';
133    UPDATE sqlite_master SET rootpage = $t1i1_r WHERE name = 't1i1';
134    PRAGMA writable_schema = 0;
135    PRAGMA schema_version = $cookie;
136  "
137} {}
138
139# This one tests the case caught by code in checkin [2313].
140do_test corrupt-3.3 {
141  db close
142  sqlite3 db test.db
143  catchsql {
144    INSERT INTO t1 VALUES('abc');
145  }
146} {1 {database disk image is malformed}}
147do_test corrupt-3.4 {
148  db close
149  sqlite3 db test.db
150  catchsql {
151    SELECT * FROM t1;
152  }
153} {1 {database disk image is malformed}}
154do_test corrupt-3.5 {
155  db close
156  sqlite3 db test.db
157  catchsql {
158    SELECT * FROM t1 WHERE oid = 10;
159  }
160} {1 {database disk image is malformed}}
161do_test corrupt-3.6 {
162  db close
163  sqlite3 db test.db
164  catchsql {
165    SELECT * FROM t1 WHERE x = 'abcde';
166  }
167} {1 {database disk image is malformed}}
168
169finish_test
170