3 # The author disclaims copyright to this source code. In place of
4 # a legal notice, here is a blessing:
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.
10 #***********************************************************************
11 # This file implements regression tests for TCL interface to the
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.
18 # $Id: tclsqlite.test,v 1.73 2009/03/16 13:19:36 danielk1977 Exp $
20 set testdir [file dirname $argv0]
21 source $testdir/tester.tcl
23 # Check the error messages generated by tclsqlite
25 set r "sqlite_orig HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
26 if {[sqlite3 -has-codec]} {
27 append r " ?-key CODECKEY?"
30 set v [catch {sqlite3 -bogus} msg]
31 regsub {really_sqlite3} $msg {sqlite3} msg
33 } [list 1 "wrong # args: should be \"$r\""]
35 set v [catch {db bogus} msg]
37 } {1 {bad option "bogus": must be authorizer, backup, 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}}
39 set v [catch {db cache bogus} msg]
41 } {1 {bad option "bogus": must be flush or size}}
43 set v [catch {db cache} msg]
45 } {1 {wrong # args: should be "db cache option ?arg?"}}
47 execsql {CREATE TABLE t1(a int, b int)}
48 execsql {INSERT INTO t1 VALUES(10,20)}
50 db eval {SELECT * FROM t1} data {
51 error "The error message"
55 } {1 {The error message}}
58 db eval {SELECT * FROM t2} data {
59 error "The error message"
63 } {1 {no such table: t2}}
66 db eval {SELECT * FROM t1} data {
75 db eval {SELECT * FROM t1} data {
82 set v [catch {db} msg]
84 } {1 {wrong # args: should be "db SUBCOMMAND ..."}}
85 if {[catch {db auth {}}]==0} {
87 set v [catch {db authorizer 1 2 3} msg]
89 } {1 {wrong # args: should be "db authorizer ?CALLBACK?"}}
92 set v [catch {db busy 1 2 3} msg]
94 } {1 {wrong # args: should be "db busy CALLBACK"}}
96 set v [catch {db progress 1} msg]
98 } {1 {wrong # args: should be "db progress N CALLBACK"}}
100 set v [catch {db changes xyz} msg]
102 } {1 {wrong # args: should be "db changes "}}
104 set v [catch {db commit_hook a b c} msg]
106 } {1 {wrong # args: should be "db commit_hook ?CALLBACK?"}}
107 ifcapable {complete} {
109 set v [catch {db complete} msg]
111 } {1 {wrong # args: should be "db complete SQL"}}
114 set v [catch {db eval} msg]
116 } {1 {wrong # args: should be "db eval ?OPTIONS? SQL ?ARRAY-NAME? ?SCRIPT?"}}
118 set v [catch {db function} msg]
120 } {1 {wrong # args: should be "db function NAME ?SWITCHES? SCRIPT"}}
122 set v [catch {db last_insert_rowid xyz} msg]
124 } {1 {wrong # args: should be "db last_insert_rowid "}}
126 set v [catch {db rekey} msg]
128 } {1 {wrong # args: should be "db rekey KEY"}}
130 set v [catch {db timeout} msg]
132 } {1 {wrong # args: should be "db timeout MILLISECONDS"}}
134 set v [catch {db collate} msg]
136 } {1 {wrong # args: should be "db collate NAME SCRIPT"}}
138 set v [catch {db collation_needed} msg]
140 } {1 {wrong # args: should be "db collation_needed SCRIPT"}}
142 set v [catch {db total_changes xyz} msg]
144 } {1 {wrong # args: should be "db total_changes "}}
146 set v [catch {db copy} msg]
148 } {1 {wrong # args: should be "db copy CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?"}}
150 set v [catch {sqlite3 db2 test.db -vfs nosuchvfs} msg]
152 } {1 {no such vfs: nosuchvfs}}
154 catch {unset ::result}
156 execsql "CREATE TABLE t\u0123x(a int, b\u1235 float)"
158 ifcapable schema_pragmas {
160 execsql "PRAGMA table_info(t\u0123x)"
161 } "0 a int 0 {} 0 1 b\u1235 float 0 {} 0"
164 execsql "INSERT INTO t\u0123x VALUES(1,2.3)"
165 db eval "SELECT * FROM t\u0123x" result break
170 # Test the onecolumn method
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;
178 set rc [catch {db onecolumn {SELECT * FROM t1 ORDER BY a}} msg]
182 db onecolumn {SELECT * FROM t1 WHERE a<0}
185 set rc [catch {db onecolumn} errmsg]
187 } {1 {wrong # args: should be "db onecolumn SQL"}}
189 set rc [catch {db onecolumn {SELECT bogus}} errmsg]
191 } {1 {no such column: bogus}}
195 set rc [catch {db one {SELECT * FROM t1 WHERE b>$b}} msg]
200 set rc [catch {db one {SELECT * FROM t1 WHERE b>$b}} msg]
205 set rc [catch {db one {
206 INSERT INTO t1 VALUES(99,510);
207 SELECT * FROM t1 WHERE b>$b
212 ifcapable {!tclvar} {
213 execsql {INSERT INTO t1 VALUES(99,510)}
216 # Turn the busy handler on and off
219 proc busy_callback {cnt} {
222 db busy busy_callback
231 # Parsing of TCL variable names within SQL into bound parameters.
234 execsql {CREATE TABLE t3(a,b,c)}
239 INSERT INTO t3 VALUES($::x(1),$::x(2),$::x(3));
245 SELECT typeof(a), typeof(b), typeof(c) FROM t3
250 set x [binary format h12 686900686f00]
252 UPDATE t3 SET a=$::x;
257 binary scan $a h12 adata
262 SELECT typeof(a), typeof(b), typeof(c) FROM t3
267 # Operation of "break" and "continue" within row scripts
270 db eval {SELECT * FROM t1} {
277 db eval {SELECT * FROM t1} {
285 db eval {SELECT * FROM t1} {
292 proc return_test {x} {
293 db eval {SELECT * FROM t1} {
294 if {$a==$x} {return $b}
314 # modify and reset the NULL representation
318 execsql {INSERT INTO t1 VALUES(30,NULL)}
319 db eval {SELECT * FROM t1 WHERE b IS NULL}
321 proc concatFunc args {return [join $args {}]}
323 db function concat concatFunc
324 db eval {SELECT concat('a', b, 'z') FROM t1 WHERE b is NULL}
332 db eval {SELECT * FROM t1 WHERE b IS NULL}
335 db function concat concatFunc
336 db eval {SELECT concat('a', b, 'z') FROM t1 WHERE b is NULL}
339 # Test the return type of user-defined functions
342 db function ret_str {return "hi"}
343 execsql {SELECT typeof(ret_str())}
346 db function ret_dbl {return [expr {rand()*0.5}]}
347 execsql {SELECT typeof(ret_dbl())}
350 db function ret_int {return [expr {int(rand()*200)}]}
351 execsql {SELECT typeof(ret_int())}
354 # Recursive calls to the same user-defined function
358 proc userfunc_r1 {n} {
359 if {$n<=0} {return 0}
360 set nm1 [expr {$n-1}]
361 return [expr {[db eval {SELECT r1($nm1)}]+$n}]
363 db function r1 userfunc_r1
364 execsql {SELECT r1(10)}
367 execsql {SELECT r1(100)}
371 # Tests for the new transaction method
377 db transaction deferred {}
380 db transaction immediate {}
383 db transaction exclusive {}
386 set rc [catch {db transaction xyzzy {}} msg]
388 } {1 {bad transaction type "xyzzy": must be deferred, exclusive, or immediate}}
390 set rc [catch {db transaction {error test-error}} msg]
395 db eval {CREATE TABLE t4(x)}
397 db eval {INSERT INTO t4 VALUES(1)}
400 db eval {SELECT * FROM t4}
405 db eval {INSERT INTO t4 VALUES(2)}
406 db eval {INSERT INTO t4 VALUES(3)}
407 db eval {INSERT INTO t4 VALUES(4)}
411 db eval {SELECT * FROM t4}
415 db eval {INSERT INTO t4 VALUES(2)}
418 db eval {INSERT INTO t4 VALUES(3)}
419 db eval {INSERT INTO t4 VALUES(4)}
424 db eval {SELECT * FROM t4}
427 for {set i 0} {$i<1} {incr i} {
429 db eval {INSERT INTO t4 VALUES(5)}
432 error "This line should not be run"
434 db eval {SELECT * FROM t4}
437 for {set i 0} {$i<10} {incr i} {
439 db eval {INSERT INTO t4 VALUES(6)}
443 db eval {SELECT * FROM t4}
447 for {set i 0} {$i<10} {incr i} {
449 db eval {INSERT INTO t4 VALUES(7)}
456 db eval {SELECT * FROM t4}
459 # Now test that [db transaction] commands may be nested with
460 # the expected results.
466 INSERT INTO t4 VALUES('one');
471 db eval { INSERT INTO t4 VALUES('two') }
473 db eval { INSERT INTO t4 VALUES('three') }
474 error "throw an error!"
480 db eval {SELECT * FROM t4}
483 # Make sure a transaction has not been left open.
484 db eval {BEGIN ; COMMIT}
488 db eval { INSERT INTO t4 VALUES('two'); }
490 db eval { INSERT INTO t4 VALUES('three') }
492 db eval { INSERT INTO t4 VALUES('four') }
496 db eval {SELECT * FROM t4}
497 } {one two three four}
501 db eval { INSERT INTO t4 VALUES('A'); }
503 db eval { INSERT INTO t4 VALUES('B') }
505 db eval { INSERT INTO t4 VALUES('C') }
506 error "throw an error!"
511 db eval {SELECT * FROM t4}
512 } {one two three four}
514 # Make sure a transaction has not been left open.
515 db eval {BEGIN ; COMMIT}
518 # Mess up a [db transaction] command by locking the database using a
519 # second connection when it tries to commit. Make sure the transaction
520 # is not still open after the "database is locked" exception is thrown.
526 SELECT * FROM sqlite_master;
531 db eval {INSERT INTO t4 VALUES('five')}
535 } {1 {database is locked}}
537 db eval {BEGIN ; COMMIT}
540 # Thwart a [db transaction] command by locking the database using a
541 # second connection with "BEGIN EXCLUSIVE". Make sure no transaction is
542 # open after the "database is locked" exception is thrown.
551 db eval {INSERT INTO t4 VALUES('five')}
555 } {1 {database is locked}}
558 db eval {BEGIN ; COMMIT}
562 db transaction exclusive {
563 catch { db2 eval {SELECT * FROM sqlite_master} } msg
567 } {db2: database is locked}
571 db eval {INSERT INTO t4 VALUES(6)}
572 db exists {SELECT x,x*2,x+x FROM t4 WHERE x==6}
575 db exists {SELECT 0 FROM t4 WHERE x==6}
578 db exists {SELECT 1 FROM t4 WHERE x==8}
581 tcl_objproc db exists {SELECT 1 FROM t4 WHERE x==8}
585 unset -nocomplain a b c version
586 set version [db version]
587 scan $version "%d.%d.%d" a b c
588 expr $a*1000000 + $b*1000 + $c
589 } [sqlite3_libversion_number]
592 # Check to see that when bindings of the form @aaa are used instead
593 # of $aaa, that objects are treated as bytearray and are inserted
598 db eval {CREATE TABLE t5(x BLOB)}
600 db eval {INSERT INTO t5 VALUES($x)}
601 db eval {SELECT typeof(x) FROM t5}
604 binary scan $x H notUsed
607 INSERT INTO t5 VALUES($x);
608 SELECT typeof(x) FROM t5;
614 INSERT INTO t5 VALUES(@x);
615 SELECT typeof(x) FROM t5;
622 INSERT INTO t5 VALUES(@y);
623 SELECT hex(x), typeof(x) FROM t5
629 proc xCall {} { return "value" }
630 do_execsql_test tcl-14.1 {
632 INSERT INTO t6 VALUES(1);
635 db one {SELECT x FROM t6 WHERE xCall()!='value'}
638 # Verify that the "exists" and "onecolumn" methods work when
639 # a "profile" is registered.
643 proc noop-profile {args} {
647 db eval {CREATE TABLE t1(a); INSERT INTO t1 VALUES(1),(2),(3);}
648 db onecolumn {SELECT a FROM t1 WHERE a>2}
651 db exists {SELECT a FROM t1 WHERE a>2}
654 db exists {SELECT a FROM t1 WHERE a>3}
656 db profile noop-profile
658 db onecolumn {SELECT a FROM t1 WHERE a>2}
661 db exists {SELECT a FROM t1 WHERE a>2}
664 db exists {SELECT a FROM t1 WHERE a>3}
668 # 2017-06-26: The --withoutnulls flag to "db eval".
670 # In the "db eval --withoutnulls SQL ARRAY" form, NULL results cause the
671 # corresponding array entry to be unset. The default behavior (without
672 # the -withoutnulls flags) is for the corresponding array value to get
673 # the [db nullvalue] string.
678 do_execsql_test tcl-16.100 {
679 CREATE TABLE t1(a,b);
680 INSERT INTO t1 VALUES(1,2),(2,NULL),(3,'xyz');
685 db eval {SELECT * FROM t1} x {
686 lappend res $x(a) [array names x]
689 } {1 {a b *} 2 {a b *} 3 {a b *}}
692 db eval -unknown {SELECT * FROM t1} x {
693 lappend res $x(a) [array names x]
697 } {1 {unknown option: "-unknown"}}
701 db eval -withoutnulls {SELECT * FROM t1} x {
702 lappend res $x(a) [array names x]
705 } {1 {a b *} 2 {a *} 3 {a b *}}