- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / sqlite / src / test / corrupt2.test
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: corrupt2.test,v 1.20 2009/04/06 17:50:03 danielk1977 Exp $
17
18 set testdir [file dirname $argv0]
19 source $testdir/tester.tcl
20
21 # Do not use a codec for tests in this file, as the database file is
22 # manipulated directly using tcl scripts (using the [hexio_write] command).
23 #
24 do_not_use_codec
25
26 set presql ""
27 catch { set presql "$::G(perm:presql);" }
28 unset -nocomplain ::G(perm:presql)
29
30 # The following tests - corrupt2-1.* - create some databases corrupted in
31 # specific ways and ensure that SQLite detects them as corrupt.
32 #
33 do_test corrupt2-1.1 {
34   execsql {
35     PRAGMA auto_vacuum=0;
36     PRAGMA page_size=1024;
37     CREATE TABLE abc(a, b, c);
38   }
39 } {}
40
41 do_test corrupt2-1.2 {
42
43   # Corrupt the 16 byte magic string at the start of the file
44   file delete -force corrupt.db
45   file delete -force corrupt.db-journal
46   copy_file test.db corrupt.db
47   set f [open corrupt.db RDWR]
48   seek $f 8 start
49   puts $f blah
50   close $f
51
52   sqlite3 db2 corrupt.db
53   catchsql "
54     $::presql
55     SELECT * FROM sqlite_master;
56   " db2
57 } {1 {file is encrypted or is not a database}}
58
59 do_test corrupt2-1.3 {
60   db2 close
61
62   # Corrupt the page-size (bytes 16 and 17 of page 1).
63   file delete -force corrupt.db
64   file delete -force corrupt.db-journal
65   copy_file test.db corrupt.db
66   set f [open corrupt.db RDWR]
67   fconfigure $f -encoding binary
68   seek $f 16 start
69   puts -nonewline $f "\x00\xFF"
70   close $f
71
72   sqlite3 db2 corrupt.db
73   catchsql "
74     $::presql
75     SELECT * FROM sqlite_master;
76   " db2
77 } {1 {file is encrypted or is not a database}}
78
79 do_test corrupt2-1.4 {
80   db2 close
81
82   # Corrupt the free-block list on page 1.
83   file delete -force corrupt.db
84   file delete -force corrupt.db-journal
85   copy_file test.db corrupt.db
86   set f [open corrupt.db RDWR]
87   fconfigure $f -encoding binary
88   seek $f 101 start
89   puts -nonewline $f "\xFF\xFF"
90   close $f
91
92   sqlite3 db2 corrupt.db
93   catchsql "
94     $::presql
95     SELECT * FROM sqlite_master;
96   " db2
97 } {1 {database disk image is malformed}}
98
99 do_test corrupt2-1.5 {
100   db2 close
101
102   # Corrupt the free-block list on page 1.
103   file delete -force corrupt.db
104   file delete -force corrupt.db-journal
105   copy_file test.db corrupt.db
106   set f [open corrupt.db RDWR]
107   fconfigure $f -encoding binary
108   seek $f 101 start
109   puts -nonewline $f "\x00\xC8"
110   seek $f 200 start
111   puts -nonewline $f "\x00\x00"
112   puts -nonewline $f "\x10\x00"
113   close $f
114
115   sqlite3 db2 corrupt.db
116   catchsql "
117     $::presql
118     SELECT * FROM sqlite_master;
119   " db2
120 } {1 {database disk image is malformed}}
121 db2 close
122
123 # Corrupt a database by having 2 indices of the same name:
124 do_test corrupt2-2.1 {
125
126   file delete -force corrupt.db
127   file delete -force corrupt.db-journal
128   copy_file test.db corrupt.db
129
130   sqlite3 db2 corrupt.db 
131   execsql "
132     $::presql
133     CREATE INDEX a1 ON abc(a);
134     CREATE INDEX a2 ON abc(b);
135     PRAGMA writable_schema = 1;
136     UPDATE sqlite_master 
137       SET name = 'a3', sql = 'CREATE INDEX a3' || substr(sql, 16, 10000)
138       WHERE type = 'index';
139     PRAGMA writable_schema = 0;
140   " db2
141
142   db2 close
143   sqlite3 db2 corrupt.db 
144   catchsql "
145     $::presql
146     SELECT * FROM sqlite_master;
147   " db2
148 } {1 {malformed database schema (a3) - index a3 already exists}}
149
150 db2 close
151
152 do_test corrupt2-3.1 {
153   file delete -force corrupt.db
154   file delete -force corrupt.db-journal
155   sqlite3 db2 corrupt.db 
156
157   execsql "
158     $::presql
159     PRAGMA auto_vacuum = 1;
160     PRAGMA page_size = 1024;
161     CREATE TABLE t1(a, b, c);
162     CREATE TABLE t2(a, b, c);
163     INSERT INTO t2 VALUES(randomblob(100), randomblob(100), randomblob(100));
164     INSERT INTO t2 SELECT * FROM t2;
165     INSERT INTO t2 SELECT * FROM t2;
166     INSERT INTO t2 SELECT * FROM t2;
167     INSERT INTO t2 SELECT * FROM t2;
168   " db2
169
170   db2 close
171
172   # On the root page of table t2 (page 4), set one of the child page-numbers
173   # to 0. This corruption will be detected when SQLite attempts to update
174   # the pointer-map after moving the content of page 4 to page 3 as part
175   # of the DROP TABLE operation below.
176   #
177   set fd [open corrupt.db r+]
178   fconfigure $fd -encoding binary -translation binary
179   seek $fd [expr 1024*3 + 12]
180   set zCelloffset [read $fd 2]
181   binary scan $zCelloffset S iCelloffset
182   seek $fd [expr 1024*3 + $iCelloffset]
183   puts -nonewline $fd "\00\00\00\00" 
184   close $fd
185
186   sqlite3 db2 corrupt.db 
187   catchsql "
188     $::presql
189     DROP TABLE t1;
190   " db2
191 } {1 {database disk image is malformed}}
192
193 do_test corrupt2-4.1 {
194   catchsql {
195     SELECT * FROM t2;
196   } db2
197 } {1 {database disk image is malformed}}
198
199 db2 close
200
201 unset -nocomplain result
202 do_test corrupt2-5.1 {
203   file delete -force corrupt.db
204   file delete -force corrupt.db-journal
205   sqlite3 db2 corrupt.db 
206
207   execsql "
208     $::presql
209     PRAGMA auto_vacuum = 0;
210     PRAGMA page_size = 1024;
211     CREATE TABLE t1(a, b, c);
212     CREATE TABLE t2(a, b, c);
213     INSERT INTO t2 VALUES(randomblob(100), randomblob(100), randomblob(100));
214     INSERT INTO t2 SELECT * FROM t2;
215     INSERT INTO t2 SELECT * FROM t2;
216     INSERT INTO t2 SELECT * FROM t2;
217     INSERT INTO t2 SELECT * FROM t2;
218     INSERT INTO t1 SELECT * FROM t2;
219   " db2
220
221   db2 close
222
223   # This block links a page from table t2 into the t1 table structure.
224   #
225   set fd [open corrupt.db r+]
226   fconfigure $fd -encoding binary -translation binary
227   seek $fd [expr 1024 + 12]
228   set zCelloffset [read $fd 2]
229   binary scan $zCelloffset S iCelloffset
230   seek $fd [expr 1024 + $iCelloffset]
231   set zChildPage [read $fd 4]
232   seek $fd [expr 2*1024 + 12]
233   set zCelloffset [read $fd 2]
234   binary scan $zCelloffset S iCelloffset
235   seek $fd [expr 2*1024 + $iCelloffset]
236   puts -nonewline $fd $zChildPage
237   close $fd
238
239   sqlite3 db2 corrupt.db 
240   db2 eval $::presql
241   db2 eval {SELECT rowid FROM t1} {
242     set result [db2 eval {pragma integrity_check}]
243     break
244   }
245   set result
246 } {{*** in database main ***
247 On tree page 2 cell 0: 2nd reference to page 10
248 On tree page 2 cell 1: Child page depth differs
249 Page 4 is never used}}
250
251 db2 close
252
253 proc corruption_test {args} {
254   set A(-corrupt) {}
255   set A(-sqlprep) {}
256   set A(-tclprep) {}
257   array set A $args
258
259   catch {db close}
260   file delete -force corrupt.db
261   file delete -force corrupt.db-journal
262
263   sqlite3 db corrupt.db 
264   db eval $::presql
265   eval $A(-tclprep)
266   db eval $A(-sqlprep)
267   db close
268
269   eval $A(-corrupt)
270
271   sqlite3 db corrupt.db
272   eval $A(-test)
273 }
274
275 ifcapable autovacuum {
276   # The tests within this block - corrupt2-6.* - aim to test corruption
277   # detection within an incremental-vacuum. When an incremental-vacuum
278   # step is executed, the last non-free page of the database file is 
279   # moved into a free space in the body of the file. After doing so,
280   # the page reference in the parent page must be updated to refer
281   # to the new location. These tests test the outcome of corrupting
282   # that page reference before performing the incremental vacuum.
283   #
284
285   # The last page in the database page is the second page 
286   # in an overflow chain.
287   #
288   corruption_test -sqlprep {
289     PRAGMA auto_vacuum = incremental;
290     PRAGMA page_size = 1024;
291     CREATE TABLE t1(a, b);
292     INSERT INTO t1 VALUES(1, randomblob(2500));
293     INSERT INTO t1 VALUES(2, randomblob(2500));
294     DELETE FROM t1 WHERE a = 1;
295   } -corrupt {
296     hexio_write corrupt.db [expr 1024*5] 00000008
297   } -test {
298     do_test corrupt2-6.1 {
299       catchsql " $::presql pragma incremental_vacuum = 1 "
300     } {1 {database disk image is malformed}}
301   }
302
303   # The last page in the database page is a non-root b-tree page.
304   #
305   corruption_test -sqlprep {
306     PRAGMA auto_vacuum = incremental;
307     PRAGMA page_size = 1024;
308     CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
309     INSERT INTO t1 VALUES(1, randomblob(2500));
310     INSERT INTO t1 VALUES(2, randomblob(50));
311     INSERT INTO t1 SELECT NULL, randomblob(50) FROM t1;
312     INSERT INTO t1 SELECT NULL, randomblob(50) FROM t1;
313     INSERT INTO t1 SELECT NULL, randomblob(50) FROM t1;
314     INSERT INTO t1 SELECT NULL, randomblob(50) FROM t1;
315     DELETE FROM t1 WHERE a = 1;
316   } -corrupt {
317     hexio_write corrupt.db [expr 1024*2 + 8] 00000009
318   } -test {
319     do_test corrupt2-6.2 {
320       catchsql " $::presql pragma incremental_vacuum = 1 "
321     } {1 {database disk image is malformed}}
322   }
323
324   # Set up a pointer-map entry so that the last page of the database
325   # file appears to be a b-tree root page. This should be detected
326   # as corruption.
327   #
328   corruption_test -sqlprep {
329     PRAGMA auto_vacuum = incremental;
330     PRAGMA page_size = 1024;
331     CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
332     INSERT INTO t1 VALUES(1, randomblob(2500));
333     INSERT INTO t1 VALUES(2, randomblob(2500));
334     INSERT INTO t1 VALUES(3, randomblob(2500));
335     DELETE FROM t1 WHERE a = 1;
336   } -corrupt {
337     set nPage [expr [file size corrupt.db] / 1024]
338     hexio_write corrupt.db [expr 1024 + ($nPage-3)*5] 010000000
339   } -test {
340     do_test corrupt2-6.3 {
341       catchsql " $::presql pragma incremental_vacuum = 1 "
342     } {1 {database disk image is malformed}}
343   }
344
345   corruption_test -sqlprep {
346     PRAGMA auto_vacuum = 1;
347     PRAGMA page_size = 1024;
348     CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
349     INSERT INTO t1 VALUES(1, randomblob(2500));
350     DELETE FROM t1 WHERE a = 1;
351   } -corrupt {
352     set nAppend [expr 1024*207 - [file size corrupt.db]]
353     set fd [open corrupt.db r+]
354     seek $fd 0 end
355     puts -nonewline $fd [string repeat x $nAppend]
356     close $fd
357     hexio_write corrupt.db 28 00000000
358   } -test {
359     do_test corrupt2-6.4 {
360       catchsql " 
361         $::presql 
362         BEGIN EXCLUSIVE;
363         COMMIT;
364       "
365     } {1 {database disk image is malformed}}
366   }
367 }
368
369
370 set sqlprep {
371   PRAGMA auto_vacuum = 0;
372   PRAGMA page_size = 1024;
373   CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
374   CREATE INDEX i1 ON t1(b);
375   INSERT INTO t1 VALUES(1, randomblob(50));
376   INSERT INTO t1 SELECT NULL, randomblob(50) FROM t1;
377   INSERT INTO t1 SELECT NULL, randomblob(50) FROM t1;
378   INSERT INTO t1 SELECT NULL, randomblob(50) FROM t1;
379   INSERT INTO t1 SELECT NULL, randomblob(50) FROM t1;
380   INSERT INTO t1 SELECT NULL, randomblob(50) FROM t1;
381   INSERT INTO t1 SELECT NULL, randomblob(50) FROM t1;
382 }
383
384 corruption_test -sqlprep $sqlprep -corrupt {
385   # Set the page-flags of one of the leaf pages of the index B-Tree to
386   # 0x0D (interpreted by SQLite as "leaf page of a table B-Tree").
387   #
388   set fd [open corrupt.db r+]
389   fconfigure $fd -translation binary -encoding binary
390   seek $fd [expr 1024*2 + 8] 
391   set zRightChild [read $fd 4]
392   binary scan $zRightChild I iRightChild
393   seek $fd [expr 1024*($iRightChild-1)]
394   puts -nonewline $fd "\x0D"
395   close $fd
396 } -test {
397   do_test corrupt2-7.1 {
398     catchsql " $::presql SELECT b FROM t1 ORDER BY b ASC "
399   } {1 {database disk image is malformed}}
400 }
401
402 corruption_test -sqlprep $sqlprep -corrupt {
403   # Mess up the page-header of one of the leaf pages of the index B-Tree.
404   # The corruption is detected as part of an OP_Prev opcode.
405   #
406   set fd [open corrupt.db r+]
407   fconfigure $fd -translation binary -encoding binary
408   seek $fd [expr 1024*2 + 12] 
409   set zCellOffset [read $fd 2]
410   binary scan $zCellOffset S iCellOffset
411   seek $fd [expr 1024*2 + $iCellOffset]
412   set zChild [read $fd 4]
413   binary scan $zChild I iChild
414   seek $fd [expr 1024*($iChild-1)+3]
415   puts -nonewline $fd "\xFFFF"
416   close $fd
417 } -test {
418   do_test corrupt2-7.1 {
419     catchsql " $::presql SELECT b FROM t1 ORDER BY b DESC "
420   } {1 {database disk image is malformed}}
421 }
422
423 corruption_test -sqlprep $sqlprep -corrupt {
424   # Set the page-flags of one of the leaf pages of the table B-Tree to
425   # 0x0A (interpreted by SQLite as "leaf page of an index B-Tree").
426   #
427   set fd [open corrupt.db r+]
428   fconfigure $fd -translation binary -encoding binary
429   seek $fd [expr 1024*1 + 8] 
430   set zRightChild [read $fd 4]
431   binary scan $zRightChild I iRightChild
432   seek $fd [expr 1024*($iRightChild-1)]
433   puts -nonewline $fd "\x0A"
434   close $fd
435 } -test {
436   do_test corrupt2-8.1 {
437     catchsql " $::presql SELECT * FROM t1 WHERE rowid=1000 "
438   } {1 {database disk image is malformed}}
439 }
440
441 corruption_test -sqlprep {
442   CREATE TABLE t1(a, b, c); CREATE TABLE t8(a, b, c); CREATE TABLE tE(a, b, c);
443   CREATE TABLE t2(a, b, c); CREATE TABLE t9(a, b, c); CREATE TABLE tF(a, b, c);
444   CREATE TABLE t3(a, b, c); CREATE TABLE tA(a, b, c); CREATE TABLE tG(a, b, c);
445   CREATE TABLE t4(a, b, c); CREATE TABLE tB(a, b, c); CREATE TABLE tH(a, b, c);
446   CREATE TABLE t5(a, b, c); CREATE TABLE tC(a, b, c); CREATE TABLE tI(a, b, c);
447   CREATE TABLE t6(a, b, c); CREATE TABLE tD(a, b, c); CREATE TABLE tJ(a, b, c);
448   CREATE TABLE x1(a, b, c); CREATE TABLE x8(a, b, c); CREATE TABLE xE(a, b, c);
449   CREATE TABLE x2(a, b, c); CREATE TABLE x9(a, b, c); CREATE TABLE xF(a, b, c);
450   CREATE TABLE x3(a, b, c); CREATE TABLE xA(a, b, c); CREATE TABLE xG(a, b, c);
451   CREATE TABLE x4(a, b, c); CREATE TABLE xB(a, b, c); CREATE TABLE xH(a, b, c);
452   CREATE TABLE x5(a, b, c); CREATE TABLE xC(a, b, c); CREATE TABLE xI(a, b, c);
453   CREATE TABLE x6(a, b, c); CREATE TABLE xD(a, b, c); CREATE TABLE xJ(a, b, c);
454 } -corrupt {
455   set fd [open corrupt.db r+]
456   fconfigure $fd -translation binary -encoding binary
457   seek $fd 108
458   set zRightChild [read $fd 4]
459   binary scan $zRightChild I iRightChild
460   seek $fd [expr 1024*($iRightChild-1)+3]
461   puts -nonewline $fd "\x00\x00"
462   close $fd
463 } -test {
464   do_test corrupt2-9.1 {
465     catchsql " $::presql SELECT sql FROM sqlite_master "
466   } {1 {database disk image is malformed}}
467 }
468
469 corruption_test -sqlprep {
470   CREATE TABLE t1(a, b, c);
471   CREATE TABLE t2(a, b, c);
472   PRAGMA writable_schema = 1;
473   UPDATE sqlite_master SET rootpage = NULL WHERE name = 't2';
474 } -test {
475   do_test corrupt2-10.1 {
476     catchsql " $::presql SELECT * FROM t2 "
477   } {1 {malformed database schema (t2)}}
478   do_test corrupt2-10.2 {
479     sqlite3_errcode db
480   } {SQLITE_CORRUPT}
481 }
482
483 corruption_test -sqlprep {
484   PRAGMA auto_vacuum = incremental;
485   CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
486   CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
487   INSERT INTO t1 VALUES(1, randstr(100,100));
488   INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
489   INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
490   INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
491   INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
492   INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
493   INSERT INTO t2 SELECT * FROM t1;
494   DELETE FROM t1;
495 } -corrupt {
496   set offset [expr [file size corrupt.db] - 1024]
497   hexio_write corrupt.db $offset FF 
498   hexio_write corrupt.db 24   12345678
499 } -test {
500   do_test corrupt2-11.1 {
501     catchsql " $::presql PRAGMA incremental_vacuum "
502   } {1 {database disk image is malformed}}
503 }
504 corruption_test -sqlprep {
505   PRAGMA auto_vacuum = incremental;
506   CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
507   CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
508   INSERT INTO t1 VALUES(1, randstr(100,100));
509   INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
510   INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
511   INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
512   INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
513   INSERT INTO t1 SELECT NULL, randstr(100,100) FROM t1;
514   INSERT INTO t2 SELECT * FROM t1;
515   DELETE FROM t1;
516 } -corrupt {
517   set pgno [expr [file size corrupt.db] / 1024]
518   hexio_write corrupt.db [expr 1024+5*($pgno-3)] 03 
519   hexio_write corrupt.db 24   12345678
520 } -test {
521   do_test corrupt2-12.1 {
522     catchsql " $::presql PRAGMA incremental_vacuum "
523   } {1 {database disk image is malformed}}
524 }
525
526 ifcapable autovacuum {
527   # It is not possible for the last page in a database file to be the
528   # pending-byte page (AKA the locking page). This test verifies that if
529   # an attempt is made to commit a transaction to such an auto-vacuum 
530   # database SQLITE_CORRUPT is returned.
531   #
532   corruption_test -tclprep {
533     db eval { 
534       PRAGMA auto_vacuum = full;
535       PRAGMA page_size = 1024;
536       CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
537       INSERT INTO t1 VALUES(NULL, randstr(50,50));
538     }
539     for {set ii 0} {$ii < 10} {incr ii} {
540       db eval " $::presql INSERT INTO t1 SELECT NULL, randstr(50,50) FROM t1 "
541     }
542   } -corrupt {
543     do_test corrupt2-13.1 {
544       file size corrupt.db
545     } $::sqlite_pending_byte
546     hexio_write corrupt.db [expr $::sqlite_pending_byte+1023] 00
547     hexio_write corrupt.db 28 00000000
548   } -test {
549     do_test corrupt2-13.2 {
550       file size corrupt.db
551     } [expr $::sqlite_pending_byte + 1024]
552     do_test corrupt2-13.3 {
553       catchsql { DELETE FROM t1 WHERE rowid < 30; }
554     } {1 {database disk image is malformed}}
555   }
556 }
557
558 finish_test