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