Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1056)

Side by Side Diff: third_party/sqlite/src/test/wal2.test

Issue 5626002: Update sqlite to 3.7.3. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/third_party/sqlite/src
Patch Set: Remove misc change. Created 10 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/sqlite/src/test/wal.test ('k') | third_party/sqlite/src/test/wal3.test » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # 2010 May 5
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. The
12 # focus of this file is testing the operation of the library in
13 # "PRAGMA journal_mode=WAL" mode.
14 #
15
16 set testdir [file dirname $argv0]
17 source $testdir/tester.tcl
18 source $testdir/lock_common.tcl
19 source $testdir/malloc_common.tcl
20 source $testdir/wal_common.tcl
21
22 ifcapable !wal {finish_test ; return }
23
24 proc set_tvfs_hdr {file args} {
25
26 # Set $nHdr to the number of bytes in the wal-index header:
27 set nHdr 48
28 set nInt [expr {$nHdr/4}]
29
30 if {[llength $args]>2} {
31 error {wrong # args: should be "set_tvfs_hdr fileName ?val1? ?val2?"}
32 }
33
34 set blob [tvfs shm $file]
35
36 if {[llength $args]} {
37 set ia [lindex $args 0]
38 set ib $ia
39 if {[llength $args]==2} {
40 set ib [lindex $args 1]
41 }
42 binary scan $blob a[expr $nHdr*2]a* dummy tail
43 set blob [binary format i${nInt}i${nInt}a* $ia $ib $tail]
44 tvfs shm $file $blob
45 }
46
47 binary scan $blob i${nInt} ints
48 return $ints
49 }
50
51 proc incr_tvfs_hdr {file idx incrval} {
52 set ints [set_tvfs_hdr $file]
53 set v [lindex $ints $idx]
54 incr v $incrval
55 lset ints $idx $v
56 set_tvfs_hdr $file $ints
57 }
58
59
60 #-------------------------------------------------------------------------
61 # Test case wal2-1.*:
62 #
63 # Set up a small database containing a single table. The database is not
64 # checkpointed during the test - all content resides in the log file.
65 #
66 # Two connections are established to the database file - a writer ([db])
67 # and a reader ([db2]). For each of the 8 integer fields in the wal-index
68 # header (6 fields and 2 checksum values), do the following:
69 #
70 # 1. Modify the database using the writer.
71 #
72 # 2. Attempt to read the database using the reader. Before the reader
73 # has a chance to snapshot the wal-index header, increment one
74 # of the the integer fields (so that the reader ends up with a corrupted
75 # header).
76 #
77 # 3. Check that the reader recovers the wal-index and reads the correct
78 # database content.
79 #
80 do_test wal2-1.0 {
81 proc tvfs_cb {method filename args} {
82 set ::filename $filename
83 return SQLITE_OK
84 }
85
86 testvfs tvfs
87 tvfs script tvfs_cb
88 tvfs filter xShmOpen
89
90 sqlite3 db test.db -vfs tvfs
91 sqlite3 db2 test.db -vfs tvfs
92
93 execsql {
94 PRAGMA journal_mode = WAL;
95 CREATE TABLE t1(a);
96 } db2
97 execsql {
98 INSERT INTO t1 VALUES(1);
99 INSERT INTO t1 VALUES(2);
100 INSERT INTO t1 VALUES(3);
101 INSERT INTO t1 VALUES(4);
102 SELECT count(a), sum(a) FROM t1;
103 }
104 } {4 10}
105 do_test wal2-1.1 {
106 execsql { SELECT count(a), sum(a) FROM t1 } db2
107 } {4 10}
108
109 set RECOVER [list \
110 {0 1 lock exclusive} {1 7 lock exclusive} \
111 {1 7 unlock exclusive} {0 1 unlock exclusive} \
112 ]
113 set READ [list \
114 {4 1 lock exclusive} {4 1 unlock exclusive} \
115 {4 1 lock shared} {4 1 unlock shared} \
116 ]
117
118 foreach {tn iInsert res wal_index_hdr_mod wal_locks} "
119 2 5 {5 15} 0 {$RECOVER $READ}
120 3 6 {6 21} 1 {$RECOVER $READ}
121 4 7 {7 28} 2 {$RECOVER $READ}
122 5 8 {8 36} 3 {$RECOVER $READ}
123 6 9 {9 45} 4 {$RECOVER $READ}
124 7 10 {10 55} 5 {$RECOVER $READ}
125 8 11 {11 66} 6 {$RECOVER $READ}
126 9 12 {12 78} 7 {$RECOVER $READ}
127 10 13 {13 91} 8 {$RECOVER $READ}
128 11 14 {14 105} 9 {$RECOVER $READ}
129 12 15 {15 120} -1 {$READ}
130 " {
131
132 do_test wal2-1.$tn.1 {
133 execsql { INSERT INTO t1 VALUES($iInsert) }
134 set ::locks [list]
135 proc tvfs_cb {method args} {
136 lappend ::locks [lindex $args 2]
137 return SQLITE_OK
138 }
139 tvfs filter xShmLock
140 if {$::wal_index_hdr_mod >= 0} {
141 incr_tvfs_hdr $::filename $::wal_index_hdr_mod 1
142 }
143 execsql { SELECT count(a), sum(a) FROM t1 } db2
144 } $res
145
146 do_test wal2-1.$tn.2 {
147 set ::locks
148 } $wal_locks
149 }
150 db close
151 db2 close
152 tvfs delete
153 file delete -force test.db test.db-wal test.db-journal
154
155 #-------------------------------------------------------------------------
156 # This test case is very similar to the previous one, except, after
157 # the reader reads the corrupt wal-index header, but before it has
158 # a chance to re-read it under the cover of the RECOVER lock, the
159 # wal-index header is replaced with a valid, but out-of-date, header.
160 #
161 # Because the header checksum looks Ok, the reader does not run recovery,
162 # it simply drops back to a READ lock and proceeds. But because the
163 # header is out-of-date, the reader reads the out-of-date snapshot.
164 #
165 # After this, the header is corrupted again and the reader is allowed
166 # to run recovery. This time, it sees an up-to-date snapshot of the
167 # database file.
168 #
169 set WRITER [list 0 1 lock exclusive]
170 set LOCKS [list \
171 {0 1 lock exclusive} {0 1 unlock exclusive} \
172 {4 1 lock exclusive} {4 1 unlock exclusive} \
173 {4 1 lock shared} {4 1 unlock shared} \
174 ]
175 do_test wal2-2.0 {
176
177 testvfs tvfs
178 tvfs script tvfs_cb
179 tvfs filter xShmOpen
180 proc tvfs_cb {method args} {
181 set ::filename [lindex $args 0]
182 return SQLITE_OK
183 }
184
185 sqlite3 db test.db -vfs tvfs
186 sqlite3 db2 test.db -vfs tvfs
187
188 execsql {
189 PRAGMA journal_mode = WAL;
190 CREATE TABLE t1(a);
191 } db2
192 execsql {
193 INSERT INTO t1 VALUES(1);
194 INSERT INTO t1 VALUES(2);
195 INSERT INTO t1 VALUES(3);
196 INSERT INTO t1 VALUES(4);
197 SELECT count(a), sum(a) FROM t1;
198 }
199 } {4 10}
200 do_test wal2-2.1 {
201 execsql { SELECT count(a), sum(a) FROM t1 } db2
202 } {4 10}
203
204 foreach {tn iInsert res0 res1 wal_index_hdr_mod} {
205 2 5 {4 10} {5 15} 0
206 3 6 {5 15} {6 21} 1
207 4 7 {6 21} {7 28} 2
208 5 8 {7 28} {8 36} 3
209 6 9 {8 36} {9 45} 4
210 7 10 {9 45} {10 55} 5
211 8 11 {10 55} {11 66} 6
212 9 12 {11 66} {12 78} 7
213 } {
214 tvfs filter xShmLock
215
216 do_test wal2-2.$tn.1 {
217 set oldhdr [set_tvfs_hdr $::filename]
218 execsql { INSERT INTO t1 VALUES($iInsert) }
219 execsql { SELECT count(a), sum(a) FROM t1 }
220 } $res1
221
222 do_test wal2-2.$tn.2 {
223 set ::locks [list]
224 proc tvfs_cb {method args} {
225 set lock [lindex $args 2]
226 lappend ::locks $lock
227 if {$lock == $::WRITER} {
228 set_tvfs_hdr $::filename $::oldhdr
229 }
230 return SQLITE_OK
231 }
232
233 if {$::wal_index_hdr_mod >= 0} {
234 incr_tvfs_hdr $::filename $::wal_index_hdr_mod 1
235 }
236 execsql { SELECT count(a), sum(a) FROM t1 } db2
237 } $res0
238
239 do_test wal2-2.$tn.3 {
240 set ::locks
241 } $LOCKS
242
243 do_test wal2-2.$tn.4 {
244 set ::locks [list]
245 proc tvfs_cb {method args} {
246 set lock [lindex $args 2]
247 lappend ::locks $lock
248 return SQLITE_OK
249 }
250
251 if {$::wal_index_hdr_mod >= 0} {
252 incr_tvfs_hdr $::filename $::wal_index_hdr_mod 1
253 }
254 execsql { SELECT count(a), sum(a) FROM t1 } db2
255 } $res1
256 }
257 db close
258 db2 close
259 tvfs delete
260 file delete -force test.db test.db-wal test.db-journal
261
262
263 if 0 {
264 #-------------------------------------------------------------------------
265 # This test case - wal2-3.* - tests the response of the library to an
266 # SQLITE_BUSY when attempting to obtain a READ or RECOVER lock.
267 #
268 # wal2-3.0 - 2: SQLITE_BUSY when obtaining a READ lock
269 # wal2-3.3 - 6: SQLITE_BUSY when obtaining a RECOVER lock
270 #
271 do_test wal2-3.0 {
272 proc tvfs_cb {method args} {
273 if {$method == "xShmLock"} {
274 if {[info exists ::locked]} { return SQLITE_BUSY }
275 }
276 return SQLITE_OK
277 }
278
279 proc busyhandler x {
280 if {$x>3} { unset -nocomplain ::locked }
281 return 0
282 }
283
284 testvfs tvfs
285 tvfs script tvfs_cb
286 sqlite3 db test.db -vfs tvfs
287 db busy busyhandler
288
289 execsql {
290 PRAGMA journal_mode = WAL;
291 CREATE TABLE t1(a);
292 INSERT INTO t1 VALUES(1);
293 INSERT INTO t1 VALUES(2);
294 INSERT INTO t1 VALUES(3);
295 INSERT INTO t1 VALUES(4);
296 }
297
298 set ::locked 1
299 info exists ::locked
300 } {1}
301 do_test wal2-3.1 {
302 execsql { SELECT count(a), sum(a) FROM t1 }
303 } {4 10}
304 do_test wal2-3.2 {
305 info exists ::locked
306 } {0}
307
308 do_test wal2-3.3 {
309 proc tvfs_cb {method args} {
310 if {$method == "xShmLock"} {
311 if {[info exists ::sabotage]} {
312 unset -nocomplain ::sabotage
313 incr_tvfs_hdr [lindex $args 0] 1 1
314 }
315 if {[info exists ::locked] && [lindex $args 2] == "RECOVER"} {
316 return SQLITE_BUSY
317 }
318 }
319 return SQLITE_OK
320 }
321 set ::sabotage 1
322 set ::locked 1
323 list [info exists ::sabotage] [info exists ::locked]
324 } {1 1}
325 do_test wal2-3.4 {
326 execsql { SELECT count(a), sum(a) FROM t1 }
327 } {4 10}
328 do_test wal2-3.5 {
329 list [info exists ::sabotage] [info exists ::locked]
330 } {0 0}
331 db close
332 tvfs delete
333 file delete -force test.db test.db-wal test.db-journal
334
335 }
336
337 #-------------------------------------------------------------------------
338 # Test that a database connection using a VFS that does not support the
339 # xShmXXX interfaces cannot open a WAL database.
340 #
341 do_test wal2-4.1 {
342 sqlite3 db test.db
343 execsql {
344 PRAGMA journal_mode = WAL;
345 CREATE TABLE data(x);
346 INSERT INTO data VALUES('need xShmOpen to see this');
347 PRAGMA wal_checkpoint;
348 }
349 } {wal}
350 do_test wal2-4.2 {
351 db close
352 testvfs tvfs -noshm 1
353 sqlite3 db test.db -vfs tvfs
354 catchsql { SELECT * FROM data }
355 } {1 {unable to open database file}}
356 do_test wal2-4.3 {
357 db close
358 testvfs tvfs
359 sqlite3 db test.db -vfs tvfs
360 catchsql { SELECT * FROM data }
361 } {0 {{need xShmOpen to see this}}}
362 db close
363 tvfs delete
364
365 #-------------------------------------------------------------------------
366 # Test that if a database connection is forced to run recovery before it
367 # can perform a checkpoint, it does not transition into RECOVER state.
368 #
369 # UPDATE: This has now changed. When running a checkpoint, if recovery is
370 # required the client grabs all exclusive locks (just as it would for a
371 # recovery performed as a pre-cursor to a normal database transaction).
372 #
373 set expected_locks [list]
374 lappend expected_locks {1 1 lock exclusive} ;# Lock checkpoint
375 lappend expected_locks {0 1 lock exclusive} ;# Lock writer
376 lappend expected_locks {2 6 lock exclusive} ;# Lock recovery & all aReadMark[]
377 lappend expected_locks {2 6 unlock exclusive} ;# Unlock recovery & aReadMark[]
378 lappend expected_locks {0 1 unlock exclusive} ;# Unlock writer
379 lappend expected_locks {3 1 lock exclusive} ;# Lock aReadMark[0]
380 lappend expected_locks {3 1 unlock exclusive} ;# Unlock aReadMark[0]
381 lappend expected_locks {1 1 unlock exclusive} ;# Unlock checkpoint
382 do_test wal2-5.1 {
383 proc tvfs_cb {method args} {
384 set ::shm_file [lindex $args 0]
385 if {$method == "xShmLock"} { lappend ::locks [lindex $args 2] }
386 return $::tvfs_cb_return
387 }
388 set tvfs_cb_return SQLITE_OK
389
390 testvfs tvfs
391 tvfs script tvfs_cb
392
393 sqlite3 db test.db -vfs tvfs
394 execsql {
395 PRAGMA journal_mode = WAL;
396 CREATE TABLE x(y);
397 INSERT INTO x VALUES(1);
398 }
399
400 incr_tvfs_hdr $::shm_file 1 1
401 set ::locks [list]
402 execsql { PRAGMA wal_checkpoint }
403 set ::locks
404 } $expected_locks
405 db close
406 tvfs delete
407
408 #-------------------------------------------------------------------------
409 # This block, test cases wal2-6.*, tests the operation of WAL with
410 # "PRAGMA locking_mode=EXCLUSIVE" set.
411 #
412 # wal2-6.1.*: Changing to WAL mode before setting locking_mode=exclusive.
413 #
414 # wal2-6.2.*: Changing to WAL mode after setting locking_mode=exclusive.
415 #
416 # wal2-6.3.*: Changing back to rollback mode from WAL mode after setting
417 # locking_mode=exclusive.
418 #
419 # wal2-6.4.*: Check that xShmLock calls are omitted in exclusive locking
420 # mode.
421 #
422 # wal2-6.5.*:
423 #
424 # wal2-6.6.*: Check that if the xShmLock() to reaquire a WAL read-lock when
425 # exiting exclusive mode fails (i.e. SQLITE_IOERR), then the
426 # connection silently remains in exclusive mode.
427 #
428 do_test wal2-6.1.1 {
429 file delete -force test.db test.db-wal test.db-journal
430 sqlite3 db test.db
431 execsql {
432 Pragma Journal_Mode = Wal;
433 Pragma Locking_Mode = Exclusive;
434 }
435 } {wal exclusive}
436 do_test wal2-6.1.2 {
437 execsql { PRAGMA lock_status }
438 } {main unlocked temp closed}
439 do_test wal2-6.1.3 {
440 execsql {
441 BEGIN;
442 CREATE TABLE t1(a, b);
443 INSERT INTO t1 VALUES(1, 2);
444 COMMIT;
445 PRAGMA lock_status;
446 }
447 } {main exclusive temp closed}
448 do_test wal2-6.1.4 {
449 execsql {
450 PRAGMA locking_mode = normal;
451 PRAGMA lock_status;
452 }
453 } {normal main exclusive temp closed}
454 do_test wal2-6.1.5 {
455 execsql {
456 SELECT * FROM t1;
457 PRAGMA lock_status;
458 }
459 } {1 2 main shared temp closed}
460 do_test wal2-6.1.6 {
461 execsql {
462 INSERT INTO t1 VALUES(3, 4);
463 PRAGMA lock_status;
464 }
465 } {main shared temp closed}
466 db close
467
468 do_test wal2-6.2.1 {
469 file delete -force test.db test.db-wal test.db-journal
470 sqlite3 db test.db
471 execsql {
472 Pragma Locking_Mode = Exclusive;
473 Pragma Journal_Mode = Wal;
474 Pragma Lock_Status;
475 }
476 } {exclusive wal main exclusive temp closed}
477 do_test wal2-6.2.2 {
478 execsql {
479 BEGIN;
480 CREATE TABLE t1(a, b);
481 INSERT INTO t1 VALUES(1, 2);
482 COMMIT;
483 Pragma loCK_STATus;
484 }
485 } {main exclusive temp closed}
486 do_test wal2-6.2.3 {
487 db close
488 sqlite3 db test.db
489 execsql { PRAGMA LOCKING_MODE = EXCLUSIVE }
490 } {exclusive}
491 do_test wal2-6.2.4 {
492 execsql {
493 SELECT * FROM t1;
494 pragma lock_status;
495 }
496 } {1 2 main shared temp closed}
497 do_test wal2-6.2.5 {
498 execsql {
499 INSERT INTO t1 VALUES(3, 4);
500 pragma lock_status;
501 }
502 } {main exclusive temp closed}
503 do_test wal2-6.2.6 {
504 execsql {
505 PRAGMA locking_mode = NORMAL;
506 pragma lock_status;
507 }
508 } {normal main exclusive temp closed}
509 do_test wal2-6.2.7 {
510 execsql {
511 BEGIN IMMEDIATE; COMMIT;
512 pragma lock_status;
513 }
514 } {main shared temp closed}
515 do_test wal2-6.2.8 {
516 execsql {
517 PRAGMA locking_mode = EXCLUSIVE;
518 BEGIN IMMEDIATE; COMMIT;
519 PRAGMA locking_mode = NORMAL;
520 }
521 execsql {
522 SELECT * FROM t1;
523 pragma lock_status;
524 }
525 } {1 2 3 4 main shared temp closed}
526 do_test wal2-6.2.9 {
527 execsql {
528 INSERT INTO t1 VALUES(5, 6);
529 SELECT * FROM t1;
530 pragma lock_status;
531 }
532 } {1 2 3 4 5 6 main shared temp closed}
533 db close
534
535 do_test wal2-6.3.1 {
536 file delete -force test.db test.db-wal test.db-journal
537 sqlite3 db test.db
538 execsql {
539 PRAGMA journal_mode = WAL;
540 PRAGMA locking_mode = exclusive;
541 BEGIN;
542 CREATE TABLE t1(x);
543 INSERT INTO t1 VALUES('Chico');
544 INSERT INTO t1 VALUES('Harpo');
545 COMMIT;
546 }
547 list [file exists test.db-wal] [file exists test.db-journal]
548 } {1 0}
549 do_test wal2-6.3.2 {
550 execsql { PRAGMA journal_mode = DELETE }
551 file exists test.db-wal
552 } {0}
553 do_test wal2-6.3.3 {
554 execsql { PRAGMA lock_status }
555 } {main exclusive temp closed}
556 do_test wal2-6.3.4 {
557 execsql {
558 BEGIN;
559 INSERT INTO t1 VALUES('Groucho');
560 }
561 list [file exists test.db-wal] [file exists test.db-journal]
562 } {0 1}
563 do_test wal2-6.3.5 {
564 execsql { PRAGMA lock_status }
565 } {main exclusive temp closed}
566 do_test wal2-6.3.6 {
567 execsql { COMMIT }
568 list [file exists test.db-wal] [file exists test.db-journal]
569 } {0 1}
570 do_test wal2-6.3.7 {
571 execsql { PRAGMA lock_status }
572 } {main exclusive temp closed}
573 db close
574
575
576 # This test - wal2-6.4.* - uses a single database connection and the
577 # [testvfs] instrumentation to test that xShmLock() is being called
578 # as expected when a WAL database is used with locking_mode=exclusive.
579 #
580 do_test wal2-6.4.1 {
581 file delete -force test.db test.db-wal test.db-journal
582 proc tvfs_cb {method args} {
583 set ::shm_file [lindex $args 0]
584 if {$method == "xShmLock"} { lappend ::locks [lindex $args 2] }
585 return "SQLITE_OK"
586 }
587 testvfs tvfs
588 tvfs script tvfs_cb
589 sqlite3 db test.db -vfs tvfs
590 } {}
591
592 set RECOVERY {
593 {0 1 lock exclusive} {1 7 lock exclusive}
594 {1 7 unlock exclusive} {0 1 unlock exclusive}
595 }
596 set READMARK0_READ {
597 {3 1 lock shared} {3 1 unlock shared}
598 }
599 set READMARK0_WRITE {
600 {3 1 lock shared}
601 {0 1 lock exclusive} {3 1 unlock shared}
602 {4 1 lock exclusive} {4 1 unlock exclusive} {4 1 lock shared}
603 {0 1 unlock exclusive} {4 1 unlock shared}
604 }
605 set READMARK1_SET {
606 {4 1 lock exclusive} {4 1 unlock exclusive}
607 }
608 set READMARK1_READ {
609 {4 1 lock shared} {4 1 unlock shared}
610 }
611 set READMARK1_WRITE {
612 {4 1 lock shared}
613 {0 1 lock exclusive} {0 1 unlock exclusive}
614 {4 1 unlock shared}
615 }
616
617 foreach {tn sql res expected_locks} {
618 2 {
619 PRAGMA journal_mode = WAL;
620 BEGIN;
621 CREATE TABLE t1(x);
622 INSERT INTO t1 VALUES('Leonard');
623 INSERT INTO t1 VALUES('Arthur');
624 COMMIT;
625 } {wal} {
626 $RECOVERY
627 $READMARK0_WRITE
628 }
629
630 3 {
631 # This test should do the READMARK1_SET locking to populate the
632 # aReadMark[1] slot with the current mxFrame value. Followed by
633 # READMARK1_READ to read the database.
634 #
635 SELECT * FROM t1
636 } {Leonard Arthur} {
637 $READMARK1_SET
638 $READMARK1_READ
639 }
640
641 4 {
642 # aReadMark[1] is already set to mxFrame. So just READMARK1_READ
643 # this time, not READMARK1_SET.
644 #
645 SELECT * FROM t1 ORDER BY x
646 } {Arthur Leonard} {
647 $READMARK1_READ
648 }
649
650 5 {
651 PRAGMA locking_mode = exclusive
652 } {exclusive} { }
653
654 6 {
655 INSERT INTO t1 VALUES('Julius Henry');
656 SELECT * FROM t1;
657 } {Leonard Arthur {Julius Henry}} {
658 $READMARK1_READ
659 }
660
661 7 {
662 INSERT INTO t1 VALUES('Karl');
663 SELECT * FROM t1;
664 } {Leonard Arthur {Julius Henry} Karl} { }
665
666 8 {
667 PRAGMA locking_mode = normal
668 } {normal} { }
669
670 9 {
671 SELECT * FROM t1 ORDER BY x
672 } {Arthur {Julius Henry} Karl Leonard} $READMARK1_READ
673
674 10 { DELETE FROM t1 } {} $READMARK1_WRITE
675
676 11 {
677 SELECT * FROM t1
678 } {} {
679 $READMARK1_SET
680 $READMARK1_READ
681 }
682 } {
683
684 set L [list]
685 foreach el [subst $expected_locks] { lappend L $el }
686
687 set S ""
688 foreach sq [split $sql "\n"] {
689 set sq [string trim $sq]
690 if {[string match {#*} $sq]==0} {append S "$sq\n"}
691 }
692
693 set ::locks [list]
694 do_test wal2-6.4.$tn.1 { execsql $S } $res
695 do_test wal2-6.4.$tn.2 { set ::locks } $L
696 }
697
698 db close
699 tvfs delete
700
701 do_test wal2-6.5.1 {
702 sqlite3 db test.db
703 execsql {
704 PRAGMA journal_mode = wal;
705 PRAGMA locking_mode = exclusive;
706 CREATE TABLE t2(a, b);
707 PRAGMA wal_checkpoint;
708 INSERT INTO t2 VALUES('I', 'II');
709 PRAGMA journal_mode;
710 }
711 } {wal exclusive wal}
712 do_test wal2-6.5.2 {
713 execsql {
714 PRAGMA locking_mode = normal;
715 INSERT INTO t2 VALUES('III', 'IV');
716 PRAGMA locking_mode = exclusive;
717 SELECT * FROM t2;
718 }
719 } {normal exclusive I II III IV}
720 do_test wal2-6.5.3 {
721 execsql { PRAGMA wal_checkpoint }
722 } {}
723 db close
724
725 proc lock_control {method filename handle spec} {
726 foreach {start n op type} $spec break
727 if {$op == "lock"} { return SQLITE_IOERR }
728 return SQLITE_OK
729 }
730 do_test wal2-6.6.1 {
731 testvfs T
732 T script lock_control
733 T filter {}
734 sqlite3 db test.db -vfs T
735 execsql { PRAGMA locking_mode = exclusive }
736 execsql { INSERT INTO t2 VALUES('V', 'VI') }
737 } {}
738 do_test wal2-6.6.2 {
739 execsql { PRAGMA locking_mode = normal }
740 T filter xShmLock
741 execsql { INSERT INTO t2 VALUES('VII', 'VIII') }
742 } {}
743 do_test wal2-6.6.3 {
744 # At this point the connection should still be in exclusive-mode, even
745 # though it tried to exit exclusive-mode when committing the INSERT
746 # statement above. To exit exclusive mode, SQLite has to take a read-lock
747 # on the WAL file using xShmLock(). Since that call failed, it remains
748 # in exclusive mode.
749 #
750 sqlite3 db2 test.db -vfs T
751 catchsql { SELECT * FROM t2 } db2
752 } {1 {database is locked}}
753 do_test wal2-6.6.2 {
754 db2 close
755 T filter {}
756 execsql { INSERT INTO t2 VALUES('IX', 'X') }
757 } {}
758 do_test wal2-6.6.3 {
759 # This time, we have successfully exited exclusive mode. So the second
760 # connection can read the database.
761 sqlite3 db2 test.db -vfs T
762 catchsql { SELECT * FROM t2 } db2
763 } {0 {I II III IV V VI VII VIII IX X}}
764
765 db close
766 db2 close
767 T delete
768
769 #-------------------------------------------------------------------------
770 # Test a theory about the checksum algorithm. Theory was false and this
771 # test did not provoke a bug.
772 #
773 file delete -force test.db test.db-wal test.db-journal
774 do_test wal2-7.1.1 {
775 sqlite3 db test.db
776 execsql {
777 PRAGMA page_size = 4096;
778 PRAGMA journal_mode = WAL;
779 CREATE TABLE t1(a, b);
780 }
781 file size test.db
782 } {4096}
783 do_test wal2-7.1.2 {
784 file copy -force test.db test2.db
785 file copy -force test.db-wal test2.db-wal
786 hexio_write test2.db-wal 48 FF
787 } {1}
788 do_test wal2-7.1.3 {
789 sqlite3 db2 test2.db
790 execsql { PRAGMA wal_checkpoint } db2
791 execsql { SELECT * FROM sqlite_master } db2
792 } {}
793 db close
794 db2 close
795 file delete -force test.db test.db-wal test.db-journal
796 do_test wal2-8.1.2 {
797 sqlite3 db test.db
798 execsql {
799 PRAGMA auto_vacuum=OFF;
800 PRAGMA page_size = 1024;
801 PRAGMA journal_mode = WAL;
802 CREATE TABLE t1(x);
803 INSERT INTO t1 VALUES(zeroblob(8188*1020));
804 CREATE TABLE t2(y);
805 }
806 execsql {
807 PRAGMA wal_checkpoint;
808 SELECT rootpage>=8192 FROM sqlite_master WHERE tbl_name = 't2';
809 }
810 } {1}
811 do_test wal2-8.1.3 {
812 execsql {
813 PRAGMA cache_size = 10;
814 CREATE TABLE t3(z);
815 BEGIN;
816 INSERT INTO t3 VALUES(randomblob(900));
817 INSERT INTO t3 SELECT randomblob(900) FROM t3;
818 INSERT INTO t2 VALUES('hello');
819 INSERT INTO t3 SELECT randomblob(900) FROM t3;
820 INSERT INTO t3 SELECT randomblob(900) FROM t3;
821 INSERT INTO t3 SELECT randomblob(900) FROM t3;
822 INSERT INTO t3 SELECT randomblob(900) FROM t3;
823 INSERT INTO t3 SELECT randomblob(900) FROM t3;
824 INSERT INTO t3 SELECT randomblob(900) FROM t3;
825 ROLLBACK;
826 }
827 execsql {
828 INSERT INTO t2 VALUES('goodbye');
829 INSERT INTO t3 SELECT randomblob(900) FROM t3;
830 INSERT INTO t3 SELECT randomblob(900) FROM t3;
831 }
832 } {}
833 do_test wal2-8.1.4 {
834 sqlite3 db2 test.db
835 execsql { SELECT * FROM t2 }
836 } {goodbye}
837 db2 close
838 db close
839
840 #-------------------------------------------------------------------------
841 # Test that even if the checksums for both are valid, if the two copies
842 # of the wal-index header in the wal-index do not match, the client
843 # runs (or at least tries to run) database recovery.
844 #
845 #
846 proc get_name {method args} { set ::filename [lindex $args 0] ; tvfs filter {} }
847 testvfs tvfs
848 tvfs script get_name
849 tvfs filter xShmOpen
850
851 file delete -force test.db test.db-wal test.db-journal
852 do_test wal2-9.1 {
853 sqlite3 db test.db -vfs tvfs
854 execsql {
855 PRAGMA journal_mode = WAL;
856 CREATE TABLE x(y);
857 INSERT INTO x VALUES('Barton');
858 INSERT INTO x VALUES('Deakin');
859 }
860
861 # Set $wih(1) to the contents of the wal-index header after
862 # the frames associated with the first two rows in table 'x' have
863 # been inserted. Then insert one more row and set $wih(2)
864 # to the new value of the wal-index header.
865 #
866 # If the $wih(1) is written into the wal-index before running
867 # a read operation, the client will see only the first two rows. If
868 # $wih(2) is written into the wal-index, the client will see
869 # three rows. If an invalid header is written into the wal-index, then
870 # the client will run recovery and see three rows.
871 #
872 set wih(1) [set_tvfs_hdr $::filename]
873 execsql { INSERT INTO x VALUES('Watson') }
874 set wih(2) [set_tvfs_hdr $::filename]
875
876 sqlite3 db2 test.db -vfs tvfs
877 execsql { SELECT * FROM x } db2
878 } {Barton Deakin Watson}
879
880 foreach {tn hdr1 hdr2 res} [list \
881 3 $wih(1) $wih(1) {Barton Deakin} \
882 4 $wih(1) $wih(2) {Barton Deakin Watson} \
883 5 $wih(2) $wih(1) {Barton Deakin Watson} \
884 6 $wih(2) $wih(2) {Barton Deakin Watson} \
885 7 $wih(1) $wih(1) {Barton Deakin} \
886 8 {0 0 0 0 0 0 0 0 0 0 0 0} {0 0 0 0 0 0 0 0 0 0 0 0} {Barton Deakin Watson}
887 ] {
888 do_test wal2-9.$tn {
889 set_tvfs_hdr $::filename $hdr1 $hdr2
890 execsql { SELECT * FROM x } db2
891 } $res
892 }
893
894 db2 close
895 db close
896
897 #-------------------------------------------------------------------------
898 # This block of tests - wal2-10.* - focus on the libraries response to
899 # new versions of the wal or wal-index formats.
900 #
901 # wal2-10.1.*: Test that the library refuses to "recover" a new WAL
902 # format.
903 #
904 # wal2-10.2.*: Test that the library refuses to read or write a database
905 # if the wal-index version is newer than it understands.
906 #
907 # At time of writing, the only versions of the wal and wal-index formats
908 # that exist are versions 3007000 (corresponding to SQLite version 3.7.0,
909 # the first version of SQLite to feature wal mode).
910 #
911 do_test wal2-10.1.1 {
912 faultsim_delete_and_reopen
913 execsql {
914 PRAGMA journal_mode = WAL;
915 CREATE TABLE t1(a, b);
916 PRAGMA wal_checkpoint;
917 INSERT INTO t1 VALUES(1, 2);
918 INSERT INTO t1 VALUES(3, 4);
919 }
920 faultsim_save_and_close
921 } {}
922 do_test wal2-10.1.2 {
923 faultsim_restore_and_reopen
924 execsql { SELECT * FROM t1 }
925 } {1 2 3 4}
926 do_test wal2-10.1.3 {
927 faultsim_restore_and_reopen
928 set hdr [wal_set_walhdr test.db-wal]
929 lindex $hdr 1
930 } {3007000}
931 do_test wal2-10.1.4 {
932 lset hdr 1 3007001
933 wal_set_walhdr test.db-wal $hdr
934 catchsql { SELECT * FROM t1 }
935 } {1 {unable to open database file}}
936
937 testvfs tvfs -default 1
938 do_test wal2-10.2.1 {
939 faultsim_restore_and_reopen
940 execsql { SELECT * FROM t1 }
941 } {1 2 3 4}
942 do_test wal2-10.2.2 {
943 set hdr [set_tvfs_hdr $::filename]
944 lindex $hdr 0
945 } {3007000}
946 do_test wal2-10.2.3 {
947 lset hdr 0 3007001
948 wal_fix_walindex_cksum hdr
949 set_tvfs_hdr $::filename $hdr
950 catchsql { SELECT * FROM t1 }
951 } {1 {unable to open database file}}
952 db close
953 tvfs delete
954
955 #-------------------------------------------------------------------------
956 # This block of tests - wal2-11.* - tests that it is not possible to put
957 # the library into an infinite loop by presenting it with a corrupt
958 # hash table (one that appears to contain a single chain of infinite
959 # length).
960 #
961 # wal2-11.1.*: While reading the hash-table.
962 #
963 # wal2-11.2.*: While writing the hash-table.
964 #
965 testvfs tvfs -default 1
966 do_test wal2-11.0 {
967 faultsim_delete_and_reopen
968 execsql {
969 PRAGMA journal_mode = WAL;
970 CREATE TABLE t1(a, b, c);
971 INSERT INTO t1 VALUES(1, 2, 3);
972 INSERT INTO t1 VALUES(4, 5, 6);
973 INSERT INTO t1 VALUES(7, 8, 9);
974 SELECT * FROM t1;
975 }
976 } {wal 1 2 3 4 5 6 7 8 9}
977
978 do_test wal2-11.1.1 {
979 sqlite3 db2 test.db
980 execsql { SELECT name FROM sqlite_master } db2
981 } {t1}
982
983 if {$::tcl_version>=8.5} {
984 # Set all zeroed slots in the first hash table to invalid values.
985 #
986 set blob [string range [tvfs shm $::filename] 0 16383]
987 set I [string range [tvfs shm $::filename] 16384 end]
988 binary scan $I t* L
989 set I [list]
990 foreach p $L {
991 lappend I [expr $p ? $p : 400]
992 }
993 append blob [binary format t* $I]
994 tvfs shm $::filename $blob
995 do_test wal2-11.2 {
996 catchsql { INSERT INTO t1 VALUES(10, 11, 12) }
997 } {1 {database disk image is malformed}}
998
999 # Fill up the hash table on the first page of shared memory with 0x55 bytes.
1000 #
1001 set blob [string range [tvfs shm $::filename] 0 16383]
1002 append blob [string repeat [binary format c 55] 16384]
1003 tvfs shm $::filename $blob
1004 do_test wal2-11.3 {
1005 catchsql { SELECT * FROM t1 } db2
1006 } {1 {database disk image is malformed}}
1007 }
1008
1009 db close
1010 db2 close
1011 tvfs delete
1012
1013 #-------------------------------------------------------------------------
1014 # If a connection is required to create a WAL or SHM file, it creates
1015 # the new files with the same file-system permissions as the database
1016 # file itself. Test this.
1017 #
1018 if {$::tcl_platform(platform) == "unix"} {
1019 faultsim_delete_and_reopen
1020 set umask [exec /bin/sh -c umask]
1021
1022 do_test wal2-12.1 {
1023 sqlite3 db test.db
1024 execsql {
1025 CREATE TABLE tx(y, z);
1026 PRAGMA journal_mode = WAL;
1027 }
1028 db close
1029 list [file exists test.db-wal] [file exists test.db-shm]
1030 } {0 0}
1031
1032 foreach {tn permissions} {
1033 1 00644
1034 2 00666
1035 3 00600
1036 4 00755
1037 } {
1038 set effective [format %.5o [expr $permissions & ~$umask]]
1039 do_test wal2-12.2.$tn.1 {
1040 file attributes test.db -permissions $permissions
1041 file attributes test.db -permissions
1042 } $permissions
1043 do_test wal2-12.2.$tn.2 {
1044 list [file exists test.db-wal] [file exists test.db-shm]
1045 } {0 0}
1046 do_test wal2-12.2.$tn.3 {
1047 sqlite3 db test.db
1048 execsql { INSERT INTO tx DEFAULT VALUES }
1049 list [file exists test.db-wal] [file exists test.db-shm]
1050 } {1 1}
1051 do_test wal2-12.2.$tn.4 {
1052 list [file attr test.db-wal -perm] [file attr test.db-shm -perm]
1053 } [list $effective $effective]
1054 do_test wal2-12.2.$tn.5 {
1055 db close
1056 list [file exists test.db-wal] [file exists test.db-shm]
1057 } {0 0}
1058 }
1059 }
1060
1061 #-------------------------------------------------------------------------
1062 # Test the libraries response to discovering that one or more of the
1063 # database, wal or shm files cannot be opened, or can only be opened
1064 # read-only.
1065 #
1066 if {$::tcl_platform(platform) == "unix"} {
1067 proc perm {} {
1068 set L [list]
1069 foreach f {test.db test.db-wal test.db-shm} {
1070 if {[file exists $f]} {
1071 lappend L [file attr $f -perm]
1072 } else {
1073 lappend L {}
1074 }
1075 }
1076 set L
1077 }
1078
1079 faultsim_delete_and_reopen
1080 execsql {
1081 PRAGMA journal_mode = WAL;
1082 CREATE TABLE t1(a, b);
1083 PRAGMA wal_checkpoint;
1084 INSERT INTO t1 VALUES('3.14', '2.72');
1085 }
1086 do_test wal2-13.1.1 {
1087 list [file exists test.db-shm] [file exists test.db-wal]
1088 } {1 1}
1089 faultsim_save_and_close
1090
1091 foreach {tn db_perm wal_perm shm_perm can_open can_read can_write} {
1092 2 00644 00644 00644 1 1 1
1093 3 00644 00400 00644 1 1 0
1094 4 00644 00644 00400 1 0 0
1095 5 00400 00644 00644 1 1 0
1096
1097 7 00644 00000 00644 1 0 0
1098 8 00644 00644 00000 1 0 0
1099 9 00000 00644 00644 0 0 0
1100 } {
1101 faultsim_restore
1102 do_test wal2-13.$tn.1 {
1103 file attr test.db -perm $db_perm
1104 file attr test.db-wal -perm $wal_perm
1105 file attr test.db-shm -perm $shm_perm
1106
1107 set L [file attr test.db -perm]
1108 lappend L [file attr test.db-wal -perm]
1109 lappend L [file attr test.db-shm -perm]
1110 } [list $db_perm $wal_perm $shm_perm]
1111
1112 # If $can_open is true, then it should be possible to open a database
1113 # handle. Otherwise, if $can_open is 0, attempting to open the db
1114 # handle throws an "unable to open database file" exception.
1115 #
1116 set r(1) {0 ok}
1117 set r(0) {1 {unable to open database file}}
1118 do_test wal2-13.$tn.2 {
1119 list [catch {sqlite3 db test.db ; set {} ok} msg] $msg
1120 } $r($can_open)
1121
1122 if {$can_open} {
1123
1124 # If $can_read is true, then the client should be able to read from
1125 # the database file. If $can_read is false, attempting to read should
1126 # throw the "unable to open database file" exception.
1127 #
1128 set a(0) {1 {unable to open database file}}
1129 set a(1) {0 {3.14 2.72}}
1130 do_test wal2-13.$tn.3 {
1131 catchsql { SELECT * FROM t1 }
1132 } $a($can_read)
1133
1134 # Now try to write to the db file. If the client can read but not
1135 # write, then it should throw the familiar "unable to open db file"
1136 # exception. If it can read but not write, the exception should
1137 # be "attempt to write a read only database".
1138 #
1139 # If the client can read and write, the operation should succeed.
1140 #
1141 set b(0,0) {1 {unable to open database file}}
1142 set b(1,0) {1 {attempt to write a readonly database}}
1143 set b(1,1) {0 {}}
1144 do_test wal2-13.$tn.4 {
1145 catchsql { INSERT INTO t1 DEFAULT VALUES }
1146 } $b($can_read,$can_write)
1147 }
1148 catch { db close }
1149 }
1150 }
1151
1152 finish_test
OLDNEW
« no previous file with comments | « third_party/sqlite/src/test/wal.test ('k') | third_party/sqlite/src/test/wal3.test » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698