diff options
Diffstat (limited to 'test/bestindex8.test')
-rw-r--r-- | test/bestindex8.test | 463 |
1 files changed, 463 insertions, 0 deletions
diff --git a/test/bestindex8.test b/test/bestindex8.test new file mode 100644 index 0000000..e95c3c6 --- /dev/null +++ b/test/bestindex8.test @@ -0,0 +1,463 @@ +# 2020-01-29 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix bestindex8 + +ifcapable !vtab { + finish_test + return +} + +register_tcl_module db + +proc vtab_command {src method args} { + switch -- $method { + xConnect { + return "CREATE TABLE xxx(a, b)" + } + + xBestIndex { + set hdl [lindex $args 0] + set clist [$hdl constraints] + set orderby [$hdl orderby] + lappend ::lBestIndexDistinct [$hdl distinct] + + #puts "ORDERBY: $orderby" + set iCons 0 + set ret [list] + foreach cons $clist { + catch { array unset C } + array set C $cons + if {$C(usable)} { + lappend ret use $iCons + } + incr iCons + } + if {$orderby=="{column 0 desc 0} {column 1 desc 0}" + || $orderby=="{column 0 desc 0}" + } { + lappend ret orderby 1 + lappend ret idxnum 1 + set ::lOrderByConsumed 1 + } + return $ret + } + + xFilter { + set idxnum [lindex $args 0] + if {$idxnum} { + return [list sql "SELECT rowid, a, b FROM $src order by 2, 3"] + } + return [list sql "SELECT rowid, a, b FROM $src"] + } + + } + + return {} +} + +do_execsql_test 1.0 { + CREATE TABLE t1(a, b); + CREATE INDEX i1 ON t1(a, b); + INSERT INTO t1 VALUES('a', 'b'), ('c', 'd'); + INSERT INTO t1 VALUES('a', 'b'), ('c', 'd'); + CREATE VIRTUAL TABLE vt1 USING tcl(vtab_command t1); + + CREATE TABLE t0(c0); + INSERT INTO t0(c0) VALUES (1), (0); +} + +foreach {tn sql bDistinct idxinsert bConsumed res} { + 1 "SELECT a, b FROM vt1" 0 0 0 {a b c d a b c d} + 2 "SELECT DISTINCT a, b FROM vt1" 2 1 1 {a b c d} + 3 "SELECT DISTINCT a FROM vt1" 2 1 1 {a c} + 4 "SELECT DISTINCT b FROM vt1" 2 1 0 {b d} + 5 "SELECT DISTINCT b FROM vt1 ORDER BY a" 0 1 1 {b d} + 6 "SELECT DISTINCT t0.c0 FROM vt1, t0 ORDER BY vt1.a" 0 1 1 {1 0} + 7 "SELECT DISTINCT a, b FROM vt1 ORDER BY a, b" 3 0 1 {a b c d} + 8 "SELECT DISTINCT a, b FROM vt1 ORDER BY a" 0 1 1 {a b c d} + 9 "SELECT DISTINCT a FROM vt1 ORDER BY a, b" 0 1 1 {a c} + + 10 "SELECT DISTINCT a, b FROM vt1 WHERE b='b'" 2 1 1 {a b} + 11 "SELECT DISTINCT a, b FROM vt1 WHERE +b='b'" 2 1 1 {a b} +} { + set ::lBestIndexDistinct "" + set ::lOrderByConsumed 0 + do_execsql_test 1.$tn.1 $sql $res + do_test 1.$tn.2 { + set ::lBestIndexDistinct + } $bDistinct + do_test 1.$tn.3 { + expr {[lsearch [execsql "explain $sql"] IdxInsert]>=0} + } $idxinsert + do_test 1.$tn.4 { + set ::lOrderByConsumed + } $bConsumed +} + +#------------------------------------------------------------------------- +reset_db +register_tcl_module db + +proc vtab_command {src method args} { + switch -- $method { + xConnect { + return "CREATE TABLE xxx(a, b)" + } + + xBestIndex { + set hdl [lindex $args 0] + set ret [list] + + set iCons 0 + foreach cons [$hdl constraints] { + array set C $cons + if {($C(op)=="limit" || $C(op)=="offset") && $C(usable)} { + lappend ret use $iCons + } + incr iCons + } + + return $ret + } + + xFilter { + lappend ::lFilterArgs [lindex $args 2] + return [list sql "SELECT rowid, a, b FROM $src"] + } + + } + + return {} +} + +do_execsql_test 2.0 { + CREATE TABLE t1(a, b); + CREATE INDEX i1 ON t1(a, b); + CREATE VIRTUAL TABLE vt1 USING tcl(vtab_command t1); +} + +do_test 2.1 { + set ::lFilterArgs [list] + execsql { SELECT * FROM vt1 LIMIT 10 } + set ::lFilterArgs +} {10} + +do_test 2.2 { + set ::lFilterArgs [list] + execsql { SELECT * FROM vt1 LIMIT 5 OFFSET 50 } + set ::lFilterArgs +} {{5 50}} + +do_test 2.3 { + set ::lFilterArgs [list] + execsql { SELECT * FROM vt1 ORDER BY a, b LIMIT 1 OFFSET 1 } + set ::lFilterArgs +} {{1 1}} + +do_test 2.4 { + set ::lFilterArgs [list] + execsql { SELECT * FROM vt1 ORDER BY a, +b LIMIT 1 OFFSET 1 } + set ::lFilterArgs +} {{}} + +#------------------------------------------------------------------------- +reset_db +register_tcl_module db + +proc vtab_command {src method args} { + switch -- $method { + xConnect { + return "CREATE TABLE xxx(a, b)" + } + + xBestIndex { + set hdl [lindex $args 0] + set lCons [$hdl constraints] + + set ret [list] + for {set i 0} {$i < [llength $lCons]} {incr i} { + array set C [lindex $lCons $i] + if {$C(usable)} { + lappend ret use $i + $hdl in $i 1 + } + } + return $ret + } + + xFilter { + set lArg [lindex $args 2] + lappend ::lFilterArg {*}$lArg + return [list sql "SELECT rowid, a, b FROM $src"] + } + + } + + return {} +} + +do_execsql_test 3.0 { + CREATE TABLE t1(a, b); + CREATE INDEX i1 ON t1(a, b); + CREATE VIRTUAL TABLE vt1 USING tcl(vtab_command t1); +} + +foreach {tn sql lfa} { + 1 "SELECT * FROM vt1 WHERE b IN (10, 20, 30)" {{10 20 30}} + 2 "SELECT * FROM vt1 WHERE b IN ('abc', 'def')" {{abc def}} + 3 "SELECT * FROM vt1 WHERE a IS NULL AND b IN ('abc', 'def')" {{} {abc def}} + 4 "SELECT * FROM vt1 WHERE a IN (1,2,3) AND b IN ('abc', 'def')" + {{1 2 3} {abc def}} + + 5 "SELECT * FROM vt1 + WHERE a IN (SELECT 1 UNION SELECT 2) AND b IN ('abc', 'def')" + {{1 2} {abc def}} + + 6 "SELECT * FROM vt1 + WHERE b IN ('abc', 'def') AND a IN (SELECT 1 UNION SELECT 2)" + {{abc def} {1 2}} +} { + do_test 3.$tn { + set ::lFilterArg [list] + execsql $sql + set ::lFilterArg + } $lfa +} + +#explain_i { SELECT * FROM vt1 WHERE b IN (10, 20, 30) } + +#------------------------------------------------------------------------- +reset_db +register_tcl_module db + +proc vtab_command {src method args} { + switch -- $method { + xConnect { + return "CREATE TABLE xxx(a, b, c)" + } + + xBestIndex { + set hdl [lindex $args 0] + set lCons [$hdl constraints] + + set ret [list] + for {set i 0} {$i < [llength $lCons]} {incr i} { + lappend ::lBestIndexRhs [$hdl rhs_value $i -] + } + return $ret + } + + xFilter { + return [list sql "SELECT rowid, a, b, c FROM $src"] + } + + } + + return {} +} + +do_execsql_test 4.0 { + CREATE TABLE t1(a, b, c); + CREATE VIRTUAL TABLE vt1 USING tcl(vtab_command t1); +} + +foreach {tn sql lbir} { + 1 "SELECT * FROM vt1 WHERE b = 10" {10} + 2 "SELECT * FROM vt1 WHERE a = 'abc' AND b < 30" {abc 30} + 3 "SELECT * FROM vt1 WHERE a = 'abc' AND b < 30+2" {abc -} + 4 "SELECT * FROM vt1 WHERE a IN (1,2,3) AND b < 30+2" {- -} + 5 "SELECT * FROM vt1 WHERE a IS 111 AND b < 30+2" {111 -} +} { + do_test 4.$tn { + set ::lBestIndexRhs [list] + execsql $sql + set ::lBestIndexRhs + } $lbir +} + +#------------------------------------------------------------------------- +reset_db +db cache size 0 +register_tcl_module db + +set ::vtab_handle_in 1 +proc vtab_command {src method args} { + switch -- $method { + xConnect { + return "CREATE TABLE xxx(a, b, c)" + } + + xBestIndex { + set lCols [list a b c] + + set hdl [lindex $args 0] + set lCons [$hdl constraints] + set lOrder [$hdl order] + + set L "" + set O "" + set W [list] + set a 0 + for {set i 0} {$i < [llength $lCons]} {incr i} { + array set C [lindex $lCons $i] + if {$C(usable)} { + if { $C(op)=="eq" } { + set bIn 0 + if {$::vtab_handle_in} { set bIn [$hdl in $i 1] } + if {$bIn} { + lappend W "[lindex $lCols $C(column)] IN (%I$a%)" + } else { + lappend W "[lindex $lCols $C(column)] = %$a%" + } + lappend ret omit $i + } + if { $C(op)=="limit" } { set L " LIMIT %$a%" ; lappend ret use $i } + if { $C(op)=="offset" } { set O " OFFSET %$a%" ; lappend ret use $i } + incr a + } + } + + set order "" + set selectlist "rowid, a, b, c" + if {[llength $lOrder]} { + array set sl [list] + set lO [list] + foreach s $lOrder { + array set C $s + set ad "" + if {$C(desc)} { set ad " DESC" } + lappend lO "[lindex $lCols $C(column)]$ad" + set sl($C(column)) 1 + } + if {[$hdl distinct]==2} { + set selectlist "DISTINCT 0" + foreach i {0 1 2} { + if {[info exists sl($i)]} { + append selectlist ", [lindex $lCols $i]" + } else { + append selectlist ", 0" + } + } + } else { + set order " ORDER BY [join $lO ,]" + } + } + + set where "" + if {[llength $W]} { set where " WHERE [join $W { AND }]" } + set sql "SELECT $selectlist FROM $src$where$order$L$O" + + lappend ret idxStr $sql + return $ret + } + + xFilter { + foreach {idxnum idxstr lArg} $args {} + set ii 0 + set sql $idxstr + foreach a $lArg { + set sql [string map [list %$ii% $a] $sql] + set sql [string map [list %I$ii% [join $a ,]] $sql] + incr ii + } + lappend ::lFilterSql $sql + + if {[regexp {OFFSET (.*)$} $sql -> off]} { + set real_sql " + WITH c(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM c WHERE i<$off ) + SELECT 0,0,0,0 FROM c + UNION ALL SELECT * FROM ( + $sql + ) + " + } else { + set real_sql $sql + } + + return [list sql $real_sql] + } + + } + + return {} +} + +do_execsql_test 5.0 { + CREATE TABLE t1(a, b, c); + CREATE VIRTUAL TABLE vt1 USING tcl(vtab_command t1); + INSERT INTO t1 VALUES(1, 2, 3); + INSERT INTO t1 VALUES(2, 3, 4); + INSERT INTO t1 VALUES(3, 4, 5); + INSERT INTO t1 VALUES(1, 5, 6); + INSERT INTO t1 VALUES(2, 6, 7); + INSERT INTO t1 VALUES(3, 7, 8); + INSERT INTO t1 VALUES(1, 8, 9); + INSERT INTO t1 VALUES(2, 9, 0); +} + +proc do_vtab_test {tn sql vtsql {res {}}} { + set ::lFilterSql [list] + uplevel [list do_execsql_test $tn.1 $sql $res] + uplevel [list do_test $tn.2 {set ::lFilterSql} [list {*}$vtsql]] +} + +do_vtab_test 5.1.1 { + SELECT DISTINCT a FROM vt1 +} { + {SELECT DISTINCT 0, a, 0, 0 FROM t1} +} {1 2 3} + +do_vtab_test 5.1.2 { + SELECT DISTINCT a FROM vt1 ORDER BY a +} { + {SELECT rowid, a, b, c FROM t1 ORDER BY a} +} {1 2 3} + +do_vtab_test 5.1.3 { + SELECT DISTINCT a FROM vt1 WHERE c IN (4,5,6,7,8) +} { + {SELECT DISTINCT 0, a, 0, 0 FROM t1 WHERE c IN (4,5,6,7,8)} +} {2 3 1} + +set ::vtab_handle_in 0 +do_vtab_test 5.1.4 { + SELECT DISTINCT a FROM vt1 WHERE c IN (4,5,6,7,8) +} { + {SELECT DISTINCT 0, a, 0, 0 FROM t1 WHERE c = 4} + {SELECT DISTINCT 0, a, 0, 0 FROM t1 WHERE c = 5} + {SELECT DISTINCT 0, a, 0, 0 FROM t1 WHERE c = 6} + {SELECT DISTINCT 0, a, 0, 0 FROM t1 WHERE c = 7} + {SELECT DISTINCT 0, a, 0, 0 FROM t1 WHERE c = 8} +} {2 3 1} + +set ::vtab_handle_in 1 +do_vtab_test 5.1.5a { + SELECT a, b, c FROM vt1 WHERE c IN (4,5,6,7,8) LIMIT 2 OFFSET 2 +} { + {SELECT rowid, a, b, c FROM t1 WHERE c IN (4,5,6,7,8) LIMIT 2 OFFSET 2} +} {1 5 6 2 6 7} + +set ::vtab_handle_in 0 +do_vtab_test 5.1.5b { + SELECT a, b, c FROM vt1 WHERE c IN (4,5,6,7,8) LIMIT 2 OFFSET 2 +} { + {SELECT rowid, a, b, c FROM t1 WHERE c = 4} + {SELECT rowid, a, b, c FROM t1 WHERE c = 5} + {SELECT rowid, a, b, c FROM t1 WHERE c = 6} + {SELECT rowid, a, b, c FROM t1 WHERE c = 7} +} {1 5 6 2 6 7} +set ::vtab_handle_in 1 + +finish_test |