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 #***********************************************************************
13 set testdir [file dirname $argv0]
14 source $testdir/tester.tcl
15 set testprefix bestindex8
22 register_tcl_module db
24 proc vtab_command {src method args} {
27 return "CREATE TABLE xxx(a, b)"
31 set hdl [lindex $args 0]
32 set clist [$hdl constraints]
33 set orderby [$hdl orderby]
34 lappend ::lBestIndexDistinct [$hdl distinct]
36 #puts "ORDERBY: $orderby"
40 catch { array unset C }
43 lappend ret use $iCons
47 if {$orderby=="{column 0 desc 0} {column 1 desc 0}"
48 || $orderby=="{column 0 desc 0}"
52 set ::lOrderByConsumed 1
58 set idxnum [lindex $args 0]
60 return [list sql "SELECT rowid, a, b FROM $src order by 2, 3"]
62 return [list sql "SELECT rowid, a, b FROM $src"]
71 CREATE TABLE t1(a, b);
72 CREATE INDEX i1 ON t1(a, b);
73 INSERT INTO t1 VALUES('a', 'b'), ('c', 'd');
74 INSERT INTO t1 VALUES('a', 'b'), ('c', 'd');
75 CREATE VIRTUAL TABLE vt1 USING tcl(vtab_command t1);
78 INSERT INTO t0(c0) VALUES (1), (0);
81 foreach {tn sql bDistinct idxinsert bConsumed res} {
82 1 "SELECT a, b FROM vt1" 0 0 0 {a b c d a b c d}
83 2 "SELECT DISTINCT a, b FROM vt1" 2 1 1 {a b c d}
84 3 "SELECT DISTINCT a FROM vt1" 2 1 1 {a c}
85 4 "SELECT DISTINCT b FROM vt1" 2 1 0 {b d}
86 5 "SELECT DISTINCT b FROM vt1 ORDER BY a" 0 1 1 {b d}
87 6 "SELECT DISTINCT t0.c0 FROM vt1, t0 ORDER BY vt1.a" 0 1 1 {1 0}
88 7 "SELECT DISTINCT a, b FROM vt1 ORDER BY a, b" 3 0 1 {a b c d}
89 8 "SELECT DISTINCT a, b FROM vt1 ORDER BY a" 0 1 1 {a b c d}
90 9 "SELECT DISTINCT a FROM vt1 ORDER BY a, b" 0 1 1 {a c}
92 10 "SELECT DISTINCT a, b FROM vt1 WHERE b='b'" 2 1 1 {a b}
93 11 "SELECT DISTINCT a, b FROM vt1 WHERE +b='b'" 2 1 1 {a b}
95 set ::lBestIndexDistinct ""
96 set ::lOrderByConsumed 0
97 do_execsql_test 1.$tn.1 $sql $res
99 set ::lBestIndexDistinct
102 expr {[lsearch [execsql "explain $sql"] IdxInsert]>=0}
105 set ::lOrderByConsumed
109 #-------------------------------------------------------------------------
111 register_tcl_module db
113 proc vtab_command {src method args} {
116 return "CREATE TABLE xxx(a, b)"
120 set hdl [lindex $args 0]
124 foreach cons [$hdl constraints] {
126 if {($C(op)=="limit" || $C(op)=="offset") && $C(usable)} {
127 lappend ret use $iCons
136 lappend ::lFilterArgs [lindex $args 2]
137 return [list sql "SELECT rowid, a, b FROM $src"]
145 do_execsql_test 2.0 {
146 CREATE TABLE t1(a, b);
147 CREATE INDEX i1 ON t1(a, b);
148 CREATE VIRTUAL TABLE vt1 USING tcl(vtab_command t1);
152 set ::lFilterArgs [list]
153 execsql { SELECT * FROM vt1 LIMIT 10 }
158 set ::lFilterArgs [list]
159 execsql { SELECT * FROM vt1 LIMIT 5 OFFSET 50 }
164 set ::lFilterArgs [list]
165 execsql { SELECT * FROM vt1 ORDER BY a, b LIMIT 1 OFFSET 1 }
170 set ::lFilterArgs [list]
171 execsql { SELECT * FROM vt1 ORDER BY a, +b LIMIT 1 OFFSET 1 }
175 #-------------------------------------------------------------------------
177 register_tcl_module db
179 proc vtab_command {src method args} {
182 return "CREATE TABLE xxx(a, b)"
186 set hdl [lindex $args 0]
187 set lCons [$hdl constraints]
190 for {set i 0} {$i < [llength $lCons]} {incr i} {
191 array set C [lindex $lCons $i]
201 set lArg [lindex $args 2]
202 lappend ::lFilterArg {*}$lArg
203 return [list sql "SELECT rowid, a, b FROM $src"]
211 do_execsql_test 3.0 {
212 CREATE TABLE t1(a, b);
213 CREATE INDEX i1 ON t1(a, b);
214 CREATE VIRTUAL TABLE vt1 USING tcl(vtab_command t1);
217 foreach {tn sql lfa} {
218 1 "SELECT * FROM vt1 WHERE b IN (10, 20, 30)" {{10 20 30}}
219 2 "SELECT * FROM vt1 WHERE b IN ('abc', 'def')" {{abc def}}
220 3 "SELECT * FROM vt1 WHERE a IS NULL AND b IN ('abc', 'def')" {{} {abc def}}
221 4 "SELECT * FROM vt1 WHERE a IN (1,2,3) AND b IN ('abc', 'def')"
225 WHERE a IN (SELECT 1 UNION SELECT 2) AND b IN ('abc', 'def')"
229 WHERE b IN ('abc', 'def') AND a IN (SELECT 1 UNION SELECT 2)"
233 set ::lFilterArg [list]
239 #explain_i { SELECT * FROM vt1 WHERE b IN (10, 20, 30) }
241 #-------------------------------------------------------------------------
243 register_tcl_module db
245 proc vtab_command {src method args} {
248 return "CREATE TABLE xxx(a, b, c)"
252 set hdl [lindex $args 0]
253 set lCons [$hdl constraints]
256 for {set i 0} {$i < [llength $lCons]} {incr i} {
257 lappend ::lBestIndexRhs [$hdl rhs_value $i -]
263 return [list sql "SELECT rowid, a, b, c FROM $src"]
271 do_execsql_test 4.0 {
272 CREATE TABLE t1(a, b, c);
273 CREATE VIRTUAL TABLE vt1 USING tcl(vtab_command t1);
276 foreach {tn sql lbir} {
277 1 "SELECT * FROM vt1 WHERE b = 10" {10}
278 2 "SELECT * FROM vt1 WHERE a = 'abc' AND b < 30" {abc 30}
279 3 "SELECT * FROM vt1 WHERE a = 'abc' AND b < 30+2" {abc -}
280 4 "SELECT * FROM vt1 WHERE a IN (1,2,3) AND b < 30+2" {- -}
281 5 "SELECT * FROM vt1 WHERE a IS 111 AND b < 30+2" {111 -}
284 set ::lBestIndexRhs [list]
290 #-------------------------------------------------------------------------
293 register_tcl_module db
295 set ::vtab_handle_in 1
296 proc vtab_command {src method args} {
299 return "CREATE TABLE xxx(a, b, c)"
303 set lCols [list a b c]
305 set hdl [lindex $args 0]
306 set lCons [$hdl constraints]
307 set lOrder [$hdl order]
313 for {set i 0} {$i < [llength $lCons]} {incr i} {
314 array set C [lindex $lCons $i]
316 if { $C(op)=="eq" } {
318 if {$::vtab_handle_in} { set bIn [$hdl in $i 1] }
320 lappend W "[lindex $lCols $C(column)] IN (%I$a%)"
322 lappend W "[lindex $lCols $C(column)] = %$a%"
326 if { $C(op)=="limit" } { set L " LIMIT %$a%" ; lappend ret use $i }
327 if { $C(op)=="offset" } { set O " OFFSET %$a%" ; lappend ret use $i }
333 set selectlist "rowid, a, b, c"
334 if {[llength $lOrder]} {
340 if {$C(desc)} { set ad " DESC" }
341 lappend lO "[lindex $lCols $C(column)]$ad"
344 if {[$hdl distinct]==2} {
345 set selectlist "DISTINCT 0"
347 if {[info exists sl($i)]} {
348 append selectlist ", [lindex $lCols $i]"
350 append selectlist ", 0"
354 set order " ORDER BY [join $lO ,]"
359 if {[llength $W]} { set where " WHERE [join $W { AND }]" }
360 set sql "SELECT $selectlist FROM $src$where$order$L$O"
362 lappend ret idxStr $sql
367 foreach {idxnum idxstr lArg} $args {}
371 set sql [string map [list %$ii% $a] $sql]
372 set sql [string map [list %I$ii% [join $a ,]] $sql]
375 lappend ::lFilterSql $sql
377 if {[regexp {OFFSET (.*)$} $sql -> off]} {
379 WITH c(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM c WHERE i<$off )
380 SELECT 0,0,0,0 FROM c
381 UNION ALL SELECT * FROM (
389 return [list sql $real_sql]
397 do_execsql_test 5.0 {
398 CREATE TABLE t1(a, b, c);
399 CREATE VIRTUAL TABLE vt1 USING tcl(vtab_command t1);
400 INSERT INTO t1 VALUES(1, 2, 3);
401 INSERT INTO t1 VALUES(2, 3, 4);
402 INSERT INTO t1 VALUES(3, 4, 5);
403 INSERT INTO t1 VALUES(1, 5, 6);
404 INSERT INTO t1 VALUES(2, 6, 7);
405 INSERT INTO t1 VALUES(3, 7, 8);
406 INSERT INTO t1 VALUES(1, 8, 9);
407 INSERT INTO t1 VALUES(2, 9, 0);
410 proc do_vtab_test {tn sql vtsql {res {}}} {
411 set ::lFilterSql [list]
412 uplevel [list do_execsql_test $tn.1 $sql $res]
413 uplevel [list do_test $tn.2 {set ::lFilterSql} [list {*}$vtsql]]
417 SELECT DISTINCT a FROM vt1
419 {SELECT DISTINCT 0, a, 0, 0 FROM t1}
423 SELECT DISTINCT a FROM vt1 ORDER BY a
425 {SELECT rowid, a, b, c FROM t1 ORDER BY a}
429 SELECT DISTINCT a FROM vt1 WHERE c IN (4,5,6,7,8)
431 {SELECT DISTINCT 0, a, 0, 0 FROM t1 WHERE c IN (4,5,6,7,8)}
434 set ::vtab_handle_in 0
436 SELECT DISTINCT a FROM vt1 WHERE c IN (4,5,6,7,8)
438 {SELECT DISTINCT 0, a, 0, 0 FROM t1 WHERE c = 4}
439 {SELECT DISTINCT 0, a, 0, 0 FROM t1 WHERE c = 5}
440 {SELECT DISTINCT 0, a, 0, 0 FROM t1 WHERE c = 6}
441 {SELECT DISTINCT 0, a, 0, 0 FROM t1 WHERE c = 7}
442 {SELECT DISTINCT 0, a, 0, 0 FROM t1 WHERE c = 8}
445 set ::vtab_handle_in 1
446 do_vtab_test 5.1.5a {
447 SELECT a, b, c FROM vt1 WHERE c IN (4,5,6,7,8) LIMIT 2 OFFSET 2
449 {SELECT rowid, a, b, c FROM t1 WHERE c IN (4,5,6,7,8) LIMIT 2 OFFSET 2}
452 set ::vtab_handle_in 0
453 do_vtab_test 5.1.5b {
454 SELECT a, b, c FROM vt1 WHERE c IN (4,5,6,7,8) LIMIT 2 OFFSET 2
456 {SELECT rowid, a, b, c FROM t1 WHERE c = 4}
457 {SELECT rowid, a, b, c FROM t1 WHERE c = 5}
458 {SELECT rowid, a, b, c FROM t1 WHERE c = 6}
459 {SELECT rowid, a, b, c FROM t1 WHERE c = 7}
461 set ::vtab_handle_in 1