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 regression tests for TCL interface to the 12# SQLite library. 13# 14# Actually, all tests are based on the TCL interface, so the main 15# interface is pretty well tested. This file contains some addition 16# tests for fringe issues that the main test suite does not cover. 17# 18# $Id: tclsqlite.test,v 1.56 2006/09/01 15:49:06 drh Exp $ 19 20set testdir [file dirname $argv0] 21source $testdir/tester.tcl 22 23# Check the error messages generated by tclsqlite 24# 25if {[sqlite3 -has-codec]} { 26 set r "sqlite_orig HANDLE FILENAME ?-key CODEC-KEY?" 27} else { 28 set r "sqlite3 HANDLE FILENAME ?MODE?" 29} 30do_test tcl-1.1 { 31 set v [catch {sqlite3 bogus} msg] 32 lappend v $msg 33} [list 1 "wrong # args: should be \"$r\""] 34do_test tcl-1.2 { 35 set v [catch {db bogus} msg] 36 lappend v $msg 37} {1 {bad option "bogus": must be authorizer, busy, cache, changes, close, collate, collation_needed, commit_hook, complete, copy, enable_load_extension, errorcode, eval, exists, function, interrupt, last_insert_rowid, nullvalue, onecolumn, profile, progress, rekey, rollback_hook, timeout, total_changes, trace, transaction, update_hook, or version}} 38do_test tcl-1.3 { 39 execsql {CREATE TABLE t1(a int, b int)} 40 execsql {INSERT INTO t1 VALUES(10,20)} 41 set v [catch { 42 db eval {SELECT * FROM t1} data { 43 error "The error message" 44 } 45 } msg] 46 lappend v $msg 47} {1 {The error message}} 48do_test tcl-1.4 { 49 set v [catch { 50 db eval {SELECT * FROM t2} data { 51 error "The error message" 52 } 53 } msg] 54 lappend v $msg 55} {1 {no such table: t2}} 56do_test tcl-1.5 { 57 set v [catch { 58 db eval {SELECT * FROM t1} data { 59 break 60 } 61 } msg] 62 lappend v $msg 63} {0 {}} 64do_test tcl-1.6 { 65 set v [catch { 66 db eval {SELECT * FROM t1} data { 67 expr x* 68 } 69 } msg] 70 regsub {:.*$} $msg {} msg 71 lappend v $msg 72} {1 {syntax error in expression "x*"}} 73do_test tcl-1.7 { 74 set v [catch {db} msg] 75 lappend v $msg 76} {1 {wrong # args: should be "db SUBCOMMAND ..."}} 77if {[catch {db auth {}}]==0} { 78 do_test tcl-1.8 { 79 set v [catch {db authorizer 1 2 3} msg] 80 lappend v $msg 81 } {1 {wrong # args: should be "db authorizer ?CALLBACK?"}} 82} 83do_test tcl-1.9 { 84 set v [catch {db busy 1 2 3} msg] 85 lappend v $msg 86} {1 {wrong # args: should be "db busy CALLBACK"}} 87do_test tcl-1.10 { 88 set v [catch {db progress 1} msg] 89 lappend v $msg 90} {1 {wrong # args: should be "db progress N CALLBACK"}} 91do_test tcl-1.11 { 92 set v [catch {db changes xyz} msg] 93 lappend v $msg 94} {1 {wrong # args: should be "db changes "}} 95do_test tcl-1.12 { 96 set v [catch {db commit_hook a b c} msg] 97 lappend v $msg 98} {1 {wrong # args: should be "db commit_hook ?CALLBACK?"}} 99ifcapable {complete} { 100 do_test tcl-1.13 { 101 set v [catch {db complete} msg] 102 lappend v $msg 103 } {1 {wrong # args: should be "db complete SQL"}} 104} 105do_test tcl-1.14 { 106 set v [catch {db eval} msg] 107 lappend v $msg 108} {1 {wrong # args: should be "db eval SQL ?ARRAY-NAME? ?SCRIPT?"}} 109do_test tcl-1.15 { 110 set v [catch {db function} msg] 111 lappend v $msg 112} {1 {wrong # args: should be "db function NAME SCRIPT"}} 113do_test tcl-1.16 { 114 set v [catch {db last_insert_rowid xyz} msg] 115 lappend v $msg 116} {1 {wrong # args: should be "db last_insert_rowid "}} 117do_test tcl-1.17 { 118 set v [catch {db rekey} msg] 119 lappend v $msg 120} {1 {wrong # args: should be "db rekey KEY"}} 121do_test tcl-1.18 { 122 set v [catch {db timeout} msg] 123 lappend v $msg 124} {1 {wrong # args: should be "db timeout MILLISECONDS"}} 125do_test tcl-1.19 { 126 set v [catch {db collate} msg] 127 lappend v $msg 128} {1 {wrong # args: should be "db collate NAME SCRIPT"}} 129do_test tcl-1.20 { 130 set v [catch {db collation_needed} msg] 131 lappend v $msg 132} {1 {wrong # args: should be "db collation_needed SCRIPT"}} 133do_test tcl-1.21 { 134 set v [catch {db total_changes xyz} msg] 135 lappend v $msg 136} {1 {wrong # args: should be "db total_changes "}} 137do_test tcl-1.20 { 138 set v [catch {db copy} msg] 139 lappend v $msg 140} {1 {wrong # args: should be "db copy CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?"}} 141 142 143if {[sqlite3 -tcl-uses-utf]} { 144 catch {unset ::result} 145 do_test tcl-2.1 { 146 execsql "CREATE TABLE t\u0123x(a int, b\u1235 float)" 147 } {} 148 ifcapable schema_pragmas { 149 do_test tcl-2.2 { 150 execsql "PRAGMA table_info(t\u0123x)" 151 } "0 a int 0 {} 0 1 b\u1235 float 0 {} 0" 152 } 153 do_test tcl-2.3 { 154 execsql "INSERT INTO t\u0123x VALUES(1,2.3)" 155 db eval "SELECT * FROM t\u0123x" result break 156 set result(*) 157 } "a b\u1235" 158} 159 160 161# Test the onecolumn method 162# 163do_test tcl-3.1 { 164 execsql { 165 INSERT INTO t1 SELECT a*2, b*2 FROM t1; 166 INSERT INTO t1 SELECT a*2+1, b*2+1 FROM t1; 167 INSERT INTO t1 SELECT a*2+3, b*2+3 FROM t1; 168 } 169 set rc [catch {db onecolumn {SELECT * FROM t1 ORDER BY a}} msg] 170 lappend rc $msg 171} {0 10} 172do_test tcl-3.2 { 173 db onecolumn {SELECT * FROM t1 WHERE a<0} 174} {} 175do_test tcl-3.3 { 176 set rc [catch {db onecolumn} errmsg] 177 lappend rc $errmsg 178} {1 {wrong # args: should be "db onecolumn SQL"}} 179do_test tcl-3.4 { 180 set rc [catch {db onecolumn {SELECT bogus}} errmsg] 181 lappend rc $errmsg 182} {1 {no such column: bogus}} 183ifcapable {tclvar} { 184 do_test tcl-3.5 { 185 set b 50 186 set rc [catch {db one {SELECT * FROM t1 WHERE b>$b}} msg] 187 lappend rc $msg 188 } {0 41} 189 do_test tcl-3.6 { 190 set b 500 191 set rc [catch {db one {SELECT * FROM t1 WHERE b>$b}} msg] 192 lappend rc $msg 193 } {0 {}} 194 do_test tcl-3.7 { 195 set b 500 196 set rc [catch {db one { 197 INSERT INTO t1 VALUES(99,510); 198 SELECT * FROM t1 WHERE b>$b 199 }} msg] 200 lappend rc $msg 201 } {0 99} 202} 203ifcapable {!tclvar} { 204 execsql {INSERT INTO t1 VALUES(99,510)} 205} 206 207# Turn the busy handler on and off 208# 209do_test tcl-4.1 { 210 proc busy_callback {cnt} { 211 break 212 } 213 db busy busy_callback 214 db busy 215} {busy_callback} 216do_test tcl-4.2 { 217 db busy {} 218 db busy 219} {} 220 221ifcapable {tclvar} { 222 # Parsing of TCL variable names within SQL into bound parameters. 223 # 224 do_test tcl-5.1 { 225 execsql {CREATE TABLE t3(a,b,c)} 226 catch {unset x} 227 set x(1) 5 228 set x(2) 7 229 execsql { 230 INSERT INTO t3 VALUES($::x(1),$::x(2),$::x(3)); 231 SELECT * FROM t3 232 } 233 } {5 7 {}} 234 do_test tcl-5.2 { 235 execsql { 236 SELECT typeof(a), typeof(b), typeof(c) FROM t3 237 } 238 } {text text null} 239 do_test tcl-5.3 { 240 catch {unset x} 241 set x [binary format h12 686900686f00] 242 execsql { 243 UPDATE t3 SET a=$::x; 244 } 245 db eval { 246 SELECT a FROM t3 247 } break 248 binary scan $a h12 adata 249 set adata 250 } {686900686f00} 251 do_test tcl-5.4 { 252 execsql { 253 SELECT typeof(a), typeof(b), typeof(c) FROM t3 254 } 255 } {blob text null} 256} 257 258# Operation of "break" and "continue" within row scripts 259# 260do_test tcl-6.1 { 261 db eval {SELECT * FROM t1} { 262 break 263 } 264 lappend a $b 265} {10 20} 266do_test tcl-6.2 { 267 set cnt 0 268 db eval {SELECT * FROM t1} { 269 if {$a>40} continue 270 incr cnt 271 } 272 set cnt 273} {4} 274do_test tcl-6.3 { 275 set cnt 0 276 db eval {SELECT * FROM t1} { 277 if {$a<40} continue 278 incr cnt 279 } 280 set cnt 281} {5} 282do_test tcl-6.4 { 283 proc return_test {x} { 284 db eval {SELECT * FROM t1} { 285 if {$a==$x} {return $b} 286 } 287 } 288 return_test 10 289} 20 290do_test tcl-6.5 { 291 return_test 20 292} 40 293do_test tcl-6.6 { 294 return_test 99 295} 510 296do_test tcl-6.7 { 297 return_test 0 298} {} 299 300do_test tcl-7.1 { 301 db version 302 expr 0 303} {0} 304 305# modify and reset the NULL representation 306# 307do_test tcl-8.1 { 308 db nullvalue NaN 309 execsql {INSERT INTO t1 VALUES(30,NULL)} 310 db eval {SELECT * FROM t1 WHERE b IS NULL} 311} {30 NaN} 312do_test tcl-8.2 { 313 db nullvalue NULL 314 db nullvalue 315} {NULL} 316do_test tcl-8.3 { 317 db nullvalue {} 318 db eval {SELECT * FROM t1 WHERE b IS NULL} 319} {30 {}} 320 321# Test the return type of user-defined functions 322# 323do_test tcl-9.1 { 324 db function ret_str {return "hi"} 325 execsql {SELECT typeof(ret_str())} 326} {text} 327do_test tcl-9.2 { 328 db function ret_dbl {return [expr {rand()*0.5}]} 329 execsql {SELECT typeof(ret_dbl())} 330} {real} 331do_test tcl-9.3 { 332 db function ret_int {return [expr {int(rand()*200)}]} 333 execsql {SELECT typeof(ret_int())} 334} {integer} 335 336# Recursive calls to the same user-defined function 337# 338ifcapable tclvar { 339 do_test tcl-9.10 { 340 proc userfunc_r1 {n} { 341 if {$n<=0} {return 0} 342 set nm1 [expr {$n-1}] 343 return [expr {[db eval {SELECT r1($nm1)}]+$n}] 344 } 345 db function r1 userfunc_r1 346 execsql {SELECT r1(10)} 347 } {55} 348 do_test tcl-9.11 { 349 execsql {SELECT r1(100)} 350 } {5050} 351} 352 353# Tests for the new transaction method 354# 355do_test tcl-10.1 { 356 db transaction {} 357} {} 358do_test tcl-10.2 { 359 db transaction deferred {} 360} {} 361do_test tcl-10.3 { 362 db transaction immediate {} 363} {} 364do_test tcl-10.4 { 365 db transaction exclusive {} 366} {} 367do_test tcl-10.5 { 368 set rc [catch {db transaction xyzzy {}} msg] 369 lappend rc $msg 370} {1 {bad transaction type "xyzzy": must be deferred, exclusive, or immediate}} 371do_test tcl-10.6 { 372 set rc [catch {db transaction {error test-error}} msg] 373 lappend rc $msg 374} {1 test-error} 375do_test tcl-10.7 { 376 db transaction { 377 db eval {CREATE TABLE t4(x)} 378 db transaction { 379 db eval {INSERT INTO t4 VALUES(1)} 380 } 381 } 382 db eval {SELECT * FROM t4} 383} 1 384do_test tcl-10.8 { 385 catch { 386 db transaction { 387 db eval {INSERT INTO t4 VALUES(2)} 388 db eval {INSERT INTO t4 VALUES(3)} 389 db eval {INSERT INTO t4 VALUES(4)} 390 error test-error 391 } 392 } 393 db eval {SELECT * FROM t4} 394} 1 395do_test tcl-10.9 { 396 db transaction { 397 db eval {INSERT INTO t4 VALUES(2)} 398 catch { 399 db transaction { 400 db eval {INSERT INTO t4 VALUES(3)} 401 db eval {INSERT INTO t4 VALUES(4)} 402 error test-error 403 } 404 } 405 } 406 db eval {SELECT * FROM t4} 407} {1 2 3 4} 408do_test tcl-10.10 { 409 for {set i 0} {$i<1} {incr i} { 410 db transaction { 411 db eval {INSERT INTO t4 VALUES(5)} 412 continue 413 } 414 } 415 db eval {SELECT * FROM t4} 416} {1 2 3 4 5} 417do_test tcl-10.11 { 418 for {set i 0} {$i<10} {incr i} { 419 db transaction { 420 db eval {INSERT INTO t4 VALUES(6)} 421 break 422 } 423 } 424 db eval {SELECT * FROM t4} 425} {1 2 3 4 5 6} 426do_test tcl-10.12 { 427 set rc [catch { 428 for {set i 0} {$i<10} {incr i} { 429 db transaction { 430 db eval {INSERT INTO t4 VALUES(7)} 431 return 432 } 433 } 434 }] 435} {2} 436do_test tcl-10.13 { 437 db eval {SELECT * FROM t4} 438} {1 2 3 4 5 6 7} 439 440do_test tcl-11.1 { 441 db exists {SELECT x,x*2,x+x FROM t4 WHERE x==4} 442} {1} 443do_test tcl-11.2 { 444 db exists {SELECT 0 FROM t4 WHERE x==4} 445} {1} 446do_test tcl-11.3 { 447 db exists {SELECT 1 FROM t4 WHERE x==8} 448} {0} 449 450do_test tcl-12.1 { 451 unset -nocomplain a b c version 452 set version [db version] 453 scan $version "%d.%d.%d" a b c 454 expr $a*1000000 + $b*1000 + $c 455} [sqlite3_libversion_number] 456 457finish_test 458