xref: /sqlite-3.40.0/test/corruptH.test (revision af3906a7)
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# This module uses hard-coded offsets which do not work if the reserved_bytes
18# value is nonzero.
19if {[nonzero_reserved_bytes]} {finish_test; return;}
20
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 {
67  db eval { PRAGMA secure_delete=1 }
68  list [catch {
69    db eval { SELECT * FROM t1 WHERE a IN (1, 2) } {
70      db eval { DELETE FROM t2 }
71    }
72  } msg] $msg
73} {1 {database disk image is malformed}}
74
75#-------------------------------------------------------------------------
76reset_db
77
78# Initialize the database.
79#
80do_execsql_test 2.1 {
81  PRAGMA auto_vacuum=0;
82  PRAGMA page_size=1024;
83
84  CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
85  INSERT INTO t1 VALUES(1, 'one');
86  INSERT INTO t1 VALUES(2, 'two');
87
88  CREATE TABLE t3(x);
89
90  CREATE TABLE t2(x PRIMARY KEY) WITHOUT ROWID;
91  INSERT INTO t2 VALUES(randomblob(100));
92
93  DROP TABLE t3;
94} {}
95
96do_test 2.2 {
97  db eval { SELECT name, rootpage FROM sqlite_master } {
98    set r($name) $rootpage
99  }
100  db close
101  set fl [hexio_get_int [hexio_read test.db 32 4]]
102
103  hexio_write test.db [expr {($fl-1) * 1024 + 0}] 00000000
104  hexio_write test.db [expr {($fl-1) * 1024 + 4}] 00000001
105  hexio_write test.db [expr {($fl-1) * 1024 + 8}] [format %.8X $r(t1)]
106  hexio_write test.db 36 00000002
107
108  sqlite3 db test.db
109} {}
110
111
112# The trick here is that the root page of the tree scanned by the outer
113# query is also currently on the free-list. So while the first seek on
114# the table (for a==1) works, by the time the second is attempted The
115# "INSERT INTO t2..." statements have recycled the root page of t1 and
116# used it as an index leaf. Normally, BtreeMovetoUnpacked() detects
117# that the PgHdr object associated with said root page does not match
118# the cursor (as it is now marked with PgHdr.intKey==0) and returns
119# SQLITE_CORRUPT.
120#
121set res23 {1 {database disk image is malformed}}
122do_test 2.3 {
123  list [catch {
124  set res [list]
125  db eval { SELECT * FROM t1 WHERE a IN (1, 2) } {
126    db eval {
127      INSERT INTO t2 SELECT randomblob(100) FROM t2;
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    }
133    lappend res $b
134  }
135  set res
136  } msg] $msg
137} $res23
138
139#-------------------------------------------------------------------------
140reset_db
141
142# Initialize the database.
143#
144do_execsql_test 3.1 {
145  PRAGMA page_size=1024;
146
147  CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
148  INSERT INTO t1 VALUES(1, 'one');
149  INSERT INTO t1 VALUES(2, 'two');
150
151  CREATE TABLE t2(c INTEGER PRAGMA KEY, d);
152  INSERT INTO t2 VALUES(1, randomblob(1100));
153} {}
154
155do_test 3.2 {
156  db eval { SELECT name, rootpage FROM sqlite_master } {
157    set r($name) $rootpage
158  }
159  db close
160
161  hexio_write test.db [expr {($r(t2)-1) * 1024 + 1020}] 00000002
162
163  sqlite3 db test.db
164} {}
165
166do_test 3.3 {
167  list [catch {
168  db eval { SELECT * FROM t1 WHERE a IN (1, 2) } {
169    db eval {
170      DELETE FROM t2 WHERE c=1;
171    }
172  }
173  } msg] $msg
174} {1 {database disk image is malformed}}
175
176finish_test
177