diff options
Diffstat (limited to 'libraries/sqlite/unix/sqlite-3.5.1/test/exclusive2.test')
-rw-r--r-- | libraries/sqlite/unix/sqlite-3.5.1/test/exclusive2.test | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/libraries/sqlite/unix/sqlite-3.5.1/test/exclusive2.test b/libraries/sqlite/unix/sqlite-3.5.1/test/exclusive2.test new file mode 100644 index 0000000..d0eeb19 --- /dev/null +++ b/libraries/sqlite/unix/sqlite-3.5.1/test/exclusive2.test | |||
@@ -0,0 +1,297 @@ | |||
1 | # 2007 March 24 | ||
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 | # $Id: exclusive2.test,v 1.8 2007/08/12 20:07:59 drh Exp $ | ||
14 | |||
15 | set testdir [file dirname $argv0] | ||
16 | source $testdir/tester.tcl | ||
17 | |||
18 | ifcapable {!pager_pragmas} { | ||
19 | finish_test | ||
20 | return | ||
21 | } | ||
22 | |||
23 | # This module does not work right if the cache spills at unexpected | ||
24 | # moments. So disable the soft-heap-limit. | ||
25 | # | ||
26 | sqlite3_soft_heap_limit 0 | ||
27 | |||
28 | proc pagerChangeCounter {filename {new ""}} { | ||
29 | set fd [open $filename RDWR] | ||
30 | fconfigure $fd -translation binary -encoding binary | ||
31 | if {$new ne ""} { | ||
32 | seek $fd 24 | ||
33 | set a [expr {($new&0xFF000000)>>24}] | ||
34 | set b [expr {($new&0x00FF0000)>>16}] | ||
35 | set c [expr {($new&0x0000FF00)>>8}] | ||
36 | set d [expr {($new&0x000000FF)}] | ||
37 | puts -nonewline $fd [binary format cccc $a $b $c $d] | ||
38 | flush $fd | ||
39 | } | ||
40 | |||
41 | seek $fd 24 | ||
42 | foreach {a b c d} [list 0 0 0 0] {} | ||
43 | binary scan [read $fd 4] cccc a b c d | ||
44 | set ret [expr ($a&0x000000FF)<<24] | ||
45 | incr ret [expr ($b&0x000000FF)<<16] | ||
46 | incr ret [expr ($c&0x000000FF)<<8] | ||
47 | incr ret [expr ($d&0x000000FF)<<0] | ||
48 | |||
49 | close $fd | ||
50 | return $ret | ||
51 | } | ||
52 | |||
53 | proc readPagerChangeCounter {filename} { | ||
54 | set fd [open $filename RDONLY] | ||
55 | fconfigure $fd -translation binary -encoding binary | ||
56 | |||
57 | seek $fd 24 | ||
58 | foreach {a b c d} [list 0 0 0 0] {} | ||
59 | binary scan [read $fd 4] cccc a b c d | ||
60 | set ret [expr ($a&0x000000FF)<<24] | ||
61 | incr ret [expr ($b&0x000000FF)<<16] | ||
62 | incr ret [expr ($c&0x000000FF)<<8] | ||
63 | incr ret [expr ($d&0x000000FF)<<0] | ||
64 | |||
65 | close $fd | ||
66 | return $ret | ||
67 | } | ||
68 | |||
69 | |||
70 | proc t1sig {{db db}} { | ||
71 | execsql {SELECT count(*), md5sum(a) FROM t1} $db | ||
72 | } | ||
73 | do_test exclusive2-1.0 { | ||
74 | readPagerChangeCounter test.db | ||
75 | } {0} | ||
76 | |||
77 | #----------------------------------------------------------------------- | ||
78 | # The following tests - exclusive2-1.X - check that: | ||
79 | # | ||
80 | # 1-3: Build a database with connection 1, calculate a signature. | ||
81 | # 4-9: Modify the database using a second connection in a way that | ||
82 | # does not modify the freelist, then reset the pager change-counter | ||
83 | # to the value it had before the modifications. | ||
84 | # 8: Check that using the first connection, the database signature | ||
85 | # is still the same. This is because it uses the in-memory cache. | ||
86 | # It can't tell the db has changed because we reset the change-counter. | ||
87 | # 9: Increment the change-counter. | ||
88 | # 10: Ensure that the first connection now sees the updated database. It | ||
89 | # sees the change-counter has been incremented and discards the | ||
90 | # invalid in-memory cache. | ||
91 | # | ||
92 | # This will only work if the database cache is large enough to hold | ||
93 | # the entire database. In the case of 1024 byte pages, this means | ||
94 | # the cache size must be at least 17. Otherwise, some pages will be | ||
95 | # loaded from the database file in step 8. | ||
96 | # | ||
97 | do_test exclusive2-1.1 { | ||
98 | execsql { | ||
99 | BEGIN; | ||
100 | CREATE TABLE t1(a, b); | ||
101 | INSERT INTO t1(a) VALUES(randstr(10, 400)); | ||
102 | INSERT INTO t1(a) VALUES(randstr(10, 400)); | ||
103 | INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1; | ||
104 | INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1; | ||
105 | INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1; | ||
106 | INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1; | ||
107 | INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1; | ||
108 | COMMIT; | ||
109 | SELECT count(*) FROM t1; | ||
110 | } | ||
111 | } {64} | ||
112 | do_test exclusive2-1.2.1 { | ||
113 | # Make sure the pager cache is large enough to store the | ||
114 | # entire database. | ||
115 | set nPage [expr [file size test.db]/1024] | ||
116 | if {$::SQLITE_DEFAULT_CACHE_SIZE < $nPage} { | ||
117 | execsql "PRAGMA cache_size = $nPage" | ||
118 | } | ||
119 | expr {[execsql {PRAGMA cache_size}] >= $nPage} | ||
120 | } {1} | ||
121 | do_test exclusive2-1.2 { | ||
122 | set ::sig [t1sig] | ||
123 | readPagerChangeCounter test.db | ||
124 | } {1} | ||
125 | do_test exclusive2-1.3 { | ||
126 | t1sig | ||
127 | } $::sig | ||
128 | do_test exclusive2-1.4 { | ||
129 | sqlite3 db2 test.db | ||
130 | t1sig db2 | ||
131 | } $::sig | ||
132 | do_test exclusive2-1.5 { | ||
133 | execsql { | ||
134 | UPDATE t1 SET b=a, a=NULL; | ||
135 | } db2 | ||
136 | expr {[t1sig db2] eq $::sig} | ||
137 | } 0 | ||
138 | do_test exclusive2-1.6 { | ||
139 | readPagerChangeCounter test.db | ||
140 | } {2} | ||
141 | do_test exclusive2-1.7 { | ||
142 | pagerChangeCounter test.db 1 | ||
143 | } {1} | ||
144 | do_test exclusive2-1.9 { | ||
145 | t1sig | ||
146 | expr {[t1sig] eq $::sig} | ||
147 | } {1} | ||
148 | do_test exclusive2-1.10 { | ||
149 | pagerChangeCounter test.db 2 | ||
150 | } {2} | ||
151 | do_test exclusive2-1.11 { | ||
152 | expr {[t1sig] eq $::sig} | ||
153 | } {0} | ||
154 | |||
155 | #-------------------------------------------------------------------- | ||
156 | # These tests - exclusive2-2.X - are similar to exclusive2-1.X, | ||
157 | # except that they are run with locking_mode=EXCLUSIVE. | ||
158 | # | ||
159 | # 1-3: Build a database with exclusive-access connection 1, | ||
160 | # calculate a signature. | ||
161 | # 4: Corrupt the database by writing 10000 bytes of garbage | ||
162 | # starting at the beginning of page 2. Check that connection 1 | ||
163 | # still works. It should be accessing the in-memory cache. | ||
164 | # 5-6: Modify the dataase change-counter. Connection 1 still works | ||
165 | # entirely from in-memory cache, because it doesn't check the | ||
166 | # change-counter. | ||
167 | # 7-8 Set the locking-mode back to normal. After the db is unlocked, | ||
168 | # SQLite detects the modified change-counter and discards the | ||
169 | # in-memory cache. Then it finds the corruption caused in step 4.... | ||
170 | # | ||
171 | # As above, this test is only applicable if the pager cache is | ||
172 | # large enough to hold the entire database. With 1024 byte pages, | ||
173 | # this means 19 pages. We also need to disable the soft-heap-limit | ||
174 | # to prevent memory-induced cache spills. | ||
175 | # | ||
176 | do_test exclusive2-2.1 { | ||
177 | execsql {PRAGMA locking_mode = exclusive;} | ||
178 | execsql { | ||
179 | BEGIN; | ||
180 | DELETE FROM t1; | ||
181 | INSERT INTO t1(a) VALUES(randstr(10, 400)); | ||
182 | INSERT INTO t1(a) VALUES(randstr(10, 400)); | ||
183 | INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1; | ||
184 | INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1; | ||
185 | INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1; | ||
186 | INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1; | ||
187 | INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1; | ||
188 | COMMIT; | ||
189 | SELECT count(*) FROM t1; | ||
190 | } | ||
191 | } {64} | ||
192 | do_test exclusive2-2.2.1 { | ||
193 | # Make sure the pager cache is large enough to store the | ||
194 | # entire database. | ||
195 | set nPage [expr [file size test.db]/1024] | ||
196 | if {$::SQLITE_DEFAULT_CACHE_SIZE < $nPage} { | ||
197 | execsql "PRAGMA cache_size = $nPage" | ||
198 | } | ||
199 | expr {[execsql {PRAGMA cache_size}] >= $nPage} | ||
200 | } {1} | ||
201 | do_test exclusive2-2.2 { | ||
202 | set ::sig [t1sig] | ||
203 | readPagerChangeCounter test.db | ||
204 | } {3} | ||
205 | do_test exclusive2-2.3 { | ||
206 | t1sig | ||
207 | } $::sig | ||
208 | |||
209 | do_test exclusive2-2.4 { | ||
210 | set fd [open test.db RDWR] | ||
211 | seek $fd 1024 | ||
212 | puts -nonewline $fd [string repeat [binary format c 0] 10000] | ||
213 | flush $fd | ||
214 | close $fd | ||
215 | t1sig | ||
216 | } $::sig | ||
217 | |||
218 | do_test exclusive2-2.5 { | ||
219 | pagerChangeCounter test.db 5 | ||
220 | } {5} | ||
221 | do_test exclusive2-2.6 { | ||
222 | t1sig | ||
223 | } $::sig | ||
224 | do_test exclusive2-2.7 { | ||
225 | execsql {PRAGMA locking_mode = normal} | ||
226 | t1sig | ||
227 | } $::sig | ||
228 | |||
229 | do_test exclusive2-2.8 { | ||
230 | set rc [catch {t1sig} msg] | ||
231 | list $rc $msg | ||
232 | } {1 {database disk image is malformed}} | ||
233 | |||
234 | #-------------------------------------------------------------------- | ||
235 | # These tests - exclusive2-3.X - verify that the pager change-counter | ||
236 | # is only incremented by the first change when in exclusive access | ||
237 | # mode. In normal mode, the change-counter is incremented once | ||
238 | # per write-transaction. | ||
239 | # | ||
240 | |||
241 | db close | ||
242 | db2 close | ||
243 | file delete -force test.db | ||
244 | file delete -force test.db-journal | ||
245 | |||
246 | do_test exclusive2-3.0 { | ||
247 | sqlite3 db test.db | ||
248 | execsql { | ||
249 | BEGIN; | ||
250 | CREATE TABLE t1(a UNIQUE); | ||
251 | INSERT INTO t1 VALUES(randstr(10, 400)); | ||
252 | INSERT INTO t1 VALUES(randstr(10, 400)); | ||
253 | COMMIT; | ||
254 | } | ||
255 | readPagerChangeCounter test.db | ||
256 | } {1} | ||
257 | do_test exclusive2-3.1 { | ||
258 | execsql { | ||
259 | INSERT INTO t1 VALUES(randstr(10, 400)); | ||
260 | } | ||
261 | readPagerChangeCounter test.db | ||
262 | } {2} | ||
263 | do_test exclusive2-3.2 { | ||
264 | execsql { | ||
265 | INSERT INTO t1 VALUES(randstr(10, 400)); | ||
266 | } | ||
267 | readPagerChangeCounter test.db | ||
268 | } {3} | ||
269 | do_test exclusive2-3.3 { | ||
270 | execsql { | ||
271 | PRAGMA locking_mode = exclusive; | ||
272 | INSERT INTO t1 VALUES(randstr(10, 400)); | ||
273 | } | ||
274 | readPagerChangeCounter test.db | ||
275 | } {4} | ||
276 | do_test exclusive2-3.4 { | ||
277 | execsql { | ||
278 | INSERT INTO t1 VALUES(randstr(10, 400)); | ||
279 | } | ||
280 | readPagerChangeCounter test.db | ||
281 | } {4} | ||
282 | do_test exclusive2-3.5 { | ||
283 | execsql { | ||
284 | PRAGMA locking_mode = normal; | ||
285 | INSERT INTO t1 VALUES(randstr(10, 400)); | ||
286 | } | ||
287 | readPagerChangeCounter test.db | ||
288 | } {4} | ||
289 | do_test exclusive2-3.6 { | ||
290 | execsql { | ||
291 | INSERT INTO t1 VALUES(randstr(10, 400)); | ||
292 | } | ||
293 | readPagerChangeCounter test.db | ||
294 | } {5} | ||
295 | sqlite3_soft_heap_limit $soft_limit | ||
296 | |||
297 | finish_test | ||