⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tester.tcl

📁 最新的sqlite3.6.2源代码
💻 TCL
📖 第 1 页 / 共 2 页
字号:
}# Delete a file or directory#proc forcedelete {filename} {  if {[catch {file delete -force $filename}]} {    exec rm -rf $filename  }}# Do an integrity check of the entire database#proc integrity_check {name} {  ifcapable integrityck {    do_test $name {      execsql {PRAGMA integrity_check}    } {ok}  }}proc fix_ifcapable_expr {expr} {  set ret ""  set state 0  for {set i 0} {$i < [string length $expr]} {incr i} {    set char [string range $expr $i $i]    set newstate [expr {[string is alnum $char] || $char eq "_"}]    if {$newstate && !$state} {      append ret {$::sqlite_options(}    }    if {!$newstate && $state} {      append ret )    }    append ret $char    set state $newstate  }  if {$state} {append ret )}  return $ret}# Evaluate a boolean expression of capabilities.  If true, execute the# code.  Omit the code if false.#proc ifcapable {expr code {else ""} {elsecode ""}} {  #regsub -all {[a-z_0-9]+} $expr {$::sqlite_options(&)} e2  set e2 [fix_ifcapable_expr $expr]  if ($e2) {    set c [catch {uplevel 1 $code} r]  } else {    set c [catch {uplevel 1 $elsecode} r]  }  return -code $c $r}# This proc execs a seperate process that crashes midway through executing# the SQL script $sql on database test.db.## The crash occurs during a sync() of file $crashfile. When the crash# occurs a random subset of all unsynced writes made by the process are# written into the files on disk. Argument $crashdelay indicates the# number of file syncs to wait before crashing.## The return value is a list of two elements. The first element is a# boolean, indicating whether or not the process actually crashed or# reported some other error. The second element in the returned list is the# error message. This is "child process exited abnormally" if the crash# occured.##   crashsql -delay CRASHDELAY -file CRASHFILE ?-blocksize BLOCKSIZE? $sql#proc crashsql {args} {  if {$::tcl_platform(platform)!="unix"} {    error "crashsql should only be used on unix"  }  set blocksize ""  set crashdelay 1  set prngseed 0  set tclbody {}  set crashfile ""  set dc ""  set sql [lindex $args end]    for {set ii 0} {$ii < [llength $args]-1} {incr ii 2} {    set z [lindex $args $ii]    set n [string length $z]    set z2 [lindex $args [expr $ii+1]]    if     {$n>1 && [string first $z -delay]==0}     {set crashdelay $z2} \    elseif {$n>1 && [string first $z -seed]==0}      {set prngseed $z2} \    elseif {$n>1 && [string first $z -file]==0}      {set crashfile $z2}  \    elseif {$n>1 && [string first $z -tclbody]==0}   {set tclbody $z2}  \    elseif {$n>1 && [string first $z -blocksize]==0} {set blocksize "-s $z2" } \    elseif {$n>1 && [string first $z -characteristics]==0} {set dc "-c {$z2}" } \    else   { error "Unrecognized option: $z" }  }  if {$crashfile eq ""} {    error "Compulsory option -file missing"  }  set cfile [file join [pwd] $crashfile]  set f [open crash.tcl w]  puts $f "sqlite3_crash_enable 1"  puts $f "sqlite3_crashparams $blocksize $dc $crashdelay $cfile"  puts $f "set sqlite_pending_byte $::sqlite_pending_byte"  puts $f "sqlite3 db test.db -vfs crash"  # This block sets the cache size of the main database to 10  # pages. This is done in case the build is configured to omit  # "PRAGMA cache_size".  puts $f {db eval {SELECT * FROM sqlite_master;}}  puts $f {set bt [btree_from_db db]}  puts $f {btree_set_cache_size $bt 10}  if {$prngseed} {    set seed [expr {$prngseed%10007+1}]    # puts seed=$seed    puts $f "db eval {SELECT randomblob($seed)}"  }  if {[string length $tclbody]>0} {    puts $f $tclbody  }  if {[string length $sql]>0} {    puts $f "db eval {"    puts $f   "$sql"    puts $f "}"  }  close $f  set r [catch {    exec [info nameofexec] crash.tcl >@stdout  } msg]  lappend r $msg}# Usage: do_ioerr_test <test number> <options...>## This proc is used to implement test cases that check that IO errors# are correctly handled. The first argument, <test number>, is an integer # used to name the tests executed by this proc. Options are as follows:##     -tclprep          TCL script to run to prepare test.#     -sqlprep          SQL script to run to prepare test.#     -tclbody          TCL script to run with IO error simulation.#     -sqlbody          TCL script to run with IO error simulation.#     -exclude          List of 'N' values not to test.#     -erc              Use extended result codes#     -persist          Make simulated I/O errors persistent#     -start            Value of 'N' to begin with (default 1)##     -cksum            Boolean. If true, test that the database does#                       not change during the execution of the test case.#proc do_ioerr_test {testname args} {  set ::ioerropts(-start) 1  set ::ioerropts(-cksum) 0  set ::ioerropts(-erc) 0  set ::ioerropts(-count) 100000000  set ::ioerropts(-persist) 1  set ::ioerropts(-ckrefcount) 0  set ::ioerropts(-restoreprng) 1  array set ::ioerropts $args  # TEMPORARY: For 3.5.9, disable testing of extended result codes. There are  # a couple of obscure IO errors that do not return them.  set ::ioerropts(-erc) 0  set ::go 1  #reset_prng_state  save_prng_state  for {set n $::ioerropts(-start)} {$::go && $n<200} {incr n} {    set ::TN $n    incr ::ioerropts(-count) -1    if {$::ioerropts(-count)<0} break     # Skip this IO error if it was specified with the "-exclude" option.    if {[info exists ::ioerropts(-exclude)]} {      if {[lsearch $::ioerropts(-exclude) $n]!=-1} continue    }    if {$::ioerropts(-restoreprng)} {      restore_prng_state    }    # Delete the files test.db and test2.db, then execute the TCL and     # SQL (in that order) to prepare for the test case.    do_test $testname.$n.1 {      set ::sqlite_io_error_pending 0      catch {db close}      catch {file delete -force test.db}      catch {file delete -force test.db-journal}      catch {file delete -force test2.db}      catch {file delete -force test2.db-journal}      set ::DB [sqlite3 db test.db; sqlite3_connection_pointer db]      sqlite3_extended_result_codes $::DB $::ioerropts(-erc)      if {[info exists ::ioerropts(-tclprep)]} {        eval $::ioerropts(-tclprep)      }      if {[info exists ::ioerropts(-sqlprep)]} {        execsql $::ioerropts(-sqlprep)      }      expr 0    } {0}    # Read the 'checksum' of the database.    if {$::ioerropts(-cksum)} {      set checksum [cksum]    }    # Set the Nth IO error to fail.    do_test $testname.$n.2 [subst {      set ::sqlite_io_error_persist $::ioerropts(-persist)      set ::sqlite_io_error_pending $n    }] $n      # Create a single TCL script from the TCL and SQL specified    # as the body of the test.    set ::ioerrorbody {}    if {[info exists ::ioerropts(-tclbody)]} {      append ::ioerrorbody "$::ioerropts(-tclbody)\n"    }    if {[info exists ::ioerropts(-sqlbody)]} {      append ::ioerrorbody "db eval {$::ioerropts(-sqlbody)}"    }    # Execute the TCL Script created in the above block. If    # there are at least N IO operations performed by SQLite as    # a result of the script, the Nth will fail.    do_test $testname.$n.3 {      set ::sqlite_io_error_hit 0      set ::sqlite_io_error_hardhit 0      set r [catch $::ioerrorbody msg]      set ::errseen $r      set rc [sqlite3_errcode $::DB]      if {$::ioerropts(-erc)} {        # If we are in extended result code mode, make sure all of the        # IOERRs we get back really do have their extended code values.        # If an extended result code is returned, the sqlite3_errcode        # TCLcommand will return a string of the form:  SQLITE_IOERR+nnnn        # where nnnn is a number        if {[regexp {^SQLITE_IOERR} $rc] && ![regexp {IOERR\+\d} $rc]} {          return $rc        }      } else {        # If we are not in extended result code mode, make sure no        # extended error codes are returned.        if {[regexp {\+\d} $rc]} {          return $rc        }      }      # The test repeats as long as $::go is non-zero.  $::go starts out      # as 1.  When a test runs to completion without hitting an I/O      # error, that means there is no point in continuing with this test      # case so set $::go to zero.      #      if {$::sqlite_io_error_pending>0} {        set ::go 0        set q 0        set ::sqlite_io_error_pending 0      } else {        set q 1      }      set s [expr $::sqlite_io_error_hit==0]      if {$::sqlite_io_error_hit>$::sqlite_io_error_hardhit && $r==0} {        set r 1      }      set ::sqlite_io_error_hit 0      # One of two things must have happened. either      #   1.  We never hit the IO error and the SQL returned OK      #   2.  An IO error was hit and the SQL failed      #      expr { ($s && !$r && !$q) || (!$s && $r && $q) }    } {1}    set ::sqlite_io_error_hit 0    set ::sqlite_io_error_pending 0    # Check that no page references were leaked. There should be     # a single reference if there is still an active transaction,     # or zero otherwise.    #    # UPDATE: If the IO error occurs after a 'BEGIN' but before any    # locks are established on database files (i.e. if the error     # occurs while attempting to detect a hot-journal file), then    # there may 0 page references and an active transaction according    # to [sqlite3_get_autocommit].    #    if {$::go && $::sqlite_io_error_hardhit && $::ioerropts(-ckrefcount)} {      do_test $testname.$n.4 {        set bt [btree_from_db db]        db_enter db        array set stats [btree_pager_stats $bt]        db_leave db        set nRef $stats(ref)        expr {$nRef == 0 || ([sqlite3_get_autocommit db]==0 && $nRef == 1)}      } {1}    }    # If there is an open database handle and no open transaction,     # and the pager is not running in exclusive-locking mode,    # check that the pager is in "unlocked" state. Theoretically,    # if a call to xUnlock() failed due to an IO error the underlying    # file may still be locked.    #    ifcapable pragma {      if { [info commands db] ne ""        && $::ioerropts(-ckrefcount)        && [db one {pragma locking_mode}] eq "normal"        && [sqlite3_get_autocommit db]      } {        do_test $testname.$n.5 {          set bt [btree_from_db db]          db_enter db          array set stats [btree_pager_stats $bt]          db_leave db          set stats(state)        } 0      }    }    # If an IO error occured, then the checksum of the database should    # be the same as before the script that caused the IO error was run.    #    if {$::go && $::sqlite_io_error_hardhit && $::ioerropts(-cksum)} {      do_test $testname.$n.6 {        catch {db close}        catch {db2 close}        set ::DB [sqlite3 db test.db; sqlite3_connection_pointer db]        cksum      } $checksum    }    set ::sqlite_io_error_hardhit 0    set ::sqlite_io_error_pending 0    if {[info exists ::ioerropts(-cleanup)]} {      catch $::ioerropts(-cleanup)    }  }  set ::sqlite_io_error_pending 0  set ::sqlite_io_error_persist 0  unset ::ioerropts}# Return a checksum based on the contents of the main database associated# with connection $db#proc cksum {{db db}} {  set txt [$db eval {      SELECT name, type, sql FROM sqlite_master order by name  }]\n  foreach tbl [$db eval {      SELECT name FROM sqlite_master WHERE type='table' order by name  }] {    append txt [$db eval "SELECT * FROM $tbl"]\n  }  foreach prag {default_synchronous default_cache_size} {    append txt $prag-[$db eval "PRAGMA $prag"]\n  }  set cksum [string length $txt]-[md5 $txt]  # puts $cksum-[file size test.db]  return $cksum}# Generate a checksum based on the contents of the main and temp tables# database $db. If the checksum of two databases is the same, and the# integrity-check passes for both, the two databases are identical.#proc allcksum {{db db}} {  set ret [list]  ifcapable tempdb {    set sql {      SELECT name FROM sqlite_master WHERE type = 'table' UNION      SELECT name FROM sqlite_temp_master WHERE type = 'table' UNION      SELECT 'sqlite_master' UNION      SELECT 'sqlite_temp_master' ORDER BY 1    }  } else {    set sql {      SELECT name FROM sqlite_master WHERE type = 'table' UNION      SELECT 'sqlite_master' ORDER BY 1    }  }  set tbllist [$db eval $sql]  set txt {}  foreach tbl $tbllist {    append txt [$db eval "SELECT * FROM $tbl"]  }  foreach prag {default_cache_size} {    append txt $prag-[$db eval "PRAGMA $prag"]\n  }  # puts txt=$txt  return [md5 $txt]}proc memdebug_log_sql {{filename mallocs.sql}} {  set data [sqlite3_memdebug_log dump]  set nFrame [expr [llength [lindex $data 0]]-2]  if {$nFrame < 0} { return "" }  set database temp  set tbl "CREATE TABLE ${database}.malloc(nCall, nByte"  for {set ii 1} {$ii <= $nFrame} {incr ii} {    append tbl ", f${ii}"  }  append tbl ");\n"  set sql ""  foreach e $data {    append sql "INSERT INTO ${database}.malloc VALUES([join $e ,]);\n"    foreach f [lrange $e 2 end] {      set frames($f) 1    }  }  set tbl2 "CREATE TABLE ${database}.frame(frame INTEGER PRIMARY KEY, line);\n"  set tbl3 "CREATE TABLE ${database}.file(name PRIMARY KEY, content);\n"  foreach f [array names frames] {    set addr [format %x $f]    set cmd "addr2line -e [info nameofexec] $addr"    set line [eval exec $cmd]    append sql "INSERT INTO ${database}.frame VALUES($f, '$line');\n"    set file [lindex [split $line :] 0]    set files($file) 1  }  foreach f [array names files] {    set contents ""    catch {      set fd [open $f]      set contents [read $fd]      close $fd    }    set contents [string map {' ''} $contents]    append sql "INSERT INTO ${database}.file VALUES('$f', '$contents');\n"  }  set fd [open $filename w]  puts $fd "BEGIN; ${tbl}${tbl2}${tbl3}${sql} ; COMMIT;"  close $fd}# Copy file $from into $to. This is used because some versions of# TCL for windows (notably the 8.4.1 binary package shipped with the# current mingw release) have a broken "file copy" command.#proc copy_file {from to} {  if {$::tcl_platform(platform)=="unix"} {    file copy -force $from $to  } else {    set f [open $from]    fconfigure $f -translation binary    set t [open $to w]    fconfigure $t -translation binary    puts -nonewline $t [read $f [file size $from]]    close $t    close $f  }}# If the library is compiled with the SQLITE_DEFAULT_AUTOVACUUM macro set# to non-zero, then set the global variable $AUTOVACUUM to 1.set AUTOVACUUM $sqlite_options(default_autovacuum)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -