diff options
Diffstat (limited to 'libraries/sqlite/unix/sqlite-3.5.1/test/malloc2.test')
-rw-r--r-- | libraries/sqlite/unix/sqlite-3.5.1/test/malloc2.test | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/libraries/sqlite/unix/sqlite-3.5.1/test/malloc2.test b/libraries/sqlite/unix/sqlite-3.5.1/test/malloc2.test new file mode 100644 index 0000000..e48a569 --- /dev/null +++ b/libraries/sqlite/unix/sqlite-3.5.1/test/malloc2.test | |||
@@ -0,0 +1,366 @@ | |||
1 | # 2005 March 18 | ||
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 | # | ||
12 | # This file attempts to check that the library can recover from a malloc() | ||
13 | # failure when sqlite3_global_recover() is invoked. | ||
14 | # | ||
15 | # (Later:) The sqlite3_global_recover() interface is now a no-op. | ||
16 | # Recovery from malloc() failures is automatic. But we keep these | ||
17 | # tests around because you can never have too many test cases. | ||
18 | # | ||
19 | # $Id: malloc2.test,v 1.8 2007/10/03 08:46:45 danielk1977 Exp $ | ||
20 | |||
21 | set testdir [file dirname $argv0] | ||
22 | source $testdir/tester.tcl | ||
23 | |||
24 | # Only run these tests if memory debugging is turned on. | ||
25 | # | ||
26 | ifcapable !memdebug { | ||
27 | puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..." | ||
28 | finish_test | ||
29 | return | ||
30 | } | ||
31 | |||
32 | sqlite3_extended_result_codes db 1 | ||
33 | |||
34 | # Generate a checksum based on the contents of the database. If the | ||
35 | # checksum of two databases is the same, and the integrity-check passes | ||
36 | # for both, the two databases are identical. | ||
37 | # | ||
38 | proc cksum {db} { | ||
39 | set ret [list] | ||
40 | ifcapable tempdb { | ||
41 | set sql { | ||
42 | SELECT name FROM sqlite_master WHERE type = 'table' UNION | ||
43 | SELECT name FROM sqlite_temp_master WHERE type = 'table' UNION | ||
44 | SELECT 'sqlite_master' UNION | ||
45 | SELECT 'sqlite_temp_master' | ||
46 | } | ||
47 | } else { | ||
48 | set sql { | ||
49 | SELECT name FROM sqlite_master WHERE type = 'table' UNION | ||
50 | SELECT 'sqlite_master' | ||
51 | } | ||
52 | } | ||
53 | set tbllist [$db eval $sql] | ||
54 | set txt {} | ||
55 | foreach tbl $tbllist { | ||
56 | append txt [$db eval "SELECT * FROM $tbl"] | ||
57 | } | ||
58 | # puts txt=$txt | ||
59 | return [md5 $txt] | ||
60 | } | ||
61 | |||
62 | proc do_malloc2_test {tn args} { | ||
63 | array set ::mallocopts $args | ||
64 | set sum [cksum db] | ||
65 | |||
66 | for {set ::n 1} {true} {incr ::n} { | ||
67 | |||
68 | # Run the SQL. Malloc number $::n is set to fail. A malloc() failure | ||
69 | # may or may not be reported. | ||
70 | sqlite3_memdebug_fail $::n -repeat 1 | ||
71 | do_test malloc2-$tn.$::n.2 { | ||
72 | set res [catchsql [string trim $::mallocopts(-sql)]] | ||
73 | set rc [expr { | ||
74 | 0==[string compare $res {1 {out of memory}}] || | ||
75 | [db errorcode] == 3082 || | ||
76 | 0==[lindex $res 0] | ||
77 | }] | ||
78 | if {$rc!=1} { | ||
79 | puts "Error: $res" | ||
80 | } | ||
81 | set rc | ||
82 | } {1} | ||
83 | |||
84 | # If $::n is greater than the number of malloc() calls required to | ||
85 | # execute the SQL, then this test is finished. Break out of the loop. | ||
86 | set nFail [sqlite3_memdebug_fail -1] | ||
87 | if {$nFail==0} break | ||
88 | |||
89 | # Nothing should work now, because the allocator should refuse to | ||
90 | # allocate any memory. | ||
91 | # | ||
92 | # Update: SQLite now automatically recovers from a malloc() failure. | ||
93 | # So the statement in the test below would work. | ||
94 | if 0 { | ||
95 | do_test malloc2-$tn.$::n.3 { | ||
96 | catchsql {SELECT 'nothing should work'} | ||
97 | } {1 {out of memory}} | ||
98 | } | ||
99 | |||
100 | # Recover from the malloc failure. | ||
101 | # | ||
102 | # Update: The new malloc() failure handling means that a transaction may | ||
103 | # still be active even if a malloc() has failed. But when these tests were | ||
104 | # written this was not the case. So do a manual ROLLBACK here so that the | ||
105 | # tests pass. | ||
106 | do_test malloc2-$tn.$::n.4 { | ||
107 | sqlite3_global_recover | ||
108 | catch { | ||
109 | execsql { | ||
110 | ROLLBACK; | ||
111 | } | ||
112 | } | ||
113 | expr 0 | ||
114 | } {0} | ||
115 | |||
116 | # Checksum the database. | ||
117 | do_test malloc2-$tn.$::n.5 { | ||
118 | cksum db | ||
119 | } $sum | ||
120 | |||
121 | integrity_check malloc2-$tn.$::n.6 | ||
122 | if {$::nErr>1} return | ||
123 | } | ||
124 | unset ::mallocopts | ||
125 | } | ||
126 | |||
127 | do_test malloc2.1.setup { | ||
128 | execsql { | ||
129 | CREATE TABLE abc(a, b, c); | ||
130 | INSERT INTO abc VALUES(10, 20, 30); | ||
131 | INSERT INTO abc VALUES(40, 50, 60); | ||
132 | CREATE INDEX abc_i ON abc(a, b, c); | ||
133 | } | ||
134 | } {} | ||
135 | do_malloc2_test 1.1 -sql { | ||
136 | SELECT * FROM abc; | ||
137 | } | ||
138 | do_malloc2_test 1.2 -sql { | ||
139 | UPDATE abc SET c = c+10; | ||
140 | } | ||
141 | do_malloc2_test 1.3 -sql { | ||
142 | INSERT INTO abc VALUES(70, 80, 90); | ||
143 | } | ||
144 | do_malloc2_test 1.4 -sql { | ||
145 | DELETE FROM abc; | ||
146 | } | ||
147 | do_test malloc2.1.5 { | ||
148 | execsql { | ||
149 | SELECT * FROM abc; | ||
150 | } | ||
151 | } {} | ||
152 | |||
153 | do_test malloc2.2.setup { | ||
154 | execsql { | ||
155 | CREATE TABLE def(a, b, c); | ||
156 | CREATE INDEX def_i1 ON def(a); | ||
157 | CREATE INDEX def_i2 ON def(c); | ||
158 | BEGIN; | ||
159 | } | ||
160 | for {set i 0} {$i<20} {incr i} { | ||
161 | execsql { | ||
162 | INSERT INTO def VALUES(randstr(300,300),randstr(300,300),randstr(300,300)); | ||
163 | } | ||
164 | } | ||
165 | execsql { | ||
166 | COMMIT; | ||
167 | } | ||
168 | } {} | ||
169 | do_malloc2_test 2 -sql { | ||
170 | BEGIN; | ||
171 | UPDATE def SET a = randstr(100,100) WHERE (oid%9)==0; | ||
172 | INSERT INTO def SELECT * FROM def WHERE (oid%13)==0; | ||
173 | |||
174 | CREATE INDEX def_i3 ON def(b); | ||
175 | |||
176 | UPDATE def SET a = randstr(100,100) WHERE (oid%9)==1; | ||
177 | INSERT INTO def SELECT * FROM def WHERE (oid%13)==1; | ||
178 | |||
179 | CREATE TABLE def2 AS SELECT * FROM def; | ||
180 | DROP TABLE def; | ||
181 | CREATE TABLE def AS SELECT * FROM def2; | ||
182 | DROP TABLE def2; | ||
183 | |||
184 | DELETE FROM def WHERE (oid%9)==2; | ||
185 | INSERT INTO def SELECT * FROM def WHERE (oid%13)==2; | ||
186 | COMMIT; | ||
187 | } | ||
188 | |||
189 | ifcapable tempdb { | ||
190 | do_test malloc2.3.setup { | ||
191 | execsql { | ||
192 | CREATE TEMP TABLE ghi(a, b, c); | ||
193 | BEGIN; | ||
194 | } | ||
195 | for {set i 0} {$i<20} {incr i} { | ||
196 | execsql { | ||
197 | INSERT INTO ghi VALUES(randstr(300,300),randstr(300,300),randstr(300,300)); | ||
198 | } | ||
199 | } | ||
200 | execsql { | ||
201 | COMMIT; | ||
202 | } | ||
203 | } {} | ||
204 | do_malloc2_test 3 -sql { | ||
205 | BEGIN; | ||
206 | CREATE INDEX ghi_i1 ON ghi(a); | ||
207 | UPDATE def SET a = randstr(100,100) WHERE (oid%2)==0; | ||
208 | UPDATE ghi SET a = randstr(100,100) WHERE (oid%2)==0; | ||
209 | COMMIT; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | ############################################################################ | ||
214 | # The test cases below are to increase the code coverage in btree.c and | ||
215 | # pager.c of this test file. The idea is that each malloc() that occurs in | ||
216 | # these two source files should be made to fail at least once. | ||
217 | # | ||
218 | catchsql { | ||
219 | DROP TABLE ghi; | ||
220 | } | ||
221 | do_malloc2_test 4.1 -sql { | ||
222 | SELECT * FROM def ORDER BY oid ASC; | ||
223 | SELECT * FROM def ORDER BY oid DESC; | ||
224 | } | ||
225 | do_malloc2_test 4.2 -sql { | ||
226 | PRAGMA cache_size = 10; | ||
227 | BEGIN; | ||
228 | |||
229 | -- This will put about 25 pages on the free list. | ||
230 | DELETE FROM def WHERE 1; | ||
231 | |||
232 | -- Allocate 32 new root pages. This will exercise the 'extract specific | ||
233 | -- page from the freelist' code when in auto-vacuum mode (see the | ||
234 | -- allocatePage() routine in btree.c). | ||
235 | CREATE TABLE t1(a UNIQUE, b UNIQUE, c UNIQUE); | ||
236 | CREATE TABLE t2(a UNIQUE, b UNIQUE, c UNIQUE); | ||
237 | CREATE TABLE t3(a UNIQUE, b UNIQUE, c UNIQUE); | ||
238 | CREATE TABLE t4(a UNIQUE, b UNIQUE, c UNIQUE); | ||
239 | CREATE TABLE t5(a UNIQUE, b UNIQUE, c UNIQUE); | ||
240 | CREATE TABLE t6(a UNIQUE, b UNIQUE, c UNIQUE); | ||
241 | CREATE TABLE t7(a UNIQUE, b UNIQUE, c UNIQUE); | ||
242 | CREATE TABLE t8(a UNIQUE, b UNIQUE, c UNIQUE); | ||
243 | |||
244 | ROLLBACK; | ||
245 | } | ||
246 | |||
247 | ######################################################################## | ||
248 | # Test that the global linked list of database handles works. An assert() | ||
249 | # will fail if there is some problem. | ||
250 | do_test malloc2-5 { | ||
251 | sqlite3 db1 test.db | ||
252 | sqlite3 db2 test.db | ||
253 | sqlite3 db3 test.db | ||
254 | sqlite3 db4 test.db | ||
255 | sqlite3 db5 test.db | ||
256 | |||
257 | sqlite3_extended_result_codes db1 1 | ||
258 | sqlite3_extended_result_codes db2 1 | ||
259 | sqlite3_extended_result_codes db3 1 | ||
260 | sqlite3_extended_result_codes db4 1 | ||
261 | sqlite3_extended_result_codes db5 1 | ||
262 | |||
263 | # Close the head of the list: | ||
264 | db5 close | ||
265 | |||
266 | # Close the end of the list: | ||
267 | db1 close | ||
268 | |||
269 | # Close a handle from the middle of the list: | ||
270 | db3 close | ||
271 | |||
272 | # Close the other two. Then open and close one more database, to make | ||
273 | # sure the head of the list was set back to NULL. | ||
274 | db2 close | ||
275 | db4 close | ||
276 | sqlite db1 test.db | ||
277 | db1 close | ||
278 | } {} | ||
279 | |||
280 | ######################################################################## | ||
281 | # Check that if a statement is active sqlite3_global_recover doesn't reset | ||
282 | # the sqlite3_malloc_failed variable. | ||
283 | # | ||
284 | # Update: There is now no sqlite3_malloc_failed variable, so these tests | ||
285 | # are not run. | ||
286 | # | ||
287 | # do_test malloc2-6.1 { | ||
288 | # set ::STMT [sqlite3_prepare $::DB {SELECT * FROM def} -1 DUMMY] | ||
289 | # sqlite3_step $::STMT | ||
290 | # } {SQLITE_ROW} | ||
291 | # do_test malloc2-6.2 { | ||
292 | # sqlite3 db1 test.db | ||
293 | # sqlite_malloc_fail 100 | ||
294 | # catchsql { | ||
295 | # SELECT * FROM def; | ||
296 | # } db1 | ||
297 | # } {1 {out of memory}} | ||
298 | # do_test malloc2-6.3 { | ||
299 | # sqlite3_global_recover | ||
300 | # } {SQLITE_BUSY} | ||
301 | # do_test malloc2-6.4 { | ||
302 | # catchsql { | ||
303 | # SELECT 'hello'; | ||
304 | # } | ||
305 | # } {1 {out of memory}} | ||
306 | # do_test malloc2-6.5 { | ||
307 | # sqlite3_reset $::STMT | ||
308 | # } {SQLITE_OK} | ||
309 | # do_test malloc2-6.6 { | ||
310 | # sqlite3_global_recover | ||
311 | # } {SQLITE_OK} | ||
312 | # do_test malloc2-6.7 { | ||
313 | # catchsql { | ||
314 | # SELECT 'hello'; | ||
315 | # } | ||
316 | # } {0 hello} | ||
317 | # do_test malloc2-6.8 { | ||
318 | # sqlite3_step $::STMT | ||
319 | # } {SQLITE_ERROR} | ||
320 | # do_test malloc2-6.9 { | ||
321 | # sqlite3_finalize $::STMT | ||
322 | # } {SQLITE_SCHEMA} | ||
323 | # do_test malloc2-6.10 { | ||
324 | # db1 close | ||
325 | # } {} | ||
326 | |||
327 | ######################################################################## | ||
328 | # Check that if an in-memory database is being used it is not possible | ||
329 | # to recover from a malloc() failure. | ||
330 | # | ||
331 | # Update: An in-memory database can now survive a malloc() failure, so these | ||
332 | # tests are not run. | ||
333 | # | ||
334 | # ifcapable memorydb { | ||
335 | # do_test malloc2-7.1 { | ||
336 | # sqlite3 db1 :memory: | ||
337 | # list | ||
338 | # } {} | ||
339 | # do_test malloc2-7.2 { | ||
340 | # sqlite_malloc_fail 100 | ||
341 | # catchsql { | ||
342 | # SELECT * FROM def; | ||
343 | # } | ||
344 | # } {1 {out of memory}} | ||
345 | # do_test malloc2-7.3 { | ||
346 | # sqlite3_global_recover | ||
347 | # } {SQLITE_ERROR} | ||
348 | # do_test malloc2-7.4 { | ||
349 | # catchsql { | ||
350 | # SELECT 'hello'; | ||
351 | # } | ||
352 | # } {1 {out of memory}} | ||
353 | # do_test malloc2-7.5 { | ||
354 | # db1 close | ||
355 | # } {} | ||
356 | # do_test malloc2-7.6 { | ||
357 | # sqlite3_global_recover | ||
358 | # } {SQLITE_OK} | ||
359 | # do_test malloc2-7.7 { | ||
360 | # catchsql { | ||
361 | # SELECT 'hello'; | ||
362 | # } | ||
363 | # } {0 hello} | ||
364 | # } | ||
365 | |||
366 | finish_test | ||