xref: /sqlite-3.40.0/test/tclsqlite.test (revision 74e4352a)
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.56 2006/09/01 15:49:06 drh 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 ?MODE?"
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, interrupt, last_insert_rowid, nullvalue, onecolumn, profile, progress, rekey, rollback_hook, timeout, total_changes, trace, transaction, update_hook, or version}}
38do_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]
70  regsub {:.*$} $msg {} msg
71  lappend v $msg
72} {1 {syntax error in expression "x*"}}
73do_test tcl-1.7 {
74  set v [catch {db} msg]
75  lappend v $msg
76} {1 {wrong # args: should be "db SUBCOMMAND ..."}}
77if {[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}
83do_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?"}}
99ifcapable {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}
105do_test tcl-1.14 {
106  set v [catch {db eval} msg]
107  lappend v $msg
108} {1 {wrong # args: should be "db eval SQL ?ARRAY-NAME? ?SCRIPT?"}}
109do_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"}}
113do_test tcl-1.16 {
114  set v [catch {db last_insert_rowid xyz} msg]
115  lappend v $msg
116} {1 {wrong # args: should be "db last_insert_rowid "}}
117do_test tcl-1.17 {
118  set v [catch {db rekey} msg]
119  lappend v $msg
120} {1 {wrong # args: should be "db rekey KEY"}}
121do_test tcl-1.18 {
122  set v [catch {db timeout} msg]
123  lappend v $msg
124} {1 {wrong # args: should be "db timeout MILLISECONDS"}}
125do_test tcl-1.19 {
126  set v [catch {db collate} msg]
127  lappend v $msg
128} {1 {wrong # args: should be "db collate NAME SCRIPT"}}
129do_test tcl-1.20 {
130  set v [catch {db collation_needed} msg]
131  lappend v $msg
132} {1 {wrong # args: should be "db collation_needed SCRIPT"}}
133do_test tcl-1.21 {
134  set v [catch {db total_changes xyz} msg]
135  lappend v $msg
136} {1 {wrong # args: should be "db total_changes "}}
137do_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?"}}
141
142
143if {[sqlite3 -tcl-uses-utf]} {
144  catch {unset ::result}
145  do_test tcl-2.1 {
146    execsql "CREATE TABLE t\u0123x(a int, b\u1235 float)"
147  } {}
148  ifcapable schema_pragmas {
149    do_test tcl-2.2 {
150      execsql "PRAGMA table_info(t\u0123x)"
151    } "0 a int 0 {} 0 1 b\u1235 float 0 {} 0"
152  }
153  do_test tcl-2.3 {
154    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
160
161# 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  }
169  set rc [catch {db onecolumn {SELECT * FROM t1 ORDER BY a}} msg]
170  lappend rc $msg
171} {0 10}
172do_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"}}
179do_test tcl-3.4 {
180  set rc [catch {db onecolumn {SELECT bogus}} errmsg]
181  lappend rc $errmsg
182} {1 {no such column: bogus}}
183ifcapable {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}
206
207# 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} {}
220
221ifcapable {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}
257
258# 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
300do_test tcl-7.1 {
301  db version
302  expr 0
303} {0}
304
305# 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
321# 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 {
328  db function ret_dbl {return [expr {rand()*0.5}]}
329  execsql {SELECT typeof(ret_dbl())}
330} {real}
331do_test tcl-9.3 {
332  db function ret_int {return [expr {int(rand()*200)}]}
333  execsql {SELECT typeof(ret_int())}
334} {integer}
335
336# Recursive calls to the same user-defined function
337#
338ifcapable 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}
352
353# 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}
439
440do_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
450do_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
457finish_test
458