xref: /titanic_41/usr/src/lib/libsqlite/test/tester.tcl (revision c5c4113dfcabb1eed3d4bdf7609de5170027a794)
1*c5c4113dSnw141292
2*c5c4113dSnw141292#pragma ident	"%Z%%M%	%I%	%E% SMI"
3*c5c4113dSnw141292
4*c5c4113dSnw141292# 2001 September 15
5*c5c4113dSnw141292#
6*c5c4113dSnw141292# The author disclaims copyright to this source code.  In place of
7*c5c4113dSnw141292# a legal notice, here is a blessing:
8*c5c4113dSnw141292#
9*c5c4113dSnw141292#    May you do good and not evil.
10*c5c4113dSnw141292#    May you find forgiveness for yourself and forgive others.
11*c5c4113dSnw141292#    May you share freely, never taking more than you give.
12*c5c4113dSnw141292#
13*c5c4113dSnw141292#***********************************************************************
14*c5c4113dSnw141292# This file implements some common TCL routines used for regression
15*c5c4113dSnw141292# testing the SQLite library
16*c5c4113dSnw141292#
17*c5c4113dSnw141292# $Id: tester.tcl,v 1.28 2004/02/14 01:39:50 drh Exp $
18*c5c4113dSnw141292
19*c5c4113dSnw141292# Make sure tclsqlite was compiled correctly.  Abort now with an
20*c5c4113dSnw141292# error message if not.
21*c5c4113dSnw141292#
22*c5c4113dSnw141292if {[sqlite -tcl-uses-utf]} {
23*c5c4113dSnw141292  if {"\u1234"=="u1234"} {
24*c5c4113dSnw141292    puts stderr "***** BUILD PROBLEM *****"
25*c5c4113dSnw141292    puts stderr "$argv0 was linked against an older version"
26*c5c4113dSnw141292    puts stderr "of TCL that does not support Unicode, but uses a header"
27*c5c4113dSnw141292    puts stderr "file (\"tcl.h\") from a new TCL version that does support"
28*c5c4113dSnw141292    puts stderr "Unicode.  This combination causes internal errors."
29*c5c4113dSnw141292    puts stderr "Recompile using a TCL library and header file that match"
30*c5c4113dSnw141292    puts stderr "and try again.\n**************************"
31*c5c4113dSnw141292    exit 1
32*c5c4113dSnw141292  }
33*c5c4113dSnw141292} else {
34*c5c4113dSnw141292  if {"\u1234"!="u1234"} {
35*c5c4113dSnw141292    puts stderr "***** BUILD PROBLEM *****"
36*c5c4113dSnw141292    puts stderr "$argv0 was linked against an newer version"
37*c5c4113dSnw141292    puts stderr "of TCL that supports Unicode, but uses a header file"
38*c5c4113dSnw141292    puts stderr "(\"tcl.h\") from a old TCL version that does not support"
39*c5c4113dSnw141292    puts stderr "Unicode.  This combination causes internal errors."
40*c5c4113dSnw141292    puts stderr "Recompile using a TCL library and header file that match"
41*c5c4113dSnw141292    puts stderr "and try again.\n**************************"
42*c5c4113dSnw141292    exit 1
43*c5c4113dSnw141292  }
44*c5c4113dSnw141292}
45*c5c4113dSnw141292
46*c5c4113dSnw141292# Use the pager codec if it is available
47*c5c4113dSnw141292#
48*c5c4113dSnw141292if {[sqlite -has-codec] && [info command sqlite_orig]==""} {
49*c5c4113dSnw141292  rename sqlite sqlite_orig
50*c5c4113dSnw141292  proc sqlite {args} {
51*c5c4113dSnw141292    if {[llength $args]==2 && [string index [lindex $args 0] 0]!="-"} {
52*c5c4113dSnw141292      lappend args -key {xyzzy}
53*c5c4113dSnw141292    }
54*c5c4113dSnw141292    uplevel 1 sqlite_orig $args
55*c5c4113dSnw141292  }
56*c5c4113dSnw141292}
57*c5c4113dSnw141292
58*c5c4113dSnw141292
59*c5c4113dSnw141292# Create a test database
60*c5c4113dSnw141292#
61*c5c4113dSnw141292catch {db close}
62*c5c4113dSnw141292file delete -force test.db
63*c5c4113dSnw141292file delete -force test.db-journal
64*c5c4113dSnw141292sqlite db ./test.db
65*c5c4113dSnw141292if {[info exists ::SETUP_SQL]} {
66*c5c4113dSnw141292  db eval $::SETUP_SQL
67*c5c4113dSnw141292}
68*c5c4113dSnw141292
69*c5c4113dSnw141292# Abort early if this script has been run before.
70*c5c4113dSnw141292#
71*c5c4113dSnw141292if {[info exists nTest]} return
72*c5c4113dSnw141292
73*c5c4113dSnw141292# Set the test counters to zero
74*c5c4113dSnw141292#
75*c5c4113dSnw141292set nErr 0
76*c5c4113dSnw141292set nTest 0
77*c5c4113dSnw141292set nProb 0
78*c5c4113dSnw141292set skip_test 0
79*c5c4113dSnw141292set failList {}
80*c5c4113dSnw141292
81*c5c4113dSnw141292# Invoke the do_test procedure to run a single test
82*c5c4113dSnw141292#
83*c5c4113dSnw141292proc do_test {name cmd expected} {
84*c5c4113dSnw141292  global argv nErr nTest skip_test
85*c5c4113dSnw141292  if {$skip_test} {
86*c5c4113dSnw141292    set skip_test 0
87*c5c4113dSnw141292    return
88*c5c4113dSnw141292  }
89*c5c4113dSnw141292  if {[llength $argv]==0} {
90*c5c4113dSnw141292    set go 1
91*c5c4113dSnw141292  } else {
92*c5c4113dSnw141292    set go 0
93*c5c4113dSnw141292    foreach pattern $argv {
94*c5c4113dSnw141292      if {[string match $pattern $name]} {
95*c5c4113dSnw141292        set go 1
96*c5c4113dSnw141292        break
97*c5c4113dSnw141292      }
98*c5c4113dSnw141292    }
99*c5c4113dSnw141292  }
100*c5c4113dSnw141292  if {!$go} return
101*c5c4113dSnw141292  incr nTest
102*c5c4113dSnw141292  puts -nonewline $name...
103*c5c4113dSnw141292  flush stdout
104*c5c4113dSnw141292  if {[catch {uplevel #0 "$cmd;\n"} result]} {
105*c5c4113dSnw141292    puts "\nError: $result"
106*c5c4113dSnw141292    incr nErr
107*c5c4113dSnw141292    lappend ::failList $name
108*c5c4113dSnw141292    if {$nErr>100} {puts "*** Giving up..."; finalize_testing}
109*c5c4113dSnw141292  } elseif {[string compare $result $expected]} {
110*c5c4113dSnw141292    puts "\nExpected: \[$expected\]\n     Got: \[$result\]"
111*c5c4113dSnw141292    incr nErr
112*c5c4113dSnw141292    lappend ::failList $name
113*c5c4113dSnw141292    if {$nErr>100} {puts "*** Giving up..."; finalize_testing}
114*c5c4113dSnw141292  } else {
115*c5c4113dSnw141292    puts " Ok"
116*c5c4113dSnw141292  }
117*c5c4113dSnw141292}
118*c5c4113dSnw141292
119*c5c4113dSnw141292# Invoke this procedure on a test that is probabilistic
120*c5c4113dSnw141292# and might fail sometimes.
121*c5c4113dSnw141292#
122*c5c4113dSnw141292proc do_probtest {name cmd expected} {
123*c5c4113dSnw141292  global argv nProb nTest skip_test
124*c5c4113dSnw141292  if {$skip_test} {
125*c5c4113dSnw141292    set skip_test 0
126*c5c4113dSnw141292    return
127*c5c4113dSnw141292  }
128*c5c4113dSnw141292  if {[llength $argv]==0} {
129*c5c4113dSnw141292    set go 1
130*c5c4113dSnw141292  } else {
131*c5c4113dSnw141292    set go 0
132*c5c4113dSnw141292    foreach pattern $argv {
133*c5c4113dSnw141292      if {[string match $pattern $name]} {
134*c5c4113dSnw141292        set go 1
135*c5c4113dSnw141292        break
136*c5c4113dSnw141292      }
137*c5c4113dSnw141292    }
138*c5c4113dSnw141292  }
139*c5c4113dSnw141292  if {!$go} return
140*c5c4113dSnw141292  incr nTest
141*c5c4113dSnw141292  puts -nonewline $name...
142*c5c4113dSnw141292  flush stdout
143*c5c4113dSnw141292  if {[catch {uplevel #0 "$cmd;\n"} result]} {
144*c5c4113dSnw141292    puts "\nError: $result"
145*c5c4113dSnw141292    incr nErr
146*c5c4113dSnw141292  } elseif {[string compare $result $expected]} {
147*c5c4113dSnw141292    puts "\nExpected: \[$expected\]\n     Got: \[$result\]"
148*c5c4113dSnw141292    puts "NOTE: The results of the previous test depend on system load"
149*c5c4113dSnw141292    puts "and processor speed.  The test may sometimes fail even if the"
150*c5c4113dSnw141292    puts "library is working correctly."
151*c5c4113dSnw141292    incr nProb
152*c5c4113dSnw141292  } else {
153*c5c4113dSnw141292    puts " Ok"
154*c5c4113dSnw141292  }
155*c5c4113dSnw141292}
156*c5c4113dSnw141292
157*c5c4113dSnw141292# The procedure uses the special "sqlite_malloc_stat" command
158*c5c4113dSnw141292# (which is only available if SQLite is compiled with -DMEMORY_DEBUG=1)
159*c5c4113dSnw141292# to see how many malloc()s have not been free()ed.  The number
160*c5c4113dSnw141292# of surplus malloc()s is stored in the global variable $::Leak.
161*c5c4113dSnw141292# If the value in $::Leak grows, it may mean there is a memory leak
162*c5c4113dSnw141292# in the library.
163*c5c4113dSnw141292#
164*c5c4113dSnw141292proc memleak_check {} {
165*c5c4113dSnw141292  if {[info command sqlite_malloc_stat]!=""} {
166*c5c4113dSnw141292    set r [sqlite_malloc_stat]
167*c5c4113dSnw141292    set ::Leak [expr {[lindex $r 0]-[lindex $r 1]}]
168*c5c4113dSnw141292  }
169*c5c4113dSnw141292}
170*c5c4113dSnw141292
171*c5c4113dSnw141292# Run this routine last
172*c5c4113dSnw141292#
173*c5c4113dSnw141292proc finish_test {} {
174*c5c4113dSnw141292  finalize_testing
175*c5c4113dSnw141292}
176*c5c4113dSnw141292proc finalize_testing {} {
177*c5c4113dSnw141292  global nTest nErr nProb sqlite_open_file_count
178*c5c4113dSnw141292  if {$nErr==0} memleak_check
179*c5c4113dSnw141292  catch {db close}
180*c5c4113dSnw141292  puts "$nErr errors out of $nTest tests"
181*c5c4113dSnw141292  puts "Failures on these tests: $::failList"
182*c5c4113dSnw141292  if {$nProb>0} {
183*c5c4113dSnw141292    puts "$nProb probabilistic tests also failed, but this does"
184*c5c4113dSnw141292    puts "not necessarily indicate a malfunction."
185*c5c4113dSnw141292  }
186*c5c4113dSnw141292  if {$sqlite_open_file_count} {
187*c5c4113dSnw141292    puts "$sqlite_open_file_count files were left open"
188*c5c4113dSnw141292    incr nErr
189*c5c4113dSnw141292  }
190*c5c4113dSnw141292  exit [expr {$nErr>0}]
191*c5c4113dSnw141292}
192*c5c4113dSnw141292
193*c5c4113dSnw141292# A procedure to execute SQL
194*c5c4113dSnw141292#
195*c5c4113dSnw141292proc execsql {sql {db db}} {
196*c5c4113dSnw141292  # puts "SQL = $sql"
197*c5c4113dSnw141292  return [$db eval $sql]
198*c5c4113dSnw141292}
199*c5c4113dSnw141292
200*c5c4113dSnw141292# Execute SQL and catch exceptions.
201*c5c4113dSnw141292#
202*c5c4113dSnw141292proc catchsql {sql {db db}} {
203*c5c4113dSnw141292  # puts "SQL = $sql"
204*c5c4113dSnw141292  set r [catch {$db eval $sql} msg]
205*c5c4113dSnw141292  lappend r $msg
206*c5c4113dSnw141292  return $r
207*c5c4113dSnw141292}
208*c5c4113dSnw141292
209*c5c4113dSnw141292# Do an VDBE code dump on the SQL given
210*c5c4113dSnw141292#
211*c5c4113dSnw141292proc explain {sql {db db}} {
212*c5c4113dSnw141292  puts ""
213*c5c4113dSnw141292  puts "addr  opcode        p1       p2     p3             "
214*c5c4113dSnw141292  puts "----  ------------  ------  ------  ---------------"
215*c5c4113dSnw141292  $db eval "explain $sql" {} {
216*c5c4113dSnw141292    puts [format {%-4d  %-12.12s  %-6d  %-6d  %s} $addr $opcode $p1 $p2 $p3]
217*c5c4113dSnw141292  }
218*c5c4113dSnw141292}
219*c5c4113dSnw141292
220*c5c4113dSnw141292# Another procedure to execute SQL.  This one includes the field
221*c5c4113dSnw141292# names in the returned list.
222*c5c4113dSnw141292#
223*c5c4113dSnw141292proc execsql2 {sql} {
224*c5c4113dSnw141292  set result {}
225*c5c4113dSnw141292  db eval $sql data {
226*c5c4113dSnw141292    foreach f $data(*) {
227*c5c4113dSnw141292      lappend result $f $data($f)
228*c5c4113dSnw141292    }
229*c5c4113dSnw141292  }
230*c5c4113dSnw141292  return $result
231*c5c4113dSnw141292}
232*c5c4113dSnw141292
233*c5c4113dSnw141292# Use the non-callback API to execute multiple SQL statements
234*c5c4113dSnw141292#
235*c5c4113dSnw141292proc stepsql {dbptr sql} {
236*c5c4113dSnw141292  set sql [string trim $sql]
237*c5c4113dSnw141292  set r 0
238*c5c4113dSnw141292  while {[string length $sql]>0} {
239*c5c4113dSnw141292    if {[catch {sqlite_compile $dbptr $sql sqltail} vm]} {
240*c5c4113dSnw141292      return [list 1 $vm]
241*c5c4113dSnw141292    }
242*c5c4113dSnw141292    set sql [string trim $sqltail]
243*c5c4113dSnw141292    while {[sqlite_step $vm N VAL COL]=="SQLITE_ROW"} {
244*c5c4113dSnw141292      foreach v $VAL {lappend r $v}
245*c5c4113dSnw141292    }
246*c5c4113dSnw141292    if {[catch {sqlite_finalize $vm} errmsg]} {
247*c5c4113dSnw141292      return [list 1 $errmsg]
248*c5c4113dSnw141292    }
249*c5c4113dSnw141292  }
250*c5c4113dSnw141292  return $r
251*c5c4113dSnw141292}
252*c5c4113dSnw141292
253*c5c4113dSnw141292# Delete a file or directory
254*c5c4113dSnw141292#
255*c5c4113dSnw141292proc forcedelete {filename} {
256*c5c4113dSnw141292  if {[catch {file delete -force $filename}]} {
257*c5c4113dSnw141292    exec rm -rf $filename
258*c5c4113dSnw141292  }
259*c5c4113dSnw141292}
260*c5c4113dSnw141292
261*c5c4113dSnw141292# Do an integrity check of the entire database
262*c5c4113dSnw141292#
263*c5c4113dSnw141292proc integrity_check {name} {
264*c5c4113dSnw141292  do_test $name {
265*c5c4113dSnw141292    execsql {PRAGMA integrity_check}
266*c5c4113dSnw141292  } {ok}
267*c5c4113dSnw141292}
268