blob: a3cb1afc8a801727ed2eb013dc932e19fc44cb4b [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" {
drh9be13392021-03-24 19:44:01 +000033 if {$opcode != "Noop" && $opcode != "Explain"} { lappend program1 $opcode }
dan50118cd2011-07-01 14:21:38 +000034 }
35 db eval "EXPLAIN $sql2" {
drh9be13392021-03-24 19:44:01 +000036 if {$opcode != "Noop" && $opcode != "Explain"} { lappend program2 $opcode }
dan50118cd2011-07-01 14:21:38 +000037 }
dan50118cd2011-07-01 14:21:38 +000038 return [expr {$program1==$program2}]
39}
40
41proc do_distinct_noop_test {tn sql} {
42 uplevel [list do_test $tn [list is_distinct_noop $sql] 1]
43}
44proc do_distinct_not_noop_test {tn sql} {
45 uplevel [list do_test $tn [list is_distinct_noop $sql] 0]
46}
47
dan6f343962011-07-01 18:26:40 +000048proc do_temptables_test {tn sql temptables} {
49 uplevel [list do_test $tn [subst -novar {
50 set ret ""
51 db eval "EXPLAIN [set sql]" {
drh1c9d8352011-09-01 16:01:27 +000052 if {$opcode == "OpenEphemeral" || $opcode == "SorterOpen"} {
drhcb49f542020-03-23 19:14:11 +000053 if {$p5!=8 && $p5!=0} { error "p5 = $p5" }
54 if {$p5==8} {
dan6f343962011-07-01 18:26:40 +000055 lappend ret hash
56 } else {
57 lappend ret btree
58 }
59 }
60 }
61 set ret
62 }] $temptables]
63}
64
dan50118cd2011-07-01 14:21:38 +000065
66#-------------------------------------------------------------------------
67# The following tests - distinct-1.* - check that the planner correctly
68# detects cases where a UNIQUE index means that a DISTINCT clause is
69# redundant. Currently the planner only detects such cases when there
70# is a single table in the FROM clause.
71#
72do_execsql_test 1.0 {
73 CREATE TABLE t1(a, b, c, d);
74 CREATE UNIQUE INDEX i1 ON t1(b, c);
75 CREATE UNIQUE INDEX i2 ON t1(d COLLATE nocase);
76
77 CREATE TABLE t2(x INTEGER PRIMARY KEY, y);
78
dan6a36f432012-04-20 16:59:24 +000079 CREATE TABLE t3(c1 PRIMARY KEY NOT NULL, c2 NOT NULL);
dan50118cd2011-07-01 14:21:38 +000080 CREATE INDEX i3 ON t3(c2);
dan6a36f432012-04-20 16:59:24 +000081
82 CREATE TABLE t4(a, b NOT NULL, c NOT NULL, d NOT NULL);
83 CREATE UNIQUE INDEX t4i1 ON t4(b, c);
84 CREATE UNIQUE INDEX t4i2 ON t4(d COLLATE nocase);
dan50118cd2011-07-01 14:21:38 +000085}
86foreach {tn noop sql} {
87
dan6a36f432012-04-20 16:59:24 +000088 1.1 0 "SELECT DISTINCT b, c FROM t1"
89 1.2 1 "SELECT DISTINCT b, c FROM t4"
90 2.1 0 "SELECT DISTINCT c FROM t1 WHERE b = ?"
91 2.2 1 "SELECT DISTINCT c FROM t4 WHERE b = ?"
dan50118cd2011-07-01 14:21:38 +000092 3 1 "SELECT DISTINCT rowid FROM t1"
93 4 1 "SELECT DISTINCT rowid, a FROM t1"
94 5 1 "SELECT DISTINCT x FROM t2"
95 6 1 "SELECT DISTINCT * FROM t2"
96 7 1 "SELECT DISTINCT * FROM (SELECT * FROM t2)"
97
dan6a36f432012-04-20 16:59:24 +000098 8.1 0 "SELECT DISTINCT * FROM t1"
99 8.2 1 "SELECT DISTINCT * FROM t4"
dan50118cd2011-07-01 14:21:38 +0000100
101 8 0 "SELECT DISTINCT a, b FROM t1"
102
103 9 0 "SELECT DISTINCT c FROM t1 WHERE b IN (1,2)"
104 10 0 "SELECT DISTINCT c FROM t1"
105 11 0 "SELECT DISTINCT b FROM t1"
106
dan6a36f432012-04-20 16:59:24 +0000107 12.1 0 "SELECT DISTINCT a, d FROM t1"
108 12.2 0 "SELECT DISTINCT a, d FROM t4"
109 13.1 0 "SELECT DISTINCT a, b, c COLLATE nocase FROM t1"
110 13.2 0 "SELECT DISTINCT a, b, c COLLATE nocase FROM t4"
111 14.1 0 "SELECT DISTINCT a, d COLLATE nocase FROM t1"
112 14.2 1 "SELECT DISTINCT a, d COLLATE nocase FROM t4"
113
114 15 0 "SELECT DISTINCT a, d COLLATE binary FROM t1"
115 16.1 0 "SELECT DISTINCT a, b, c COLLATE binary FROM t1"
116 16.2 1 "SELECT DISTINCT a, b, c COLLATE binary FROM t4"
dan50118cd2011-07-01 14:21:38 +0000117
118 16 0 "SELECT DISTINCT t1.rowid FROM t1, t2"
119 17 0 { /* Technically, it would be possible to detect that DISTINCT
120 ** is a no-op in cases like the following. But SQLite does not
121 ** do so. */
122 SELECT DISTINCT t1.rowid FROM t1, t2 WHERE t1.rowid=t2.rowid }
123
124 18 1 "SELECT DISTINCT c1, c2 FROM t3"
125 19 1 "SELECT DISTINCT c1 FROM t3"
126 20 1 "SELECT DISTINCT * FROM t3"
127 21 0 "SELECT DISTINCT c2 FROM t3"
128
129 22 0 "SELECT DISTINCT * FROM (SELECT 1, 2, 3 UNION SELECT 4, 5, 6)"
dan50118cd2011-07-01 14:21:38 +0000130
131 24 0 "SELECT DISTINCT rowid/2 FROM t1"
132 25 1 "SELECT DISTINCT rowid/2, rowid FROM t1"
dan6a36f432012-04-20 16:59:24 +0000133 26.1 0 "SELECT DISTINCT rowid/2, b FROM t1 WHERE c = ?"
134 26.2 1 "SELECT DISTINCT rowid/2, b FROM t4 WHERE c = ?"
dan50118cd2011-07-01 14:21:38 +0000135} {
136 if {$noop} {
137 do_distinct_noop_test 1.$tn $sql
138 } else {
139 do_distinct_not_noop_test 1.$tn $sql
140 }
141}
142
dan6f343962011-07-01 18:26:40 +0000143#-------------------------------------------------------------------------
144# The following tests - distinct-2.* - test cases where an index is
145# used to deliver results in order of the DISTINCT expressions.
146#
147drop_all_tables
148do_execsql_test 2.0 {
149 CREATE TABLE t1(a, b, c);
150
151 CREATE INDEX i1 ON t1(a, b);
152 CREATE INDEX i2 ON t1(b COLLATE nocase, c COLLATE nocase);
153
154 INSERT INTO t1 VALUES('a', 'b', 'c');
155 INSERT INTO t1 VALUES('A', 'B', 'C');
156 INSERT INTO t1 VALUES('a', 'b', 'c');
157 INSERT INTO t1 VALUES('A', 'B', 'C');
158}
159
160foreach {tn sql temptables res} {
161 1 "a, b FROM t1" {} {A B a b}
162 2 "b, a FROM t1" {} {B A b a}
drh6284db92014-03-19 23:24:49 +0000163 3 "a, b, c FROM t1" {hash} {A B C a b c}
dan6f343962011-07-01 18:26:40 +0000164 4 "a, b, c FROM t1 ORDER BY a, b, c" {btree} {A B C a b c}
165 5 "b FROM t1 WHERE a = 'a'" {} {b}
drh4fe425a2013-06-12 17:08:06 +0000166 6 "b FROM t1 ORDER BY +b COLLATE binary" {btree hash} {B b}
dan6f343962011-07-01 18:26:40 +0000167 7 "a FROM t1" {} {A a}
168 8 "b COLLATE nocase FROM t1" {} {b}
drh4e8b9922018-04-18 18:19:25 +0000169 9 "b COLLATE nocase FROM t1 ORDER BY b COLLATE nocase" {} {b}
dan6f343962011-07-01 18:26:40 +0000170} {
171 do_execsql_test 2.$tn.1 "SELECT DISTINCT $sql" $res
172 do_temptables_test 2.$tn.2 "SELECT DISTINCT $sql" $temptables
173}
dan50118cd2011-07-01 14:21:38 +0000174
dan94e08d92011-07-02 06:44:05 +0000175do_execsql_test 2.A {
drh3f4d1d12012-09-15 18:45:54 +0000176 SELECT (SELECT DISTINCT o.a FROM t1 AS i) FROM t1 AS o ORDER BY rowid;
dan94e08d92011-07-02 06:44:05 +0000177} {a A a A}
dan50118cd2011-07-01 14:21:38 +0000178
drh053a1282012-09-19 21:15:46 +0000179do_test 3.0 {
180 db eval {
181 CREATE TABLE t3(a INTEGER, b INTEGER, c, UNIQUE(a,b));
182 INSERT INTO t3 VALUES
183 (null, null, 1),
184 (null, null, 2),
185 (null, 3, 4),
186 (null, 3, 5),
187 (6, null, 7),
188 (6, null, 8);
189 SELECT DISTINCT a, b FROM t3 ORDER BY +a, +b;
190 }
191} {{} {} {} 3 6 {}}
192do_test 3.1 {
193 regexp {OpenEphemeral} [db eval {
194 EXPLAIN SELECT DISTINCT a, b FROM t3 ORDER BY +a, +b;
195 }]
196} {0}
dan50118cd2011-07-01 14:21:38 +0000197
drh826af372014-02-08 19:12:21 +0000198#-------------------------------------------------------------------------
199# Ticket [fccbde530a6583bf2748400919f1603d5425995c] (2014-01-08)
200# The logic that computes DISTINCT sometimes thinks that a zeroblob()
201# and a blob of all zeros are different when they should be the same.
202#
203do_execsql_test 4.1 {
204 DROP TABLE IF EXISTS t1;
205 DROP TABLE IF EXISTS t2;
206 CREATE TABLE t1(a INTEGER);
207 INSERT INTO t1 VALUES(3);
208 INSERT INTO t1 VALUES(2);
209 INSERT INTO t1 VALUES(1);
210 INSERT INTO t1 VALUES(2);
211 INSERT INTO t1 VALUES(3);
212 INSERT INTO t1 VALUES(1);
213 CREATE TABLE t2(x);
214 INSERT INTO t2
215 SELECT DISTINCT
216 CASE a WHEN 1 THEN x'0000000000'
217 WHEN 2 THEN zeroblob(5)
218 ELSE 'xyzzy' END
219 FROM t1;
220 SELECT quote(x) FROM t2 ORDER BY 1;
221} {'xyzzy' X'0000000000'}
222
drhdea7d702014-12-04 21:54:58 +0000223#----------------------------------------------------------------------------
224# Ticket [c5ea805691bfc4204b1cb9e9aa0103bd48bc7d34] (2014-12-04)
225# Make sure that DISTINCT works together with ORDER BY and descending
226# indexes.
227#
228do_execsql_test 5.1 {
229 DROP TABLE IF EXISTS t1;
230 CREATE TABLE t1(x);
231 INSERT INTO t1(x) VALUES(3),(1),(5),(2),(6),(4),(5),(1),(3);
232 CREATE INDEX t1x ON t1(x DESC);
233 SELECT DISTINCT x FROM t1 ORDER BY x ASC;
234} {1 2 3 4 5 6}
235do_execsql_test 5.2 {
236 SELECT DISTINCT x FROM t1 ORDER BY x DESC;
237} {6 5 4 3 2 1}
238do_execsql_test 5.3 {
239 SELECT DISTINCT x FROM t1 ORDER BY x;
240} {1 2 3 4 5 6}
241do_execsql_test 5.4 {
242 DROP INDEX t1x;
243 CREATE INDEX t1x ON t1(x ASC);
244 SELECT DISTINCT x FROM t1 ORDER BY x ASC;
245} {1 2 3 4 5 6}
246do_execsql_test 5.5 {
247 SELECT DISTINCT x FROM t1 ORDER BY x DESC;
248} {6 5 4 3 2 1}
249do_execsql_test 5.6 {
250 SELECT DISTINCT x FROM t1 ORDER BY x;
251} {1 2 3 4 5 6}
252
drh2edc5fd2015-11-24 02:10:52 +0000253#-------------------------------------------------------------------------
254# 2015-11-23. Problem discovered by Kostya Serebryany using libFuzzer
255#
256db close
257sqlite3 db :memory:
258do_execsql_test 6.1 {
259 CREATE TABLE jjj(x);
260 SELECT (SELECT 'mmm' UNION SELECT DISTINCT max(name) ORDER BY 1)
261 FROM sqlite_master;
262} {jjj}
263do_execsql_test 6.2 {
264 CREATE TABLE nnn(x);
265 SELECT (SELECT 'mmm' UNION SELECT DISTINCT max(name) ORDER BY 1)
266 FROM sqlite_master;
267} {mmm}
268
dan9e10f9a2020-01-06 17:06:12 +0000269#-------------------------------------------------------------------------
270# Ticket [9c944882]
271#
272reset_db
273do_execsql_test 7.0 {
274 CREATE TABLE t1(a INTEGER PRIMARY KEY);
275 CREATE TABLE t3(a INTEGER PRIMARY KEY);
276
277 CREATE TABLE t4(x);
278 CREATE TABLE t5(y);
279
280 INSERT INTO t5 VALUES(1), (2), (2);
281 INSERT INTO t1 VALUES(2);
282 INSERT INTO t3 VALUES(2);
283 INSERT INTO t4 VALUES(2);
284}
285
286do_execsql_test 7.1 {
287 WITH t2(b) AS (
288 SELECT DISTINCT y FROM t5 ORDER BY y
289 )
290 SELECT * FROM
291 t4 CROSS JOIN t3 CROSS JOIN t1
292 WHERE (t1.a=t3.a) AND (SELECT count(*) FROM t2 AS y WHERE t4.x!='abc')=t1.a
293} {2 2 2}
drh2edc5fd2015-11-24 02:10:52 +0000294
drh204b6342021-04-06 23:29:41 +0000295# 2021-04-06 forum post https://sqlite.org/forum/forumpost/66954e9ece
296reset_db
297do_execsql_test 8.0 {
298 CREATE TABLE person ( pid INT) ;
299 CREATE UNIQUE INDEX idx ON person ( pid ) WHERE pid == 1;
300 INSERT INTO person VALUES (1), (10), (10);
301 SELECT DISTINCT pid FROM person where pid = 10;
302} {10}
303
dan50118cd2011-07-01 14:21:38 +0000304finish_test