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 #***********************************************************************
14 set testdir [file dirname $argv0]
15 source $testdir/tester.tcl
16 set testprefix bestindex1
23 register_tcl_module db
25 proc vtab_command {method args} {
28 return "CREATE TABLE t1(a, b, c)"
32 set clist [lindex $args 0]
33 if {[llength $clist]!=1} { error "unexpected constraint list" }
34 catch { array unset C }
35 array set C [lindex $clist 0]
37 return "omit 0 cost 0 rows 1 idxnum 555 idxstr eq!"
39 return "cost 1000000 rows 0 idxnum 0 idxstr scan..."
49 CREATE VIRTUAL TABLE x1 USING tcl(vtab_command);
53 SELECT * FROM x1 WHERE a = 'abc'
55 0 0 0 {SCAN TABLE x1 VIRTUAL TABLE INDEX 555:eq!}
59 SELECT * FROM x1 WHERE a IN ('abc', 'def');
61 0 0 0 {SCAN TABLE x1 VIRTUAL TABLE INDEX 555:eq!}
64 #-------------------------------------------------------------------------
67 register_tcl_module db
69 # Parameter $mode may be one of:
71 # "omit" - Implement filtering. Set the omit flag.
72 # "use" - Implement filtering. Use the constraint, but do not set omit.
73 # "use2" - Do not implement filtering. Use the constraint anyway.
76 proc t1_vtab {mode method args} {
79 return "CREATE TABLE t1(a, b)"
83 set SQL_FILTER {SELECT * FROM t1x WHERE a='%1%'}
84 set SQL_SCAN {SELECT * FROM t1x}
86 set clist [lindex $args 0]
88 for {set idx 0} {$idx < [llength $clist]} {incr idx} {
90 array set C [lindex $clist $idx]
91 if {$C(column)==0 && $C(op)=="eq" && $C(usable)} {
94 return [list omit $idx rows 10 cost 10 idxstr $SQL_FILTER]
97 return [list use $idx rows 10 cost 10 idxstr $SQL_FILTER]
100 return [list use $idx rows 10 cost 10 idxstr $SQL_SCAN]
103 error "Bad mode - $mode"
109 return [list idxstr {SELECT * FROM t1x}]
113 set map [list %1% [lindex $args 2 0]]
114 set sql [string map $map [lindex $args 1]]
115 return [list sql $sql]
122 do_execsql_test 2.1 {
123 CREATE TABLE t1x(i INTEGER PRIMARY KEY, a, b);
124 INSERT INTO t1x VALUES(1, 'one', 1);
125 INSERT INTO t1x VALUES(2, 'two', 2);
126 INSERT INTO t1x VALUES(3, 'three', 3);
127 INSERT INTO t1x VALUES(4, 'four', 4);
133 do_execsql_test 2.2.$mode.1 "
134 DROP TABLE IF EXISTS t1;
135 CREATE VIRTUAL TABLE t1 USING tcl(t1_vtab $mode);
138 do_execsql_test 2.2.$mode.2 {SELECT * FROM t1} {one 1 two 2 three 3 four 4}
139 do_execsql_test 2.2.$mode.3 {SELECT rowid FROM t1} {1 2 3 4}
140 do_execsql_test 2.2.$mode.4 {SELECT rowid FROM t1 WHERE a='two'} {2}
142 do_execsql_test 2.2.$mode.5 {
143 SELECT rowid FROM t1 WHERE a IN ('one', 'four') ORDER BY +rowid
147 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x WHERE a='%1%'}
148 0 0 0 {USE TEMP B-TREE FOR ORDER BY}
151 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x WHERE a='%1%'}
152 0 0 0 {USE TEMP B-TREE FOR ORDER BY}
155 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x}
156 0 0 0 {USE TEMP B-TREE FOR ORDER BY}
159 do_eqp_test 2.2.$mode.6 {
160 SELECT rowid FROM t1 WHERE a IN ('one', 'four') ORDER BY +rowid
165 # Demonstrate a register overwrite problem when using two virtual
166 # tables where the outer loop uses the IN operator.
168 set G(collist) [list PrimaryKey flagA columnA]
169 set G(cols) [join $G(collist) ,]
172 proc vtab_command {method args} {
177 return "CREATE TABLE t1($G(cols))"
181 set clist [lindex $args 0]
187 for {set idx 0} {$idx < [llength $clist]} {incr idx} {
188 array set c [lindex $clist $idx]
189 if {$c(op)=="eq" && $c(usable)} {
190 lappend W "[lindex $G(collist) $c(column)] = %$i%"
197 set sql "SELECT rowid, * FROM t1"
199 set sql "SELECT rowid, * FROM t1 WHERE [join $W { AND }]"
202 return [concat [list idxstr $sql] $U]
206 foreach {idxnum idxstr vals} $args {}
209 for {set i 0} {$i < [llength $vals]} {incr i} {
211 set v [lindex $vals $i]
212 if {[string is integer $v]} {
218 set sql [string map $map $idxstr]
221 return [list sql $sql]
231 register_tcl_module db
233 do_execsql_test 3.1 "
234 CREATE TABLE t1($G(cols));
235 INSERT INTO t1 VALUES(1, 0, 'ValueA');
236 INSERT INTO t1 VALUES(2, 0, 'ValueA');
237 INSERT INTO t1 VALUES(3, 0, 'ValueB');
238 INSERT INTO t1 VALUES(4, 0, 'ValueB');
241 do_execsql_test 3.2 {
242 CREATE VIRTUAL TABLE VirtualTableA USING tcl(vtab_command);
243 CREATE VIRTUAL TABLE VirtualTableB USING tcl(vtab_command);
246 do_execsql_test 3.3 { SELECT primarykey FROM VirtualTableA } {1 2 3 4}
248 do_execsql_test 3.4 {
250 VirtualTableA a CROSS JOIN VirtualTableB b ON b.PrimaryKey=a.PrimaryKey
251 WHERE a.ColumnA IN ('ValueA', 'ValueB') AND a.FlagA=0
253 1 0 ValueA 1 0 ValueA
254 2 0 ValueA 2 0 ValueA
255 3 0 ValueB 3 0 ValueB
256 4 0 ValueB 4 0 ValueB
259 do_execsql_test 3.5 {
261 VirtualTableA a CROSS JOIN VirtualTableB b ON b.PrimaryKey=a.PrimaryKey
262 WHERE a.FlagA=0 AND a.ColumnA IN ('ValueA', 'ValueB')
264 1 0 ValueA 1 0 ValueA
265 2 0 ValueA 2 0 ValueA
266 3 0 ValueB 3 0 ValueB
267 4 0 ValueB 4 0 ValueB