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 # Test the virtual table interface. In particular the xBestIndex
15 set testdir [file dirname $argv0]
16 source $testdir/tester.tcl
17 set testprefix bestindex4
24 #-------------------------------------------------------------------------
25 # Virtual table callback for a virtual table named $tbl.
27 proc vtab_cmd {method args} {
31 set binops(isnot) "IS NOT"
34 set unops(isnotnull) "IS NOT NULL"
35 set unops(isnull) "IS NULL"
43 return "CREATE TABLE t1(a, b, c)"
47 foreach {clist orderby mask} $args {}
54 for {set i 0} {$i < [llength $clist]} {incr i} {
56 array set C [lindex $clist $i]
58 if {[info exists binops($C(op))]} {
60 lappend str "$cols($C(column)) $binops($C(op)) %$v%"
62 set cost [expr $cost / 2]
64 if {[info exists unops($C(op))]} {
66 lappend str "$cols($C(column)) $unops($C(op))"
68 set cost [expr $cost / 2]
73 lappend ret idxstr [join $str " AND "]
74 lappend ret cost $cost
79 set q [lindex $args 1]
80 set a [lindex $args 2]
81 for {set v 0} {$v < [llength $a]} {incr v} {
82 set val [lindex $a $v]
83 set q [string map [list %$v% '$val'] $q]
85 if {$q==""} { set q 1 }
86 lappend ::xFilterQueries "WHERE $q"
87 return [list sql "SELECT rowid, * FROM t1x WHERE $q"]
93 proc vtab_simple {method args} {
96 return "CREATE TABLE t2(x)"
99 return [list cost 999999.0]
102 return [list sql "SELECT rowid, * FROM t2x"]
108 register_tcl_module db
110 proc do_vtab_query_test {tn query result} {
111 set ::xFilterQueries [list]
113 do_test $tn [string map [list %QUERY% $query] {
114 set r [execsql {%QUERY%}]
115 set r [concat $::xFilterQueries $r]
121 do_execsql_test 1.0 {
122 CREATE VIRTUAL TABLE t1 USING tcl('vtab_cmd');
123 CREATE TABLE t1x(a INTEGER, b TEXT, c REAL);
124 INSERT INTO t1x VALUES(1, 2, 3);
125 INSERT INTO t1x VALUES(4, 5, 6);
126 INSERT INTO t1x VALUES(7, 8, 9);
128 CREATE VIRTUAL TABLE t2 USING tcl('vtab_simple');
129 CREATE TABLE t2x(x INTEGER);
130 INSERT INTO t2x VALUES(1);
133 do_vtab_query_test 1.1 { SELECT * FROM t1 WHERE a!='hello'; } {
135 1 2 3.0 4 5 6.0 7 8 9.0
138 do_vtab_query_test 1.2.1 { SELECT * FROM t1 WHERE b!=8 } {
142 do_vtab_query_test 1.2.2 { SELECT * FROM t1 WHERE 8!=b } {
147 do_vtab_query_test 1.3 { SELECT * FROM t1 WHERE c IS NOT 3 } {
151 do_vtab_query_test 1.3.2 { SELECT * FROM t1 WHERE 3 IS NOT c } {
156 do_vtab_query_test 1.4.1 { SELECT * FROM t1, t2 WHERE x != a } {
160 do_vtab_query_test 1.4.2 { SELECT * FROM t1, t2 WHERE a != x } {
165 do_vtab_query_test 1.5.1 { SELECT * FROM t1 WHERE a IS NOT NULL } {
166 "WHERE a IS NOT NULL"
167 1 2 3.0 4 5 6.0 7 8 9.0
169 do_vtab_query_test 1.5.2 { SELECT * FROM t1 WHERE NULL IS NOT a } {
171 1 2 3.0 4 5 6.0 7 8 9.0
174 do_vtab_query_test 1.6.1 { SELECT * FROM t1 WHERE a IS NULL } {
178 do_vtab_query_test 1.6.2 { SELECT * FROM t1 WHERE NULL IS a } {
182 do_vtab_query_test 1.7.1 { SELECT * FROM t1 WHERE (a, b) IS (1, 2) } {
183 "WHERE a IS '1' AND b IS '2'"
186 do_vtab_query_test 1.7.2 { SELECT * FROM t1 WHERE (5, 4) IS (b, a) } {
187 {WHERE b IS '5' AND a IS '4'}
191 #---------------------------------------------------------------------
192 do_execsql_test 2.0.0 {
194 INSERT INTO t1x VALUES('a', 'b', 'c');
196 do_execsql_test 2.0.1 { SELECT * FROM t1 } {a b c}
197 do_execsql_test 2.0.2 { SELECT * FROM t1 WHERE (a, b) != ('a', 'b'); } {}
199 do_execsql_test 2.1.0 {
201 INSERT INTO t1x VALUES(7, 8, 9);
203 do_execsql_test 2.1.1 { SELECT * FROM t1 } {7 8 9.0}
204 do_execsql_test 2.1.2 { SELECT * FROM t1 WHERE (a, b) != (7, '8') } {}
205 do_execsql_test 2.1.3 { SELECT * FROM t1 WHERE a!=7 OR b!='8' }
206 do_execsql_test 2.1.4 { SELECT * FROM t1 WHERE a!=7 OR b!='8' }
209 do_execsql_test 2.2.1 {
210 CREATE TABLE t3(a INTEGER, b TEXT);
211 INSERT INTO t3 VALUES(45, 46);
213 do_execsql_test 2.2.2 { SELECT * FROM t3 WHERE (a, b) != (45, 46); }
214 do_execsql_test 2.2.3 { SELECT * FROM t3 WHERE (a, b) != ('45', '46'); }
215 do_execsql_test 2.2.4 { SELECT * FROM t3 WHERE (a, b) == (45, 46); } {45 46}
216 do_execsql_test 2.2.5 { SELECT * FROM t3 WHERE (a, b) == ('45', '46'); } {45 46}
218 #---------------------------------------------------------------------
219 # Test the != operator on a virtual table with column affinities.
221 proc vtab_simple_integer {method args} {
224 return "CREATE TABLE t4(x INTEGER)"
227 return [list cost 999999.0]
230 return [list sql "SELECT rowid, * FROM t4x"]
236 do_execsql_test 3.0 {
237 CREATE TABLE t4x(a INTEGER);
238 INSERT INTO t4x VALUES(245);
239 CREATE VIRTUAL TABLE t4 USING tcl('vtab_simple_integer');
241 do_execsql_test 3.1 { SELECT rowid, * FROM t4 WHERE x=245; } {1 245}
242 do_execsql_test 3.2 { SELECT rowid, * FROM t4 WHERE x='245'; } {1 245}
243 do_execsql_test 3.3 { SELECT rowid, * FROM t4 WHERE x!=245; } {}
244 do_execsql_test 3.4 { SELECT rowid, * FROM t4 WHERE x!='245'; } {}
246 do_execsql_test 3.5 { SELECT rowid, * FROM t4 WHERE rowid!=1 OR x!='245'; } {}