OLD | NEW |
1 # 2001 September 15 | 1 # 2001 September 15 |
2 # | 2 # |
3 # The author disclaims copyright to this source code. In place of | 3 # The author disclaims copyright to this source code. In place of |
4 # a legal notice, here is a blessing: | 4 # a legal notice, here is a blessing: |
5 # | 5 # |
6 # May you do good and not evil. | 6 # May you do good and not evil. |
7 # May you find forgiveness for yourself and forgive others. | 7 # May you find forgiveness for yourself and forgive others. |
8 # May you share freely, never taking more than you give. | 8 # May you share freely, never taking more than you give. |
9 # | 9 # |
10 #*********************************************************************** | 10 #*********************************************************************** |
11 # This file implements some common TCL routines used for regression | 11 # This file implements some common TCL routines used for regression |
12 # testing the SQLite library | 12 # testing the SQLite library |
13 # | 13 # |
14 # $Id: tester.tcl,v 1.143 2009/04/09 01:23:49 drh Exp $ | 14 # $Id: tester.tcl,v 1.143 2009/04/09 01:23:49 drh Exp $ |
15 | 15 |
16 # | 16 #------------------------------------------------------------------------- |
17 # What for user input before continuing. This gives an opportunity | 17 # The commands provided by the code in this file to help with creating |
18 # to connect profiling tools to the process. | 18 # test cases are as follows: |
19 # | 19 # |
20 for {set i 0} {$i<[llength $argv]} {incr i} { | 20 # Commands to manipulate the db and the file-system at a high level: |
21 if {[regexp {^-+pause$} [lindex $argv $i] all value]} { | 21 # |
22 puts -nonewline "Press RETURN to begin..." | 22 # copy_file FROM TO |
23 flush stdout | 23 # drop_all_table ?DB? |
24 gets stdin | 24 # forcedelete FILENAME |
25 set argv [lreplace $argv $i $i] | 25 # |
26 } | 26 # Test the capability of the SQLite version built into the interpreter to |
27 } | 27 # determine if a specific test can be run: |
28 | 28 # |
| 29 # ifcapable EXPR |
| 30 # |
| 31 # Calulate checksums based on database contents: |
| 32 # |
| 33 # dbcksum DB DBNAME |
| 34 # allcksum ?DB? |
| 35 # cksum ?DB? |
| 36 # |
| 37 # Commands to execute/explain SQL statements: |
| 38 # |
| 39 # stepsql DB SQL |
| 40 # execsql2 SQL |
| 41 # explain_no_trace SQL |
| 42 # explain SQL ?DB? |
| 43 # catchsql SQL ?DB? |
| 44 # execsql SQL ?DB? |
| 45 # |
| 46 # Commands to run test cases: |
| 47 # |
| 48 # do_ioerr_test TESTNAME ARGS... |
| 49 # crashsql ARGS... |
| 50 # integrity_check TESTNAME ?DB? |
| 51 # do_test TESTNAME SCRIPT EXPECTED |
| 52 # do_execsql_test TESTNAME SQL EXPECTED |
| 53 # do_catchsql_test TESTNAME SQL EXPECTED |
| 54 # |
| 55 # Commands providing a lower level interface to the global test counters: |
| 56 # |
| 57 # set_test_counter COUNTER ?VALUE? |
| 58 # omit_test TESTNAME REASON |
| 59 # fail_test TESTNAME |
| 60 # incr_ntest |
| 61 # |
| 62 # Command run at the end of each test file: |
| 63 # |
| 64 # finish_test |
| 65 # |
| 66 # Commands to help create test files that run with the "WAL" and other |
| 67 # permutations (see file permutations.test): |
| 68 # |
| 69 # wal_is_wal_mode |
| 70 # wal_set_journal_mode ?DB? |
| 71 # wal_check_journal_mode TESTNAME?DB? |
| 72 # permutation |
| 73 # presql |
| 74 # |
| 75 |
| 76 # Set the precision of FP arithmatic used by the interpreter. And |
| 77 # configure SQLite to take database file locks on the page that begins |
| 78 # 64KB into the database file instead of the one 1GB in. This means |
| 79 # the code that handles that special case can be tested without creating |
| 80 # very large database files. |
| 81 # |
29 set tcl_precision 15 | 82 set tcl_precision 15 |
30 sqlite3_test_control_pending_byte 0x0010000 | 83 sqlite3_test_control_pending_byte 0x0010000 |
31 | 84 |
32 # | 85 |
33 # Check the command-line arguments for a default soft-heap-limit. | 86 # If the pager codec is available, create a wrapper for the [sqlite3] |
34 # Store this default value in the global variable ::soft_limit and | 87 # command that appends "-key {xyzzy}" to the command line. i.e. this: |
35 # update the soft-heap-limit each time this script is run. In that | 88 # |
36 # way if an individual test file changes the soft-heap-limit, it | 89 # sqlite3 db test.db |
37 # will be reset at the start of the next test file. | 90 # |
38 # | 91 # becomes |
39 if {![info exists soft_limit]} { | 92 # |
40 set soft_limit 0 | 93 # sqlite3 db test.db -key {xyzzy} |
41 for {set i 0} {$i<[llength $argv]} {incr i} { | 94 # |
42 if {[regexp {^--soft-heap-limit=(.+)$} [lindex $argv $i] all value]} { | 95 if {[info command sqlite_orig]==""} { |
43 if {$value!="off"} { | |
44 set soft_limit $value | |
45 } | |
46 set argv [lreplace $argv $i $i] | |
47 } | |
48 } | |
49 } | |
50 sqlite3_soft_heap_limit $soft_limit | |
51 | |
52 # | |
53 # Check the command-line arguments to set the memory debugger | |
54 # backtrace depth. | |
55 # | |
56 # See the sqlite3_memdebug_backtrace() function in mem2.c or | |
57 # test_malloc.c for additional information. | |
58 # | |
59 for {set i 0} {$i<[llength $argv]} {incr i} { | |
60 if {[lindex $argv $i] eq "--malloctrace"} { | |
61 set argv [lreplace $argv $i $i] | |
62 sqlite3_memdebug_backtrace 10 | |
63 sqlite3_memdebug_log start | |
64 set tester_do_malloctrace 1 | |
65 } | |
66 } | |
67 for {set i 0} {$i<[llength $argv]} {incr i} { | |
68 if {[regexp {^--backtrace=(\d+)$} [lindex $argv $i] all value]} { | |
69 sqlite3_memdebug_backtrace $value | |
70 set argv [lreplace $argv $i $i] | |
71 } | |
72 } | |
73 | |
74 | |
75 proc ostrace_call {zCall nClick zFile i32 i64} { | |
76 set s "INSERT INTO ostrace VALUES('$zCall', $nClick, '$zFile', $i32, $i64);" | |
77 puts $::ostrace_fd $s | |
78 } | |
79 | |
80 for {set i 0} {$i<[llength $argv]} {incr i} { | |
81 if {[lindex $argv $i] eq "--ossummary" || [lindex $argv $i] eq "--ostrace"} { | |
82 sqlite3_instvfs create -default ostrace | |
83 set tester_do_ostrace 1 | |
84 set ostrace_fd [open ostrace.sql w] | |
85 puts $ostrace_fd "BEGIN;" | |
86 if {[lindex $argv $i] eq "--ostrace"} { | |
87 set s "CREATE TABLE ostrace" | |
88 append s "(method TEXT, clicks INT, file TEXT, i32 INT, i64 INT);" | |
89 puts $ostrace_fd $s | |
90 sqlite3_instvfs configure ostrace ostrace_call | |
91 sqlite3_instvfs configure ostrace ostrace_call | |
92 } | |
93 set argv [lreplace $argv $i $i] | |
94 } | |
95 if {[lindex $argv $i] eq "--binarylog"} { | |
96 set tester_do_binarylog 1 | |
97 set argv [lreplace $argv $i $i] | |
98 } | |
99 } | |
100 | |
101 # | |
102 # Check the command-line arguments to set the maximum number of | |
103 # errors tolerated before halting. | |
104 # | |
105 if {![info exists maxErr]} { | |
106 set maxErr 1000 | |
107 } | |
108 for {set i 0} {$i<[llength $argv]} {incr i} { | |
109 if {[regexp {^--maxerror=(\d+)$} [lindex $argv $i] all maxErr]} { | |
110 set argv [lreplace $argv $i $i] | |
111 } | |
112 } | |
113 #puts "Max error = $maxErr" | |
114 | |
115 | |
116 # Use the pager codec if it is available | |
117 # | |
118 if {[sqlite3 -has-codec] && [info command sqlite_orig]==""} { | |
119 rename sqlite3 sqlite_orig | 96 rename sqlite3 sqlite_orig |
120 proc sqlite3 {args} { | 97 proc sqlite3 {args} { |
121 if {[llength $args]==2 && [string index [lindex $args 0] 0]!="-"} { | 98 if {[llength $args]>=2 && [string index [lindex $args 0] 0]!="-"} { |
122 lappend args -key {xyzzy} | 99 # This command is opening a new database connection. |
| 100 # |
| 101 if {[info exists ::G(perm:sqlite3_args)]} { |
| 102 set args [concat $args $::G(perm:sqlite3_args)] |
| 103 } |
| 104 if {[sqlite_orig -has-codec] && ![info exists ::do_not_use_codec]} { |
| 105 lappend args -key {xyzzy} |
| 106 } |
| 107 |
| 108 set res [uplevel 1 sqlite_orig $args] |
| 109 if {[info exists ::G(perm:presql)]} { |
| 110 [lindex $args 0] eval $::G(perm:presql) |
| 111 } |
| 112 set res |
| 113 } else { |
| 114 # This command is not opening a new database connection. Pass the |
| 115 # arguments through to the C implemenation as the are. |
| 116 # |
| 117 uplevel 1 sqlite_orig $args |
123 } | 118 } |
124 uplevel 1 sqlite_orig $args | 119 } |
125 } | 120 } |
126 } | 121 |
127 | 122 proc execpresql {handle args} { |
128 | 123 trace remove execution $handle enter [list execpresql $handle] |
129 # Create a test database | 124 if {[info exists ::G(perm:presql)]} { |
130 # | 125 $handle eval $::G(perm:presql) |
131 if {![info exists nTest]} { | 126 } |
| 127 } |
| 128 |
| 129 # This command should be called after loading tester.tcl from within |
| 130 # all test scripts that are incompatible with encryption codecs. |
| 131 # |
| 132 proc do_not_use_codec {} { |
| 133 set ::do_not_use_codec 1 |
| 134 reset_db |
| 135 } |
| 136 |
| 137 # The following block only runs the first time this file is sourced. It |
| 138 # does not run in slave interpreters (since the ::cmdlinearg array is |
| 139 # populated before the test script is run in slave interpreters). |
| 140 # |
| 141 if {[info exists cmdlinearg]==0} { |
| 142 |
| 143 # Parse any options specified in the $argv array. This script accepts the |
| 144 # following options: |
| 145 # |
| 146 # --pause |
| 147 # --soft-heap-limit=NN |
| 148 # --maxerror=NN |
| 149 # --malloctrace=N |
| 150 # --backtrace=N |
| 151 # --binarylog=N |
| 152 # --soak=N |
| 153 # |
| 154 set cmdlinearg(soft-heap-limit) 0 |
| 155 set cmdlinearg(maxerror) 1000 |
| 156 set cmdlinearg(malloctrace) 0 |
| 157 set cmdlinearg(backtrace) 10 |
| 158 set cmdlinearg(binarylog) 0 |
| 159 set cmdlinearg(soak) 0 |
| 160 |
| 161 set leftover [list] |
| 162 foreach a $argv { |
| 163 switch -regexp -- $a { |
| 164 {^-+pause$} { |
| 165 # Wait for user input before continuing. This is to give the user an |
| 166 # opportunity to connect profiling tools to the process. |
| 167 puts -nonewline "Press RETURN to begin..." |
| 168 flush stdout |
| 169 gets stdin |
| 170 } |
| 171 {^-+soft-heap-limit=.+$} { |
| 172 foreach {dummy cmdlinearg(soft-heap-limit)} [split $a =] break |
| 173 } |
| 174 {^-+maxerror=.+$} { |
| 175 foreach {dummy cmdlinearg(maxerror)} [split $a =] break |
| 176 } |
| 177 {^-+malloctrace=.+$} { |
| 178 foreach {dummy cmdlinearg(malloctrace)} [split $a =] break |
| 179 if {$cmdlinearg(malloctrace)} { |
| 180 sqlite3_memdebug_log start |
| 181 } |
| 182 } |
| 183 {^-+backtrace=.+$} { |
| 184 foreach {dummy cmdlinearg(backtrace)} [split $a =] break |
| 185 sqlite3_memdebug_backtrace $value |
| 186 } |
| 187 {^-+binarylog=.+$} { |
| 188 foreach {dummy cmdlinearg(binarylog)} [split $a =] break |
| 189 } |
| 190 {^-+soak=.+$} { |
| 191 foreach {dummy cmdlinearg(soak)} [split $a =] break |
| 192 set ::G(issoak) $cmdlinearg(soak) |
| 193 } |
| 194 default { |
| 195 lappend leftover $a |
| 196 } |
| 197 } |
| 198 } |
| 199 set argv $leftover |
| 200 |
| 201 # Install the malloc layer used to inject OOM errors. And the 'automatic' |
| 202 # extensions. This only needs to be done once for the process. |
| 203 # |
132 sqlite3_shutdown | 204 sqlite3_shutdown |
133 install_malloc_faultsim 1 | 205 install_malloc_faultsim 1 |
134 sqlite3_initialize | 206 sqlite3_initialize |
135 autoinstall_test_functions | 207 autoinstall_test_functions |
136 if {[info exists tester_do_binarylog]} { | 208 |
137 sqlite3_instvfs binarylog -default binarylog ostrace.bin | 209 # If the --binarylog option was specified, create the logging VFS. This |
138 sqlite3_instvfs marker binarylog "$argv0 $argv" | 210 # call installs the new VFS as the default for all SQLite connections. |
139 } | 211 # |
140 } | 212 if {$cmdlinearg(binarylog)} { |
141 | 213 vfslog new binarylog {} vfslog.bin |
| 214 } |
| 215 |
| 216 # Set the backtrace depth, if malloc tracing is enabled. |
| 217 # |
| 218 if {$cmdlinearg(malloctrace)} { |
| 219 sqlite3_memdebug_backtrace $cmdlinearg(backtrace) |
| 220 } |
| 221 } |
| 222 |
| 223 # Update the soft-heap-limit each time this script is run. In that |
| 224 # way if an individual test file changes the soft-heap-limit, it |
| 225 # will be reset at the start of the next test file. |
| 226 # |
| 227 sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit) |
| 228 |
| 229 # Create a test database |
| 230 # |
142 proc reset_db {} { | 231 proc reset_db {} { |
143 catch {db close} | 232 catch {db close} |
144 file delete -force test.db | 233 file delete -force test.db |
145 file delete -force test.db-journal | 234 file delete -force test.db-journal |
| 235 file delete -force test.db-wal |
146 sqlite3 db ./test.db | 236 sqlite3 db ./test.db |
147 set ::DB [sqlite3_connection_pointer db] | 237 set ::DB [sqlite3_connection_pointer db] |
148 if {[info exists ::SETUP_SQL]} { | 238 if {[info exists ::SETUP_SQL]} { |
149 db eval $::SETUP_SQL | 239 db eval $::SETUP_SQL |
150 } | 240 } |
151 } | 241 } |
152 reset_db | 242 reset_db |
153 | 243 |
154 # Abort early if this script has been run before. | 244 # Abort early if this script has been run before. |
155 # | 245 # |
156 if {[info exists nTest]} return | 246 if {[info exists TC(count)]} return |
157 | 247 |
158 # Set the test counters to zero | 248 # Make sure memory statistics are enabled. |
159 # | 249 # |
160 set nErr 0 | 250 sqlite3_config_memstatus 1 |
161 set nTest 0 | 251 |
162 set skip_test 0 | 252 # Initialize the test counters and set up commands to access them. |
163 set failList {} | 253 # Or, if this is a slave interpreter, set up aliases to write the |
164 set omitList {} | 254 # counters in the parent interpreter. |
165 if {![info exists speedTest]} { | 255 # |
166 set speedTest 0 | 256 if {0==[info exists ::SLAVE]} { |
| 257 set TC(errors) 0 |
| 258 set TC(count) 0 |
| 259 set TC(fail_list) [list] |
| 260 set TC(omit_list) [list] |
| 261 |
| 262 proc set_test_counter {counter args} { |
| 263 if {[llength $args]} { |
| 264 set ::TC($counter) [lindex $args 0] |
| 265 } |
| 266 set ::TC($counter) |
| 267 } |
167 } | 268 } |
168 | 269 |
169 # Record the fact that a sequence of tests were omitted. | 270 # Record the fact that a sequence of tests were omitted. |
170 # | 271 # |
171 proc omit_test {name reason} { | 272 proc omit_test {name reason} { |
172 global omitList | 273 set omitList [set_test_counter omit_list] |
173 lappend omitList [list $name $reason] | 274 lappend omitList [list $name $reason] |
| 275 set_test_counter omit_list $omitList |
174 } | 276 } |
175 | 277 |
| 278 # Record the fact that a test failed. |
| 279 # |
| 280 proc fail_test {name} { |
| 281 set f [set_test_counter fail_list] |
| 282 lappend f $name |
| 283 set_test_counter fail_list $f |
| 284 set_test_counter errors [expr [set_test_counter errors] + 1] |
| 285 |
| 286 set nFail [set_test_counter errors] |
| 287 if {$nFail>=$::cmdlinearg(maxerror)} { |
| 288 puts "*** Giving up..." |
| 289 finalize_testing |
| 290 } |
| 291 } |
| 292 |
| 293 # Increment the number of tests run |
| 294 # |
| 295 proc incr_ntest {} { |
| 296 set_test_counter count [expr [set_test_counter count] + 1] |
| 297 } |
| 298 |
| 299 |
176 # Invoke the do_test procedure to run a single test | 300 # Invoke the do_test procedure to run a single test |
177 # | 301 # |
178 proc do_test {name cmd expected} { | 302 proc do_test {name cmd expected} { |
179 global argv nErr nTest skip_test maxErr | 303 |
| 304 global argv cmdlinearg |
| 305 |
180 sqlite3_memdebug_settitle $name | 306 sqlite3_memdebug_settitle $name |
181 if {[info exists ::tester_do_binarylog]} { | 307 |
182 sqlite3_instvfs marker binarylog "Start of $name" | 308 # if {[llength $argv]==0} { |
| 309 # set go 1 |
| 310 # } else { |
| 311 # set go 0 |
| 312 # foreach pattern $argv { |
| 313 # if {[string match $pattern $name]} { |
| 314 # set go 1 |
| 315 # break |
| 316 # } |
| 317 # } |
| 318 # } |
| 319 |
| 320 if {[info exists ::G(perm:prefix)]} { |
| 321 set name "$::G(perm:prefix)$name" |
183 } | 322 } |
184 if {$skip_test} { | 323 |
185 set skip_test 0 | 324 incr_ntest |
186 return | |
187 } | |
188 if {[llength $argv]==0} { | |
189 set go 1 | |
190 } else { | |
191 set go 0 | |
192 foreach pattern $argv { | |
193 if {[string match $pattern $name]} { | |
194 set go 1 | |
195 break | |
196 } | |
197 } | |
198 } | |
199 if {!$go} return | |
200 incr nTest | |
201 puts -nonewline $name... | 325 puts -nonewline $name... |
202 flush stdout | 326 flush stdout |
203 if {[catch {uplevel #0 "$cmd;\n"} result]} { | 327 if {[catch {uplevel #0 "$cmd;\n"} result]} { |
204 puts "\nError: $result" | 328 puts "\nError: $result" |
205 incr nErr | 329 fail_test $name |
206 lappend ::failList $name | |
207 if {$nErr>$maxErr} {puts "*** Giving up..."; finalize_testing} | |
208 } elseif {[string compare $result $expected]} { | 330 } elseif {[string compare $result $expected]} { |
209 puts "\nExpected: \[$expected\]\n Got: \[$result\]" | 331 puts "\nExpected: \[$expected\]\n Got: \[$result\]" |
210 incr nErr | 332 fail_test $name |
211 lappend ::failList $name | |
212 if {$nErr>=$maxErr} {puts "*** Giving up..."; finalize_testing} | |
213 } else { | 333 } else { |
214 puts " Ok" | 334 puts " Ok" |
215 } | 335 } |
216 flush stdout | 336 flush stdout |
217 if {[info exists ::tester_do_binarylog]} { | 337 } |
218 sqlite3_instvfs marker binarylog "End of $name" | 338 |
| 339 proc fix_testname {varname} { |
| 340 upvar $varname testname |
| 341 if {[info exists ::testprefix] |
| 342 && [string is digit [string range $testname 0 0]] |
| 343 } { |
| 344 set testname "${::testprefix}-$testname" |
| 345 } |
| 346 } |
| 347 |
| 348 proc do_execsql_test {testname sql {result {}}} { |
| 349 fix_testname testname |
| 350 uplevel do_test $testname [list "execsql {$sql}"] [list $result] |
| 351 } |
| 352 proc do_catchsql_test {testname sql result} { |
| 353 fix_testname testname |
| 354 uplevel do_test $testname [list "catchsql {$sql}"] [list $result] |
| 355 } |
| 356 |
| 357 #------------------------------------------------------------------------- |
| 358 # Usage: do_select_tests PREFIX ?SWITCHES? TESTLIST |
| 359 # |
| 360 # Where switches are: |
| 361 # |
| 362 # -errorformat FMTSTRING |
| 363 # -count |
| 364 # -query SQL |
| 365 # -tclquery TCL |
| 366 # -repair TCL |
| 367 # |
| 368 proc do_select_tests {prefix args} { |
| 369 |
| 370 set testlist [lindex $args end] |
| 371 set switches [lrange $args 0 end-1] |
| 372 |
| 373 set errfmt "" |
| 374 set countonly 0 |
| 375 set tclquery "" |
| 376 set repair "" |
| 377 |
| 378 for {set i 0} {$i < [llength $switches]} {incr i} { |
| 379 set s [lindex $switches $i] |
| 380 set n [string length $s] |
| 381 if {$n>=2 && [string equal -length $n $s "-query"]} { |
| 382 set tclquery [list execsql [lindex $switches [incr i]]] |
| 383 } elseif {$n>=2 && [string equal -length $n $s "-tclquery"]} { |
| 384 set tclquery [lindex $switches [incr i]] |
| 385 } elseif {$n>=2 && [string equal -length $n $s "-errorformat"]} { |
| 386 set errfmt [lindex $switches [incr i]] |
| 387 } elseif {$n>=2 && [string equal -length $n $s "-repair"]} { |
| 388 set repair [lindex $switches [incr i]] |
| 389 } elseif {$n>=2 && [string equal -length $n $s "-count"]} { |
| 390 set countonly 1 |
| 391 } else { |
| 392 error "unknown switch: $s" |
| 393 } |
| 394 } |
| 395 |
| 396 if {$countonly && $errfmt!=""} { |
| 397 error "Cannot use -count and -errorformat together" |
| 398 } |
| 399 set nTestlist [llength $testlist] |
| 400 if {$nTestlist%3 || $nTestlist==0 } { |
| 401 error "SELECT test list contains [llength $testlist] elements" |
| 402 } |
| 403 |
| 404 eval $repair |
| 405 foreach {tn sql res} $testlist { |
| 406 if {$tclquery != ""} { |
| 407 execsql $sql |
| 408 uplevel do_test ${prefix}.$tn [list $tclquery] [list [list {*}$res]] |
| 409 } elseif {$countonly} { |
| 410 set nRow 0 |
| 411 db eval $sql {incr nRow} |
| 412 uplevel do_test ${prefix}.$tn [list [list set {} $nRow]] [list $res] |
| 413 } elseif {$errfmt==""} { |
| 414 uplevel do_execsql_test ${prefix}.${tn} [list $sql] [list [list {*}$res]] |
| 415 } else { |
| 416 set res [list 1 [string trim [format $errfmt {*}$res]]] |
| 417 uplevel do_catchsql_test ${prefix}.${tn} [list $sql] [list $res] |
| 418 } |
| 419 eval $repair |
| 420 } |
| 421 |
| 422 } |
| 423 |
| 424 proc delete_all_data {} { |
| 425 db eval {SELECT tbl_name AS t FROM sqlite_master WHERE type = 'table'} { |
| 426 db eval "DELETE FROM '[string map {' ''} $t]'" |
219 } | 427 } |
220 } | 428 } |
221 | 429 |
222 # Run an SQL script. | 430 # Run an SQL script. |
223 # Return the number of microseconds per statement. | 431 # Return the number of microseconds per statement. |
224 # | 432 # |
225 proc speed_trial {name numstmt units sql} { | 433 proc speed_trial {name numstmt units sql} { |
226 puts -nonewline [format {%-21.21s } $name...] | 434 puts -nonewline [format {%-21.21s } $name...] |
227 flush stdout | 435 flush stdout |
228 set speed [time {sqlite3_exec_nr db $sql}] | 436 set speed [time {sqlite3_exec_nr db $sql}] |
(...skipping 19 matching lines...) Expand all Loading... |
248 set rate [format %20.5f [expr {1000000.0*$numstmt/$tm}]] | 456 set rate [format %20.5f [expr {1000000.0*$numstmt/$tm}]] |
249 } | 457 } |
250 set u2 $units/s | 458 set u2 $units/s |
251 puts [format {%12d uS %s %s} $tm $rate $u2] | 459 puts [format {%12d uS %s %s} $tm $rate $u2] |
252 global total_time | 460 global total_time |
253 set total_time [expr {$total_time+$tm}] | 461 set total_time [expr {$total_time+$tm}] |
254 } | 462 } |
255 proc speed_trial_init {name} { | 463 proc speed_trial_init {name} { |
256 global total_time | 464 global total_time |
257 set total_time 0 | 465 set total_time 0 |
| 466 sqlite3 versdb :memory: |
| 467 set vers [versdb one {SELECT sqlite_source_id()}] |
| 468 versdb close |
| 469 puts "SQLite $vers" |
258 } | 470 } |
259 proc speed_trial_summary {name} { | 471 proc speed_trial_summary {name} { |
260 global total_time | 472 global total_time |
261 puts [format {%-21.21s %12d uS TOTAL} $name $total_time] | 473 puts [format {%-21.21s %12d uS TOTAL} $name $total_time] |
262 } | 474 } |
263 | 475 |
264 # Run this routine last | 476 # Run this routine last |
265 # | 477 # |
266 proc finish_test {} { | 478 proc finish_test {} { |
267 finalize_testing | 479 catch {db close} |
| 480 catch {db2 close} |
| 481 catch {db3 close} |
| 482 if {0==[info exists ::SLAVE]} { finalize_testing } |
268 } | 483 } |
269 proc finalize_testing {} { | 484 proc finalize_testing {} { |
270 global nTest nErr sqlite_open_file_count omitList | 485 global sqlite_open_file_count |
| 486 |
| 487 set omitList [set_test_counter omit_list] |
271 | 488 |
272 catch {db close} | 489 catch {db close} |
273 catch {db2 close} | 490 catch {db2 close} |
274 catch {db3 close} | 491 catch {db3 close} |
275 | 492 |
276 vfs_unlink_test | 493 vfs_unlink_test |
277 sqlite3 db {} | 494 sqlite3 db {} |
278 # sqlite3_clear_tsd_memdebug | 495 # sqlite3_clear_tsd_memdebug |
279 db close | 496 db close |
280 sqlite3_reset_auto_extension | 497 sqlite3_reset_auto_extension |
281 set heaplimit [sqlite3_soft_heap_limit] | 498 |
282 if {$heaplimit!=$::soft_limit} { | |
283 puts "soft-heap-limit changed by this script\ | |
284 from $::soft_limit to $heaplimit" | |
285 } elseif {$heaplimit!="" && $heaplimit>0} { | |
286 puts "soft-heap-limit set to $heaplimit" | |
287 } | |
288 sqlite3_soft_heap_limit 0 | 499 sqlite3_soft_heap_limit 0 |
289 incr nTest | 500 set nTest [incr_ntest] |
| 501 set nErr [set_test_counter errors] |
| 502 |
290 puts "$nErr errors out of $nTest tests" | 503 puts "$nErr errors out of $nTest tests" |
291 if {$nErr>0} { | 504 if {$nErr>0} { |
292 puts "Failures on these tests: $::failList" | 505 puts "Failures on these tests: [set_test_counter fail_list]" |
293 } | 506 } |
294 run_thread_tests 1 | 507 run_thread_tests 1 |
295 if {[llength $omitList]>0} { | 508 if {[llength $omitList]>0} { |
296 puts "Omitted test cases:" | 509 puts "Omitted test cases:" |
297 set prec {} | 510 set prec {} |
298 foreach {rec} [lsort $omitList] { | 511 foreach {rec} [lsort $omitList] { |
299 if {$rec==$prec} continue | 512 if {$rec==$prec} continue |
300 set prec $rec | 513 set prec $rec |
301 puts [format { %-12s %s} [lindex $rec 0] [lindex $rec 1]] | 514 puts [format { %-12s %s} [lindex $rec 0] [lindex $rec 1]] |
302 } | 515 } |
303 } | 516 } |
304 if {$nErr>0 && ![working_64bit_int]} { | 517 if {$nErr>0 && ![working_64bit_int]} { |
305 puts "******************************************************************" | 518 puts "******************************************************************" |
306 puts "N.B.: The version of TCL that you used to build this test harness" | 519 puts "N.B.: The version of TCL that you used to build this test harness" |
307 puts "is defective in that it does not support 64-bit integers. Some or" | 520 puts "is defective in that it does not support 64-bit integers. Some or" |
308 puts "all of the test failures above might be a result from this defect" | 521 puts "all of the test failures above might be a result from this defect" |
309 puts "in your TCL build." | 522 puts "in your TCL build." |
310 puts "******************************************************************" | 523 puts "******************************************************************" |
311 } | 524 } |
312 if {[info exists ::tester_do_binarylog]} { | 525 if {$::cmdlinearg(binarylog)} { |
313 sqlite3_instvfs destroy binarylog | 526 vfslog finalize binarylog |
314 } | 527 } |
315 if {$sqlite_open_file_count} { | 528 if {$sqlite_open_file_count} { |
316 puts "$sqlite_open_file_count files were left open" | 529 puts "$sqlite_open_file_count files were left open" |
317 incr nErr | 530 incr nErr |
318 } | 531 } |
319 if {[info exists ::tester_do_ostrace]} { | 532 if {[lindex [sqlite3_status SQLITE_STATUS_MALLOC_COUNT 0] 1]>0 || |
320 puts "Writing ostrace.sql..." | 533 [sqlite3_memory_used]>0} { |
321 set fd $::ostrace_fd | 534 puts "Unfreed memory: [sqlite3_memory_used] bytes in\ |
322 | 535 [lindex [sqlite3_status SQLITE_STATUS_MALLOC_COUNT 0] 1] allocations" |
323 puts -nonewline $fd "CREATE TABLE ossummary" | |
324 puts $fd "(method TEXT, clicks INTEGER, count INTEGER);" | |
325 foreach row [sqlite3_instvfs report ostrace] { | |
326 foreach {method count clicks} $row break | |
327 puts $fd "INSERT INTO ossummary VALUES('$method', $clicks, $count);" | |
328 } | |
329 puts $fd "COMMIT;" | |
330 close $fd | |
331 sqlite3_instvfs destroy ostrace | |
332 } | |
333 if {[sqlite3_memory_used]>0} { | |
334 puts "Unfreed memory: [sqlite3_memory_used] bytes" | |
335 incr nErr | 536 incr nErr |
336 ifcapable memdebug||mem5||(mem3&&debug) { | 537 ifcapable memdebug||mem5||(mem3&&debug) { |
337 puts "Writing unfreed memory log to \"./memleak.txt\"" | 538 puts "Writing unfreed memory log to \"./memleak.txt\"" |
338 sqlite3_memdebug_dump ./memleak.txt | 539 sqlite3_memdebug_dump ./memleak.txt |
339 } | 540 } |
340 } else { | 541 } else { |
341 puts "All memory allocations freed - no leaks" | 542 puts "All memory allocations freed - no leaks" |
342 ifcapable memdebug||mem5 { | 543 ifcapable memdebug||mem5 { |
343 sqlite3_memdebug_dump ./memusage.txt | 544 sqlite3_memdebug_dump ./memusage.txt |
344 } | 545 } |
345 } | 546 } |
346 show_memstats | 547 show_memstats |
347 puts "Maximum memory usage: [sqlite3_memory_highwater 1] bytes" | 548 puts "Maximum memory usage: [sqlite3_memory_highwater 1] bytes" |
348 puts "Current memory usage: [sqlite3_memory_highwater] bytes" | 549 puts "Current memory usage: [sqlite3_memory_highwater] bytes" |
349 if {[info commands sqlite3_memdebug_malloc_count] ne ""} { | 550 if {[info commands sqlite3_memdebug_malloc_count] ne ""} { |
350 puts "Number of malloc() : [sqlite3_memdebug_malloc_count] calls" | 551 puts "Number of malloc() : [sqlite3_memdebug_malloc_count] calls" |
351 } | 552 } |
352 if {[info exists ::tester_do_malloctrace]} { | 553 if {$::cmdlinearg(malloctrace)} { |
353 puts "Writing mallocs.sql..." | 554 puts "Writing mallocs.sql..." |
354 memdebug_log_sql | 555 memdebug_log_sql |
355 sqlite3_memdebug_log stop | 556 sqlite3_memdebug_log stop |
356 sqlite3_memdebug_log clear | 557 sqlite3_memdebug_log clear |
357 | 558 |
358 if {[sqlite3_memory_used]>0} { | 559 if {[sqlite3_memory_used]>0} { |
359 puts "Writing leaks.sql..." | 560 puts "Writing leaks.sql..." |
360 sqlite3_memdebug_log sync | 561 sqlite3_memdebug_log sync |
361 memdebug_log_sql leaks.sql | 562 memdebug_log_sql leaks.sql |
362 } | 563 } |
363 } | 564 } |
364 foreach f [glob -nocomplain test.db-*-journal] { | 565 foreach f [glob -nocomplain test.db-*-journal] { |
365 file delete -force $f | 566 file delete -force $f |
366 } | 567 } |
367 foreach f [glob -nocomplain test.db-mj*] { | 568 foreach f [glob -nocomplain test.db-mj*] { |
368 file delete -force $f | 569 file delete -force $f |
369 } | 570 } |
370 exit [expr {$nErr>0}] | 571 exit [expr {$nErr>0}] |
371 } | 572 } |
372 | 573 |
373 # Display memory statistics for analysis and debugging purposes. | 574 # Display memory statistics for analysis and debugging purposes. |
374 # | 575 # |
375 proc show_memstats {} { | 576 proc show_memstats {} { |
376 set x [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] | 577 set x [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] |
377 set y [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] | 578 set y [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] |
378 set val [format {now %10d max %10d max-size %10d} \ | 579 set val [format {now %10d max %10d max-size %10d} \ |
379 [lindex $x 1] [lindex $x 2] [lindex $y 2]] | 580 [lindex $x 1] [lindex $x 2] [lindex $y 2]] |
380 puts "Memory used: $val" | 581 puts "Memory used: $val" |
| 582 set x [sqlite3_status SQLITE_STATUS_MALLOC_COUNT 0] |
| 583 set val [format {now %10d max %10d} [lindex $x 1] [lindex $x 2]] |
| 584 puts "Allocation count: $val" |
381 set x [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] | 585 set x [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] |
382 set y [sqlite3_status SQLITE_STATUS_PAGECACHE_SIZE 0] | 586 set y [sqlite3_status SQLITE_STATUS_PAGECACHE_SIZE 0] |
383 set val [format {now %10d max %10d max-size %10d} \ | 587 set val [format {now %10d max %10d max-size %10d} \ |
384 [lindex $x 1] [lindex $x 2] [lindex $y 2]] | 588 [lindex $x 1] [lindex $x 2] [lindex $y 2]] |
385 puts "Page-cache used: $val" | 589 puts "Page-cache used: $val" |
386 set x [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] | 590 set x [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] |
387 set val [format {now %10d max %10d} [lindex $x 1] [lindex $x 2]] | 591 set val [format {now %10d max %10d} [lindex $x 1] [lindex $x 2]] |
388 puts "Page-cache overflow: $val" | 592 puts "Page-cache overflow: $val" |
389 set x [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] | 593 set x [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] |
390 set val [format {now %10d max %10d} [lindex $x 1] [lindex $x 2]] | 594 set val [format {now %10d max %10d} [lindex $x 1] [lindex $x 2]] |
(...skipping 14 matching lines...) Expand all Loading... |
405 # | 609 # |
406 proc execsql {sql {db db}} { | 610 proc execsql {sql {db db}} { |
407 # puts "SQL = $sql" | 611 # puts "SQL = $sql" |
408 uplevel [list $db eval $sql] | 612 uplevel [list $db eval $sql] |
409 } | 613 } |
410 | 614 |
411 # Execute SQL and catch exceptions. | 615 # Execute SQL and catch exceptions. |
412 # | 616 # |
413 proc catchsql {sql {db db}} { | 617 proc catchsql {sql {db db}} { |
414 # puts "SQL = $sql" | 618 # puts "SQL = $sql" |
415 set r [catch {$db eval $sql} msg] | 619 set r [catch [list uplevel [list $db eval $sql]] msg] |
416 lappend r $msg | 620 lappend r $msg |
417 return $r | 621 return $r |
418 } | 622 } |
419 | 623 |
420 # Do an VDBE code dump on the SQL given | 624 # Do an VDBE code dump on the SQL given |
421 # | 625 # |
422 proc explain {sql {db db}} { | 626 proc explain {sql {db db}} { |
423 puts "" | 627 puts "" |
424 puts "addr opcode p1 p2 p3 p4 p5 #" | 628 puts "addr opcode p1 p2 p3 p4 p5 #" |
425 puts "---- ------------ ------ ------ ------ --------------- -- -" | 629 puts "---- ------------ ------ ------ ------ --------------- -- -" |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
472 } | 676 } |
473 if {[catch {sqlite3_finalize $vm} errmsg]} { | 677 if {[catch {sqlite3_finalize $vm} errmsg]} { |
474 return [list 1 $errmsg] | 678 return [list 1 $errmsg] |
475 } | 679 } |
476 } | 680 } |
477 return $r | 681 return $r |
478 } | 682 } |
479 | 683 |
480 # Delete a file or directory | 684 # Delete a file or directory |
481 # | 685 # |
482 proc forcedelete {filename} { | 686 proc forcedelete {args} { |
483 if {[catch {file delete -force $filename}]} { | 687 foreach filename $args { |
484 exec rm -rf $filename | 688 # On windows, sometimes even a [file delete -force] can fail just after |
| 689 # a file is closed. The cause is usually "tag-alongs" - programs like |
| 690 # anti-virus software, automatic backup tools and various explorer |
| 691 # extensions that keep a file open a little longer than we expect, causing |
| 692 # the delete to fail. |
| 693 # |
| 694 # The solution is to wait a short amount of time before retrying the |
| 695 # delete. |
| 696 # |
| 697 set nRetry 50 ;# Maximum number of retries. |
| 698 set nDelay 100 ;# Delay in ms before retrying. |
| 699 for {set i 0} {$i<$nRetry} {incr i} { |
| 700 set rc [catch {file delete -force $filename} msg] |
| 701 if {$rc==0} break |
| 702 after $nDelay |
| 703 } |
| 704 if {$rc} { error $msg } |
485 } | 705 } |
486 } | 706 } |
487 | 707 |
488 # Do an integrity check of the entire database | 708 # Do an integrity check of the entire database |
489 # | 709 # |
490 proc integrity_check {name {db db}} { | 710 proc integrity_check {name {db db}} { |
491 ifcapable integrityck { | 711 ifcapable integrityck { |
492 do_test $name [list execsql {PRAGMA integrity_check} $db] {ok} | 712 do_test $name [list execsql {PRAGMA integrity_check} $db] {ok} |
493 } | 713 } |
494 } | 714 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
536 # | 756 # |
537 # The return value is a list of two elements. The first element is a | 757 # The return value is a list of two elements. The first element is a |
538 # boolean, indicating whether or not the process actually crashed or | 758 # boolean, indicating whether or not the process actually crashed or |
539 # reported some other error. The second element in the returned list is the | 759 # reported some other error. The second element in the returned list is the |
540 # error message. This is "child process exited abnormally" if the crash | 760 # error message. This is "child process exited abnormally" if the crash |
541 # occured. | 761 # occured. |
542 # | 762 # |
543 # crashsql -delay CRASHDELAY -file CRASHFILE ?-blocksize BLOCKSIZE? $sql | 763 # crashsql -delay CRASHDELAY -file CRASHFILE ?-blocksize BLOCKSIZE? $sql |
544 # | 764 # |
545 proc crashsql {args} { | 765 proc crashsql {args} { |
546 if {$::tcl_platform(platform)!="unix"} { | |
547 error "crashsql should only be used on unix" | |
548 } | |
549 | 766 |
550 set blocksize "" | 767 set blocksize "" |
551 set crashdelay 1 | 768 set crashdelay 1 |
552 set prngseed 0 | 769 set prngseed 0 |
553 set tclbody {} | 770 set tclbody {} |
554 set crashfile "" | 771 set crashfile "" |
555 set dc "" | 772 set dc "" |
556 set sql [lindex $args end] | 773 set sql [lindex $args end] |
557 | 774 |
558 for {set ii 0} {$ii < [llength $args]-1} {incr ii 2} { | 775 for {set ii 0} {$ii < [llength $args]-1} {incr ii 2} { |
559 set z [lindex $args $ii] | 776 set z [lindex $args $ii] |
560 set n [string length $z] | 777 set n [string length $z] |
561 set z2 [lindex $args [expr $ii+1]] | 778 set z2 [lindex $args [expr $ii+1]] |
562 | 779 |
563 if {$n>1 && [string first $z -delay]==0} {set crashdelay $z2} \ | 780 if {$n>1 && [string first $z -delay]==0} {set crashdelay $z2} \ |
564 elseif {$n>1 && [string first $z -seed]==0} {set prngseed $z2} \ | 781 elseif {$n>1 && [string first $z -seed]==0} {set prngseed $z2} \ |
565 elseif {$n>1 && [string first $z -file]==0} {set crashfile $z2} \ | 782 elseif {$n>1 && [string first $z -file]==0} {set crashfile $z2} \ |
566 elseif {$n>1 && [string first $z -tclbody]==0} {set tclbody $z2} \ | 783 elseif {$n>1 && [string first $z -tclbody]==0} {set tclbody $z2} \ |
567 elseif {$n>1 && [string first $z -blocksize]==0} {set blocksize "-s $z2" } \ | 784 elseif {$n>1 && [string first $z -blocksize]==0} {set blocksize "-s $z2" } \ |
568 elseif {$n>1 && [string first $z -characteristics]==0} {set dc "-c {$z2}" }
\ | 785 elseif {$n>1 && [string first $z -characteristics]==0} {set dc "-c {$z2}" }
\ |
569 else { error "Unrecognized option: $z" } | 786 else { error "Unrecognized option: $z" } |
570 } | 787 } |
571 | 788 |
572 if {$crashfile eq ""} { | 789 if {$crashfile eq ""} { |
573 error "Compulsory option -file missing" | 790 error "Compulsory option -file missing" |
574 } | 791 } |
575 | 792 |
576 set cfile [file join [pwd] $crashfile] | 793 # $crashfile gets compared to the native filename in |
| 794 # cfSync(), which can be different then what TCL uses by |
| 795 # default, so here we force it to the "nativename" format. |
| 796 set cfile [string map {\\ \\\\} [file nativename [file join [pwd] $crashfile]]
] |
577 | 797 |
578 set f [open crash.tcl w] | 798 set f [open crash.tcl w] |
579 puts $f "sqlite3_crash_enable 1" | 799 puts $f "sqlite3_crash_enable 1" |
580 puts $f "sqlite3_crashparams $blocksize $dc $crashdelay $cfile" | 800 puts $f "sqlite3_crashparams $blocksize $dc $crashdelay $cfile" |
581 puts $f "sqlite3_test_control_pending_byte $::sqlite_pending_byte" | 801 puts $f "sqlite3_test_control_pending_byte $::sqlite_pending_byte" |
582 puts $f "sqlite3 db test.db -vfs crash" | 802 puts $f "sqlite3 db test.db -vfs crash" |
583 | 803 |
584 # This block sets the cache size of the main database to 10 | 804 # This block sets the cache size of the main database to 10 |
585 # pages. This is done in case the build is configured to omit | 805 # pages. This is done in case the build is configured to omit |
586 # "PRAGMA cache_size". | 806 # "PRAGMA cache_size". |
587 puts $f {db eval {SELECT * FROM sqlite_master;}} | 807 puts $f {db eval {SELECT * FROM sqlite_master;}} |
588 puts $f {set bt [btree_from_db db]} | 808 puts $f {set bt [btree_from_db db]} |
589 puts $f {btree_set_cache_size $bt 10} | 809 puts $f {btree_set_cache_size $bt 10} |
590 if {$prngseed} { | 810 if {$prngseed} { |
591 set seed [expr {$prngseed%10007+1}] | 811 set seed [expr {$prngseed%10007+1}] |
592 # puts seed=$seed | 812 # puts seed=$seed |
593 puts $f "db eval {SELECT randomblob($seed)}" | 813 puts $f "db eval {SELECT randomblob($seed)}" |
594 } | 814 } |
595 | 815 |
596 if {[string length $tclbody]>0} { | 816 if {[string length $tclbody]>0} { |
597 puts $f $tclbody | 817 puts $f $tclbody |
598 } | 818 } |
599 if {[string length $sql]>0} { | 819 if {[string length $sql]>0} { |
600 puts $f "db eval {" | 820 puts $f "db eval {" |
601 puts $f "$sql" | 821 puts $f "$sql" |
602 puts $f "}" | 822 puts $f "}" |
603 } | 823 } |
604 close $f | 824 close $f |
605 | |
606 set r [catch { | 825 set r [catch { |
607 exec [info nameofexec] crash.tcl >@stdout | 826 exec [info nameofexec] crash.tcl >@stdout |
608 } msg] | 827 } msg] |
| 828 |
| 829 # Windows/ActiveState TCL returns a slightly different |
| 830 # error message. We map that to the expected message |
| 831 # so that we don't have to change all of the test |
| 832 # cases. |
| 833 if {$::tcl_platform(platform)=="windows"} { |
| 834 if {$msg=="child killed: unknown signal"} { |
| 835 set msg "child process exited abnormally" |
| 836 } |
| 837 } |
| 838 |
609 lappend r $msg | 839 lappend r $msg |
610 } | 840 } |
611 | 841 |
612 # Usage: do_ioerr_test <test number> <options...> | 842 # Usage: do_ioerr_test <test number> <options...> |
613 # | 843 # |
614 # This proc is used to implement test cases that check that IO errors | 844 # This proc is used to implement test cases that check that IO errors |
615 # are correctly handled. The first argument, <test number>, is an integer | 845 # are correctly handled. The first argument, <test number>, is an integer |
616 # used to name the tests executed by this proc. Options are as follows: | 846 # used to name the tests executed by this proc. Options are as follows: |
617 # | 847 # |
618 # -tclprep TCL script to run to prepare test. | 848 # -tclprep TCL script to run to prepare test. |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
741 set s [expr $::sqlite_io_error_hit==0] | 971 set s [expr $::sqlite_io_error_hit==0] |
742 if {$::sqlite_io_error_hit>$::sqlite_io_error_hardhit && $r==0} { | 972 if {$::sqlite_io_error_hit>$::sqlite_io_error_hardhit && $r==0} { |
743 set r 1 | 973 set r 1 |
744 } | 974 } |
745 set ::sqlite_io_error_hit 0 | 975 set ::sqlite_io_error_hit 0 |
746 | 976 |
747 # One of two things must have happened. either | 977 # One of two things must have happened. either |
748 # 1. We never hit the IO error and the SQL returned OK | 978 # 1. We never hit the IO error and the SQL returned OK |
749 # 2. An IO error was hit and the SQL failed | 979 # 2. An IO error was hit and the SQL failed |
750 # | 980 # |
| 981 #puts "s=$s r=$r q=$q" |
751 expr { ($s && !$r && !$q) || (!$s && $r && $q) } | 982 expr { ($s && !$r && !$q) || (!$s && $r && $q) } |
752 } {1} | 983 } {1} |
753 | 984 |
754 set ::sqlite_io_error_hit 0 | 985 set ::sqlite_io_error_hit 0 |
755 set ::sqlite_io_error_pending 0 | 986 set ::sqlite_io_error_pending 0 |
756 | 987 |
757 # Check that no page references were leaked. There should be | 988 # Check that no page references were leaked. There should be |
758 # a single reference if there is still an active transaction, | 989 # a single reference if there is still an active transaction, |
759 # or zero otherwise. | 990 # or zero otherwise. |
760 # | 991 # |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
951 set f [open $from] | 1182 set f [open $from] |
952 fconfigure $f -translation binary | 1183 fconfigure $f -translation binary |
953 set t [open $to w] | 1184 set t [open $to w] |
954 fconfigure $t -translation binary | 1185 fconfigure $t -translation binary |
955 puts -nonewline $t [read $f [file size $from]] | 1186 puts -nonewline $t [read $f [file size $from]] |
956 close $t | 1187 close $t |
957 close $f | 1188 close $f |
958 } | 1189 } |
959 } | 1190 } |
960 | 1191 |
| 1192 # Drop all tables in database [db] |
| 1193 proc drop_all_tables {{db db}} { |
| 1194 ifcapable trigger&&foreignkey { |
| 1195 set pk [$db one "PRAGMA foreign_keys"] |
| 1196 $db eval "PRAGMA foreign_keys = OFF" |
| 1197 } |
| 1198 foreach {idx name file} [db eval {PRAGMA database_list}] { |
| 1199 if {$idx==1} { |
| 1200 set master sqlite_temp_master |
| 1201 } else { |
| 1202 set master $name.sqlite_master |
| 1203 } |
| 1204 foreach {t type} [$db eval " |
| 1205 SELECT name, type FROM $master |
| 1206 WHERE type IN('table', 'view') AND name NOT LIKE 'sqliteX_%' ESCAPE 'X' |
| 1207 "] { |
| 1208 $db eval "DROP $type \"$t\"" |
| 1209 } |
| 1210 } |
| 1211 ifcapable trigger&&foreignkey { |
| 1212 $db eval "PRAGMA foreign_keys = $pk" |
| 1213 } |
| 1214 } |
| 1215 |
| 1216 #------------------------------------------------------------------------- |
| 1217 # If a test script is executed with global variable $::G(perm:name) set to |
| 1218 # "wal", then the tests are run in WAL mode. Otherwise, they should be run |
| 1219 # in rollback mode. The following Tcl procs are used to make this less |
| 1220 # intrusive: |
| 1221 # |
| 1222 # wal_set_journal_mode ?DB? |
| 1223 # |
| 1224 # If running a WAL test, execute "PRAGMA journal_mode = wal" using |
| 1225 # connection handle DB. Otherwise, this command is a no-op. |
| 1226 # |
| 1227 # wal_check_journal_mode TESTNAME ?DB? |
| 1228 # |
| 1229 # If running a WAL test, execute a tests case that fails if the main |
| 1230 # database for connection handle DB is not currently a WAL database. |
| 1231 # Otherwise (if not running a WAL permutation) this is a no-op. |
| 1232 # |
| 1233 # wal_is_wal_mode |
| 1234 # |
| 1235 # Returns true if this test should be run in WAL mode. False otherwise. |
| 1236 # |
| 1237 proc wal_is_wal_mode {} { |
| 1238 expr {[permutation] eq "wal"} |
| 1239 } |
| 1240 proc wal_set_journal_mode {{db db}} { |
| 1241 if { [wal_is_wal_mode] } { |
| 1242 $db eval "PRAGMA journal_mode = WAL" |
| 1243 } |
| 1244 } |
| 1245 proc wal_check_journal_mode {testname {db db}} { |
| 1246 if { [wal_is_wal_mode] } { |
| 1247 $db eval { SELECT * FROM sqlite_master } |
| 1248 do_test $testname [list $db eval "PRAGMA main.journal_mode"] {wal} |
| 1249 } |
| 1250 } |
| 1251 |
| 1252 proc permutation {} { |
| 1253 set perm "" |
| 1254 catch {set perm $::G(perm:name)} |
| 1255 set perm |
| 1256 } |
| 1257 proc presql {} { |
| 1258 set presql "" |
| 1259 catch {set presql $::G(perm:presql)} |
| 1260 set presql |
| 1261 } |
| 1262 |
| 1263 #------------------------------------------------------------------------- |
| 1264 # |
| 1265 proc slave_test_script {script} { |
| 1266 |
| 1267 # Create the interpreter used to run the test script. |
| 1268 interp create tinterp |
| 1269 |
| 1270 # Populate some global variables that tester.tcl expects to see. |
| 1271 foreach {var value} [list \ |
| 1272 ::argv0 $::argv0 \ |
| 1273 ::argv {} \ |
| 1274 ::SLAVE 1 \ |
| 1275 ] { |
| 1276 interp eval tinterp [list set $var $value] |
| 1277 } |
| 1278 |
| 1279 # The alias used to access the global test counters. |
| 1280 tinterp alias set_test_counter set_test_counter |
| 1281 |
| 1282 # Set up the ::cmdlinearg array in the slave. |
| 1283 interp eval tinterp [list array set ::cmdlinearg [array get ::cmdlinearg]] |
| 1284 |
| 1285 # Set up the ::G array in the slave. |
| 1286 interp eval tinterp [list array set ::G [array get ::G]] |
| 1287 |
| 1288 # Load the various test interfaces implemented in C. |
| 1289 load_testfixture_extensions tinterp |
| 1290 |
| 1291 # Run the test script. |
| 1292 interp eval tinterp $script |
| 1293 |
| 1294 # Check if the interpreter call [run_thread_tests] |
| 1295 if { [interp eval tinterp {info exists ::run_thread_tests_called}] } { |
| 1296 set ::run_thread_tests_called 1 |
| 1297 } |
| 1298 |
| 1299 # Delete the interpreter used to run the test script. |
| 1300 interp delete tinterp |
| 1301 } |
| 1302 |
| 1303 proc slave_test_file {zFile} { |
| 1304 set tail [file tail $zFile] |
| 1305 |
| 1306 # Remember the value of the shared-cache setting. So that it is possible |
| 1307 # to check afterwards that it was not modified by the test script. |
| 1308 # |
| 1309 ifcapable shared_cache { set scs [sqlite3_enable_shared_cache] } |
| 1310 |
| 1311 # Run the test script in a slave interpreter. |
| 1312 # |
| 1313 unset -nocomplain ::run_thread_tests_called |
| 1314 reset_prng_state |
| 1315 set ::sqlite_open_file_count 0 |
| 1316 set time [time { slave_test_script [list source $zFile] }] |
| 1317 set ms [expr [lindex $time 0] / 1000] |
| 1318 |
| 1319 # Test that all files opened by the test script were closed. Omit this |
| 1320 # if the test script has "thread" in its name. The open file counter |
| 1321 # is not thread-safe. |
| 1322 # |
| 1323 if {[info exists ::run_thread_tests_called]==0} { |
| 1324 do_test ${tail}-closeallfiles { expr {$::sqlite_open_file_count>0} } {0} |
| 1325 } |
| 1326 set ::sqlite_open_file_count 0 |
| 1327 |
| 1328 # Test that the global "shared-cache" setting was not altered by |
| 1329 # the test script. |
| 1330 # |
| 1331 ifcapable shared_cache { |
| 1332 set res [expr {[sqlite3_enable_shared_cache] == $scs}] |
| 1333 do_test ${tail}-sharedcachesetting [list set {} $res] 1 |
| 1334 } |
| 1335 |
| 1336 # Add some info to the output. |
| 1337 # |
| 1338 puts "Time: $tail $ms ms" |
| 1339 show_memstats |
| 1340 } |
| 1341 |
| 1342 # Open a new connection on database test.db and execute the SQL script |
| 1343 # supplied as an argument. Before returning, close the new conection and |
| 1344 # restore the 4 byte fields starting at header offsets 28, 92 and 96 |
| 1345 # to the values they held before the SQL was executed. This simulates |
| 1346 # a write by a pre-3.7.0 client. |
| 1347 # |
| 1348 proc sql36231 {sql} { |
| 1349 set B [hexio_read test.db 92 8] |
| 1350 set A [hexio_read test.db 28 4] |
| 1351 sqlite3 db36231 test.db |
| 1352 catch { db36231 func a_string a_string } |
| 1353 execsql $sql db36231 |
| 1354 db36231 close |
| 1355 hexio_write test.db 28 $A |
| 1356 hexio_write test.db 92 $B |
| 1357 return "" |
| 1358 } |
| 1359 |
961 # If the library is compiled with the SQLITE_DEFAULT_AUTOVACUUM macro set | 1360 # If the library is compiled with the SQLITE_DEFAULT_AUTOVACUUM macro set |
962 # to non-zero, then set the global variable $AUTOVACUUM to 1. | 1361 # to non-zero, then set the global variable $AUTOVACUUM to 1. |
963 set AUTOVACUUM $sqlite_options(default_autovacuum) | 1362 set AUTOVACUUM $sqlite_options(default_autovacuum) |
964 | 1363 |
965 source $testdir/thread_common.tcl | 1364 source $testdir/thread_common.tcl |
OLD | NEW |