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 if {[sqlite3 -has-codec]} {
26 set r "sqlite_orig HANDLE FILENAME ?-key CODEC-KEY?"
28 set r "sqlite_orig HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
31 set v [catch {sqlite3 bogus} msg]
32 regsub {really_sqlite3} $msg {sqlite3} msg
34 } [list 1 "wrong # args: should be \"$r\""]
36 set v [catch {db bogus} msg]
38 } {1 {bad option "bogus": must be authorizer, backup, 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, restore, rollback_hook, status, timeout, total_changes, trace, transaction, unlock_notify, update_hook, version, or wal_hook}}
40 set v [catch {db cache bogus} msg]
42 } {1 {bad option "bogus": must be flush or size}}
44 set v [catch {db cache} msg]
46 } {1 {wrong # args: should be "db cache option ?arg?"}}
48 execsql {CREATE TABLE t1(a int, b int)}
49 execsql {INSERT INTO t1 VALUES(10,20)}
51 db eval {SELECT * FROM t1} data {
52 error "The error message"
56 } {1 {The error message}}
59 db eval {SELECT * FROM t2} data {
60 error "The error message"
64 } {1 {no such table: t2}}
67 db eval {SELECT * FROM t1} data {
76 db eval {SELECT * FROM t1} data {
83 set v [catch {db} msg]
85 } {1 {wrong # args: should be "db SUBCOMMAND ..."}}
86 if {[catch {db auth {}}]==0} {
88 set v [catch {db authorizer 1 2 3} msg]
90 } {1 {wrong # args: should be "db authorizer ?CALLBACK?"}}
93 set v [catch {db busy 1 2 3} msg]
95 } {1 {wrong # args: should be "db busy CALLBACK"}}
97 set v [catch {db progress 1} msg]
99 } {1 {wrong # args: should be "db progress N CALLBACK"}}
101 set v [catch {db changes xyz} msg]
103 } {1 {wrong # args: should be "db changes "}}
105 set v [catch {db commit_hook a b c} msg]
107 } {1 {wrong # args: should be "db commit_hook ?CALLBACK?"}}
108 ifcapable {complete} {
110 set v [catch {db complete} msg]
112 } {1 {wrong # args: should be "db complete SQL"}}
115 set v [catch {db eval} msg]
117 } {1 {wrong # args: should be "db eval SQL ?ARRAY-NAME? ?SCRIPT?"}}
119 set v [catch {db function} msg]
121 } {1 {wrong # args: should be "db function NAME [-argcount N] SCRIPT"}}
123 set v [catch {db last_insert_rowid xyz} msg]
125 } {1 {wrong # args: should be "db last_insert_rowid "}}
127 set v [catch {db rekey} msg]
129 } {1 {wrong # args: should be "db rekey KEY"}}
131 set v [catch {db timeout} msg]
133 } {1 {wrong # args: should be "db timeout MILLISECONDS"}}
135 set v [catch {db collate} msg]
137 } {1 {wrong # args: should be "db collate NAME SCRIPT"}}
139 set v [catch {db collation_needed} msg]
141 } {1 {wrong # args: should be "db collation_needed SCRIPT"}}
143 set v [catch {db total_changes xyz} msg]
145 } {1 {wrong # args: should be "db total_changes "}}
147 set v [catch {db copy} msg]
149 } {1 {wrong # args: should be "db copy CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?"}}
151 set v [catch {sqlite3 db2 test.db -vfs nosuchvfs} msg]
153 } {1 {no such vfs: nosuchvfs}}
155 catch {unset ::result}
157 execsql "CREATE TABLE t\u0123x(a int, b\u1235 float)"
159 ifcapable schema_pragmas {
161 execsql "PRAGMA table_info(t\u0123x)"
162 } "0 a int 0 {} 0 1 b\u1235 float 0 {} 0"
165 execsql "INSERT INTO t\u0123x VALUES(1,2.3)"
166 db eval "SELECT * FROM t\u0123x" result break
171 # Test the onecolumn method
175 INSERT INTO t1 SELECT a*2, b*2 FROM t1;
176 INSERT INTO t1 SELECT a*2+1, b*2+1 FROM t1;
177 INSERT INTO t1 SELECT a*2+3, b*2+3 FROM t1;
179 set rc [catch {db onecolumn {SELECT * FROM t1 ORDER BY a}} msg]
183 db onecolumn {SELECT * FROM t1 WHERE a<0}
186 set rc [catch {db onecolumn} errmsg]
188 } {1 {wrong # args: should be "db onecolumn SQL"}}
190 set rc [catch {db onecolumn {SELECT bogus}} errmsg]
192 } {1 {no such column: bogus}}
196 set rc [catch {db one {SELECT * FROM t1 WHERE b>$b}} msg]
201 set rc [catch {db one {SELECT * FROM t1 WHERE b>$b}} msg]
206 set rc [catch {db one {
207 INSERT INTO t1 VALUES(99,510);
208 SELECT * FROM t1 WHERE b>$b
213 ifcapable {!tclvar} {
214 execsql {INSERT INTO t1 VALUES(99,510)}
217 # Turn the busy handler on and off
220 proc busy_callback {cnt} {
223 db busy busy_callback
232 # Parsing of TCL variable names within SQL into bound parameters.
235 execsql {CREATE TABLE t3(a,b,c)}
240 INSERT INTO t3 VALUES($::x(1),$::x(2),$::x(3));
246 SELECT typeof(a), typeof(b), typeof(c) FROM t3
251 set x [binary format h12 686900686f00]
253 UPDATE t3 SET a=$::x;
258 binary scan $a h12 adata
263 SELECT typeof(a), typeof(b), typeof(c) FROM t3
268 # Operation of "break" and "continue" within row scripts
271 db eval {SELECT * FROM t1} {
278 db eval {SELECT * FROM t1} {
286 db eval {SELECT * FROM t1} {
293 proc return_test {x} {
294 db eval {SELECT * FROM t1} {
295 if {$a==$x} {return $b}
315 # modify and reset the NULL representation
319 execsql {INSERT INTO t1 VALUES(30,NULL)}
320 db eval {SELECT * FROM t1 WHERE b IS NULL}
322 proc concatFunc args {return [join $args {}]}
324 db function concat concatFunc
325 db eval {SELECT concat('a', b, 'z') FROM t1 WHERE b is NULL}
333 db eval {SELECT * FROM t1 WHERE b IS NULL}
336 db function concat concatFunc
337 db eval {SELECT concat('a', b, 'z') FROM t1 WHERE b is NULL}
340 # Test the return type of user-defined functions
343 db function ret_str {return "hi"}
344 execsql {SELECT typeof(ret_str())}
347 db function ret_dbl {return [expr {rand()*0.5}]}
348 execsql {SELECT typeof(ret_dbl())}
351 db function ret_int {return [expr {int(rand()*200)}]}
352 execsql {SELECT typeof(ret_int())}
355 # Recursive calls to the same user-defined function
359 proc userfunc_r1 {n} {
360 if {$n<=0} {return 0}
361 set nm1 [expr {$n-1}]
362 return [expr {[db eval {SELECT r1($nm1)}]+$n}]
364 db function r1 userfunc_r1
365 execsql {SELECT r1(10)}
368 execsql {SELECT r1(100)}
372 # Tests for the new transaction method
378 db transaction deferred {}
381 db transaction immediate {}
384 db transaction exclusive {}
387 set rc [catch {db transaction xyzzy {}} msg]
389 } {1 {bad transaction type "xyzzy": must be deferred, exclusive, or immediate}}
391 set rc [catch {db transaction {error test-error}} msg]
396 db eval {CREATE TABLE t4(x)}
398 db eval {INSERT INTO t4 VALUES(1)}
401 db eval {SELECT * FROM t4}
406 db eval {INSERT INTO t4 VALUES(2)}
407 db eval {INSERT INTO t4 VALUES(3)}
408 db eval {INSERT INTO t4 VALUES(4)}
412 db eval {SELECT * FROM t4}
416 db eval {INSERT INTO t4 VALUES(2)}
419 db eval {INSERT INTO t4 VALUES(3)}
420 db eval {INSERT INTO t4 VALUES(4)}
425 db eval {SELECT * FROM t4}
428 for {set i 0} {$i<1} {incr i} {
430 db eval {INSERT INTO t4 VALUES(5)}
433 error "This line should not be run"
435 db eval {SELECT * FROM t4}
438 for {set i 0} {$i<10} {incr i} {
440 db eval {INSERT INTO t4 VALUES(6)}
444 db eval {SELECT * FROM t4}
448 for {set i 0} {$i<10} {incr i} {
450 db eval {INSERT INTO t4 VALUES(7)}
457 db eval {SELECT * FROM t4}
460 # Now test that [db transaction] commands may be nested with
461 # the expected results.
467 INSERT INTO t4 VALUES('one');
472 db eval { INSERT INTO t4 VALUES('two') }
474 db eval { INSERT INTO t4 VALUES('three') }
475 error "throw an error!"
481 db eval {SELECT * FROM t4}
484 # Make sure a transaction has not been left open.
485 db eval {BEGIN ; COMMIT}
489 db eval { INSERT INTO t4 VALUES('two'); }
491 db eval { INSERT INTO t4 VALUES('three') }
493 db eval { INSERT INTO t4 VALUES('four') }
497 db eval {SELECT * FROM t4}
498 } {one two three four}
502 db eval { INSERT INTO t4 VALUES('A'); }
504 db eval { INSERT INTO t4 VALUES('B') }
506 db eval { INSERT INTO t4 VALUES('C') }
507 error "throw an error!"
512 db eval {SELECT * FROM t4}
513 } {one two three four}
515 # Make sure a transaction has not been left open.
516 db eval {BEGIN ; COMMIT}
519 # Mess up a [db transaction] command by locking the database using a
520 # second connection when it tries to commit. Make sure the transaction
521 # is not still open after the "database is locked" exception is thrown.
527 SELECT * FROM sqlite_master;
532 db eval {INSERT INTO t4 VALUES('five')}
536 } {1 {database is locked}}
538 db eval {BEGIN ; COMMIT}
541 # Thwart a [db transaction] command by locking the database using a
542 # second connection with "BEGIN EXCLUSIVE". Make sure no transaction is
543 # open after the "database is locked" exception is thrown.
552 db eval {INSERT INTO t4 VALUES('five')}
556 } {1 {database is locked}}
559 db eval {BEGIN ; COMMIT}
563 db transaction exclusive {
564 catch { db2 eval {SELECT * FROM sqlite_master} } msg
568 } {db2: database is locked}
572 db eval {INSERT INTO t4 VALUES(6)}
573 db exists {SELECT x,x*2,x+x FROM t4 WHERE x==6}
576 db exists {SELECT 0 FROM t4 WHERE x==6}
579 db exists {SELECT 1 FROM t4 WHERE x==8}
582 tcl_objproc db exists {SELECT 1 FROM t4 WHERE x==8}
586 unset -nocomplain a b c version
587 set version [db version]
588 scan $version "%d.%d.%d" a b c
589 expr $a*1000000 + $b*1000 + $c
590 } [sqlite3_libversion_number]
593 # Check to see that when bindings of the form @aaa are used instead
594 # of $aaa, that objects are treated as bytearray and are inserted
599 db eval {CREATE TABLE t5(x BLOB)}
601 db eval {INSERT INTO t5 VALUES($x)}
602 db eval {SELECT typeof(x) FROM t5}
605 binary scan $x H notUsed
608 INSERT INTO t5 VALUES($x);
609 SELECT typeof(x) FROM t5;
615 INSERT INTO t5 VALUES(@x);
616 SELECT typeof(x) FROM t5;
623 INSERT INTO t5 VALUES(@y);
624 SELECT hex(x), typeof(x) FROM t5
630 proc xCall {} { return "value" }
631 do_execsql_test tcl-14.1 {
633 INSERT INTO t6 VALUES(1);
636 db one {SELECT x FROM t6 WHERE xCall()!='value'}