3 # The author disclaims copyright to this source code. In place of
4 # a legal notice, here is a blessing:
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.
10 #***********************************************************************
11 # This file implements regression tests for SQLite library.
13 # $Id: exclusive2.test,v 1.10 2008/11/27 02:22:11 drh Exp $
15 set testdir [file dirname $argv0]
16 source $testdir/tester.tcl
18 # Do not use a codec for tests in this file, as the database file is
19 # manipulated directly using tcl scripts (using the [hexio_write] command).
23 ifcapable {!pager_pragmas} {
28 # This module does not work right if the cache spills at unexpected
29 # moments. So disable the soft-heap-limit.
31 sqlite3_soft_heap_limit 0
33 proc pagerChangeCounter {filename new {fd ""}} {
35 set fd [open $filename RDWR]
36 fconfigure $fd -translation binary -encoding binary
43 set a [expr {($new&0xFF000000)>>24}]
44 set b [expr {($new&0x00FF0000)>>16}]
45 set c [expr {($new&0x0000FF00)>>8}]
46 set d [expr {($new&0x000000FF)}]
47 puts -nonewline $fd [binary format cccc $a $b $c $d]
52 foreach {a b c d} [list 0 0 0 0] {}
53 binary scan [read $fd 4] cccc a b c d
54 set ret [expr ($a&0x000000FF)<<24]
55 incr ret [expr ($b&0x000000FF)<<16]
56 incr ret [expr ($c&0x000000FF)<<8]
57 incr ret [expr ($d&0x000000FF)<<0]
59 if {$needClose} {close $fd}
63 proc readPagerChangeCounter {filename} {
64 set fd [open $filename RDONLY]
65 fconfigure $fd -translation binary -encoding binary
68 foreach {a b c d} [list 0 0 0 0] {}
69 binary scan [read $fd 4] cccc a b c d
70 set ret [expr ($a&0x000000FF)<<24]
71 incr ret [expr ($b&0x000000FF)<<16]
72 incr ret [expr ($c&0x000000FF)<<8]
73 incr ret [expr ($d&0x000000FF)<<0]
80 proc t1sig {{db db}} {
81 execsql {SELECT count(*), md5sum(a) FROM t1} $db
83 do_test exclusive2-1.0 {
84 readPagerChangeCounter test.db
87 #-----------------------------------------------------------------------
88 # The following tests - exclusive2-1.X - check that:
90 # 1-3: Build a database with connection 1, calculate a signature.
91 # 4-7: Modify the database using a second connection in a way that
92 # does not modify the freelist, then reset the pager change-counter
93 # to the value it had before the modifications.
94 # 8: Check that using the first connection, the database signature
95 # is still the same. This is because it uses the in-memory cache.
96 # It can't tell the db has changed because we reset the change-counter.
97 # 9: Increment the change-counter.
98 # 10: Ensure that the first connection now sees the updated database. It
99 # sees the change-counter has been incremented and discards the
100 # invalid in-memory cache.
102 # This will only work if the database cache is large enough to hold
103 # the entire database. In the case of 1024 byte pages, this means
104 # the cache size must be at least 17. Otherwise, some pages will be
105 # loaded from the database file in step 8.
107 # For similar reasons, this test does not work with the memsubsys1 permutation.
108 # Permutation memsubsys1 configures the pcache subsystem to use a static
109 # allocation of 24 pages (shared between all pagers). This is not enough for
112 do_test exclusive2-1.1 {
115 CREATE TABLE t1(a, b);
116 INSERT INTO t1(a) VALUES(randstr(10, 400));
117 INSERT INTO t1(a) VALUES(randstr(10, 400));
118 INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
119 INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
120 INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
121 INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
122 INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
124 SELECT count(*) FROM t1;
127 do_test exclusive2-1.2.1 {
128 # Make sure the pager cache is large enough to store the
130 set nPage [expr [file size test.db]/1024]
131 if {$::SQLITE_DEFAULT_CACHE_SIZE < $nPage} {
132 execsql "PRAGMA cache_size = $nPage"
134 expr {[execsql {PRAGMA cache_size}] >= $nPage}
136 do_test exclusive2-1.2 {
138 readPagerChangeCounter test.db
140 do_test exclusive2-1.3 {
143 do_test exclusive2-1.4 {
147 do_test exclusive2-1.5 {
149 UPDATE t1 SET b=a, a=NULL;
151 expr {[t1sig db2] eq $::sig}
153 do_test exclusive2-1.6 {
154 readPagerChangeCounter test.db
156 do_test exclusive2-1.7 {
157 pagerChangeCounter test.db 1
159 if {[permutation] != "memsubsys1"} {
160 do_test exclusive2-1.9 {
162 expr {[t1sig] eq $::sig}
165 do_test exclusive2-1.10 {
166 pagerChangeCounter test.db 2
168 do_test exclusive2-1.11 {
169 expr {[t1sig] eq $::sig}
173 #--------------------------------------------------------------------
174 # These tests - exclusive2-2.X - are similar to exclusive2-1.X,
175 # except that they are run with locking_mode=EXCLUSIVE.
177 # 1-3: Build a database with exclusive-access connection 1,
178 # calculate a signature.
179 # 4: Corrupt the database by writing 10000 bytes of garbage
180 # starting at the beginning of page 2. Check that connection 1
181 # still works. It should be accessing the in-memory cache.
182 # 5-6: Modify the dataase change-counter. Connection 1 still works
183 # entirely from in-memory cache, because it doesn't check the
185 # 7-8 Set the locking-mode back to normal. After the db is unlocked,
186 # SQLite detects the modified change-counter and discards the
187 # in-memory cache. Then it finds the corruption caused in step 4....
189 # As above, this test is only applicable if the pager cache is
190 # large enough to hold the entire database. With 1024 byte pages,
191 # this means 19 pages. We also need to disable the soft-heap-limit
192 # to prevent memory-induced cache spills.
194 do_test exclusive2-2.1 {
195 execsql {PRAGMA cache_size=1000;}
196 execsql {PRAGMA locking_mode = exclusive;}
200 INSERT INTO t1(a) VALUES(randstr(10, 400));
201 INSERT INTO t1(a) VALUES(randstr(10, 400));
202 INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
203 INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
204 INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
205 INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
206 INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
208 SELECT count(*) FROM t1;
211 do_test exclusive2-2.2.1 {
212 # Make sure the pager cache is large enough to store the
214 set nPage [expr [file size test.db]/1024]
215 if {$::SQLITE_DEFAULT_CACHE_SIZE < $nPage} {
216 execsql "PRAGMA cache_size = $nPage"
218 expr {[execsql {PRAGMA cache_size}] >= $nPage}
220 do_test exclusive2-2.2 {
222 readPagerChangeCounter test.db
224 do_test exclusive2-2.3 {
228 do_test exclusive2-2.4 {
229 set ::fd [open test.db RDWR]
230 fconfigure $::fd -translation binary
232 puts -nonewline $::fd [string repeat [binary format c 0] 10000]
237 do_test exclusive2-2.5 {
238 pagerChangeCounter test.db 5 $::fd
240 do_test exclusive2-2.6 {
243 do_test exclusive2-2.7 {
244 execsql {PRAGMA locking_mode = normal}
248 do_test exclusive2-2.8 {
249 set rc [catch {t1sig} msg]
251 } {1 {database disk image is malformed}}
253 #--------------------------------------------------------------------
254 # These tests - exclusive2-3.X - verify that the pager change-counter
255 # is only incremented by the first change when in exclusive access
256 # mode. In normal mode, the change-counter is incremented once
257 # per write-transaction.
262 file delete -force test.db
263 file delete -force test.db-journal
265 do_test exclusive2-3.0 {
269 CREATE TABLE t1(a UNIQUE);
270 INSERT INTO t1 VALUES(randstr(200, 200));
271 INSERT INTO t1 VALUES(randstr(200, 200));
274 readPagerChangeCounter test.db
276 do_test exclusive2-3.1 {
278 INSERT INTO t1 VALUES(randstr(200, 200));
280 readPagerChangeCounter test.db
282 do_test exclusive2-3.2 {
284 INSERT INTO t1 VALUES(randstr(200, 200));
286 readPagerChangeCounter test.db
288 do_test exclusive2-3.3 {
290 PRAGMA locking_mode = exclusive;
291 INSERT INTO t1 VALUES(randstr(200, 200));
293 readPagerChangeCounter test.db
295 do_test exclusive2-3.4 {
298 INSERT INTO t1 VALUES(randstr(200, 200));
300 readPagerChangeCounter test.db
302 do_test exclusive2-3.5 {
304 PRAGMA locking_mode = normal;
305 INSERT INTO t1 VALUES(randstr(200, 200));
307 readPagerChangeCounter test.db
309 do_test exclusive2-3.6 {
311 INSERT INTO t1 VALUES(randstr(200, 200));
313 readPagerChangeCounter test.db
315 sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit)