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.73 2009/03/16 13:19:36 danielk1977 Exp $ 19 20catch {sqlite3} 21 22set testdir [file dirname $argv0] 23source $testdir/tester.tcl 24set testprefix tcl 25 26# Check the error messages generated by tclsqlite 27# 28set r "sqlite_orig HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?" 29if {[sqlite3 -has-codec]} { 30 append r " ?-key CODECKEY?" 31} 32do_test tcl-1.1 { 33 set v [catch {sqlite3 -bogus} msg] 34 regsub {really_sqlite3} $msg {sqlite3} msg 35 lappend v $msg 36} [list 1 "wrong # args: should be \"$r\""] 37do_test tcl-1.1.1 { 38 set v [catch {sqlite3} msg] 39 regsub {really_sqlite3} $msg {sqlite3} msg 40 lappend v $msg 41} [list 1 "wrong # args: should be \"$r\""] 42do_test tcl-1.2 { 43 set v [catch {db bogus} msg] 44 lappend v $msg 45} {1 {bad option "bogus": must be authorizer, backup, bind_fallback, busy, cache, changes, close, collate, collation_needed, commit_hook, complete, copy, deserialize, enable_load_extension, errorcode, eval, exists, function, incrblob, interrupt, last_insert_rowid, nullvalue, onecolumn, preupdate, profile, progress, rekey, restore, rollback_hook, serialize, status, timeout, total_changes, trace, trace_v2, transaction, unlock_notify, update_hook, version, or wal_hook}} 46do_test tcl-1.2.1 { 47 set v [catch {db cache bogus} msg] 48 lappend v $msg 49} {1 {bad option "bogus": must be flush or size}} 50do_test tcl-1.2.2 { 51 set v [catch {db cache} msg] 52 lappend v $msg 53} {1 {wrong # args: should be "db cache option ?arg?"}} 54do_test tcl-1.3 { 55 execsql {CREATE TABLE t1(a int, b int)} 56 execsql {INSERT INTO t1 VALUES(10,20)} 57 set v [catch { 58 db eval {SELECT * FROM t1} data { 59 error "The error message" 60 } 61 } msg] 62 lappend v $msg 63} {1 {The error message}} 64do_test tcl-1.4 { 65 set v [catch { 66 db eval {SELECT * FROM t2} data { 67 error "The error message" 68 } 69 } msg] 70 lappend v $msg 71} {1 {no such table: t2}} 72do_test tcl-1.5 { 73 set v [catch { 74 db eval {SELECT * FROM t1} data { 75 break 76 } 77 } msg] 78 lappend v $msg 79} {0 {}} 80catch {expr x*} msg 81do_test tcl-1.6 { 82 set v [catch { 83 db eval {SELECT * FROM t1} data { 84 expr x* 85 } 86 } msg] 87 lappend v $msg 88} [list 1 $msg] 89do_test tcl-1.7 { 90 set v [catch {db} msg] 91 lappend v $msg 92} {1 {wrong # args: should be "db SUBCOMMAND ..."}} 93if {[catch {db auth {}}]==0} { 94 do_test tcl-1.8 { 95 set v [catch {db authorizer 1 2 3} msg] 96 lappend v $msg 97 } {1 {wrong # args: should be "db authorizer ?CALLBACK?"}} 98} 99do_test tcl-1.9 { 100 set v [catch {db busy 1 2 3} msg] 101 lappend v $msg 102} {1 {wrong # args: should be "db busy CALLBACK"}} 103do_test tcl-1.10 { 104 set v [catch {db progress 1} msg] 105 lappend v $msg 106} {1 {wrong # args: should be "db progress N CALLBACK"}} 107do_test tcl-1.11 { 108 set v [catch {db changes xyz} msg] 109 lappend v $msg 110} {1 {wrong # args: should be "db changes "}} 111do_test tcl-1.12 { 112 set v [catch {db commit_hook a b c} msg] 113 lappend v $msg 114} {1 {wrong # args: should be "db commit_hook ?CALLBACK?"}} 115ifcapable {complete} { 116 do_test tcl-1.13 { 117 set v [catch {db complete} msg] 118 lappend v $msg 119 } {1 {wrong # args: should be "db complete SQL"}} 120} 121do_test tcl-1.14 { 122 set v [catch {db eval} msg] 123 lappend v $msg 124} {1 {wrong # args: should be "db eval ?OPTIONS? SQL ?ARRAY-NAME? ?SCRIPT?"}} 125do_test tcl-1.15 { 126 set v [catch {db function} msg] 127 lappend v $msg 128} {1 {wrong # args: should be "db function NAME ?SWITCHES? SCRIPT"}} 129do_test tcl-1.16 { 130 set v [catch {db last_insert_rowid xyz} msg] 131 lappend v $msg 132} {1 {wrong # args: should be "db last_insert_rowid "}} 133do_test tcl-1.17 { 134 set v [catch {db rekey} msg] 135 lappend v $msg 136} {1 {wrong # args: should be "db rekey KEY"}} 137do_test tcl-1.18 { 138 set v [catch {db timeout} msg] 139 lappend v $msg 140} {1 {wrong # args: should be "db timeout MILLISECONDS"}} 141do_test tcl-1.19 { 142 set v [catch {db collate} msg] 143 lappend v $msg 144} {1 {wrong # args: should be "db collate NAME SCRIPT"}} 145do_test tcl-1.20 { 146 set v [catch {db collation_needed} msg] 147 lappend v $msg 148} {1 {wrong # args: should be "db collation_needed SCRIPT"}} 149do_test tcl-1.21 { 150 set v [catch {db total_changes xyz} msg] 151 lappend v $msg 152} {1 {wrong # args: should be "db total_changes "}} 153do_test tcl-1.22 { 154 set v [catch {db copy} msg] 155 lappend v $msg 156} {1 {wrong # args: should be "db copy CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?"}} 157do_test tcl-1.23 { 158 set v [catch {sqlite3 db2 test.db -vfs nosuchvfs} msg] 159 lappend v $msg 160} {1 {no such vfs: nosuchvfs}} 161 162catch {unset ::result} 163do_test tcl-2.1 { 164 execsql "CREATE TABLE t\u0123x(a int, b\u1235 float)" 165} {} 166ifcapable schema_pragmas { 167 do_test tcl-2.2 { 168 execsql "PRAGMA table_info(t\u0123x)" 169 } "0 a int 0 {} 0 1 b\u1235 float 0 {} 0" 170} 171do_test tcl-2.3 { 172 execsql "INSERT INTO t\u0123x VALUES(1,2.3)" 173 db eval "SELECT * FROM t\u0123x" result break 174 set result(*) 175} "a b\u1235" 176 177 178# Test the onecolumn method 179# 180do_test tcl-3.1 { 181 execsql { 182 INSERT INTO t1 SELECT a*2, b*2 FROM t1; 183 INSERT INTO t1 SELECT a*2+1, b*2+1 FROM t1; 184 INSERT INTO t1 SELECT a*2+3, b*2+3 FROM t1; 185 } 186 set rc [catch {db onecolumn {SELECT * FROM t1 ORDER BY a}} msg] 187 lappend rc $msg 188} {0 10} 189do_test tcl-3.2 { 190 db onecolumn {SELECT * FROM t1 WHERE a<0} 191} {} 192do_test tcl-3.3 { 193 set rc [catch {db onecolumn} errmsg] 194 lappend rc $errmsg 195} {1 {wrong # args: should be "db onecolumn SQL"}} 196do_test tcl-3.4 { 197 set rc [catch {db onecolumn {SELECT bogus}} errmsg] 198 lappend rc $errmsg 199} {1 {no such column: bogus}} 200ifcapable {tclvar} { 201 do_test tcl-3.5 { 202 set b 50 203 set rc [catch {db one {SELECT * FROM t1 WHERE b>$b}} msg] 204 lappend rc $msg 205 } {0 41} 206 do_test tcl-3.6 { 207 set b 500 208 set rc [catch {db one {SELECT * FROM t1 WHERE b>$b}} msg] 209 lappend rc $msg 210 } {0 {}} 211 do_test tcl-3.7 { 212 set b 500 213 set rc [catch {db one { 214 INSERT INTO t1 VALUES(99,510); 215 SELECT * FROM t1 WHERE b>$b 216 }} msg] 217 lappend rc $msg 218 } {0 99} 219} 220ifcapable {!tclvar} { 221 execsql {INSERT INTO t1 VALUES(99,510)} 222} 223 224# Turn the busy handler on and off 225# 226do_test tcl-4.1 { 227 proc busy_callback {cnt} { 228 break 229 } 230 db busy busy_callback 231 db busy 232} {busy_callback} 233do_test tcl-4.2 { 234 db busy {} 235 db busy 236} {} 237 238ifcapable {tclvar} { 239 # Parsing of TCL variable names within SQL into bound parameters. 240 # 241 do_test tcl-5.1 { 242 execsql {CREATE TABLE t3(a,b,c)} 243 catch {unset x} 244 set x(1) A 245 set x(2) B 246 execsql { 247 INSERT INTO t3 VALUES($::x(1),$::x(2),$::x(3)); 248 SELECT * FROM t3 249 } 250 } {A B {}} 251 do_test tcl-5.2 { 252 execsql { 253 SELECT typeof(a), typeof(b), typeof(c) FROM t3 254 } 255 } {text text null} 256 do_test tcl-5.3 { 257 catch {unset x} 258 set x [binary format h12 686900686f00] 259 execsql { 260 UPDATE t3 SET a=$::x; 261 } 262 db eval { 263 SELECT a FROM t3 264 } break 265 binary scan $a h12 adata 266 set adata 267 } {686900686f00} 268 do_test tcl-5.4 { 269 execsql { 270 SELECT typeof(a), typeof(b), typeof(c) FROM t3 271 } 272 } {blob text null} 273} 274 275# Operation of "break" and "continue" within row scripts 276# 277do_test tcl-6.1 { 278 db eval {SELECT * FROM t1} { 279 break 280 } 281 lappend a $b 282} {10 20} 283do_test tcl-6.2 { 284 set cnt 0 285 db eval {SELECT * FROM t1} { 286 if {$a>40} continue 287 incr cnt 288 } 289 set cnt 290} {4} 291do_test tcl-6.3 { 292 set cnt 0 293 db eval {SELECT * FROM t1} { 294 if {$a<40} continue 295 incr cnt 296 } 297 set cnt 298} {5} 299do_test tcl-6.4 { 300 proc return_test {x} { 301 db eval {SELECT * FROM t1} { 302 if {$a==$x} {return $b} 303 } 304 } 305 return_test 10 306} 20 307do_test tcl-6.5 { 308 return_test 20 309} 40 310do_test tcl-6.6 { 311 return_test 99 312} 510 313do_test tcl-6.7 { 314 return_test 0 315} {} 316 317do_test tcl-7.1 { 318 db version 319 expr 0 320} {0} 321 322# modify and reset the NULL representation 323# 324do_test tcl-8.1 { 325 db nullvalue NaN 326 execsql {INSERT INTO t1 VALUES(30,NULL)} 327 db eval {SELECT * FROM t1 WHERE b IS NULL} 328} {30 NaN} 329proc concatFunc args {return [join $args {}]} 330do_test tcl-8.2 { 331 db function concat concatFunc 332 db eval {SELECT concat('a', b, 'z') FROM t1 WHERE b is NULL} 333} {aNaNz} 334do_test tcl-8.3 { 335 db nullvalue NULL 336 db nullvalue 337} {NULL} 338do_test tcl-8.4 { 339 db nullvalue {} 340 db eval {SELECT * FROM t1 WHERE b IS NULL} 341} {30 {}} 342do_test tcl-8.5 { 343 db function concat concatFunc 344 db eval {SELECT concat('a', b, 'z') FROM t1 WHERE b is NULL} 345} {az} 346 347# Test the return type of user-defined functions 348# 349do_test tcl-9.1 { 350 db function ret_str {return "hi"} 351 execsql {SELECT typeof(ret_str())} 352} {text} 353do_test tcl-9.2 { 354 db function ret_dbl {return [expr {rand()*0.5}]} 355 execsql {SELECT typeof(ret_dbl())} 356} {real} 357do_test tcl-9.3 { 358 db function ret_int {return [expr {int(rand()*200)}]} 359 execsql {SELECT typeof(ret_int())} 360} {integer} 361 362# Recursive calls to the same user-defined function 363# 364ifcapable tclvar { 365 do_test tcl-9.10 { 366 proc userfunc_r1 {n} { 367 if {$n<=0} {return 0} 368 set nm1 [expr {$n-1}] 369 return [expr {[db eval {SELECT r1($nm1)}]+$n}] 370 } 371 db function r1 userfunc_r1 372 execsql {SELECT r1(10)} 373 } {55} 374 do_test tcl-9.11 { 375 execsql {SELECT r1(100)} 376 } {5050} 377} 378 379# Tests for the new transaction method 380# 381do_test tcl-10.1 { 382 db transaction {} 383} {} 384do_test tcl-10.2 { 385 db transaction deferred {} 386} {} 387do_test tcl-10.3 { 388 db transaction immediate {} 389} {} 390do_test tcl-10.4 { 391 db transaction exclusive {} 392} {} 393do_test tcl-10.5 { 394 set rc [catch {db transaction xyzzy {}} msg] 395 lappend rc $msg 396} {1 {bad transaction type "xyzzy": must be deferred, exclusive, or immediate}} 397do_test tcl-10.6 { 398 set rc [catch {db transaction {error test-error}} msg] 399 lappend rc $msg 400} {1 test-error} 401do_test tcl-10.7 { 402 db transaction { 403 db eval {CREATE TABLE t4(x)} 404 db transaction { 405 db eval {INSERT INTO t4 VALUES(1)} 406 } 407 } 408 db eval {SELECT * FROM t4} 409} 1 410do_test tcl-10.8 { 411 catch { 412 db transaction { 413 db eval {INSERT INTO t4 VALUES(2)} 414 db eval {INSERT INTO t4 VALUES(3)} 415 db eval {INSERT INTO t4 VALUES(4)} 416 error test-error 417 } 418 } 419 db eval {SELECT * FROM t4} 420} 1 421do_test tcl-10.9 { 422 db transaction { 423 db eval {INSERT INTO t4 VALUES(2)} 424 catch { 425 db transaction { 426 db eval {INSERT INTO t4 VALUES(3)} 427 db eval {INSERT INTO t4 VALUES(4)} 428 error test-error 429 } 430 } 431 } 432 db eval {SELECT * FROM t4} 433} {1 2} 434do_test tcl-10.10 { 435 for {set i 0} {$i<1} {incr i} { 436 db transaction { 437 db eval {INSERT INTO t4 VALUES(5)} 438 continue 439 } 440 error "This line should not be run" 441 } 442 db eval {SELECT * FROM t4} 443} {1 2 5} 444do_test tcl-10.11 { 445 for {set i 0} {$i<10} {incr i} { 446 db transaction { 447 db eval {INSERT INTO t4 VALUES(6)} 448 break 449 } 450 } 451 db eval {SELECT * FROM t4} 452} {1 2 5 6} 453do_test tcl-10.12 { 454 set rc [catch { 455 for {set i 0} {$i<10} {incr i} { 456 db transaction { 457 db eval {INSERT INTO t4 VALUES(7)} 458 return 459 } 460 } 461 }] 462} {2} 463do_test tcl-10.13 { 464 db eval {SELECT * FROM t4} 465} {1 2 5 6 7} 466 467# Now test that [db transaction] commands may be nested with 468# the expected results. 469# 470do_test tcl-10.14 { 471 db transaction { 472 db eval { 473 DELETE FROM t4; 474 INSERT INTO t4 VALUES('one'); 475 } 476 477 catch { 478 db transaction { 479 db eval { INSERT INTO t4 VALUES('two') } 480 db transaction { 481 db eval { INSERT INTO t4 VALUES('three') } 482 error "throw an error!" 483 } 484 } 485 } 486 } 487 488 db eval {SELECT * FROM t4} 489} {one} 490do_test tcl-10.15 { 491 # Make sure a transaction has not been left open. 492 db eval {BEGIN ; COMMIT} 493} {} 494do_test tcl-10.16 { 495 db transaction { 496 db eval { INSERT INTO t4 VALUES('two'); } 497 db transaction { 498 db eval { INSERT INTO t4 VALUES('three') } 499 db transaction { 500 db eval { INSERT INTO t4 VALUES('four') } 501 } 502 } 503 } 504 db eval {SELECT * FROM t4} 505} {one two three four} 506do_test tcl-10.17 { 507 catch { 508 db transaction { 509 db eval { INSERT INTO t4 VALUES('A'); } 510 db transaction { 511 db eval { INSERT INTO t4 VALUES('B') } 512 db transaction { 513 db eval { INSERT INTO t4 VALUES('C') } 514 error "throw an error!" 515 } 516 } 517 } 518 } 519 db eval {SELECT * FROM t4} 520} {one two three four} 521do_test tcl-10.18 { 522 # Make sure a transaction has not been left open. 523 db eval {BEGIN ; COMMIT} 524} {} 525 526# Mess up a [db transaction] command by locking the database using a 527# second connection when it tries to commit. Make sure the transaction 528# is not still open after the "database is locked" exception is thrown. 529# 530do_test tcl-10.18 { 531 sqlite3 db2 test.db 532 db2 eval { 533 BEGIN; 534 SELECT * FROM sqlite_master; 535 } 536 537 set rc [catch { 538 db transaction { 539 db eval {INSERT INTO t4 VALUES('five')} 540 } 541 } msg] 542 list $rc $msg 543} {1 {database is locked}} 544do_test tcl-10.19 { 545 db eval {BEGIN ; COMMIT} 546} {} 547 548# Thwart a [db transaction] command by locking the database using a 549# second connection with "BEGIN EXCLUSIVE". Make sure no transaction is 550# open after the "database is locked" exception is thrown. 551# 552do_test tcl-10.20 { 553 db2 eval { 554 COMMIT; 555 BEGIN EXCLUSIVE; 556 } 557 set rc [catch { 558 db transaction { 559 db eval {INSERT INTO t4 VALUES('five')} 560 } 561 } msg] 562 list $rc $msg 563} {1 {database is locked}} 564do_test tcl-10.21 { 565 db2 close 566 db eval {BEGIN ; COMMIT} 567} {} 568do_test tcl-10.22 { 569 sqlite3 db2 test.db 570 db transaction exclusive { 571 catch { db2 eval {SELECT * FROM sqlite_master} } msg 572 set msg "db2: $msg" 573 } 574 set msg 575} {db2: database is locked} 576db2 close 577 578do_test tcl-11.1 { 579 db eval {INSERT INTO t4 VALUES(6)} 580 db exists {SELECT x,x*2,x+x FROM t4 WHERE x==6} 581} {1} 582do_test tcl-11.2 { 583 db exists {SELECT 0 FROM t4 WHERE x==6} 584} {1} 585do_test tcl-11.3 { 586 db exists {SELECT 1 FROM t4 WHERE x==8} 587} {0} 588do_test tcl-11.3.1 { 589 tcl_objproc db exists {SELECT 1 FROM t4 WHERE x==8} 590} {0} 591 592do_test tcl-12.1 { 593 unset -nocomplain a b c version 594 set version [db version] 595 scan $version "%d.%d.%d" a b c 596 expr $a*1000000 + $b*1000 + $c 597} [sqlite3_libversion_number] 598 599 600# Check to see that when bindings of the form @aaa are used instead 601# of $aaa, that objects are treated as bytearray and are inserted 602# as BLOBs. 603# 604ifcapable tclvar { 605 do_test tcl-13.1 { 606 db eval {CREATE TABLE t5(x BLOB)} 607 set x abc123 608 db eval {INSERT INTO t5 VALUES($x)} 609 db eval {SELECT typeof(x) FROM t5} 610 } {text} 611 do_test tcl-13.2 { 612 binary scan $x H notUsed 613 db eval { 614 DELETE FROM t5; 615 INSERT INTO t5 VALUES($x); 616 SELECT typeof(x) FROM t5; 617 } 618 } {text} 619 do_test tcl-13.3 { 620 db eval { 621 DELETE FROM t5; 622 INSERT INTO t5 VALUES(@x); 623 SELECT typeof(x) FROM t5; 624 } 625 } {blob} 626 do_test tcl-13.4 { 627 set y 1234 628 db eval { 629 DELETE FROM t5; 630 INSERT INTO t5 VALUES(@y); 631 SELECT hex(x), typeof(x) FROM t5 632 } 633 } {31323334 blob} 634} 635 636db func xCall xCall 637proc xCall {} { return "value" } 638do_execsql_test tcl-14.1 { 639 CREATE TABLE t6(x); 640 INSERT INTO t6 VALUES(1); 641} 642do_test tcl-14.2 { 643 db one {SELECT x FROM t6 WHERE xCall()!='value'} 644} {} 645 646# Verify that the "exists" and "onecolumn" methods work when 647# a "profile" is registered. 648# 649catch {db close} 650sqlite3 db :memory: 651proc noop-profile {args} { 652 return 653} 654do_test tcl-15.0 { 655 db eval {CREATE TABLE t1(a); INSERT INTO t1 VALUES(1),(2),(3);} 656 db onecolumn {SELECT a FROM t1 WHERE a>2} 657} {3} 658do_test tcl-15.1 { 659 db exists {SELECT a FROM t1 WHERE a>2} 660} {1} 661do_test tcl-15.2 { 662 db exists {SELECT a FROM t1 WHERE a>3} 663} {0} 664db profile noop-profile 665do_test tcl-15.3 { 666 db onecolumn {SELECT a FROM t1 WHERE a>2} 667} {3} 668do_test tcl-15.4 { 669 db exists {SELECT a FROM t1 WHERE a>2} 670} {1} 671do_test tcl-15.5 { 672 db exists {SELECT a FROM t1 WHERE a>3} 673} {0} 674 675 676# 2017-06-26: The --withoutnulls flag to "db eval". 677# 678# In the "db eval --withoutnulls SQL ARRAY" form, NULL results cause the 679# corresponding array entry to be unset. The default behavior (without 680# the -withoutnulls flags) is for the corresponding array value to get 681# the [db nullvalue] string. 682# 683catch {db close} 684forcedelete test.db 685sqlite3 db test.db 686do_execsql_test tcl-16.100 { 687 CREATE TABLE t1(a,b); 688 INSERT INTO t1 VALUES(1,2),(2,NULL),(3,'xyz'); 689} 690do_test tcl-16.101 { 691 set res {} 692 unset -nocomplain x 693 db eval {SELECT * FROM t1} x { 694 lappend res $x(a) [array names x] 695 } 696 set res 697} {1 {a b *} 2 {a b *} 3 {a b *}} 698do_test tcl-16.102 { 699 set res [catch { 700 db eval -unknown {SELECT * FROM t1} x { 701 lappend res $x(a) [array names x] 702 } 703 } rc] 704 lappend res $rc 705} {1 {unknown option: "-unknown"}} 706do_test tcl-16.103 { 707 set res {} 708 unset -nocomplain x 709 db eval -withoutnulls {SELECT * FROM t1} x { 710 lappend res $x(a) [array names x] 711 } 712 set res 713} {1 {a b *} 2 {a *} 3 {a b *}} 714 715#------------------------------------------------------------------------- 716# Test the -type option to [db function]. 717# 718reset_db 719proc add {a b} { return [expr $a + $b] } 720proc ret {a} { return $a } 721 722db function add_i -returntype integer add 723db function add_r -ret real add 724db function add_t -return text add 725db function add_b -returntype blob add 726db function add_a -returntype any add 727 728db function ret_i -returntype int ret 729db function ret_r -returntype real ret 730db function ret_t -returntype text ret 731db function ret_b -returntype blob ret 732db function ret_a -r any ret 733 734do_execsql_test 17.0 { 735 SELECT quote( add_i(2, 3) ); 736 SELECT quote( add_r(2, 3) ); 737 SELECT quote( add_t(2, 3) ); 738 SELECT quote( add_b(2, 3) ); 739 SELECT quote( add_a(2, 3) ); 740} {5 5.0 '5' X'35' 5} 741 742do_execsql_test 17.1 { 743 SELECT quote( add_i(2.2, 3.3) ); 744 SELECT quote( add_r(2.2, 3.3) ); 745 SELECT quote( add_t(2.2, 3.3) ); 746 SELECT quote( add_b(2.2, 3.3) ); 747 SELECT quote( add_a(2.2, 3.3) ); 748} {5.5 5.5 '5.5' X'352E35' 5.5} 749 750do_execsql_test 17.2 { 751 SELECT quote( ret_i(2.5) ); 752 SELECT quote( ret_r(2.5) ); 753 SELECT quote( ret_t(2.5) ); 754 SELECT quote( ret_b(2.5) ); 755 SELECT quote( ret_a(2.5) ); 756} {2.5 2.5 '2.5' X'322E35' 2.5} 757 758do_execsql_test 17.3 { 759 SELECT quote( ret_i('2.5') ); 760 SELECT quote( ret_r('2.5') ); 761 SELECT quote( ret_t('2.5') ); 762 SELECT quote( ret_b('2.5') ); 763 SELECT quote( ret_a('2.5') ); 764} {2.5 2.5 '2.5' X'322E35' '2.5'} 765 766do_execsql_test 17.4 { 767 SELECT quote( ret_i('abc') ); 768 SELECT quote( ret_r('abc') ); 769 SELECT quote( ret_t('abc') ); 770 SELECT quote( ret_b('abc') ); 771 SELECT quote( ret_a('abc') ); 772} {'abc' 'abc' 'abc' X'616263' 'abc'} 773 774do_execsql_test 17.5 { 775 SELECT quote( ret_i(X'616263') ); 776 SELECT quote( ret_r(X'616263') ); 777 SELECT quote( ret_t(X'616263') ); 778 SELECT quote( ret_b(X'616263') ); 779 SELECT quote( ret_a(X'616263') ); 780} {'abc' 'abc' 'abc' X'616263' X'616263'} 781 782do_test 17.6.1 { 783 list [catch { db function xyz -return object ret } msg] $msg 784} {1 {bad type "object": must be integer, real, text, blob, or any}} 785 786do_test 17.6.2 { 787 list [catch { db function xyz -return ret } msg] $msg 788} {1 {option requires an argument: -return}} 789 790do_test 17.6.3 { 791 list [catch { db function xyz -n object ret } msg] $msg 792} {1 {bad option "-n": must be -argcount, -deterministic or -returntype}} 793 794# 2019-02-28: The "bind_fallback" command. 795# 796do_test 18.100 { 797 unset -nocomplain bindings abc def ghi jkl mno e01 e02 798 set bindings(abc) [expr {1+2}] 799 set bindings(def) {hello} 800 set bindings(ghi) [expr {3.1415926*1.0}] 801 proc bind_callback {nm} { 802 global bindings 803 set n2 [string range $nm 1 end] 804 if {[info exists bindings($n2)]} { 805 return $bindings($n2) 806 } 807 if {[string match e* $n2]} { 808 error "no such variable: $nm" 809 } 810 return -code return {} 811 } 812 db bind_fallback bind_callback 813 db eval {SELECT $abc, typeof($abc), $def, typeof($def), $ghi, typeof($ghi)} 814} {3 integer hello text 3.1415926 real} 815do_test 18.110 { 816 db eval {SELECT quote(@def), typeof(@def)} 817} {X'68656C6C6F' blob} 818do_execsql_test 18.120 { 819 SELECT typeof($mno); 820} {null} 821do_catchsql_test 18.130 { 822 SELECT $e01; 823} {1 {no such variable: $e01}} 824do_test 18.140 { 825 db bind_fallback 826} {bind_callback} 827do_test 18.200 { 828 db bind_fallback {} 829 db eval {SELECT $abc, typeof($abc), $def, typeof($def), $ghi, typeof($ghi)} 830} {{} null {} null {} null} 831do_test 18.300 { 832 unset -nocomplain bindings 833 proc bind_callback {nm} {lappend ::bindings $nm} 834 db bind_fallback bind_callback 835 db eval {SELECT $abc, @def, $ghi(123), :mno} 836 set bindings 837} {{$abc} @def {$ghi(123)} :mno} 838do_test 18.900 { 839 set rc [catch {db bind_fallback a b} msg] 840 lappend rc $msg 841} {1 {wrong # args: should be "db bind_fallback ?CALLBACK?"}} 842do_test 18.910 { 843 db bind_fallback bind_fallback_does_not_exist 844} {} 845do_catchsql_test 19.911 { 846 SELECT $abc, typeof($abc), $def, typeof($def), $ghi, typeof($ghi); 847} {1 {invalid command name "bind_fallback_does_not_exist"}} 848db bind_fallback {} 849 850finish_test 851