distinct.test 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. # 2011 July 1
  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 SQLite library. The
  12. # focus of this script is the DISTINCT modifier.
  13. #
  14. set testdir [file dirname $argv0]
  15. source $testdir/tester.tcl
  16. ifcapable !compound {
  17. finish_test
  18. return
  19. }
  20. set testprefix distinct
  21. proc is_distinct_noop {sql} {
  22. set sql1 $sql
  23. set sql2 [string map {DISTINCT ""} $sql]
  24. set program1 [list]
  25. set program2 [list]
  26. db eval "EXPLAIN $sql1" {
  27. if {$opcode != "Noop"} { lappend program1 $opcode }
  28. }
  29. db eval "EXPLAIN $sql2" {
  30. if {$opcode != "Noop"} { lappend program2 $opcode }
  31. }
  32. return [expr {$program1==$program2}]
  33. }
  34. proc do_distinct_noop_test {tn sql} {
  35. uplevel [list do_test $tn [list is_distinct_noop $sql] 1]
  36. }
  37. proc do_distinct_not_noop_test {tn sql} {
  38. uplevel [list do_test $tn [list is_distinct_noop $sql] 0]
  39. }
  40. proc do_temptables_test {tn sql temptables} {
  41. uplevel [list do_test $tn [subst -novar {
  42. set ret ""
  43. db eval "EXPLAIN [set sql]" {
  44. if {$opcode == "OpenEphemeral" || $opcode == "SorterOpen"} {
  45. if {$p5 != "08" && $p5!="00"} { error "p5 = $p5" }
  46. if {$p5 == "08"} {
  47. lappend ret hash
  48. } else {
  49. lappend ret btree
  50. }
  51. }
  52. }
  53. set ret
  54. }] $temptables]
  55. }
  56. #-------------------------------------------------------------------------
  57. # The following tests - distinct-1.* - check that the planner correctly
  58. # detects cases where a UNIQUE index means that a DISTINCT clause is
  59. # redundant. Currently the planner only detects such cases when there
  60. # is a single table in the FROM clause.
  61. #
  62. do_execsql_test 1.0 {
  63. CREATE TABLE t1(a, b, c, d);
  64. CREATE UNIQUE INDEX i1 ON t1(b, c);
  65. CREATE UNIQUE INDEX i2 ON t1(d COLLATE nocase);
  66. CREATE TABLE t2(x INTEGER PRIMARY KEY, y);
  67. CREATE TABLE t3(c1 PRIMARY KEY NOT NULL, c2 NOT NULL);
  68. CREATE INDEX i3 ON t3(c2);
  69. CREATE TABLE t4(a, b NOT NULL, c NOT NULL, d NOT NULL);
  70. CREATE UNIQUE INDEX t4i1 ON t4(b, c);
  71. CREATE UNIQUE INDEX t4i2 ON t4(d COLLATE nocase);
  72. }
  73. foreach {tn noop sql} {
  74. 1.1 0 "SELECT DISTINCT b, c FROM t1"
  75. 1.2 1 "SELECT DISTINCT b, c FROM t4"
  76. 2.1 0 "SELECT DISTINCT c FROM t1 WHERE b = ?"
  77. 2.2 1 "SELECT DISTINCT c FROM t4 WHERE b = ?"
  78. 3 1 "SELECT DISTINCT rowid FROM t1"
  79. 4 1 "SELECT DISTINCT rowid, a FROM t1"
  80. 5 1 "SELECT DISTINCT x FROM t2"
  81. 6 1 "SELECT DISTINCT * FROM t2"
  82. 7 1 "SELECT DISTINCT * FROM (SELECT * FROM t2)"
  83. 8.1 0 "SELECT DISTINCT * FROM t1"
  84. 8.2 1 "SELECT DISTINCT * FROM t4"
  85. 8 0 "SELECT DISTINCT a, b FROM t1"
  86. 9 0 "SELECT DISTINCT c FROM t1 WHERE b IN (1,2)"
  87. 10 0 "SELECT DISTINCT c FROM t1"
  88. 11 0 "SELECT DISTINCT b FROM t1"
  89. 12.1 0 "SELECT DISTINCT a, d FROM t1"
  90. 12.2 0 "SELECT DISTINCT a, d FROM t4"
  91. 13.1 0 "SELECT DISTINCT a, b, c COLLATE nocase FROM t1"
  92. 13.2 0 "SELECT DISTINCT a, b, c COLLATE nocase FROM t4"
  93. 14.1 0 "SELECT DISTINCT a, d COLLATE nocase FROM t1"
  94. 14.2 1 "SELECT DISTINCT a, d COLLATE nocase FROM t4"
  95. 15 0 "SELECT DISTINCT a, d COLLATE binary FROM t1"
  96. 16.1 0 "SELECT DISTINCT a, b, c COLLATE binary FROM t1"
  97. 16.2 1 "SELECT DISTINCT a, b, c COLLATE binary FROM t4"
  98. 16 0 "SELECT DISTINCT t1.rowid FROM t1, t2"
  99. 17 0 { /* Technically, it would be possible to detect that DISTINCT
  100. ** is a no-op in cases like the following. But SQLite does not
  101. ** do so. */
  102. SELECT DISTINCT t1.rowid FROM t1, t2 WHERE t1.rowid=t2.rowid }
  103. 18 1 "SELECT DISTINCT c1, c2 FROM t3"
  104. 19 1 "SELECT DISTINCT c1 FROM t3"
  105. 20 1 "SELECT DISTINCT * FROM t3"
  106. 21 0 "SELECT DISTINCT c2 FROM t3"
  107. 22 0 "SELECT DISTINCT * FROM (SELECT 1, 2, 3 UNION SELECT 4, 5, 6)"
  108. 23 1 "SELECT DISTINCT rowid FROM (SELECT 1, 2, 3 UNION SELECT 4, 5, 6)"
  109. 24 0 "SELECT DISTINCT rowid/2 FROM t1"
  110. 25 1 "SELECT DISTINCT rowid/2, rowid FROM t1"
  111. 26.1 0 "SELECT DISTINCT rowid/2, b FROM t1 WHERE c = ?"
  112. 26.2 1 "SELECT DISTINCT rowid/2, b FROM t4 WHERE c = ?"
  113. } {
  114. if {$noop} {
  115. do_distinct_noop_test 1.$tn $sql
  116. } else {
  117. do_distinct_not_noop_test 1.$tn $sql
  118. }
  119. }
  120. #-------------------------------------------------------------------------
  121. # The following tests - distinct-2.* - test cases where an index is
  122. # used to deliver results in order of the DISTINCT expressions.
  123. #
  124. drop_all_tables
  125. do_execsql_test 2.0 {
  126. CREATE TABLE t1(a, b, c);
  127. CREATE INDEX i1 ON t1(a, b);
  128. CREATE INDEX i2 ON t1(b COLLATE nocase, c COLLATE nocase);
  129. INSERT INTO t1 VALUES('a', 'b', 'c');
  130. INSERT INTO t1 VALUES('A', 'B', 'C');
  131. INSERT INTO t1 VALUES('a', 'b', 'c');
  132. INSERT INTO t1 VALUES('A', 'B', 'C');
  133. }
  134. foreach {tn sql temptables res} {
  135. 1 "a, b FROM t1" {} {A B a b}
  136. 2 "b, a FROM t1" {} {B A b a}
  137. 3 "a, b, c FROM t1" {hash} {a b c A B C}
  138. 4 "a, b, c FROM t1 ORDER BY a, b, c" {btree} {A B C a b c}
  139. 5 "b FROM t1 WHERE a = 'a'" {} {b}
  140. 6 "b FROM t1 ORDER BY +b COLLATE binary" {btree hash} {B b}
  141. 7 "a FROM t1" {} {A a}
  142. 8 "b COLLATE nocase FROM t1" {} {b}
  143. 9 "b COLLATE nocase FROM t1 ORDER BY b COLLATE nocase" {} {b}
  144. } {
  145. do_execsql_test 2.$tn.1 "SELECT DISTINCT $sql" $res
  146. do_temptables_test 2.$tn.2 "SELECT DISTINCT $sql" $temptables
  147. }
  148. do_execsql_test 2.A {
  149. SELECT (SELECT DISTINCT o.a FROM t1 AS i) FROM t1 AS o ORDER BY rowid;
  150. } {a A a A}
  151. do_test 3.0 {
  152. db eval {
  153. CREATE TABLE t3(a INTEGER, b INTEGER, c, UNIQUE(a,b));
  154. INSERT INTO t3 VALUES
  155. (null, null, 1),
  156. (null, null, 2),
  157. (null, 3, 4),
  158. (null, 3, 5),
  159. (6, null, 7),
  160. (6, null, 8);
  161. SELECT DISTINCT a, b FROM t3 ORDER BY +a, +b;
  162. }
  163. } {{} {} {} 3 6 {}}
  164. do_test 3.1 {
  165. regexp {OpenEphemeral} [db eval {
  166. EXPLAIN SELECT DISTINCT a, b FROM t3 ORDER BY +a, +b;
  167. }]
  168. } {0}
  169. finish_test