xref: /sqlite-3.40.0/test/corruptH.test (revision af3906a7)
17df42abaSdan# 2014-01-20
27df42abaSdan#
37df42abaSdan# The author disclaims copyright to this source code.  In place of
47df42abaSdan# a legal notice, here is a blessing:
57df42abaSdan#
67df42abaSdan#    May you do good and not evil.
77df42abaSdan#    May you find forgiveness for yourself and forgive others.
87df42abaSdan#    May you share freely, never taking more than you give.
97df42abaSdan#
107df42abaSdan#***********************************************************************
117df42abaSdan#
127df42abaSdan
137df42abaSdanset testdir [file dirname $argv0]
147df42abaSdansource $testdir/tester.tcl
157df42abaSdanset testprefix corruptH
167df42abaSdan
17*af3906a7Sdrh# This module uses hard-coded offsets which do not work if the reserved_bytes
18*af3906a7Sdrh# value is nonzero.
19*af3906a7Sdrhif {[nonzero_reserved_bytes]} {finish_test; return;}
20*af3906a7Sdrh
217df42abaSdandatabase_may_be_corrupt
227df42abaSdan
23f0ec2a5eSdan# The corruption migrations tested by the code in this file are not detected
24f0ec2a5eSdan# mmap mode.
25f0ec2a5eSdan#
26f0ec2a5eSdan# The reason is that in mmap mode, the different queries may use different
27f0ec2a5eSdan# PgHdr objects for the same page (same data, but different PgHdr container
28f0ec2a5eSdan# objects). And so the corruption is not detected.
29f0ec2a5eSdan#
30f0ec2a5eSdanif {[permutation]=="mmap"} {
31f0ec2a5eSdan  finish_test
32f0ec2a5eSdan  return
33f0ec2a5eSdan}
34f0ec2a5eSdan
357df42abaSdan# Initialize the database.
367df42abaSdan#
377df42abaSdando_execsql_test 1.1 {
387df42abaSdan  PRAGMA page_size=1024;
397df42abaSdan
407df42abaSdan  CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
417df42abaSdan  INSERT INTO t1 VALUES(1, 'one');
427df42abaSdan  INSERT INTO t1 VALUES(2, 'two');
437df42abaSdan
447df42abaSdan  CREATE TABLE t2(x);
457df42abaSdan  INSERT INTO t2 VALUES(randomblob(200));
467df42abaSdan  INSERT INTO t2 SELECT randomblob(200) FROM t2;
477df42abaSdan  INSERT INTO t2 SELECT randomblob(200) FROM t2;
487df42abaSdan  INSERT INTO t2 SELECT randomblob(200) FROM t2;
497df42abaSdan  INSERT INTO t2 SELECT randomblob(200) FROM t2;
507df42abaSdan  INSERT INTO t2 SELECT randomblob(200) FROM t2;
517df42abaSdan  INSERT INTO t2 SELECT randomblob(200) FROM t2;
527df42abaSdan} {}
537df42abaSdan
547df42abaSdan# Corrupt the file so that the root page of t1 is also linked into t2 as
557df42abaSdan# a leaf page.
567df42abaSdan#
577df42abaSdando_test 1.2 {
587df42abaSdan  db eval { SELECT name, rootpage FROM sqlite_master } {
597df42abaSdan    set r($name) $rootpage
607df42abaSdan  }
617df42abaSdan  db close
627df42abaSdan  hexio_write test.db [expr {($r(t2)-1)*1024 + 11}] [format %.2X $r(t1)]
637df42abaSdan  sqlite3 db test.db
647df42abaSdan} {}
657df42abaSdan
667df42abaSdando_test 1.3 {
677df42abaSdan  db eval { PRAGMA secure_delete=1 }
687df42abaSdan  list [catch {
697df42abaSdan    db eval { SELECT * FROM t1 WHERE a IN (1, 2) } {
707df42abaSdan      db eval { DELETE FROM t2 }
717df42abaSdan    }
727df42abaSdan  } msg] $msg
737df42abaSdan} {1 {database disk image is malformed}}
747df42abaSdan
757df42abaSdan#-------------------------------------------------------------------------
767df42abaSdanreset_db
777df42abaSdan
787df42abaSdan# Initialize the database.
797df42abaSdan#
807df42abaSdando_execsql_test 2.1 {
81abfe0346Sdan  PRAGMA auto_vacuum=0;
827df42abaSdan  PRAGMA page_size=1024;
837df42abaSdan
847df42abaSdan  CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
857df42abaSdan  INSERT INTO t1 VALUES(1, 'one');
867df42abaSdan  INSERT INTO t1 VALUES(2, 'two');
877df42abaSdan
887df42abaSdan  CREATE TABLE t3(x);
897df42abaSdan
907df42abaSdan  CREATE TABLE t2(x PRIMARY KEY) WITHOUT ROWID;
917df42abaSdan  INSERT INTO t2 VALUES(randomblob(100));
927df42abaSdan
937df42abaSdan  DROP TABLE t3;
947df42abaSdan} {}
957df42abaSdan
967df42abaSdando_test 2.2 {
977df42abaSdan  db eval { SELECT name, rootpage FROM sqlite_master } {
987df42abaSdan    set r($name) $rootpage
997df42abaSdan  }
1007df42abaSdan  db close
1017df42abaSdan  set fl [hexio_get_int [hexio_read test.db 32 4]]
1027df42abaSdan
1037df42abaSdan  hexio_write test.db [expr {($fl-1) * 1024 + 0}] 00000000
1047df42abaSdan  hexio_write test.db [expr {($fl-1) * 1024 + 4}] 00000001
1057df42abaSdan  hexio_write test.db [expr {($fl-1) * 1024 + 8}] [format %.8X $r(t1)]
1067df42abaSdan  hexio_write test.db 36 00000002
1077df42abaSdan
1087df42abaSdan  sqlite3 db test.db
1097df42abaSdan} {}
1107df42abaSdan
111705a4875Sdan
112705a4875Sdan# The trick here is that the root page of the tree scanned by the outer
113705a4875Sdan# query is also currently on the free-list. So while the first seek on
114705a4875Sdan# the table (for a==1) works, by the time the second is attempted The
115705a4875Sdan# "INSERT INTO t2..." statements have recycled the root page of t1 and
116705a4875Sdan# used it as an index leaf. Normally, BtreeMovetoUnpacked() detects
117705a4875Sdan# that the PgHdr object associated with said root page does not match
118705a4875Sdan# the cursor (as it is now marked with PgHdr.intKey==0) and returns
119705a4875Sdan# SQLITE_CORRUPT.
120705a4875Sdan#
121705a4875Sdanset res23 {1 {database disk image is malformed}}
1227df42abaSdando_test 2.3 {
1237df42abaSdan  list [catch {
124705a4875Sdan  set res [list]
1257df42abaSdan  db eval { SELECT * FROM t1 WHERE a IN (1, 2) } {
1267df42abaSdan    db eval {
1277df42abaSdan      INSERT INTO t2 SELECT randomblob(100) FROM t2;
1287df42abaSdan      INSERT INTO t2 SELECT randomblob(100) FROM t2;
1297df42abaSdan      INSERT INTO t2 SELECT randomblob(100) FROM t2;
1307df42abaSdan      INSERT INTO t2 SELECT randomblob(100) FROM t2;
1317df42abaSdan      INSERT INTO t2 SELECT randomblob(100) FROM t2;
1327df42abaSdan    }
133705a4875Sdan    lappend res $b
1347df42abaSdan  }
135705a4875Sdan  set res
1367df42abaSdan  } msg] $msg
137705a4875Sdan} $res23
1387df42abaSdan
1397df42abaSdan#-------------------------------------------------------------------------
1407df42abaSdanreset_db
1417df42abaSdan
1427df42abaSdan# Initialize the database.
1437df42abaSdan#
1447df42abaSdando_execsql_test 3.1 {
1457df42abaSdan  PRAGMA page_size=1024;
1467df42abaSdan
1477df42abaSdan  CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
1487df42abaSdan  INSERT INTO t1 VALUES(1, 'one');
1497df42abaSdan  INSERT INTO t1 VALUES(2, 'two');
1507df42abaSdan
1517df42abaSdan  CREATE TABLE t2(c INTEGER PRAGMA KEY, d);
1527df42abaSdan  INSERT INTO t2 VALUES(1, randomblob(1100));
1537df42abaSdan} {}
1547df42abaSdan
1557df42abaSdando_test 3.2 {
1567df42abaSdan  db eval { SELECT name, rootpage FROM sqlite_master } {
1577df42abaSdan    set r($name) $rootpage
1587df42abaSdan  }
1597df42abaSdan  db close
1607df42abaSdan
1617df42abaSdan  hexio_write test.db [expr {($r(t2)-1) * 1024 + 1020}] 00000002
1627df42abaSdan
1637df42abaSdan  sqlite3 db test.db
1647df42abaSdan} {}
1657df42abaSdan
1667df42abaSdando_test 3.3 {
1677df42abaSdan  list [catch {
1687df42abaSdan  db eval { SELECT * FROM t1 WHERE a IN (1, 2) } {
1697df42abaSdan    db eval {
1707df42abaSdan      DELETE FROM t2 WHERE c=1;
1717df42abaSdan    }
1727df42abaSdan  }
1737df42abaSdan  } msg] $msg
1747df42abaSdan} {1 {database disk image is malformed}}
1757df42abaSdan
1767df42abaSdanfinish_test
177