wasCSharpSQLite – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 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