blob: a24716cd4abd6fd88d1f400d25274cbfcaa88cd7 [file] [log] [blame]
drh5a3032b2007-09-03 16:12:09 +00001# 2007 May 05
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 contains common code used by many different malloc tests
13# within the test suite.
14#
danielk197798c21902008-09-23 16:41:29 +000015# $Id: malloc_common.tcl,v 1.22 2008/09/23 16:41:30 danielk1977 Exp $
danielk1977c9cf9012007-05-30 10:36:47 +000016
drh5a3032b2007-09-03 16:12:09 +000017# If we did not compile with malloc testing enabled, then do nothing.
18#
drh3088d592008-03-21 16:45:47 +000019ifcapable builtin_test {
drh5efaf072008-03-18 00:07:10 +000020 set MEMDEBUG 1
21} else {
drheee4c8c2008-02-18 22:24:57 +000022 set MEMDEBUG 0
danielk1977369ff422007-09-03 07:31:09 +000023 return 0
danielk1977cdc3a6b2007-08-25 13:09:26 +000024}
25
dan1f55e282010-06-03 09:25:10 +000026# Transient and persistent OOM errors:
27#
28set FAULTSIM(oom-transient) [list \
29 -injectstart {oom_injectstart 0} \
30 -injectstop oom_injectstop \
31 -injecterrlist {{1 {out of memory}}} \
32]
33set FAULTSIM(oom-persistent) [list \
34 -injectstart {oom_injectstart 1000000} \
35 -injectstop oom_injectstop \
36 -injecterrlist {{1 {out of memory}}} \
37]
38
39# Transient and persistent IO errors:
40#
41set FAULTSIM(ioerr-transient) [list \
42 -injectstart {ioerr_injectstart 0} \
43 -injectstop ioerr_injectstop \
44 -injecterrlist {{1 {disk I/O error}}} \
45]
46set FAULTSIM(ioerr-persistent) [list \
47 -injectstart {ioerr_injectstart 1} \
48 -injectstop ioerr_injectstop \
49 -injecterrlist {{1 {disk I/O error}}} \
50]
51
52# Transient and persistent SHM errors:
53#
54set FAULTSIM(shmerr-transient) [list \
55 -injectinstall shmerr_injectinstall \
56 -injectstart {shmerr_injectstart 0} \
57 -injectstop shmerr_injectstop \
58 -injecterrlist {{1 {disk I/O error}}} \
59 -injectuninstall shmerr_injectuninstall \
60]
61set FAULTSIM(shmerr-persistent) [list \
62 -injectinstall shmerr_injectinstall \
63 -injectstart {shmerr_injectstart 1} \
64 -injectstop shmerr_injectstop \
65 -injecterrlist {{1 {disk I/O error}}} \
66 -injectuninstall shmerr_injectuninstall \
67]
68
69
dana4bc1232010-06-01 17:46:38 +000070
71#--------------------------------------------------------------------------
72# Usage do_faultsim_test NAME ?OPTIONS...?
73#
74# -faults List of fault types to simulate.
75#
76# -prep Script to execute before -body.
77#
78# -body Script to execute (with fault injection).
79#
80# -test Script to execute after -body.
81#
82proc do_faultsim_test {name args} {
dan1f55e282010-06-03 09:25:10 +000083 global FAULTSIM
84
85 set DEFAULT(-faults) [array names FAULTSIM]
dana4bc1232010-06-01 17:46:38 +000086 set DEFAULT(-prep) ""
87 set DEFAULT(-body) ""
88 set DEFAULT(-test) ""
89
90 array set O [array get DEFAULT]
91 array set O $args
92 foreach o [array names O] {
93 if {[info exists DEFAULT($o)]==0} { error "unknown option: $o" }
94 }
95
dan1f55e282010-06-03 09:25:10 +000096 set faultlist [list]
dana4bc1232010-06-01 17:46:38 +000097 foreach f $O(-faults) {
dan1f55e282010-06-03 09:25:10 +000098 set flist [array names FAULTSIM $f]
99 if {[llength $flist]==0} { error "unknown fault: $f" }
100 set faultlist [concat $faultlist $flist]
dana4bc1232010-06-01 17:46:38 +0000101 }
dan1f55e282010-06-03 09:25:10 +0000102
dana4bc1232010-06-01 17:46:38 +0000103 set testspec [list -prep $O(-prep) -body $O(-body) -test $O(-test)]
dan1f55e282010-06-03 09:25:10 +0000104 foreach f [lsort -unique $faultlist] {
105 eval do_one_faultsim_test "$name-$f" $FAULTSIM($f) $testspec
dana4bc1232010-06-01 17:46:38 +0000106 }
107}
108
109#-------------------------------------------------------------------------
110# Procedures to save and restore the current file-system state:
111#
danb0ac3e32010-06-16 10:55:42 +0000112# faultsim_save
dana4bc1232010-06-01 17:46:38 +0000113# faultsim_save_and_close
114# faultsim_restore_and_reopen
danb0ac3e32010-06-16 10:55:42 +0000115# faultsim_delete_and_reopen
dana4bc1232010-06-01 17:46:38 +0000116#
danb0ac3e32010-06-16 10:55:42 +0000117proc faultsim_save {} {
118 foreach f [glob -nocomplain sv_test.db*] { file delete -force $f }
119 foreach f [glob -nocomplain test.db*] {
120 set f2 "sv_$f"
121 file copy -force $f $f2
dana4bc1232010-06-01 17:46:38 +0000122 }
danb0ac3e32010-06-16 10:55:42 +0000123}
124proc faultsim_save_and_close {} {
125 faultsim_save
dana4bc1232010-06-01 17:46:38 +0000126 catch { db close }
127 return ""
128}
129proc faultsim_restore_and_reopen {} {
130 catch { db close }
danb0ac3e32010-06-16 10:55:42 +0000131 foreach f [glob -nocomplain test.db*] { file delete -force $f }
132 foreach f2 [glob -nocomplain sv_test.db*] {
133 set f [string range $f2 3 end]
134 file copy -force $f2 $f
dana4bc1232010-06-01 17:46:38 +0000135 }
136 sqlite3 db test.db
137 sqlite3_extended_result_codes db 1
138 sqlite3_db_config_lookaside db 0 0 0
139}
140
dan1f55e282010-06-03 09:25:10 +0000141proc faultsim_integrity_check {{db db}} {
142 set ic [$db eval { PRAGMA integrity_check }]
143 if {$ic != "ok"} { error "Integrity check: $ic" }
144}
dana4bc1232010-06-01 17:46:38 +0000145
dan1f55e282010-06-03 09:25:10 +0000146proc faultsim_delete_and_reopen {{file test.db}} {
147 catch { db close }
danb0ac3e32010-06-16 10:55:42 +0000148 foreach f [glob -nocomplain test.db*] { file delete -force $f }
dan1f55e282010-06-03 09:25:10 +0000149 sqlite3 db test.db
150}
151
152
153# The following procs are used as [do_one_faultsim_test] callbacks when
154# injecting OOM faults into test cases.
dan8521abf2010-05-31 06:38:34 +0000155#
156proc oom_injectstart {nRepeat iFail} {
157 sqlite3_memdebug_fail $iFail -repeat $nRepeat
158}
159proc oom_injectstop {} {
160 sqlite3_memdebug_fail -1
161}
162
dan1f55e282010-06-03 09:25:10 +0000163# The following procs are used as [do_one_faultsim_test] callbacks when
164# injecting IO error faults into test cases.
165#
dana4bc1232010-06-01 17:46:38 +0000166proc ioerr_injectstart {persist iFail} {
167 set ::sqlite_io_error_persist $persist
168 set ::sqlite_io_error_pending $iFail
169}
170proc ioerr_injectstop {} {
171 set sv $::sqlite_io_error_hit
172 set ::sqlite_io_error_persist 0
173 set ::sqlite_io_error_pending 0
174 set ::sqlite_io_error_hardhit 0
175 set ::sqlite_io_error_hit 0
176 set ::sqlite_io_error_pending 0
177 return $sv
178}
179
dan1f55e282010-06-03 09:25:10 +0000180# The following procs are used as [do_one_faultsim_test] callbacks when
181# injecting shared-memory related error faults into test cases.
182#
183proc shmerr_injectinstall {} {
184 testvfs shmfault -default true
185}
186proc shmerr_injectuninstall {} {
187 catch {db close}
188 catch {db2 close}
189 shmfault delete
190}
191proc shmerr_injectstart {persist iFail} {
192 shmfault ioerr $iFail $persist
193}
194proc shmerr_injectstop {} {
195 shmfault ioerr 0 0
196}
197
dana4bc1232010-06-01 17:46:38 +0000198# This command is not called directly. It is used by the
199# [faultsim_test_result] command created by [do_faultsim_test] and used
200# by -test scripts.
dan8521abf2010-05-31 06:38:34 +0000201#
dana4bc1232010-06-01 17:46:38 +0000202proc faultsim_test_result_int {args} {
dan8521abf2010-05-31 06:38:34 +0000203 upvar testrc testrc testresult testresult testnfail testnfail
204 set t [list $testrc $testresult]
dana4bc1232010-06-01 17:46:38 +0000205 set r $args
dan8521abf2010-05-31 06:38:34 +0000206 if { ($testnfail==0 && $t != [lindex $r 0]) || [lsearch $r $t]<0 } {
207 error "nfail=$testnfail rc=$testrc result=$testresult"
208 }
209}
210
dana4bc1232010-06-01 17:46:38 +0000211#--------------------------------------------------------------------------
212# Usage do_one_faultsim_test NAME ?OPTIONS...?
dan8521abf2010-05-31 06:38:34 +0000213#
214# The first argument, <test number>, is used as a prefix of the test names
215# taken by tests executed by this command. Options are as follows. All
216# options take a single argument.
217#
218# -injectstart Script to enable fault-injection.
219#
220# -injectstop Script to disable fault-injection.
221#
dana4bc1232010-06-01 17:46:38 +0000222# -injecterrlist List of generally acceptable test results (i.e. error
223# messages). Example: [list {1 {out of memory}}]
224#
dan1f55e282010-06-03 09:25:10 +0000225# -injectinstall
226#
227# -injectuninstall
228#
dan8521abf2010-05-31 06:38:34 +0000229# -prep Script to execute before -body.
230#
231# -body Script to execute (with fault injection).
232#
233# -test Script to execute after -body.
234#
dana4bc1232010-06-01 17:46:38 +0000235proc do_one_faultsim_test {testname args} {
dan8521abf2010-05-31 06:38:34 +0000236
dan1f55e282010-06-03 09:25:10 +0000237 set DEFAULT(-injectstart) "expr"
238 set DEFAULT(-injectstop) "expr 0"
239 set DEFAULT(-injecterrlist) [list]
240 set DEFAULT(-injectinstall) ""
241 set DEFAULT(-injectuninstall) ""
242 set DEFAULT(-prep) ""
243 set DEFAULT(-body) ""
244 set DEFAULT(-test) ""
dan8521abf2010-05-31 06:38:34 +0000245
246 array set O [array get DEFAULT]
247 array set O $args
248 foreach o [array names O] {
249 if {[info exists DEFAULT($o)]==0} { error "unknown option: $o" }
250 }
251
252 proc faultsim_test_proc {testrc testresult testnfail} $O(-test)
dana4bc1232010-06-01 17:46:38 +0000253 proc faultsim_test_result {args} "
254 uplevel faultsim_test_result_int \$args [list $O(-injecterrlist)]
255 "
dan8521abf2010-05-31 06:38:34 +0000256
dan1f55e282010-06-03 09:25:10 +0000257 eval $O(-injectinstall)
258
dan8521abf2010-05-31 06:38:34 +0000259 set stop 0
260 for {set iFail 1} {!$stop} {incr iFail} {
261
262 # Evaluate the -prep script.
263 #
264 eval $O(-prep)
265
266 # Start the fault-injection. Run the -body script. Stop the fault
267 # injection. Local var $nfail is set to the total number of faults
268 # injected into the system this trial.
269 #
270 eval $O(-injectstart) $iFail
271 set rc [catch $O(-body) res]
272 set nfail [eval $O(-injectstop)]
273
274 # Run the -test script. If it throws no error, consider this trial
275 # sucessful. If it does throw an error, cause a [do_test] test to
276 # fail (and print out the unexpected exception thrown by the -test
277 # script at the same time).
278 #
279 set rc [catch [list faultsim_test_proc $rc $res $nfail] res]
280 if {$rc == 0} {set res ok}
281 do_test $testname.$iFail [list list $rc $res] {0 ok}
282
283 # If no faults where injected this trial, don't bother running
284 # any more. This test is finished.
285 #
286 if {$nfail==0} { set stop 1 }
287 }
dan1f55e282010-06-03 09:25:10 +0000288
289 eval $O(-injectuninstall)
dan8521abf2010-05-31 06:38:34 +0000290}
291
danielk1977c9cf9012007-05-30 10:36:47 +0000292# Usage: do_malloc_test <test number> <options...>
293#
294# The first argument, <test number>, is an integer used to name the
295# tests executed by this proc. Options are as follows:
296#
297# -tclprep TCL script to run to prepare test.
298# -sqlprep SQL script to run to prepare test.
299# -tclbody TCL script to run with malloc failure simulation.
300# -sqlbody TCL script to run with malloc failure simulation.
301# -cleanup TCL script to run after the test.
302#
303# This command runs a series of tests to verify SQLite's ability
304# to handle an out-of-memory condition gracefully. It is assumed
305# that if this condition occurs a malloc() call will return a
306# NULL pointer. Linux, for example, doesn't do that by default. See
307# the "BUGS" section of malloc(3).
308#
309# Each iteration of a loop, the TCL commands in any argument passed
310# to the -tclbody switch, followed by the SQL commands in any argument
311# passed to the -sqlbody switch are executed. Each iteration the
312# Nth call to sqliteMalloc() is made to fail, where N is increased
313# each time the loop runs starting from 1. When all commands execute
314# successfully, the loop ends.
315#
316proc do_malloc_test {tn args} {
317 array unset ::mallocopts
318 array set ::mallocopts $args
319
320 if {[string is integer $tn]} {
321 set tn malloc-$tn
322 }
drhf3a65f72007-08-22 20:18:21 +0000323 if {[info exists ::mallocopts(-start)]} {
324 set start $::mallocopts(-start)
325 } else {
danielk1977ae72d982007-10-03 08:46:44 +0000326 set start 0
drhf3a65f72007-08-22 20:18:21 +0000327 }
drh1527ff42008-01-18 17:03:32 +0000328 if {[info exists ::mallocopts(-end)]} {
329 set end $::mallocopts(-end)
330 } else {
331 set end 50000
332 }
drh93aed5a2008-01-16 17:46:38 +0000333 save_prng_state
danielk1977c9cf9012007-05-30 10:36:47 +0000334
drh643167f2008-01-22 21:30:53 +0000335 foreach ::iRepeat {0 10000000} {
danielk1977a1644fd2007-08-29 12:31:25 +0000336 set ::go 1
drh1527ff42008-01-18 17:03:32 +0000337 for {set ::n $start} {$::go && $::n <= $end} {incr ::n} {
danielk1977c9cf9012007-05-30 10:36:47 +0000338
danielk1977a1644fd2007-08-29 12:31:25 +0000339 # If $::iRepeat is 0, then the malloc() failure is transient - it
340 # fails and then subsequent calls succeed. If $::iRepeat is 1,
341 # then the failure is persistent - once malloc() fails it keeps
342 # failing.
danielk1977c9cf9012007-05-30 10:36:47 +0000343 #
danielk1977a1644fd2007-08-29 12:31:25 +0000344 set zRepeat "transient"
345 if {$::iRepeat} {set zRepeat "persistent"}
drh93aed5a2008-01-16 17:46:38 +0000346 restore_prng_state
347 foreach file [glob -nocomplain test.db-mj*] {file delete -force $file}
danielk1977c9cf9012007-05-30 10:36:47 +0000348
danielk1977a1644fd2007-08-29 12:31:25 +0000349 do_test ${tn}.${zRepeat}.${::n} {
350
351 # Remove all traces of database files test.db and test2.db
352 # from the file-system. Then open (empty database) "test.db"
353 # with the handle [db].
354 #
355 catch {db close}
356 catch {file delete -force test.db}
357 catch {file delete -force test.db-journal}
dan5e9e4822010-05-03 18:01:21 +0000358 catch {file delete -force test.db-wal}
danielk1977a1644fd2007-08-29 12:31:25 +0000359 catch {file delete -force test2.db}
360 catch {file delete -force test2.db-journal}
dan5e9e4822010-05-03 18:01:21 +0000361 catch {file delete -force test2.db-wal}
danielk1977a1644fd2007-08-29 12:31:25 +0000362 if {[info exists ::mallocopts(-testdb)]} {
363 file copy $::mallocopts(-testdb) test.db
danielk1977c9cf9012007-05-30 10:36:47 +0000364 }
danielk1977ae72d982007-10-03 08:46:44 +0000365 catch { sqlite3 db test.db }
366 if {[info commands db] ne ""} {
367 sqlite3_extended_result_codes db 1
368 }
drhe9d1c722008-08-04 20:13:26 +0000369 sqlite3_db_config_lookaside db 0 0 0
danielk1977a1644fd2007-08-29 12:31:25 +0000370
371 # Execute any -tclprep and -sqlprep scripts.
372 #
373 if {[info exists ::mallocopts(-tclprep)]} {
374 eval $::mallocopts(-tclprep)
375 }
376 if {[info exists ::mallocopts(-sqlprep)]} {
377 execsql $::mallocopts(-sqlprep)
378 }
379
380 # Now set the ${::n}th malloc() to fail and execute the -tclbody
381 # and -sqlbody scripts.
382 #
383 sqlite3_memdebug_fail $::n -repeat $::iRepeat
384 set ::mallocbody {}
385 if {[info exists ::mallocopts(-tclbody)]} {
386 append ::mallocbody "$::mallocopts(-tclbody)\n"
387 }
388 if {[info exists ::mallocopts(-sqlbody)]} {
389 append ::mallocbody "db eval {$::mallocopts(-sqlbody)}"
390 }
danielk1977c9cf9012007-05-30 10:36:47 +0000391
danielk1977a1644fd2007-08-29 12:31:25 +0000392 # The following block sets local variables as follows:
393 #
394 # isFail - True if an error (any error) was reported by sqlite.
395 # nFail - The total number of simulated malloc() failures.
396 # nBenign - The number of benign simulated malloc() failures.
397 #
398 set isFail [catch $::mallocbody msg]
399 set nFail [sqlite3_memdebug_fail -1 -benigncnt nBenign]
drh643167f2008-01-22 21:30:53 +0000400 # puts -nonewline " (isFail=$isFail nFail=$nFail nBenign=$nBenign) "
danielk1977a1644fd2007-08-29 12:31:25 +0000401
402 # If one or more mallocs failed, run this loop body again.
403 #
404 set go [expr {$nFail>0}]
405
406 if {($nFail-$nBenign)==0} {
407 if {$isFail} {
408 set v2 $msg
409 } else {
410 set isFail 1
411 set v2 1
412 }
413 } elseif {!$isFail} {
414 set v2 $msg
danielk1977ae72d982007-10-03 08:46:44 +0000415 } elseif {
416 [info command db]=="" ||
417 [db errorcode]==7 ||
danielk1977ae72d982007-10-03 08:46:44 +0000418 $msg=="out of memory"
419 } {
danielk1977a1644fd2007-08-29 12:31:25 +0000420 set v2 1
421 } else {
422 set v2 $msg
danielk1977ae72d982007-10-03 08:46:44 +0000423 puts [db errorcode]
danielk1977a1644fd2007-08-29 12:31:25 +0000424 }
425 lappend isFail $v2
426 } {1 1}
427
428 if {[info exists ::mallocopts(-cleanup)]} {
429 catch [list uplevel #0 $::mallocopts(-cleanup)] msg
430 }
danielk1977c9cf9012007-05-30 10:36:47 +0000431 }
432 }
433 unset ::mallocopts
danielk197777519402007-08-30 11:48:31 +0000434 sqlite3_memdebug_fail -1
danielk1977c9cf9012007-05-30 10:36:47 +0000435}
danef378022010-05-04 11:06:03 +0000436
437
438#-------------------------------------------------------------------------
439# This proc is used to test a single SELECT statement. Parameter $name is
440# passed a name for the test case (i.e. "fts3_malloc-1.4.1") and parameter
441# $sql is passed the text of the SELECT statement. Parameter $result is
442# set to the expected output if the SELECT statement is successfully
443# executed using [db eval].
444#
445# Example:
446#
447# do_select_test testcase-1.1 "SELECT 1+1, 1+2" {1 2}
448#
449# If global variable DO_MALLOC_TEST is set to a non-zero value, or if
450# it is not defined at all, then OOM testing is performed on the SELECT
451# statement. Each OOM test case is said to pass if either (a) executing
452# the SELECT statement succeeds and the results match those specified
453# by parameter $result, or (b) TCL throws an "out of memory" error.
454#
455# If DO_MALLOC_TEST is defined and set to zero, then the SELECT statement
456# is executed just once. In this case the test case passes if the results
457# match the expected results passed via parameter $result.
458#
459proc do_select_test {name sql result} {
460 uplevel [list doPassiveTest 0 $name $sql [list 0 $result]]
461}
462
463proc do_restart_select_test {name sql result} {
464 uplevel [list doPassiveTest 1 $name $sql [list 0 $result]]
465}
466
467proc do_error_test {name sql error} {
468 uplevel [list doPassiveTest 0 $name $sql [list 1 $error]]
469}
470
471proc doPassiveTest {isRestart name sql catchres} {
472 if {![info exists ::DO_MALLOC_TEST]} { set ::DO_MALLOC_TEST 1 }
473
474 switch $::DO_MALLOC_TEST {
475 0 { # No malloc failures.
476 do_test $name [list set {} [uplevel [list catchsql $sql]]] $catchres
477 return
478 }
479 1 { # Simulate transient failures.
480 set nRepeat 1
481 set zName "transient"
482 set nStartLimit 100000
483 set nBackup 1
484 }
485 2 { # Simulate persistent failures.
486 set nRepeat 1
487 set zName "persistent"
488 set nStartLimit 100000
489 set nBackup 1
490 }
491 3 { # Simulate transient failures with extra brute force.
492 set nRepeat 100000
493 set zName "ridiculous"
494 set nStartLimit 1
495 set nBackup 10
496 }
497 }
498
499 # The set of acceptable results from running [catchsql $sql].
500 #
501 set answers [list {1 {out of memory}} $catchres]
502 set str [join $answers " OR "]
503
504 set nFail 1
505 for {set iLimit $nStartLimit} {$nFail} {incr iLimit} {
506 for {set iFail 1} {$nFail && $iFail<=$iLimit} {incr iFail} {
507 for {set iTest 0} {$iTest<$nBackup && ($iFail-$iTest)>0} {incr iTest} {
508
509 if {$isRestart} { sqlite3 db test.db }
510
511 sqlite3_memdebug_fail [expr $iFail-$iTest] -repeat $nRepeat
512 set res [uplevel [list catchsql $sql]]
513 if {[lsearch -exact $answers $res]>=0} { set res $str }
514 set testname "$name.$zName.$iFail"
515 do_test "$name.$zName.$iLimit.$iFail" [list set {} $res] $str
516
517 set nFail [sqlite3_memdebug_fail -1 -benigncnt nBenign]
518 }
519 }
520 }
521}
522
523
524#-------------------------------------------------------------------------
525# Test a single write to the database. In this case a "write" is a
526# DELETE, UPDATE or INSERT statement.
527#
528# If OOM testing is performed, there are several acceptable outcomes:
529#
530# 1) The write succeeds. No error is returned.
531#
532# 2) An "out of memory" exception is thrown and:
533#
534# a) The statement has no effect, OR
535# b) The current transaction is rolled back, OR
536# c) The statement succeeds. This can only happen if the connection
537# is in auto-commit mode (after the statement is executed, so this
538# includes COMMIT statements).
539#
540# If the write operation eventually succeeds, zero is returned. If a
541# transaction is rolled back, non-zero is returned.
542#
543# Parameter $name is the name to use for the test case (or test cases).
544# The second parameter, $tbl, should be the name of the database table
545# being modified. Parameter $sql contains the SQL statement to test.
546#
547proc do_write_test {name tbl sql} {
548 if {![info exists ::DO_MALLOC_TEST]} { set ::DO_MALLOC_TEST 1 }
549
550 # Figure out an statement to get a checksum for table $tbl.
551 db eval "SELECT * FROM $tbl" V break
552 set cksumsql "SELECT md5sum([join [concat rowid $V(*)] ,]) FROM $tbl"
553
554 # Calculate the initial table checksum.
555 set cksum1 [db one $cksumsql]
556
557 if {$::DO_MALLOC_TEST } {
558 set answers [list {1 {out of memory}} {0 {}}]
559 if {$::DO_MALLOC_TEST==1} {
560 set modes {100000 transient}
561 } else {
562 set modes {1 persistent}
563 }
564 } else {
565 set answers [list {0 {}}]
566 set modes [list 0 nofail]
567 }
568 set str [join $answers " OR "]
569
570 foreach {nRepeat zName} $modes {
571 for {set iFail 1} 1 {incr iFail} {
572 if {$::DO_MALLOC_TEST} {sqlite3_memdebug_fail $iFail -repeat $nRepeat}
573
574 set res [uplevel [list catchsql $sql]]
575 set nFail [sqlite3_memdebug_fail -1 -benigncnt nBenign]
576 if {$nFail==0} {
577 do_test $name.$zName.$iFail [list set {} $res] {0 {}}
578 return
579 } else {
580 if {[lsearch $answers $res]>=0} {
581 set res $str
582 }
583 do_test $name.$zName.$iFail [list set {} $res] $str
584 set cksum2 [db one $cksumsql]
585 if {$cksum1 != $cksum2} return
586 }
587 }
588 }
589}