blob: 2b006d3e61cf57dd223e459e7109acdd0e0da451 [file] [log] [blame]
dan50118cd2011-07-01 14:21:38 +00001# 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
15set testdir [file dirname $argv0]
16source $testdir/tester.tcl
17
dan2f56da32012-02-13 10:00:35 +000018ifcapable !compound {
19 finish_test
20 return
21}
22
dan50118cd2011-07-01 14:21:38 +000023set testprefix distinct
24
25
26proc is_distinct_noop {sql} {
27 set sql1 $sql
28 set sql2 [string map {DISTINCT ""} $sql]
29
30 set program1 [list]
31 set program2 [list]
32 db eval "EXPLAIN $sql1" {
33 if {$opcode != "Noop"} { lappend program1 $opcode }
34 }
35 db eval "EXPLAIN $sql2" {
36 if {$opcode != "Noop"} { lappend program2 $opcode }
37 }
38
39 return [expr {$program1==$program2}]
40}
41
42proc do_distinct_noop_test {tn sql} {
43 uplevel [list do_test $tn [list is_distinct_noop $sql] 1]
44}
45proc do_distinct_not_noop_test {tn sql} {
46 uplevel [list do_test $tn [list is_distinct_noop $sql] 0]
47}
48
dan6f343962011-07-01 18:26:40 +000049proc do_temptables_test {tn sql temptables} {
50 uplevel [list do_test $tn [subst -novar {
51 set ret ""
52 db eval "EXPLAIN [set sql]" {
drh1c9d8352011-09-01 16:01:27 +000053 if {$opcode == "OpenEphemeral" || $opcode == "SorterOpen"} {
drh33f111d2012-01-17 15:29:14 +000054 if {$p5 != "08" && $p5!="00"} { error "p5 = $p5" }
55 if {$p5 == "08"} {
dan6f343962011-07-01 18:26:40 +000056 lappend ret hash
57 } else {
58 lappend ret btree
59 }
60 }
61 }
62 set ret
63 }] $temptables]
64}
65
dan50118cd2011-07-01 14:21:38 +000066
67#-------------------------------------------------------------------------
68# The following tests - distinct-1.* - check that the planner correctly
69# detects cases where a UNIQUE index means that a DISTINCT clause is
70# redundant. Currently the planner only detects such cases when there
71# is a single table in the FROM clause.
72#
73do_execsql_test 1.0 {
74 CREATE TABLE t1(a, b, c, d);
75 CREATE UNIQUE INDEX i1 ON t1(b, c);
76 CREATE UNIQUE INDEX i2 ON t1(d COLLATE nocase);
77
78 CREATE TABLE t2(x INTEGER PRIMARY KEY, y);
79
dan6a36f432012-04-20 16:59:24 +000080 CREATE TABLE t3(c1 PRIMARY KEY NOT NULL, c2 NOT NULL);
dan50118cd2011-07-01 14:21:38 +000081 CREATE INDEX i3 ON t3(c2);
dan6a36f432012-04-20 16:59:24 +000082
83 CREATE TABLE t4(a, b NOT NULL, c NOT NULL, d NOT NULL);
84 CREATE UNIQUE INDEX t4i1 ON t4(b, c);
85 CREATE UNIQUE INDEX t4i2 ON t4(d COLLATE nocase);
dan50118cd2011-07-01 14:21:38 +000086}
87foreach {tn noop sql} {
88
dan6a36f432012-04-20 16:59:24 +000089 1.1 0 "SELECT DISTINCT b, c FROM t1"
90 1.2 1 "SELECT DISTINCT b, c FROM t4"
91 2.1 0 "SELECT DISTINCT c FROM t1 WHERE b = ?"
92 2.2 1 "SELECT DISTINCT c FROM t4 WHERE b = ?"
dan50118cd2011-07-01 14:21:38 +000093 3 1 "SELECT DISTINCT rowid FROM t1"
94 4 1 "SELECT DISTINCT rowid, a FROM t1"
95 5 1 "SELECT DISTINCT x FROM t2"
96 6 1 "SELECT DISTINCT * FROM t2"
97 7 1 "SELECT DISTINCT * FROM (SELECT * FROM t2)"
98
dan6a36f432012-04-20 16:59:24 +000099 8.1 0 "SELECT DISTINCT * FROM t1"
100 8.2 1 "SELECT DISTINCT * FROM t4"
dan50118cd2011-07-01 14:21:38 +0000101
102 8 0 "SELECT DISTINCT a, b FROM t1"
103
104 9 0 "SELECT DISTINCT c FROM t1 WHERE b IN (1,2)"
105 10 0 "SELECT DISTINCT c FROM t1"
106 11 0 "SELECT DISTINCT b FROM t1"
107
dan6a36f432012-04-20 16:59:24 +0000108 12.1 0 "SELECT DISTINCT a, d FROM t1"
109 12.2 0 "SELECT DISTINCT a, d FROM t4"
110 13.1 0 "SELECT DISTINCT a, b, c COLLATE nocase FROM t1"
111 13.2 0 "SELECT DISTINCT a, b, c COLLATE nocase FROM t4"
112 14.1 0 "SELECT DISTINCT a, d COLLATE nocase FROM t1"
113 14.2 1 "SELECT DISTINCT a, d COLLATE nocase FROM t4"
114
115 15 0 "SELECT DISTINCT a, d COLLATE binary FROM t1"
116 16.1 0 "SELECT DISTINCT a, b, c COLLATE binary FROM t1"
117 16.2 1 "SELECT DISTINCT a, b, c COLLATE binary FROM t4"
dan50118cd2011-07-01 14:21:38 +0000118
119 16 0 "SELECT DISTINCT t1.rowid FROM t1, t2"
120 17 0 { /* Technically, it would be possible to detect that DISTINCT
121 ** is a no-op in cases like the following. But SQLite does not
122 ** do so. */
123 SELECT DISTINCT t1.rowid FROM t1, t2 WHERE t1.rowid=t2.rowid }
124
125 18 1 "SELECT DISTINCT c1, c2 FROM t3"
126 19 1 "SELECT DISTINCT c1 FROM t3"
127 20 1 "SELECT DISTINCT * FROM t3"
128 21 0 "SELECT DISTINCT c2 FROM t3"
129
130 22 0 "SELECT DISTINCT * FROM (SELECT 1, 2, 3 UNION SELECT 4, 5, 6)"
131 23 1 "SELECT DISTINCT rowid FROM (SELECT 1, 2, 3 UNION SELECT 4, 5, 6)"
132
133 24 0 "SELECT DISTINCT rowid/2 FROM t1"
134 25 1 "SELECT DISTINCT rowid/2, rowid FROM t1"
dan6a36f432012-04-20 16:59:24 +0000135 26.1 0 "SELECT DISTINCT rowid/2, b FROM t1 WHERE c = ?"
136 26.2 1 "SELECT DISTINCT rowid/2, b FROM t4 WHERE c = ?"
dan50118cd2011-07-01 14:21:38 +0000137} {
138 if {$noop} {
139 do_distinct_noop_test 1.$tn $sql
140 } else {
141 do_distinct_not_noop_test 1.$tn $sql
142 }
143}
144
dan6f343962011-07-01 18:26:40 +0000145#-------------------------------------------------------------------------
146# The following tests - distinct-2.* - test cases where an index is
147# used to deliver results in order of the DISTINCT expressions.
148#
149drop_all_tables
150do_execsql_test 2.0 {
151 CREATE TABLE t1(a, b, c);
152
153 CREATE INDEX i1 ON t1(a, b);
154 CREATE INDEX i2 ON t1(b COLLATE nocase, c COLLATE nocase);
155
156 INSERT INTO t1 VALUES('a', 'b', 'c');
157 INSERT INTO t1 VALUES('A', 'B', 'C');
158 INSERT INTO t1 VALUES('a', 'b', 'c');
159 INSERT INTO t1 VALUES('A', 'B', 'C');
160}
161
162foreach {tn sql temptables res} {
163 1 "a, b FROM t1" {} {A B a b}
164 2 "b, a FROM t1" {} {B A b a}
165 3 "a, b, c FROM t1" {hash} {a b c A B C}
166 4 "a, b, c FROM t1 ORDER BY a, b, c" {btree} {A B C a b c}
167 5 "b FROM t1 WHERE a = 'a'" {} {b}
drh4fe425a2013-06-12 17:08:06 +0000168 6 "b FROM t1 ORDER BY +b COLLATE binary" {btree hash} {B b}
dan6f343962011-07-01 18:26:40 +0000169 7 "a FROM t1" {} {A a}
170 8 "b COLLATE nocase FROM t1" {} {b}
drh580c8c12012-12-08 03:34:04 +0000171 9 "b COLLATE nocase FROM t1 ORDER BY b COLLATE nocase" {} {b}
dan6f343962011-07-01 18:26:40 +0000172} {
173 do_execsql_test 2.$tn.1 "SELECT DISTINCT $sql" $res
174 do_temptables_test 2.$tn.2 "SELECT DISTINCT $sql" $temptables
175}
dan50118cd2011-07-01 14:21:38 +0000176
dan94e08d92011-07-02 06:44:05 +0000177do_execsql_test 2.A {
drh3f4d1d12012-09-15 18:45:54 +0000178 SELECT (SELECT DISTINCT o.a FROM t1 AS i) FROM t1 AS o ORDER BY rowid;
dan94e08d92011-07-02 06:44:05 +0000179} {a A a A}
dan50118cd2011-07-01 14:21:38 +0000180
drh053a1282012-09-19 21:15:46 +0000181do_test 3.0 {
182 db eval {
183 CREATE TABLE t3(a INTEGER, b INTEGER, c, UNIQUE(a,b));
184 INSERT INTO t3 VALUES
185 (null, null, 1),
186 (null, null, 2),
187 (null, 3, 4),
188 (null, 3, 5),
189 (6, null, 7),
190 (6, null, 8);
191 SELECT DISTINCT a, b FROM t3 ORDER BY +a, +b;
192 }
193} {{} {} {} 3 6 {}}
194do_test 3.1 {
195 regexp {OpenEphemeral} [db eval {
196 EXPLAIN SELECT DISTINCT a, b FROM t3 ORDER BY +a, +b;
197 }]
198} {0}
dan50118cd2011-07-01 14:21:38 +0000199
200finish_test