xref: /sqlite-3.40.0/test/having.test (revision 85d31b9f)
1ab31a845Sdan# 2017 April 30
2ab31a845Sdan#
3ab31a845Sdan# The author disclaims copyright to this source code.  In place of
4ab31a845Sdan# a legal notice, here is a blessing:
5ab31a845Sdan#
6ab31a845Sdan#    May you do good and not evil.
7ab31a845Sdan#    May you find forgiveness for yourself and forgive others.
8ab31a845Sdan#    May you share freely, never taking more than you give.
9ab31a845Sdan#
10ab31a845Sdan#***********************************************************************
11ab31a845Sdan#
12ab31a845Sdan# Test the HAVING->WHERE optimization.
13ab31a845Sdan#
14ab31a845Sdan
15ab31a845Sdanset testdir [file dirname $argv0]
16ab31a845Sdansource $testdir/tester.tcl
17ab31a845Sdanset testprefix having
18ab31a845Sdan
19ab31a845Sdando_execsql_test 1.0 {
20181a1167Sdan  CREATE TABLE t2(c, d);
21181a1167Sdan
22ab31a845Sdan  CREATE TABLE t1(a, b);
23ab31a845Sdan  INSERT INTO t1 VALUES(1, 1);
24ab31a845Sdan  INSERT INTO t1 VALUES(2, 2);
25ab31a845Sdan  INSERT INTO t1 VALUES(1, 3);
26ab31a845Sdan  INSERT INTO t1 VALUES(2, 4);
27ab31a845Sdan  INSERT INTO t1 VALUES(1, 5);
28ab31a845Sdan  INSERT INTO t1 VALUES(2, 6);
29ab31a845Sdan} {}
30ab31a845Sdan
31ab31a845Sdanforeach {tn sql res} {
32ab31a845Sdan  1 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING a=2" {2 12}
33ab31a845Sdan  2 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING a=2 AND sum(b)>10" {2 12}
34ab31a845Sdan  3 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING sum(b)>12" {}
35ab31a845Sdan} {
36ab31a845Sdan  do_execsql_test 1.$tn $sql $res
37ab31a845Sdan}
38ab31a845Sdan
39181a1167Sdan# Run an EXPLAIN command for both SQL statements. Return true if
40181a1167Sdan# the outputs are identical, or false otherwise.
41181a1167Sdan#
42ab31a845Sdanproc compare_vdbe {sql1 sql2} {
43ab31a845Sdan  set r1 [list]
44ab31a845Sdan  set r2 [list]
45181a1167Sdan  db eval "explain $sql1" { lappend r1 $opcode $p1 $p2 $p3 $p4 $p5}
46181a1167Sdan  db eval "explain $sql2" { lappend r2 $opcode $p1 $p2 $p3 $p4 $p5}
47ab31a845Sdan  return [expr {$r1==$r2}]
48ab31a845Sdan}
49ab31a845Sdan
50ab31a845Sdanproc do_compare_vdbe_test {tn sql1 sql2 res} {
51ab31a845Sdan  uplevel [list do_test $tn [list compare_vdbe $sql1 $sql2] $res]
52ab31a845Sdan}
53ab31a845Sdan
54181a1167Sdan#-------------------------------------------------------------------------
55181a1167Sdan# Test that various statements that are eligible for the optimization
56181a1167Sdan# produce the same VDBE code as optimizing by hand does.
57181a1167Sdan#
58ab31a845Sdanforeach {tn sql1 sql2} {
59ab31a845Sdan  1 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING a=2"
60ab31a845Sdan    "SELECT a, sum(b) FROM t1 WHERE a=2 GROUP BY a"
61ab31a845Sdan
62ab31a845Sdan  2 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING sum(b)>5 AND a=2"
63ab31a845Sdan    "SELECT a, sum(b) FROM t1 WHERE a=2 GROUP BY a HAVING sum(b)>5"
64ab31a845Sdan
65ab31a845Sdan  3 "SELECT a, sum(b) FROM t1 GROUP BY a COLLATE binary HAVING a=2"
66ab31a845Sdan    "SELECT a, sum(b) FROM t1 WHERE a=2 GROUP BY a COLLATE binary"
67ab31a845Sdan
68f39168e4Sdan  5 "SELECT a, sum(b) FROM t1 GROUP BY a COLLATE binary HAVING 1"
69f39168e4Sdan    "SELECT a, sum(b) FROM t1 WHERE 1 GROUP BY a COLLATE binary"
70181a1167Sdan
71181a1167Sdan  6 "SELECT count(*) FROM t1,t2 WHERE a=c GROUP BY b, d HAVING b=d"
72181a1167Sdan    "SELECT count(*) FROM t1,t2 WHERE a=c AND b=d GROUP BY b, d"
73181a1167Sdan
74181a1167Sdan  7 {
75181a1167Sdan      SELECT count(*) FROM t1,t2 WHERE a=c GROUP BY b, d
76181a1167Sdan      HAVING b=d COLLATE nocase
77ab31a845Sdan    } {
78181a1167Sdan      SELECT count(*) FROM t1,t2 WHERE a=c AND b=d COLLATE nocase
79181a1167Sdan      GROUP BY b, d
80ab31a845Sdan    }
81ab31a845Sdan
82181a1167Sdan  8 "SELECT a, sum(b) FROM t1 GROUP BY a||b HAVING substr(a||b, 1, 1)='a'"
83181a1167Sdan    "SELECT a, sum(b) FROM t1 WHERE substr(a||b, 1, 1)='a' GROUP BY a||b"
84181a1167Sdan} {
85181a1167Sdan  do_compare_vdbe_test 2.$tn $sql1 $sql2 1
86181a1167Sdan}
87181a1167Sdan
88508e2d00Sdrh# The (4) test in the above set used to generate identical bytecode, but
89508e2d00Sdrh# that is no longer the case.  The byte code is equivalent, though.
90508e2d00Sdrh#
91508e2d00Sdrhdo_execsql_test 2.4a {
92508e2d00Sdrh  SELECT x,y FROM (
93508e2d00Sdrh    SELECT a AS x, sum(b) AS y FROM t1
94508e2d00Sdrh    GROUP BY a
95508e2d00Sdrh  ) WHERE x BETWEEN 2 AND 9999
96508e2d00Sdrh} {2 12}
97508e2d00Sdrhdo_execsql_test 2.4b {
98508e2d00Sdrh  SELECT x,y FROM (
99508e2d00Sdrh    SELECT a AS x, sum(b) AS y FROM t1
100508e2d00Sdrh    WHERE x BETWEEN 2 AND 9999
101508e2d00Sdrh    GROUP BY a
102508e2d00Sdrh  )
103508e2d00Sdrh} {2 12}
104508e2d00Sdrh
105508e2d00Sdrh
106181a1167Sdan#-------------------------------------------------------------------------
107181a1167Sdan# 1: Test that the optimization is only applied if the GROUP BY term
108181a1167Sdan#    uses BINARY collation.
109181a1167Sdan#
110181a1167Sdan# 2: Not applied if there is a non-deterministic function in the HAVING
111181a1167Sdan#    term.
112181a1167Sdan#
113ab31a845Sdanforeach {tn sql1 sql2} {
114ab31a845Sdan  1 "SELECT a, sum(b) FROM t1 GROUP BY a COLLATE nocase HAVING a=2"
115ab31a845Sdan    "SELECT a, sum(b) FROM t1 WHERE a=2 GROUP BY a COLLATE nocase"
116181a1167Sdan
117181a1167Sdan  2 "SELECT a, sum(b) FROM t1 GROUP BY a HAVING randomblob(a)<X'88'"
118181a1167Sdan    "SELECT a, sum(b) FROM t1 WHERE randomblob(a)<X'88' GROUP BY a"
119ab31a845Sdan} {
120181a1167Sdan  do_compare_vdbe_test 3.$tn $sql1 $sql2 0
121ab31a845Sdan}
122ab31a845Sdan
123181a1167Sdan
124181a1167Sdan#-------------------------------------------------------------------------
125181a1167Sdan# Test that non-deterministic functions disqualify a term from being
126181a1167Sdan# moved from the HAVING to WHERE clause.
127181a1167Sdan#
128181a1167Sdando_execsql_test 4.1 {
129181a1167Sdan  CREATE TABLE t3(a, b);
130181a1167Sdan  INSERT INTO t3 VALUES(1, 1);
131181a1167Sdan  INSERT INTO t3 VALUES(1, 2);
132181a1167Sdan  INSERT INTO t3 VALUES(1, 3);
133181a1167Sdan  INSERT INTO t3 VALUES(2, 1);
134181a1167Sdan  INSERT INTO t3 VALUES(2, 2);
135181a1167Sdan  INSERT INTO t3 VALUES(2, 3);
136181a1167Sdan}
137181a1167Sdan
138181a1167Sdanproc nondeter {args} {
139181a1167Sdan  incr ::nondeter_ret
140181a1167Sdan  expr {$::nondeter_ret % 2}
141181a1167Sdan}
142181a1167Sdandb func nondeter nondeter
143181a1167Sdan
144181a1167Sdanset ::nondeter_ret 0
145181a1167Sdando_execsql_test 4.2 {
146181a1167Sdan  SELECT a, sum(b) FROM t3 GROUP BY a HAVING nondeter(a)
147181a1167Sdan} {1 6}
148181a1167Sdan
149181a1167Sdan# If the term where moved, the query above would return the same
150181a1167Sdan# result as the following. But it does not.
151181a1167Sdan#
152181a1167Sdanset ::nondeter_ret 0
153181a1167Sdando_execsql_test 4.3 {
154181a1167Sdan  SELECT a, sum(b) FROM t3 WHERE nondeter(a) GROUP BY a
155181a1167Sdan} {1 4 2 2}
156181a1167Sdan
157f39168e4Sdan#-------------------------------------------------------------------------
158f39168e4Sdanreset_db
159f39168e4Sdando_execsql_test 5.0 {
160f39168e4Sdan  CREATE TABLE t1(a, b);
161f39168e4Sdan  CREATE TABLE t2(x, y);
162f39168e4Sdan  INSERT INTO t1 VALUES('a', 'b');
163f39168e4Sdan}
164f39168e4Sdan
165f39168e4Sdan# The WHERE clause (a=2), uses an aggregate column from the outer query.
166f39168e4Sdan# If the HAVING term (0) is moved into the WHERE clause in this case,
167f39168e4Sdan# SQLite would at one point optimize (a=2 AND 0) to simply (0). Which
168f39168e4Sdan# is logically correct, but happened to cause problems in aggregate
169f39168e4Sdan# processing for the outer query. This test case verifies that those
170f39168e4Sdan# problems are no longer present.
171f39168e4Sdando_execsql_test 5.1 {
172f39168e4Sdan  SELECT min(b), (
173f39168e4Sdan    SELECT x FROM t2 WHERE a=2 GROUP BY y HAVING 0
174f39168e4Sdan  ) FROM t1;
175f39168e4Sdan} {b {}}
176f39168e4Sdan
177*85d31b9fSdrh# From chromium
178*85d31b9fSdrh# https://bugs.chromium.org/p/chromium/issues/detail?id=1161869
179*85d31b9fSdrh#
180*85d31b9fSdrhdo_execsql_test 5.2 {
181*85d31b9fSdrh  SELECT EXISTS (
182*85d31b9fSdrh    SELECT * FROM (
183*85d31b9fSdrh      SELECT * FROM (
184*85d31b9fSdrh        SELECT 1
185*85d31b9fSdrh      ) WHERE Col0 = 1   GROUP BY 1
186*85d31b9fSdrh    )   WHERE 0
187*85d31b9fSdrh  )
188*85d31b9fSdrh  FROM (SELECT 1 Col0)   GROUP BY 1
189*85d31b9fSdrh} {0}
190181a1167Sdan
191ab31a845Sdanfinish_test
192