PageRenderTime 58ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/test/tester.tcl

https://bitbucket.org/eumario/csharp-sqlite
TCL | 1519 lines | 1177 code | 76 blank | 266 comment | 94 complexity | 96a29aa1d2071d0894983e301a69c43b MD5 | raw file
  1. # 2001 September 15
  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 some common TCL routines used for regression
  12. # testing the SQLite library
  13. #
  14. # $Id: tester.tcl,v 1.143 2009/04/09 01:23:49 drh Exp $
  15. ########################################################################
  16. # Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
  17. # C#-SQLite is an independent reimplementation of the SQLite software library
  18. #
  19. # SQLITE_SOURCE_ID: SQLITE_SOURCE_ID: 2011-05-19 13:26:54 ed1da510a239ea767a01dc332b667119fa3c908e
  20. #-------------------------------------------------------------------------
  21. # The commands provided by the code in this file to help with creating
  22. # test cases are as follows:
  23. #
  24. # Commands to manipulate the db and the file-system at a high level:
  25. #
  26. # copy_file FROM TO
  27. # drop_all_table ?DB?
  28. # forcedelete FILENAME
  29. #
  30. # Test the capability of the SQLite version built into the interpreter to
  31. # determine if a specific test can be run:
  32. #
  33. # ifcapable EXPR
  34. #
  35. # Calulate checksums based on database contents:
  36. #
  37. # dbcksum DB DBNAME
  38. # allcksum ?DB?
  39. # cksum ?DB?
  40. #
  41. # Commands to execute/explain SQL statements:
  42. #
  43. # stepsql DB SQL
  44. # execsql2 SQL
  45. # explain_no_trace SQL
  46. # explain SQL ?DB?
  47. # catchsql SQL ?DB?
  48. # execsql SQL ?DB?
  49. #
  50. # Commands to run test cases:
  51. #
  52. # do_ioerr_test TESTNAME ARGS...
  53. # crashsql ARGS...
  54. # integrity_check TESTNAME ?DB?
  55. # do_test TESTNAME SCRIPT EXPECTED
  56. # do_execsql_test TESTNAME SQL EXPECTED
  57. # do_catchsql_test TESTNAME SQL EXPECTED
  58. #
  59. # Commands providing a lower level interface to the global test counters:
  60. #
  61. # set_test_counter COUNTER ?VALUE?
  62. # omit_test TESTNAME REASON
  63. # fail_test TESTNAME
  64. # incr_ntest
  65. #
  66. # Command run at the end of each test file:
  67. #
  68. # finish_test
  69. #
  70. # Commands to help create test files that run with the "WAL" and other
  71. # permutations (see file permutations.test):
  72. #
  73. # wal_is_wal_mode
  74. # wal_set_journal_mode ?DB?
  75. # wal_check_journal_mode TESTNAME?DB?
  76. # permutation
  77. # presql
  78. #
  79. # Set the precision of FP arithmatic used by the interpreter. And
  80. # configure SQLite to take database file locks on the page that begins
  81. # 64KB into the database file instead of the one 1GB in. This means
  82. # the code that handles that special case can be tested without creating
  83. # very large database files.
  84. #
  85. set tcl_precision 15
  86. sqlite3_test_control_pending_byte 0x0010000
  87. # If the pager codec is available, create a wrapper for the [sqlite3]
  88. # command that appends "-key {xyzzy}" to the command line. i.e. this:
  89. #
  90. # sqlite3 db test.db
  91. #
  92. # becomes
  93. #
  94. # sqlite3 db test.db -key {xyzzy}
  95. #
  96. if {[info command sqlite_orig]==""} {
  97. rename sqlite3 sqlite_orig
  98. proc sqlite3 {args} {
  99. if {[llength $args]>=2 && [string index [lindex $args 0] 0]!="-"} {
  100. # This command is opening a new database connection.
  101. #
  102. if {[info exists ::G(perm:sqlite3_args)]} {
  103. set args [concat $args $::G(perm:sqlite3_args)]
  104. }
  105. if {[sqlite_orig -has-codec] && ![info exists ::do_not_use_codec]} {
  106. lappend args -key {xyzzy}
  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. if {[info exists ::G(perm:dbconfig)]} {
  113. set ::dbhandle [lindex $args 0]
  114. uplevel #0 $::G(perm:dbconfig)
  115. }
  116. set res
  117. } else {
  118. # This command is not opening a new database connection. Pass the
  119. # arguments through to the C implemenation as the are.
  120. #
  121. uplevel 1 sqlite_orig $args
  122. }
  123. }
  124. }
  125. proc execpresql {handle args} {
  126. trace remove execution $handle enter [list execpresql $handle]
  127. if {[info exists ::G(perm:presql)]} {
  128. $handle eval $::G(perm:presql)
  129. }
  130. }
  131. # This command should be called after loading tester.tcl from within
  132. # all test scripts that are incompatible with encryption codecs.
  133. #
  134. proc do_not_use_codec {} {
  135. set ::do_not_use_codec 1
  136. reset_db
  137. }
  138. # The following block only runs the first time this file is sourced. It
  139. # does not run in slave interpreters (since the ::cmdlinearg array is
  140. # populated before the test script is run in slave interpreters).
  141. #
  142. if {[info exists cmdlinearg]==0} {
  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. # --start=[$permutation:]$testfile
  154. #
  155. set cmdlinearg(soft-heap-limit) 0
  156. set cmdlinearg(maxerror) 1000
  157. set cmdlinearg(malloctrace) 0
  158. set cmdlinearg(backtrace) 10
  159. set cmdlinearg(binarylog) 0
  160. set cmdlinearg(soak) 0
  161. set cmdlinearg(start) ""
  162. set leftover [list]
  163. foreach a $argv {
  164. switch -regexp -- $a {
  165. {^-+pause$} {
  166. # Wait for user input before continuing. This is to give the user an
  167. # opportunity to connect profiling tools to the process.
  168. puts -nonewline "Press RETURN to begin..."
  169. flush stdout
  170. gets stdin
  171. }
  172. {^-+soft-heap-limit=.+$} {
  173. foreach {dummy cmdlinearg(soft-heap-limit)} [split $a =] break
  174. }
  175. {^-+maxerror=.+$} {
  176. foreach {dummy cmdlinearg(maxerror)} [split $a =] break
  177. }
  178. {^-+malloctrace=.+$} {
  179. foreach {dummy cmdlinearg(malloctrace)} [split $a =] break
  180. if {$cmdlinearg(malloctrace)} {
  181. sqlite3_memdebug_log start
  182. }
  183. }
  184. {^-+backtrace=.+$} {
  185. foreach {dummy cmdlinearg(backtrace)} [split $a =] break
  186. sqlite3_memdebug_backtrace $value
  187. }
  188. {^-+binarylog=.+$} {
  189. foreach {dummy cmdlinearg(binarylog)} [split $a =] break
  190. }
  191. {^-+soak=.+$} {
  192. foreach {dummy cmdlinearg(soak)} [split $a =] break
  193. set ::G(issoak) $cmdlinearg(soak)
  194. }
  195. {^-+start=.+$} {
  196. foreach {dummy cmdlinearg(start)} [split $a =] break
  197. set ::G(start:file) $cmdlinearg(start)
  198. if {[regexp {(.*):(.*)} $cmdlinearg(start) -> s.perm s.file]} {
  199. set ::G(start:permutation) ${s.perm}
  200. set ::G(start:file) ${s.file}
  201. }
  202. if {$::G(start:file) == ""} {unset ::G(start:file)}
  203. }
  204. default {
  205. lappend leftover $a
  206. }
  207. }
  208. }
  209. set argv $leftover
  210. # Install the malloc layer used to inject OOM errors. And the 'automatic'
  211. # extensions. This only needs to be done once for the process.
  212. #
  213. sqlite3_shutdown
  214. ################################
  215. # not implemented in C#-SQLite #
  216. ################################
  217. # install_malloc_faultsim 1
  218. ################################
  219. sqlite3_initialize
  220. autoinstall_test_functions
  221. # If the --binarylog option was specified, create the logging VFS. This
  222. # call installs the new VFS as the default for all SQLite connections.
  223. #
  224. if {$cmdlinearg(binarylog)} {
  225. vfslog new binarylog {} vfslog.bin
  226. }
  227. # Set the backtrace depth, if malloc tracing is enabled.
  228. #
  229. if {$cmdlinearg(malloctrace)} {
  230. sqlite3_memdebug_backtrace $cmdlinearg(backtrace)
  231. }
  232. }
  233. # Update the soft-heap-limit each time this script is run. In that
  234. # way if an individual test file changes the soft-heap-limit, it
  235. # will be reset at the start of the next test file.
  236. #
  237. sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit)
  238. # Create a test database
  239. #
  240. proc reset_db {} {
  241. catch {db close}
  242. file delete -force test.db
  243. file delete -force test.db-journal
  244. file delete -force test.db-wal
  245. sqlite3 db ./test.db
  246. set ::DB [sqlite3_connection_pointer db]
  247. if {[info exists ::SETUP_SQL]} {
  248. db eval $::SETUP_SQL
  249. }
  250. }
  251. reset_db
  252. # Abort early if this script has been run before.
  253. #
  254. if {[info exists TC(count)]} return
  255. # Make sure memory statistics are enabled.
  256. #
  257. sqlite3_config_memstatus 1
  258. # Initialize the test counters and set up commands to access them.
  259. # Or, if this is a slave interpreter, set up aliases to write the
  260. # counters in the parent interpreter.
  261. #
  262. if {0==[info exists ::SLAVE]} {
  263. set TC(errors) 0
  264. set TC(count) 0
  265. set TC(fail_list) [list]
  266. set TC(omit_list) [list]
  267. proc set_test_counter {counter args} {
  268. if {[llength $args]} {
  269. set ::TC($counter) [lindex $args 0]
  270. }
  271. set ::TC($counter)
  272. }
  273. }
  274. # Record the fact that a sequence of tests were omitted.
  275. #
  276. proc omit_test {name reason} {
  277. set omitList [set_test_counter omit_list]
  278. lappend omitList [list $name $reason]
  279. set_test_counter omit_list $omitList
  280. }
  281. # Record the fact that a test failed.
  282. #
  283. proc fail_test {name} {
  284. set f [set_test_counter fail_list]
  285. lappend f $name
  286. set_test_counter fail_list $f
  287. set_test_counter errors [expr [set_test_counter errors] + 1]
  288. set nFail [set_test_counter errors]
  289. if {$nFail>=$::cmdlinearg(maxerror)} {
  290. puts "*** Giving up..."
  291. finalize_testing
  292. }
  293. }
  294. # Increment the number of tests run
  295. #
  296. proc incr_ntest {} {
  297. set_test_counter count [expr [set_test_counter count] + 1]
  298. }
  299. # Invoke the do_test procedure to run a single test
  300. #
  301. proc do_test {name cmd expected} {
  302. global argv cmdlinearg
  303. fix_testname name
  304. sqlite3_memdebug_settitle $name
  305. # if {[llength $argv]==0} {
  306. # set go 1
  307. # } else {
  308. # set go 0
  309. # foreach pattern $argv {
  310. # if {[string match $pattern $name]} {
  311. # set go 1
  312. # break
  313. # }
  314. # }
  315. # }
  316. if {[info exists ::G(perm:prefix)]} {
  317. set name "$::G(perm:prefix)$name"
  318. }
  319. incr_ntest
  320. puts -nonewline $name...
  321. flush stdout
  322. if {[catch {uplevel #0 "$cmd;\n"} result]} {
  323. puts "\nError: $result"
  324. fail_test $name
  325. } else {
  326. #
  327. # TCL implementation BUG can return {{}} for empty string
  328. # 2011-06-11 Noah Hart -- To be fixed
  329. #
  330. set REPLACE "{{}} "
  331. regsub -all $REPLACE $expected "" expected
  332. regsub -all $REPLACE $result "" result
  333. set REPLACE "{{}}"
  334. regsub -all $REPLACE $expected "" expected
  335. regsub -all $REPLACE $result "" result
  336. if {[string compare $result $expected]} {
  337. set WHITESPACE "{} \t\r\n" ;# white space & Extra braces
  338. set REPLACE "(\[$WHITESPACE])"
  339. regsub -all $REPLACE $expected "" testEXP
  340. regsub -all $REPLACE $result "" testRES
  341. if { [string compare $testRES $testEXP]} {
  342. puts "\nExpected: \[$expected\]\n Got: \[$result\]"
  343. fail_test $name
  344. } else {
  345. puts " Ok"
  346. }
  347. } else {
  348. puts " Ok"
  349. }
  350. }
  351. flush stdout
  352. }
  353. # Implemented in the changes in Tcl/Tk 8.5 as part of TIP #272[1].
  354. # Downward compatible pure-Tcl version:
  355. proc lreverse list {
  356. set res {}
  357. set i [llength $list]
  358. while {$i > 0} {lappend res [lindex $list [incr i -1]]}
  359. set res
  360. } ;# RS
  361. proc filepath_normalize {p} {
  362. # test cases should be written to assume "unix"-like file paths
  363. if {$::tcl_platform(platform)!="unix"} {
  364. # lreverse*2 as a hack to remove any unneeded {} after the string map
  365. lreverse [lreverse [string map {\\ /} [regsub -nocase -all {[a-z]:[/\\]+} $p {/}]]]
  366. } {
  367. set p
  368. }
  369. }
  370. proc do_filepath_test {name cmd expected} {
  371. uplevel [list do_test $name [
  372. subst -nocommands { filepath_normalize [ $cmd ] }
  373. ] [filepath_normalize $expected]]
  374. }
  375. proc realnum_normalize {r} {
  376. # different TCL versions display floating point values differently.
  377. string map {1.#INF inf Inf inf .0e e} [regsub -all {(e[+-])0+} $r {\1}]
  378. }
  379. proc do_realnum_test {name cmd expected} {
  380. uplevel [list do_test $name [
  381. subst -nocommands { realnum_normalize [ $cmd ] }
  382. ] [realnum_normalize $expected]]
  383. }
  384. proc fix_testname {varname} {
  385. upvar $varname testname
  386. if {[info exists ::testprefix]
  387. && [string is digit [string range $testname 0 0]]
  388. } {
  389. set testname "${::testprefix}-$testname"
  390. }
  391. }
  392. proc do_execsql_test {testname sql {result {}}} {
  393. fix_testname testname
  394. uplevel do_test [list $testname] [list "execsql {$sql}"] [list [list {*}$result]]
  395. }
  396. proc do_catchsql_test {testname sql result} {
  397. fix_testname testname
  398. uplevel do_test [list $testname] [list "catchsql {$sql}"] [list $result]
  399. }
  400. proc do_eqp_test {name sql res} {
  401. uplevel do_execsql_test $name [list "EXPLAIN QUERY PLAN $sql"] [list $res]
  402. }
  403. #-------------------------------------------------------------------------
  404. # Usage: do_select_tests PREFIX ?SWITCHES? TESTLIST
  405. #
  406. # Where switches are:
  407. #
  408. # -errorformat FMTSTRING
  409. # -count
  410. # -query SQL
  411. # -tclquery TCL
  412. # -repair TCL
  413. #
  414. proc do_select_tests {prefix args} {
  415. set testlist [lindex $args end]
  416. set switches [lrange $args 0 end-1]
  417. set errfmt ""
  418. set countonly 0
  419. set tclquery ""
  420. set repair ""
  421. for {set i 0} {$i < [llength $switches]} {incr i} {
  422. set s [lindex $switches $i]
  423. set n [string length $s]
  424. if {$n>=2 && [string equal -length $n $s "-query"]} {
  425. set tclquery [list execsql [lindex $switches [incr i]]]
  426. } elseif {$n>=2 && [string equal -length $n $s "-tclquery"]} {
  427. set tclquery [lindex $switches [incr i]]
  428. } elseif {$n>=2 && [string equal -length $n $s "-errorformat"]} {
  429. set errfmt [lindex $switches [incr i]]
  430. } elseif {$n>=2 && [string equal -length $n $s "-repair"]} {
  431. set repair [lindex $switches [incr i]]
  432. } elseif {$n>=2 && [string equal -length $n $s "-count"]} {
  433. set countonly 1
  434. } else {
  435. error "unknown switch: $s"
  436. }
  437. }
  438. if {$countonly && $errfmt!=""} {
  439. error "Cannot use -count and -errorformat together"
  440. }
  441. set nTestlist [llength $testlist]
  442. if {$nTestlist%3 || $nTestlist==0 } {
  443. error "SELECT test list contains [llength $testlist] elements"
  444. }
  445. eval $repair
  446. foreach {tn sql res} $testlist {
  447. if {$tclquery != ""} {
  448. execsql $sql
  449. uplevel do_test ${prefix}.$tn [list $tclquery] [list [list {*}$res]]
  450. } elseif {$countonly} {
  451. set nRow 0
  452. db eval $sql {incr nRow}
  453. uplevel do_test ${prefix}.$tn [list [list set {} $nRow]] [list $res]
  454. } elseif {$errfmt==""} {
  455. uplevel do_execsql_test ${prefix}.${tn} [list $sql] [list [list {*}$res]]
  456. } else {
  457. set res [list 1 [string trim [format $errfmt {*}$res]]]
  458. uplevel do_catchsql_test ${prefix}.${tn} [list $sql] [list $res]
  459. }
  460. eval $repair
  461. }
  462. }
  463. proc delete_all_data {} {
  464. db eval {SELECT tbl_name AS t FROM sqlite_master WHERE type = 'table'} {
  465. db eval "DELETE FROM '[string map {' ''} $t]'"
  466. }
  467. }
  468. # Run an SQL script.
  469. # Return the number of microseconds per statement.
  470. #
  471. proc speed_trial {name numstmt units sql} {
  472. puts -nonewline [format {%-21.21s } $name...]
  473. flush stdout
  474. set speed [time {sqlite3_exec_nr db $sql}]
  475. set tm [lindex $speed 0]
  476. if {$tm == 0} {
  477. set rate [format %20s "many"]
  478. } else {
  479. set rate [format %20.5f [expr {1000000.0*$numstmt/$tm}]]
  480. }
  481. set u2 $units/s
  482. puts [format {%12d uS %s %s} $tm $rate $u2]
  483. global total_time
  484. set total_time [expr {$total_time+$tm}]
  485. lappend ::speed_trial_times $name $tm
  486. }
  487. proc speed_trial_tcl {name numstmt units script} {
  488. puts -nonewline [format {%-21.21s } $name...]
  489. flush stdout
  490. set speed [time {eval $script}]
  491. set tm [lindex $speed 0]
  492. if {$tm == 0} {
  493. set rate [format %20s "many"]
  494. } else {
  495. set rate [format %20.5f [expr {1000000.0*$numstmt/$tm}]]
  496. }
  497. set u2 $units/s
  498. puts [format {%12d uS %s %s} $tm $rate $u2]
  499. global total_time
  500. set total_time [expr {$total_time+$tm}]
  501. lappend ::speed_trial_times $name $tm
  502. }
  503. proc speed_trial_init {name} {
  504. global total_time
  505. set total_time 0
  506. set ::speed_trial_times [list]
  507. sqlite3 versdb :memory:
  508. set vers [versdb one {SELECT sqlite_source_id()}]
  509. versdb close
  510. puts "SQLite $vers"
  511. }
  512. proc speed_trial_summary {name} {
  513. global total_time
  514. puts [format {%-21.21s %12d uS TOTAL} $name $total_time]
  515. if { 0 } {
  516. sqlite3 versdb :memory:
  517. set vers [lindex [versdb one {SELECT sqlite_source_id()}] 0]
  518. versdb close
  519. puts "CREATE TABLE IF NOT EXISTS time(version, script, test, us);"
  520. foreach {test us} $::speed_trial_times {
  521. puts "INSERT INTO time VALUES('$vers', '$name', '$test', $us);"
  522. }
  523. }
  524. }
  525. # Run this routine last
  526. #
  527. proc finish_test {} {
  528. catch {db close}
  529. catch {db2 close}
  530. catch {db3 close}
  531. if {0==[info exists ::SLAVE]} { finalize_testing }
  532. }
  533. proc finalize_testing {} {
  534. global sqlite_open_file_count
  535. set omitList [set_test_counter omit_list]
  536. catch {db close}
  537. catch {db2 close}
  538. catch {db3 close}
  539. vfs_unlink_test
  540. sqlite3 db {}
  541. # sqlite3_clear_tsd_memdebug
  542. db close
  543. sqlite3_reset_auto_extension
  544. sqlite3_soft_heap_limit 0
  545. set nTest [incr_ntest]
  546. set nErr [set_test_counter errors]
  547. puts "$nErr errors out of $nTest tests"
  548. if {$nErr>0} {
  549. puts "Failures on these tests: [set_test_counter fail_list]"
  550. }
  551. run_thread_tests 1
  552. if {[llength $omitList]>0} {
  553. puts "Omitted test cases:"
  554. set prec {}
  555. foreach {rec} [lsort $omitList] {
  556. if {$rec==$prec} continue
  557. set prec $rec
  558. puts [format { %-12s %s} [lindex $rec 0] [lindex $rec 1]]
  559. }
  560. }
  561. if {$nErr>0 && ![working_64bit_int]} {
  562. puts "******************************************************************"
  563. puts "N.B.: The version of TCL that you used to build this test harness"
  564. puts "is defective in that it does not support 64-bit integers. Some or"
  565. puts "all of the test failures above might be a result from this defect"
  566. puts "in your TCL build."
  567. puts "******************************************************************"
  568. }
  569. if {$::cmdlinearg(binarylog)} {
  570. vfslog finalize binarylog
  571. }
  572. if {$sqlite_open_file_count} {
  573. puts "$sqlite_open_file_count files were left open"
  574. incr nErr
  575. }
  576. ifcapable malloc {
  577. if {[lindex [sqlite3_status SQLITE_STATUS_MALLOC_COUNT 0] 1]>0 ||
  578. [sqlite3_memory_used]>0} {
  579. puts "Unfreed memory: [sqlite3_memory_used] bytes in\
  580. [lindex [sqlite3_status SQLITE_STATUS_MALLOC_COUNT 0] 1] allocations"
  581. incr nErr
  582. ifcapable memdebug||mem5||(mem3&&debug) {
  583. puts "Writing unfreed memory log to \"./memleak.txt\""
  584. sqlite3_memdebug_dump ./memleak.txt
  585. }
  586. } else {
  587. puts "All memory allocations freed - no leaks"
  588. ifcapable memdebug||mem5 {
  589. sqlite3_memdebug_dump ./memusage.txt
  590. }
  591. }
  592. show_memstats
  593. #puts "Maximum memory usage: [sqlite3_memory_highwater 1] bytes"
  594. #puts "Current memory usage: [sqlite3_memory_highwater] bytes"
  595. if {[info commands sqlite3_memdebug_malloc_count] ne ""} {
  596. puts "Number of malloc() : [sqlite3_memdebug_malloc_count] calls"
  597. }
  598. if {$::cmdlinearg(malloctrace)} {
  599. puts "Writing mallocs.sql..."
  600. memdebug_log_sql
  601. sqlite3_memdebug_log stop
  602. sqlite3_memdebug_log clear
  603. if {[sqlite3_memory_used]>0} {
  604. puts "Writing leaks.sql..."
  605. sqlite3_memdebug_log sync
  606. memdebug_log_sql leaks.sql
  607. }
  608. }
  609. } else {
  610. puts "Memory usage not tracked"
  611. }
  612. foreach f [glob -nocomplain test.db-*-journal] {
  613. file delete -force $f
  614. }
  615. foreach f [glob -nocomplain test.db-mj*] {
  616. file delete -force $f
  617. }
  618. puts -nonewline "Press RETURN to exit..."; gets stdin
  619. exit [expr {$nErr>0}]
  620. }
  621. # Display memory statistics for analysis and debugging purposes.
  622. #
  623. proc show_memstats {} {
  624. set x [sqlite3_status SQLITE_STATUS_MEMORY_USED 0]
  625. set y [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0]
  626. set val [format {now %10d max %10d max-size %10d} \
  627. [lindex $x 1] [lindex $x 2] [lindex $y 2]]
  628. puts "Memory used: $val"
  629. set x [sqlite3_status SQLITE_STATUS_MALLOC_COUNT 0]
  630. set val [format {now %10d max %10d} [lindex $x 1] [lindex $x 2]]
  631. puts "Allocation count: $val"
  632. set x [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0]
  633. set y [sqlite3_status SQLITE_STATUS_PAGECACHE_SIZE 0]
  634. set val [format {now %10d max %10d max-size %10d} \
  635. [lindex $x 1] [lindex $x 2] [lindex $y 2]]
  636. puts "Page-cache used: $val"
  637. set x [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0]
  638. set val [format {now %10d max %10d} [lindex $x 1] [lindex $x 2]]
  639. puts "Page-cache overflow: $val"
  640. set x [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0]
  641. set val [format {now %10d max %10d} [lindex $x 1] [lindex $x 2]]
  642. puts "Scratch memory used: $val"
  643. set x [sqlite3_status SQLITE_STATUS_SCRATCH_OVERFLOW 0]
  644. set y [sqlite3_status SQLITE_STATUS_SCRATCH_SIZE 0]
  645. set val [format {now %10d max %10d max-size %10d} \
  646. [lindex $x 1] [lindex $x 2] [lindex $y 2]]
  647. puts "Scratch overflow: $val"
  648. ifcapable yytrackmaxstackdepth {
  649. set x [sqlite3_status SQLITE_STATUS_PARSER_STACK 0]
  650. set val [format { max %10d} [lindex $x 2]]
  651. puts "Parser stack depth: $val"
  652. }
  653. }
  654. # A procedure to execute SQL
  655. #
  656. proc execsql {sql {db db}} {
  657. # puts "SQL = $sql"
  658. uplevel [list $db eval $sql]
  659. }
  660. # Execute SQL and catch exceptions.
  661. #
  662. proc catchsql {sql {db db}} {
  663. # puts "SQL = $sql"
  664. set r [catch [list uplevel [list $db eval $sql]] msg]
  665. lappend r $msg
  666. return $r
  667. }
  668. # Do an VDBE code dump on the SQL given
  669. #
  670. proc explain {sql {db db}} {
  671. puts ""
  672. puts "addr opcode p1 p2 p3 p4 p5 #"
  673. puts "---- ------------ ------ ------ ------ --------------- -- -"
  674. $db eval "explain $sql" {} {
  675. puts [format {%-4d %-12.12s %-6d %-6d %-6d % -17s %s %s} \
  676. $addr $opcode $p1 $p2 $p3 $p4 $p5 $comment
  677. ]
  678. }
  679. }
  680. # Show the VDBE program for an SQL statement but omit the Trace
  681. # opcode at the beginning. This procedure can be used to prove
  682. # that different SQL statements generate exactly the same VDBE code.
  683. #
  684. proc explain_no_trace {sql} {
  685. set tr [db eval "EXPLAIN $sql"]
  686. return [lrange $tr 7 end]
  687. }
  688. # Another procedure to execute SQL. This one includes the field
  689. # names in the returned list.
  690. #
  691. proc execsql2 {sql} {
  692. set result {}
  693. db eval $sql data {
  694. foreach f $data(*) {
  695. lappend result $f $data($f)
  696. }
  697. }
  698. return $result
  699. }
  700. # Use the non-callback API to execute multiple SQL statements
  701. #
  702. proc stepsql {dbptr sql} {
  703. set sql [string trim $sql]
  704. set r 0
  705. while {[string length $sql]>0} {
  706. if {[catch {sqlite3_prepare $dbptr $sql -1 sqltail} vm]} {
  707. return [list 1 $vm]
  708. }
  709. set sql [string trim $sqltail]
  710. # while {[sqlite_step $vm N VAL COL]=="SQLITE_ROW"} {
  711. # foreach v $VAL {lappend r $v}
  712. # }
  713. while {[sqlite3_step $vm]=="SQLITE_ROW"} {
  714. for {set i 0} {$i<[sqlite3_data_count $vm]} {incr i} {
  715. lappend r [sqlite3_column_text $vm $i]
  716. }
  717. }
  718. if {[catch {sqlite3_finalize $vm} errmsg]} {
  719. return [list 1 $errmsg]
  720. }
  721. }
  722. return $r
  723. }
  724. # Delete a file or directory
  725. #
  726. proc forcedelete {args} {
  727. foreach filename $args {
  728. # On windows, sometimes even a [file delete -force] can fail just after
  729. # a file is closed. The cause is usually "tag-alongs" - programs like
  730. # anti-virus software, automatic backup tools and various explorer
  731. # extensions that keep a file open a little longer than we expect, causing
  732. # the delete to fail.
  733. #
  734. # The solution is to wait a short amount of time before retrying the
  735. # delete.
  736. #
  737. set nRetry 50 ;# Maximum number of retries.
  738. set nDelay 100 ;# Delay in ms before retrying.
  739. for {set i 0} {$i<$nRetry} {incr i} {
  740. set rc [catch {file delete -force $filename} msg]
  741. if {$rc==0} break
  742. after $nDelay
  743. }
  744. if {$rc} { error $msg }
  745. }
  746. }
  747. # Do an integrity check of the entire database
  748. #
  749. proc integrity_check {name {db db}} {
  750. ifcapable integrityck {
  751. do_test $name [list execsql {PRAGMA integrity_check} $db] {ok}
  752. }
  753. }
  754. # Return true if the SQL statement passed as the second argument uses a
  755. # statement transaction.
  756. #
  757. proc sql_uses_stmt {db sql} {
  758. set stmt [sqlite3_prepare $db $sql -1 dummy]
  759. set uses [uses_stmt_journal $stmt]
  760. sqlite3_finalize $stmt
  761. return $uses
  762. }
  763. proc fix_ifcapable_expr {expr} {
  764. set ret ""
  765. set state 0
  766. for {set i 0} {$i < [string length $expr]} {incr i} {
  767. set char [string range $expr $i $i]
  768. set newstate [expr {[string is alnum $char] || $char eq "_"}]
  769. if {$newstate && !$state} {
  770. append ret {$::sqlite_options(}
  771. }
  772. if {!$newstate && $state} {
  773. append ret )
  774. }
  775. append ret $char
  776. set state $newstate
  777. }
  778. if {$state} {append ret )}
  779. return $ret
  780. }
  781. # Evaluate a boolean expression of capabilities. If true, execute the
  782. # code. Omit the code if false.
  783. #
  784. proc ifcapable {expr code {else ""} {elsecode ""}} {
  785. #regsub -all {[a-z_0-9]+} $expr {$::sqlite_options(&)} e2
  786. set e2 [fix_ifcapable_expr $expr]
  787. if ($e2) {
  788. set c [catch {uplevel 1 $code} r]
  789. } else {
  790. set c [catch {uplevel 1 $elsecode} r]
  791. }
  792. return -code $c $r
  793. }
  794. # This proc execs a seperate process that crashes midway through executing
  795. # the SQL script $sql on database test.db.
  796. #
  797. # The crash occurs during a sync() of file $crashfile. When the crash
  798. # occurs a random subset of all unsynced writes made by the process are
  799. # written into the files on disk. Argument $crashdelay indicates the
  800. # number of file syncs to wait before crashing.
  801. #
  802. # The return value is a list of two elements. The first element is a
  803. # boolean, indicating whether or not the process actually crashed or
  804. # reported some other error. The second element in the returned list is the
  805. # error message. This is "child process exited abnormally" if the crash
  806. # occured.
  807. #
  808. # crashsql -delay CRASHDELAY -file CRASHFILE ?-blocksize BLOCKSIZE? $sql
  809. #
  810. proc crashsql {args} {
  811. set blocksize ""
  812. set crashdelay 1
  813. set prngseed 0
  814. set tclbody {}
  815. set crashfile ""
  816. set dc ""
  817. set sql [lindex $args end]
  818. for {set ii 0} {$ii < [llength $args]-1} {incr ii 2} {
  819. set z [lindex $args $ii]
  820. set n [string length $z]
  821. set z2 [lindex $args [expr $ii+1]]
  822. if {$n>1 && [string first $z -delay]==0} {set crashdelay $z2} \
  823. elseif {$n>1 && [string first $z -seed]==0} {set prngseed $z2} \
  824. elseif {$n>1 && [string first $z -file]==0} {set crashfile $z2} \
  825. elseif {$n>1 && [string first $z -tclbody]==0} {set tclbody $z2} \
  826. elseif {$n>1 && [string first $z -blocksize]==0} {set blocksize "-s $z2" } \
  827. elseif {$n>1 && [string first $z -characteristics]==0} {set dc "-c {$z2}" } \
  828. else { error "Unrecognized option: $z" }
  829. }
  830. if {$crashfile eq ""} {
  831. error "Compulsory option -file missing"
  832. }
  833. # $crashfile gets compared to the native filename in
  834. # cfSync(), which can be different then what TCL uses by
  835. # default, so here we force it to the "nativename" format.
  836. set cfile [string map {\\ \\\\} [file nativename [file join [pwd] $crashfile]]]
  837. set f [open crash.tcl w]
  838. puts $f "sqlite3_crash_enable 1"
  839. puts $f "sqlite3_crashparams $blocksize $dc $crashdelay $cfile"
  840. puts $f "sqlite3_test_control_pending_byte $::sqlite_pending_byte"
  841. puts $f "sqlite3 db test.db -vfs crash"
  842. # This block sets the cache size of the main database to 10
  843. # pages. This is done in case the build is configured to omit
  844. # "PRAGMA cache_size".
  845. puts $f {db eval {SELECT * FROM sqlite_master;}}
  846. puts $f {set bt [btree_from_db db]}
  847. puts $f {btree_set_cache_size $bt 10}
  848. if {$prngseed} {
  849. set seed [expr {$prngseed%10007+1}]
  850. # puts seed=$seed
  851. puts $f "db eval {SELECT randomblob($seed)}"
  852. }
  853. if {[string length $tclbody]>0} {
  854. puts $f $tclbody
  855. }
  856. if {[string length $sql]>0} {
  857. puts $f "db eval {"
  858. puts $f "$sql"
  859. puts $f "}"
  860. }
  861. close $f
  862. set r [catch {
  863. exec [info nameofexec] crash.tcl >@stdout
  864. } msg]
  865. # Windows/ActiveState TCL returns a slightly different
  866. # error message. We map that to the expected message
  867. # so that we don't have to change all of the test
  868. # cases.
  869. if {$::tcl_platform(platform)=="windows"} {
  870. if {$msg=="child killed: unknown signal"} {
  871. set msg "child process exited abnormally"
  872. }
  873. }
  874. lappend r $msg
  875. }
  876. # Usage: do_ioerr_test <test number> <options...>
  877. #
  878. # This proc is used to implement test cases that check that IO errors
  879. # are correctly handled. The first argument, <test number>, is an integer
  880. # used to name the tests executed by this proc. Options are as follows:
  881. #
  882. # -tclprep TCL script to run to prepare test.
  883. # -sqlprep SQL script to run to prepare test.
  884. # -tclbody TCL script to run with IO error simulation.
  885. # -sqlbody TCL script to run with IO error simulation.
  886. # -exclude List of 'N' values not to test.
  887. # -erc Use extended result codes
  888. # -persist Make simulated I/O errors persistent
  889. # -start Value of 'N' to begin with (default 1)
  890. #
  891. # -cksum Boolean. If true, test that the database does
  892. # not change during the execution of the test case.
  893. #
  894. proc do_ioerr_test {testname args} {
  895. set ::ioerropts(-start) 1
  896. set ::ioerropts(-cksum) 0
  897. set ::ioerropts(-erc) 0
  898. set ::ioerropts(-count) 100000000
  899. set ::ioerropts(-persist) 1
  900. set ::ioerropts(-ckrefcount) 0
  901. set ::ioerropts(-restoreprng) 1
  902. array set ::ioerropts $args
  903. # TEMPORARY: For 3.5.9, disable testing of extended result codes. There are
  904. # a couple of obscure IO errors that do not return them.
  905. set ::ioerropts(-erc) 0
  906. set ::go 1
  907. #reset_prng_state
  908. save_prng_state
  909. for {set n $::ioerropts(-start)} {$::go} {incr n} {
  910. set ::TN $n
  911. incr ::ioerropts(-count) -1
  912. if {$::ioerropts(-count)<0} break
  913. # Skip this IO error if it was specified with the "-exclude" option.
  914. if {[info exists ::ioerropts(-exclude)]} {
  915. if {[lsearch $::ioerropts(-exclude) $n]!=-1} continue
  916. }
  917. if {$::ioerropts(-restoreprng)} {
  918. restore_prng_state
  919. }
  920. # Delete the files test.db and test2.db, then execute the TCL and
  921. # SQL (in that order) to prepare for the test case.
  922. do_test $testname.$n.1 {
  923. set ::sqlite_io_error_pending 0
  924. catch {db close}
  925. catch {db2 close}
  926. catch {file delete -force test.db}
  927. catch {file delete -force test.db-journal}
  928. catch {file delete -force test2.db}
  929. catch {file delete -force test2.db-journal}
  930. set ::DB [sqlite3 db test.db; sqlite3_connection_pointer db]
  931. sqlite3_extended_result_codes $::DB $::ioerropts(-erc)
  932. if {[info exists ::ioerropts(-tclprep)]} {
  933. eval $::ioerropts(-tclprep)
  934. }
  935. if {[info exists ::ioerropts(-sqlprep)]} {
  936. execsql $::ioerropts(-sqlprep)
  937. }
  938. expr 0
  939. } {0}
  940. # Read the 'checksum' of the database.
  941. if {$::ioerropts(-cksum)} {
  942. set checksum [cksum]
  943. }
  944. # Set the Nth IO error to fail.
  945. do_test $testname.$n.2 [subst {
  946. set ::sqlite_io_error_persist $::ioerropts(-persist)
  947. set ::sqlite_io_error_pending $n
  948. }] $n
  949. # Create a single TCL script from the TCL and SQL specified
  950. # as the body of the test.
  951. set ::ioerrorbody {}
  952. if {[info exists ::ioerropts(-tclbody)]} {
  953. append ::ioerrorbody "$::ioerropts(-tclbody)\n"
  954. }
  955. if {[info exists ::ioerropts(-sqlbody)]} {
  956. append ::ioerrorbody "db eval {$::ioerropts(-sqlbody)}"
  957. }
  958. # Execute the TCL Script created in the above block. If
  959. # there are at least N IO operations performed by SQLite as
  960. # a result of the script, the Nth will fail.
  961. do_test $testname.$n.3 {
  962. set ::sqlite_io_error_hit 0
  963. set ::sqlite_io_error_hardhit 0
  964. set r [catch $::ioerrorbody msg]
  965. set ::errseen $r
  966. set rc [sqlite3_errcode $::DB]
  967. if {$::ioerropts(-erc)} {
  968. # If we are in extended result code mode, make sure all of the
  969. # IOERRs we get back really do have their extended code values.
  970. # If an extended result code is returned, the sqlite3_errcode
  971. # TCLcommand will return a string of the form: SQLITE_IOERR+nnnn
  972. # where nnnn is a number
  973. if {[regexp {^SQLITE_IOERR} $rc] && ![regexp {IOERR\+\d} $rc]} {
  974. return $rc
  975. }
  976. } else {
  977. # If we are not in extended result code mode, make sure no
  978. # extended error codes are returned.
  979. if {[regexp {\+\d} $rc]} {
  980. return $rc
  981. }
  982. }
  983. # The test repeats as long as $::go is non-zero. $::go starts out
  984. # as 1. When a test runs to completion without hitting an I/O
  985. # error, that means there is no point in continuing with this test
  986. # case so set $::go to zero.
  987. #
  988. if {$::sqlite_io_error_pending>0} {
  989. set ::go 0
  990. set q 0
  991. set ::sqlite_io_error_pending 0
  992. } else {
  993. set q 1
  994. }
  995. set s [expr $::sqlite_io_error_hit==0]
  996. if {$::sqlite_io_error_hit>$::sqlite_io_error_hardhit && $r==0} {
  997. set r 1
  998. }
  999. set ::sqlite_io_error_hit 0
  1000. # One of two things must have happened. either
  1001. # 1. We never hit the IO error and the SQL returned OK
  1002. # 2. An IO error was hit and the SQL failed
  1003. #
  1004. #puts "s=$s r=$r q=$q"
  1005. expr { ($s && !$r && !$q) || (!$s && $r && $q) }
  1006. } {1}
  1007. set ::sqlite_io_error_hit 0
  1008. set ::sqlite_io_error_pending 0
  1009. # Check that no page references were leaked. There should be
  1010. # a single reference if there is still an active transaction,
  1011. # or zero otherwise.
  1012. #
  1013. # UPDATE: If the IO error occurs after a 'BEGIN' but before any
  1014. # locks are established on database files (i.e. if the error
  1015. # occurs while attempting to detect a hot-journal file), then
  1016. # there may 0 page references and an active transaction according
  1017. # to [sqlite3_get_autocommit].
  1018. #
  1019. if {$::go && $::sqlite_io_error_hardhit && $::ioerropts(-ckrefcount)} {
  1020. do_test $testname.$n.4 {
  1021. set bt [btree_from_db db]
  1022. db_enter db
  1023. array set stats [btree_pager_stats $bt]
  1024. db_leave db
  1025. set nRef $stats(ref)
  1026. expr {$nRef == 0 || ([sqlite3_get_autocommit db]==0 && $nRef == 1)}
  1027. } {1}
  1028. }
  1029. # If there is an open database handle and no open transaction,
  1030. # and the pager is not running in exclusive-locking mode,
  1031. # check that the pager is in "unlocked" state. Theoretically,
  1032. # if a call to xUnlock() failed due to an IO error the underlying
  1033. # file may still be locked.
  1034. #
  1035. ifcapable pragma {
  1036. if { [info commands db] ne ""
  1037. && $::ioerropts(-ckrefcount)
  1038. && [db one {pragma locking_mode}] eq "normal"
  1039. && [sqlite3_get_autocommit db]
  1040. } {
  1041. do_test $testname.$n.5 {
  1042. set bt [btree_from_db db]
  1043. db_enter db
  1044. array set stats [btree_pager_stats $bt]
  1045. db_leave db
  1046. set stats(state)
  1047. } 0
  1048. }
  1049. }
  1050. # If an IO error occured, then the checksum of the database should
  1051. # be the same as before the script that caused the IO error was run.
  1052. #
  1053. if {$::go && $::sqlite_io_error_hardhit && $::ioerropts(-cksum)} {
  1054. do_test $testname.$n.6 {
  1055. catch {db close}
  1056. catch {db2 close}
  1057. set ::DB [sqlite3 db test.db; sqlite3_connection_pointer db]
  1058. cksum
  1059. } $checksum
  1060. }
  1061. set ::sqlite_io_error_hardhit 0
  1062. set ::sqlite_io_error_pending 0
  1063. if {[info exists ::ioerropts(-cleanup)]} {
  1064. catch $::ioerropts(-cleanup)
  1065. }
  1066. }
  1067. set ::sqlite_io_error_pending 0
  1068. set ::sqlite_io_error_persist 0
  1069. unset ::ioerropts
  1070. }
  1071. # Return a checksum based on the contents of the main database associated
  1072. # with connection $db
  1073. #
  1074. proc cksum {{db db}} {
  1075. set txt [$db eval {
  1076. SELECT name, type, sql FROM sqlite_master order by name
  1077. }]\n
  1078. foreach tbl [$db eval {
  1079. SELECT name FROM sqlite_master WHERE type='table' order by name
  1080. }] {
  1081. append txt [$db eval "SELECT * FROM $tbl"]\n
  1082. }
  1083. foreach prag {default_synchronous default_cache_size} {
  1084. append txt $prag-[$db eval "PRAGMA $prag"]\n
  1085. }
  1086. set cksum [string length $txt]-[md5 $txt]
  1087. # puts $cksum-[file size test.db]
  1088. return $cksum
  1089. }
  1090. # Generate a checksum based on the contents of the main and temp tables
  1091. # database $db. If the checksum of two databases is the same, and the
  1092. # integrity-check passes for both, the two databases are identical.
  1093. #
  1094. proc allcksum {{db db}} {
  1095. set ret [list]
  1096. ifcapable tempdb {
  1097. set sql {
  1098. SELECT name FROM sqlite_master WHERE type = 'table' UNION
  1099. SELECT name FROM sqlite_temp_master WHERE type = 'table' UNION
  1100. SELECT 'sqlite_master' UNION
  1101. SELECT 'sqlite_temp_master' ORDER BY 1
  1102. }
  1103. } else {
  1104. set sql {
  1105. SELECT name FROM sqlite_master WHERE type = 'table' UNION
  1106. SELECT 'sqlite_master' ORDER BY 1
  1107. }
  1108. }
  1109. set tbllist [$db eval $sql]
  1110. set txt {}
  1111. foreach tbl $tbllist {
  1112. append txt [$db eval "SELECT * FROM $tbl"]
  1113. }
  1114. foreach prag {default_cache_size} {
  1115. append txt $prag-[$db eval "PRAGMA $prag"]\n
  1116. }
  1117. # puts txt=$txt
  1118. return [md5 $txt]
  1119. }
  1120. # Generate a checksum based on the contents of a single database with
  1121. # a database connection. The name of the database is $dbname.
  1122. # Examples of $dbname are "temp" or "main".
  1123. #
  1124. proc dbcksum {db dbname} {
  1125. if {$dbname=="temp"} {
  1126. set master sqlite_temp_master
  1127. } else {
  1128. set master $dbname.sqlite_master
  1129. }
  1130. set alltab [$db eval "SELECT name FROM $master WHERE type='table'"]
  1131. set txt [$db eval "SELECT * FROM $master"]\n
  1132. foreach tab $alltab {
  1133. append txt [$db eval "SELECT * FROM $dbname.$tab"]\n
  1134. }
  1135. return [md5 $txt]
  1136. }
  1137. proc memdebug_log_sql {{filename mallocs.sql}} {
  1138. set data [sqlite3_memdebug_log dump]
  1139. set nFrame [expr [llength [lindex $data 0]]-2]
  1140. if {$nFrame < 0} { return "" }
  1141. set database temp
  1142. set tbl "CREATE TABLE ${database}.malloc(zTest, nCall, nByte, lStack);"
  1143. set sql ""
  1144. foreach e $data {
  1145. set nCall [lindex $e 0]
  1146. set nByte [lindex $e 1]
  1147. set lStack [lrange $e 2 end]
  1148. append sql "INSERT INTO ${database}.malloc VALUES"
  1149. append sql "('test', $nCall, $nByte, '$lStack');\n"
  1150. foreach f $lStack {
  1151. set frames($f) 1
  1152. }
  1153. }
  1154. set tbl2 "CREATE TABLE ${database}.frame(frame INTEGER PRIMARY KEY, line);\n"
  1155. set tbl3 "CREATE TABLE ${database}.file(name PRIMARY KEY, content);\n"
  1156. foreach f [array names frames] {
  1157. set addr [format %x $f]
  1158. set cmd "addr2line -e [info nameofexec] $addr"
  1159. set line [eval exec $cmd]
  1160. append sql "INSERT INTO ${database}.frame VALUES($f, '$line');\n"
  1161. set file [lindex [split $line :] 0]
  1162. set files($file) 1
  1163. }
  1164. foreach f [array names files] {
  1165. set contents ""
  1166. catch {
  1167. set fd [open $f]
  1168. set contents [read $fd]
  1169. close $fd
  1170. }
  1171. set contents [string map {' ''} $contents]
  1172. append sql "INSERT INTO ${database}.file VALUES('$f', '$contents');\n"
  1173. }
  1174. set fd [open $filename w]
  1175. puts $fd "BEGIN; ${tbl}${tbl2}${tbl3}${sql} ; COMMIT;"
  1176. close $fd
  1177. }
  1178. # Copy file $from into $to. This is used because some versions of
  1179. # TCL for windows (notably the 8.4.1 binary package shipped with the
  1180. # current mingw release) have a broken "file copy" command.
  1181. #
  1182. proc copy_file {from to} {
  1183. if {$::tcl_platform(platform)=="unix"} {
  1184. file copy -force $from $to
  1185. } else {
  1186. set f [open $from]
  1187. fconfigure $f -translation binary
  1188. set t [open $to w]
  1189. fconfigure $t -translation binary
  1190. puts -nonewline $t [read $f [file size $from]]
  1191. close $t
  1192. close $f
  1193. }
  1194. }
  1195. # Drop all tables in database [db]
  1196. proc drop_all_tables {{db db}} {
  1197. ifcapable trigger&&foreignkey {
  1198. set pk [$db one "PRAGMA foreign_keys"]
  1199. $db eval "PRAGMA foreign_keys = OFF"
  1200. }
  1201. foreach {idx name file} [db eval {PRAGMA database_list}] {
  1202. if {$idx==1} {
  1203. set master sqlite_temp_master
  1204. } else {
  1205. set master $name.sqlite_master
  1206. }
  1207. foreach {t type} [$db eval "
  1208. SELECT name, type FROM $master
  1209. WHERE type IN('table', 'view') AND name NOT LIKE 'sqliteX_%' ESCAPE 'X'
  1210. "] {
  1211. $db eval "DROP $type \"$t\""
  1212. }
  1213. }
  1214. ifcapable trigger&&foreignkey {
  1215. $db eval "PRAGMA foreign_keys = $pk"
  1216. }
  1217. }
  1218. #-------------------------------------------------------------------------
  1219. # If a test script is executed with global variable $::G(perm:name) set to
  1220. # "wal", then the tests are run in WAL mode. Otherwise, they should be run
  1221. # in rollback mode. The following Tcl procs are used to make this less
  1222. # intrusive:
  1223. #
  1224. # wal_set_journal_mode ?DB?
  1225. #
  1226. # If running a WAL test, execute "PRAGMA journal_mode = wal" using
  1227. # connection handle DB. Otherwise, this command is a no-op.
  1228. #
  1229. # wal_check_journal_mode TESTNAME ?DB?
  1230. #
  1231. # If running a WAL test, execute a tests case that fails if the main
  1232. # database for connection handle DB is not currently a WAL database.
  1233. # Otherwise (if not running a WAL permutation) this is a no-op.
  1234. #
  1235. # wal_is_wal_mode
  1236. #
  1237. # Returns true if this test should be run in WAL mode. False otherwise.
  1238. #
  1239. proc wal_is_wal_mode {} {
  1240. expr {[permutation] eq "wal"}
  1241. }
  1242. proc wal_set_journal_mode {{db db}} {
  1243. if { [wal_is_wal_mode] } {
  1244. $db eval "PRAGMA journal_mode = WAL"
  1245. }
  1246. }
  1247. proc wal_check_journal_mode {testname {db db}} {
  1248. if { [wal_is_wal_mode] } {
  1249. $db eval { SELECT * FROM sqlite_master }
  1250. do_test $testname [list $db eval "PRAGMA main.journal_mode"] {wal}
  1251. }
  1252. }
  1253. proc permutation {} {
  1254. set perm ""
  1255. catch {set perm $::G(perm:name)}
  1256. set perm
  1257. }
  1258. proc presql {} {
  1259. set presql ""
  1260. catch {set presql $::G(perm:presql)}
  1261. set presql
  1262. }
  1263. #-------------------------------------------------------------------------
  1264. #
  1265. proc slave_test_script {script} {
  1266. # Create the interpreter used to run the test script.
  1267. interp create tinterp
  1268. # Populate some global variables that tester.tcl expects to see.
  1269. foreach {var value} [list \
  1270. ::argv0 $::argv0 \
  1271. ::argv {} \
  1272. ::SLAVE 1 \
  1273. ] {
  1274. interp eval tinterp [list set $var $value]
  1275. }
  1276. # The alias used to access the global test counters.
  1277. tinterp alias set_test_counter set_test_counter
  1278. # Set up the ::cmdlinearg array in the slave.
  1279. interp eval tinterp [list array set ::cmdlinearg [array get ::cmdlinearg]]
  1280. # Set up the ::G array in the slave.
  1281. interp eval tinterp [list array set ::G [array get ::G]]
  1282. # Load the various test interfaces implemented in C.
  1283. load_testfixture_extensions tinterp
  1284. # Run the test script.
  1285. interp eval tinterp $script
  1286. # Check if the interpreter call [run_thread_tests]
  1287. if { [interp eval tinterp {info exists ::run_thread_tests_called}] } {
  1288. set ::run_thread_tests_called 1
  1289. }
  1290. # Delete the interpreter used to run the test script.
  1291. interp delete tinterp
  1292. }
  1293. proc slave_test_file {zFile} {
  1294. set tail [file tail $zFile]
  1295. if {[info exists ::G(start:permutation)]} {
  1296. if {[permutation] != $::G(start:permutation)} return
  1297. unset ::G(start:permutation)
  1298. }
  1299. if {[info exists ::G(start:file)]} {
  1300. if {$tail != $::G(start:file) && $tail!="$::G(start:file).test"} return
  1301. unset ::G(start:file)
  1302. }
  1303. # Remember the value of the shared-cache setting. So that it is possible
  1304. # to check afterwards that it was not modified by the test script.
  1305. #
  1306. ifcapable shared_cache { set scs [sqlite3_enable_shared_cache] }
  1307. # Run the test script in a slave interpreter.
  1308. #
  1309. unset -nocomplain ::run_thread_tests_called
  1310. reset_prng_state
  1311. set ::sqlite_open_file_count 0
  1312. set time [time { slave_test_script [list source $zFile] }]
  1313. set ms [expr [lindex $time 0] / 1000]
  1314. # Test that all files opened by the test script were closed. Omit this
  1315. # if the test script has "thread" in its name. The open file counter
  1316. # is not thread-safe.
  1317. #
  1318. if {[info exists ::run_thread_tests_called]==0} {
  1319. do_test ${tail}-closeallfiles { expr {$::sqlite_open_file_count>0} } {0}
  1320. }
  1321. set ::sqlite_open_file_count 0
  1322. # Test that the global "shared-cache" setting was not altered by
  1323. # the test script.
  1324. #
  1325. ifcapable shared_cache {
  1326. set res [expr {[sqlite3_enable_shared_cache] == $scs}]
  1327. do_test ${tail}-sharedcachesetting [list set {} $res] 1
  1328. }
  1329. # Add some info to the output.
  1330. #
  1331. puts "Time: $tail $ms ms"
  1332. #show_memstats
  1333. }
  1334. # Open a new connection on database test.db and execute the SQL script
  1335. # supplied as an argument. Before returning, close the new conection and
  1336. # restore the 4 byte fields starting at header offsets 28, 92 and 96
  1337. # to the values they held before the SQL was executed. This simulates
  1338. # a write by a pre-3.7.0 client.
  1339. #
  1340. proc sql36231 {sql} {
  1341. set B [hexio_read test.db 92 8]
  1342. set A [hexio_read test.db 28 4]
  1343. sqlite3 db36231 test.db
  1344. catch { db36231 func a_string a_string }
  1345. execsql $sql db36231
  1346. db36231 close
  1347. hexio_write test.db 28 $A
  1348. hexio_write test.db 92 $B
  1349. return ""
  1350. }
  1351. proc db_save {} {
  1352. foreach f [glob -nocomplain sv_test.db*] { forcedelete $f }
  1353. foreach f [glob -nocomplain test.db*] {
  1354. set f2 "sv_$f"
  1355. file copy -force $f $f2
  1356. }
  1357. }
  1358. proc db_save_and_close {} {
  1359. db_save
  1360. catch { db close }
  1361. return ""
  1362. }
  1363. proc db_restore {} {
  1364. foreach f [glob -nocomplain test.db*] { forcedelete $f }
  1365. foreach f2 [glob -nocomplain sv_test.db*] {
  1366. set f [string range $f2 3 end]
  1367. file copy -force $f2 $f
  1368. }
  1369. }
  1370. proc db_restore_and_reopen {{dbfile test.db}} {
  1371. catch { db close }
  1372. db_restore
  1373. sqlite3 db $dbfile
  1374. }
  1375. proc db_delete_and_reopen {{file test.db}} {
  1376. catch { db close }
  1377. foreach f [glob -nocomplain test.db*] { file delete -force $f }
  1378. sqlite3 db $file
  1379. }
  1380. # If the library is compiled with the SQLITE_DEFAULT_AUTOVACUUM macro set
  1381. # to non-zero, then set the global variable $AUTOVACUUM to 1.
  1382. set AUTOVACUUM $sqlite_options(default_autovacuum)
  1383. source $testdir/thread_common.tcl
  1384. source $testdir/malloc_common.tcl