blob: 30eccdd76f8aef00a72a18eedb686168635e60d0 [file] [log] [blame]
drhb19a2bc2001-09-16 00:13:26 +00001# 2001 September 15
drh960e8c62001-04-03 16:53:21 +00002#
drhb19a2bc2001-09-16 00:13:26 +00003# The author disclaims copyright to this source code. In place of
4# a legal notice, here is a blessing:
drh960e8c62001-04-03 16:53:21 +00005#
drhb19a2bc2001-09-16 00:13:26 +00006# 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.
drh960e8c62001-04-03 16:53:21 +00009#
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#
drh1c747812007-06-19 23:01:41 +000018# $Id: tclsqlite.test,v 1.59 2007/06/19 23:01:42 drh Exp $
drh960e8c62001-04-03 16:53:21 +000019
20set testdir [file dirname $argv0]
21source $testdir/tester.tcl
22
23# Check the error messages generated by tclsqlite
24#
drhef4ac8f2004-06-19 00:16:31 +000025if {[sqlite3 -has-codec]} {
drh9eb9e262004-02-11 02:18:05 +000026 set r "sqlite_orig HANDLE FILENAME ?-key CODEC-KEY?"
drh22fbcb82004-02-01 01:22:50 +000027} else {
drhef4ac8f2004-06-19 00:16:31 +000028 set r "sqlite3 HANDLE FILENAME ?MODE?"
drh22fbcb82004-02-01 01:22:50 +000029}
drh960e8c62001-04-03 16:53:21 +000030do_test tcl-1.1 {
drhef4ac8f2004-06-19 00:16:31 +000031 set v [catch {sqlite3 bogus} msg]
drh960e8c62001-04-03 16:53:21 +000032 lappend v $msg
drh22fbcb82004-02-01 01:22:50 +000033} [list 1 "wrong # args: should be \"$r\""]
drh960e8c62001-04-03 16:53:21 +000034do_test tcl-1.2 {
35 set v [catch {db bogus} msg]
36 lappend v $msg
danielk1977b4e9af92007-05-01 17:49:49 +000037} {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}}
drh960e8c62001-04-03 16:53:21 +000038do_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]
drha297b5c2002-01-15 18:39:43 +000070 regsub {:.*$} $msg {} msg
drh960e8c62001-04-03 16:53:21 +000071 lappend v $msg
72} {1 {syntax error in expression "x*"}}
drh0f14e2e2004-06-29 12:39:08 +000073do_test tcl-1.7 {
74 set v [catch {db} msg]
75 lappend v $msg
76} {1 {wrong # args: should be "db SUBCOMMAND ..."}}
drh1211de32004-07-26 12:24:22 +000077if {[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}
drh0f14e2e2004-06-29 12:39:08 +000083do_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?"}}
drhccae6022005-02-26 17:31:26 +000099ifcapable {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}
drh0f14e2e2004-06-29 12:39:08 +0000105do_test tcl-1.14 {
106 set v [catch {db eval} msg]
107 lappend v $msg
drh895d7472004-08-20 16:02:39 +0000108} {1 {wrong # args: should be "db eval SQL ?ARRAY-NAME? ?SCRIPT?"}}
drh0f14e2e2004-06-29 12:39:08 +0000109do_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"}}
danielk19777ddad962005-12-12 06:53:03 +0000113do_test tcl-1.16 {
drh0f14e2e2004-06-29 12:39:08 +0000114 set v [catch {db last_insert_rowid xyz} msg]
115 lappend v $msg
116} {1 {wrong # args: should be "db last_insert_rowid "}}
danielk19777ddad962005-12-12 06:53:03 +0000117do_test tcl-1.17 {
drh0f14e2e2004-06-29 12:39:08 +0000118 set v [catch {db rekey} msg]
119 lappend v $msg
120} {1 {wrong # args: should be "db rekey KEY"}}
danielk19777ddad962005-12-12 06:53:03 +0000121do_test tcl-1.18 {
drh0f14e2e2004-06-29 12:39:08 +0000122 set v [catch {db timeout} msg]
123 lappend v $msg
124} {1 {wrong # args: should be "db timeout MILLISECONDS"}}
danielk19777ddad962005-12-12 06:53:03 +0000125do_test tcl-1.19 {
drh0f14e2e2004-06-29 12:39:08 +0000126 set v [catch {db collate} msg]
127 lappend v $msg
128} {1 {wrong # args: should be "db collate NAME SCRIPT"}}
danielk19777ddad962005-12-12 06:53:03 +0000129do_test tcl-1.20 {
drh0f14e2e2004-06-29 12:39:08 +0000130 set v [catch {db collation_needed} msg]
131 lappend v $msg
132} {1 {wrong # args: should be "db collation_needed SCRIPT"}}
danielk19777ddad962005-12-12 06:53:03 +0000133do_test tcl-1.21 {
drh0f14e2e2004-06-29 12:39:08 +0000134 set v [catch {db total_changes xyz} msg]
135 lappend v $msg
136} {1 {wrong # args: should be "db total_changes "}}
tpoindex1067fe12004-12-17 15:41:11 +0000137do_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?"}}
drh0f14e2e2004-06-29 12:39:08 +0000141
drh960e8c62001-04-03 16:53:21 +0000142
drhef4ac8f2004-06-19 00:16:31 +0000143if {[sqlite3 -tcl-uses-utf]} {
drhc275b4e2004-07-19 17:25:24 +0000144 catch {unset ::result}
drh6d4abfb2001-10-22 02:58:08 +0000145 do_test tcl-2.1 {
146 execsql "CREATE TABLE t\u0123x(a int, b\u1235 float)"
danielk197727188fb2004-11-23 10:13:03 +0000147 } {}
148 ifcapable schema_pragmas {
149 do_test tcl-2.2 {
150 execsql "PRAGMA table_info(t\u0123x)"
drh9f6696a2006-02-09 16:52:23 +0000151 } "0 a int 0 {} 0 1 b\u1235 float 0 {} 0"
danielk197727188fb2004-11-23 10:13:03 +0000152 }
153 do_test tcl-2.3 {
drh6d4abfb2001-10-22 02:58:08 +0000154 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
drh6d4abfb2001-10-22 02:58:08 +0000160
drh5d9d7572003-08-19 14:31:01 +0000161# 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 }
drh22fbcb82004-02-01 01:22:50 +0000169 set rc [catch {db onecolumn {SELECT * FROM t1 ORDER BY a}} msg]
170 lappend rc $msg
171} {0 10}
drh5d9d7572003-08-19 14:31:01 +0000172do_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"}}
drh0f14e2e2004-06-29 12:39:08 +0000179do_test tcl-3.4 {
180 set rc [catch {db onecolumn {SELECT bogus}} errmsg]
181 lappend rc $errmsg
182} {1 {no such column: bogus}}
drh6bf89572004-11-03 16:27:01 +0000183ifcapable {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}
drh5d9d7572003-08-19 14:31:01 +0000206
drh0f14e2e2004-06-29 12:39:08 +0000207# 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} {}
drh6d4abfb2001-10-22 02:58:08 +0000220
drh6bf89572004-11-03 16:27:01 +0000221ifcapable {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}
drh92febd92004-08-20 18:34:20 +0000257
drhfd241b02004-09-13 13:46:01 +0000258# 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
danielk19774397de52005-01-12 12:44:03 +0000300do_test tcl-7.1 {
301 db version
302 expr 0
303} {0}
304
danielk197755c45f22005-04-03 23:54:43 +0000305# 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
drhc7f269d2005-05-05 10:30:29 +0000321# 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 {
drh9645d8d2006-09-01 15:49:05 +0000328 db function ret_dbl {return [expr {rand()*0.5}]}
drhc7f269d2005-05-05 10:30:29 +0000329 execsql {SELECT typeof(ret_dbl())}
330} {real}
331do_test tcl-9.3 {
drh9645d8d2006-09-01 15:49:05 +0000332 db function ret_int {return [expr {int(rand()*200)}]}
drhc7f269d2005-05-05 10:30:29 +0000333 execsql {SELECT typeof(ret_int())}
334} {integer}
335
drhd1e47332005-06-26 17:55:33 +0000336# Recursive calls to the same user-defined function
337#
danielk19773bdca9c2006-01-17 09:35:01 +0000338ifcapable 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}
drhd1e47332005-06-26 17:55:33 +0000352
drhb5555e72005-08-02 17:15:14 +0000353# 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}
drhc7f269d2005-05-05 10:30:29 +0000439
drh97f2ebc2005-12-10 21:19:04 +0000440do_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
danielk1977161fb792006-01-24 10:58:21 +0000450do_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
drh4f5e80f2007-06-19 17:15:46 +0000457
458# Check to see that when bindings of the form @aaa are used instead
drh1c747812007-06-19 23:01:41 +0000459# of $aaa, that objects are treated as bytearray and are inserted
460# as BLOBs.
drh4f5e80f2007-06-19 17:15:46 +0000461#
462do_test tcl-13.1 {
463 db eval {CREATE TABLE t5(x BLOB)}
464 set x abc123
465 db eval {INSERT INTO t5 VALUES($x)}
466 db eval {SELECT typeof(x) FROM t5}
467} {text}
468do_test tcl-13.2 {
469 binary scan $x H notUsed
470 db eval {
471 DELETE FROM t5;
472 INSERT INTO t5 VALUES($x);
473 SELECT typeof(x) FROM t5;
474 }
475} {text}
476do_test tcl-13.3 {
drh4f5e80f2007-06-19 17:15:46 +0000477 db eval {
478 DELETE FROM t5;
479 INSERT INTO t5 VALUES(@x);
480 SELECT typeof(x) FROM t5;
481 }
482} {blob}
drh1c747812007-06-19 23:01:41 +0000483do_test tcl-13.4 {
484 set y 1234
485 db eval {
486 DELETE FROM t5;
487 INSERT INTO t5 VALUES(@y);
488 SELECT hex(x), typeof(x) FROM t5
489 }
490} {31323334 blob}
491
drh4f5e80f2007-06-19 17:15:46 +0000492
drh960e8c62001-04-03 16:53:21 +0000493finish_test