xref: /sqlite-3.40.0/test/corruptH.test (revision f0ec2a5e)
1# 2014-01-20
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#
12
13set testdir [file dirname $argv0]
14source $testdir/tester.tcl
15set testprefix corruptH
16
17# Do not use a codec for tests in this file, as the database file is
18# manipulated directly using tcl scripts (using the [hexio_write] command).
19#
20do_not_use_codec
21database_may_be_corrupt
22
23# The corruption migrations tested by the code in this file are not detected
24# mmap mode.
25#
26# The reason is that in mmap mode, the different queries may use different
27# PgHdr objects for the same page (same data, but different PgHdr container
28# objects). And so the corruption is not detected.
29#
30if {[permutation]=="mmap"} {
31  finish_test
32  return
33}
34
35# Initialize the database.
36#
37do_execsql_test 1.1 {
38  PRAGMA page_size=1024;
39
40  CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
41  INSERT INTO t1 VALUES(1, 'one');
42  INSERT INTO t1 VALUES(2, 'two');
43
44  CREATE TABLE t2(x);
45  INSERT INTO t2 VALUES(randomblob(200));
46  INSERT INTO t2 SELECT randomblob(200) FROM t2;
47  INSERT INTO t2 SELECT randomblob(200) FROM t2;
48  INSERT INTO t2 SELECT randomblob(200) FROM t2;
49  INSERT INTO t2 SELECT randomblob(200) FROM t2;
50  INSERT INTO t2 SELECT randomblob(200) FROM t2;
51  INSERT INTO t2 SELECT randomblob(200) FROM t2;
52} {}
53
54# Corrupt the file so that the root page of t1 is also linked into t2 as
55# a leaf page.
56#
57do_test 1.2 {
58  db eval { SELECT name, rootpage FROM sqlite_master } {
59    set r($name) $rootpage
60  }
61  db close
62  hexio_write test.db [expr {($r(t2)-1)*1024 + 11}] [format %.2X $r(t1)]
63  sqlite3 db test.db
64} {}
65
66do_test 1.3 {
67breakpoint
68  db eval { PRAGMA secure_delete=1 }
69  list [catch {
70    db eval { SELECT * FROM t1 WHERE a IN (1, 2) } {
71      db eval { DELETE FROM t2 }
72    }
73  } msg] $msg
74} {1 {database disk image is malformed}}
75
76#-------------------------------------------------------------------------
77reset_db
78
79# Initialize the database.
80#
81do_execsql_test 2.1 {
82  PRAGMA auto_vacuum=0;
83  PRAGMA page_size=1024;
84
85  CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
86  INSERT INTO t1 VALUES(1, 'one');
87  INSERT INTO t1 VALUES(2, 'two');
88
89  CREATE TABLE t3(x);
90
91  CREATE TABLE t2(x PRIMARY KEY) WITHOUT ROWID;
92  INSERT INTO t2 VALUES(randomblob(100));
93
94  DROP TABLE t3;
95} {}
96
97do_test 2.2 {
98  db eval { SELECT name, rootpage FROM sqlite_master } {
99    set r($name) $rootpage
100  }
101  db close
102  set fl [hexio_get_int [hexio_read test.db 32 4]]
103
104  hexio_write test.db [expr {($fl-1) * 1024 + 0}] 00000000
105  hexio_write test.db [expr {($fl-1) * 1024 + 4}] 00000001
106  hexio_write test.db [expr {($fl-1) * 1024 + 8}] [format %.8X $r(t1)]
107  hexio_write test.db 36 00000002
108
109  sqlite3 db test.db
110} {}
111
112
113# The trick here is that the root page of the tree scanned by the outer
114# query is also currently on the free-list. So while the first seek on
115# the table (for a==1) works, by the time the second is attempted The
116# "INSERT INTO t2..." statements have recycled the root page of t1 and
117# used it as an index leaf. Normally, BtreeMovetoUnpacked() detects
118# that the PgHdr object associated with said root page does not match
119# the cursor (as it is now marked with PgHdr.intKey==0) and returns
120# SQLITE_CORRUPT.
121#
122set res23 {1 {database disk image is malformed}}
123do_test 2.3 {
124  list [catch {
125  set res [list]
126  db eval { SELECT * FROM t1 WHERE a IN (1, 2) } {
127    db eval {
128      INSERT INTO t2 SELECT randomblob(100) FROM t2;
129      INSERT INTO t2 SELECT randomblob(100) FROM t2;
130      INSERT INTO t2 SELECT randomblob(100) FROM t2;
131      INSERT INTO t2 SELECT randomblob(100) FROM t2;
132      INSERT INTO t2 SELECT randomblob(100) FROM t2;
133    }
134    lappend res $b
135  }
136  set res
137  } msg] $msg
138} $res23
139
140#-------------------------------------------------------------------------
141reset_db
142
143# Initialize the database.
144#
145do_execsql_test 3.1 {
146  PRAGMA page_size=1024;
147
148  CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
149  INSERT INTO t1 VALUES(1, 'one');
150  INSERT INTO t1 VALUES(2, 'two');
151
152  CREATE TABLE t2(c INTEGER PRAGMA KEY, d);
153  INSERT INTO t2 VALUES(1, randomblob(1100));
154} {}
155
156do_test 3.2 {
157  db eval { SELECT name, rootpage FROM sqlite_master } {
158    set r($name) $rootpage
159  }
160  db close
161
162  hexio_write test.db [expr {($r(t2)-1) * 1024 + 1020}] 00000002
163
164  sqlite3 db test.db
165} {}
166
167do_test 3.3 {
168  list [catch {
169  db eval { SELECT * FROM t1 WHERE a IN (1, 2) } {
170    db eval {
171      DELETE FROM t2 WHERE c=1;
172    }
173  }
174  } msg] $msg
175} {1 {database disk image is malformed}}
176
177finish_test
178
179