# tests adapted from logictest -- aggregate

exec-ddl
CREATE TABLE kv (
  k INT PRIMARY KEY,
  v INT,
  w INT,
  s STRING
)
----
TABLE kv
 ├── k int not null
 ├── v int
 ├── w int
 ├── s string
 └── INDEX primary
      └── k int not null

# Presence of HAVING triggers aggregation, reducing results to one row (even without GROUP BY).
build
SELECT 3 r FROM kv HAVING TRUE
----
project
 ├── columns: r:5(int!null)
 ├── select
 │    ├── scalar-group-by
 │    │    └── project
 │    │         └── scan kv
 │    │              └── columns: k:1(int!null) v:2(int) w:3(int) s:4(string)
 │    └── filters
 │         └── true [type=bool]
 └── projections
      └── const: 3 [type=int]

build
SELECT s, count(*) FROM kv GROUP BY s HAVING count(*) > 1
----
select
 ├── columns: s:4(string) count:5(int!null)
 ├── group-by
 │    ├── columns: s:4(string) count_rows:5(int)
 │    ├── grouping columns: s:4(string)
 │    ├── project
 │    │    ├── columns: s:4(string)
 │    │    └── scan kv
 │    │         └── columns: k:1(int!null) v:2(int) w:3(int) s:4(string)
 │    └── aggregations
 │         └── count-rows [type=int]
 └── filters
      └── gt [type=bool]
           ├── variable: count_rows [type=int]
           └── const: 1 [type=int]

build
SELECT max(k), min(v) FROM kv HAVING min(v) > 2
----
select
 ├── columns: max:5(int) min:6(int!null)
 ├── scalar-group-by
 │    ├── columns: max:5(int) min:6(int)
 │    ├── project
 │    │    ├── columns: k:1(int!null) v:2(int)
 │    │    └── scan kv
 │    │         └── columns: k:1(int!null) v:2(int) w:3(int) s:4(string)
 │    └── aggregations
 │         ├── max [type=int]
 │         │    └── variable: k [type=int]
 │         └── min [type=int]
 │              └── variable: v [type=int]
 └── filters
      └── gt [type=bool]
           ├── variable: min [type=int]
           └── const: 2 [type=int]

build
SELECT max(k), min(v) FROM kv HAVING max(v) > 2
----
project
 ├── columns: max:5(int) min:6(int)
 └── select
      ├── columns: max:5(int) min:6(int) max:7(int!null)
      ├── scalar-group-by
      │    ├── columns: max:5(int) min:6(int) max:7(int)
      │    ├── project
      │    │    ├── columns: k:1(int!null) v:2(int)
      │    │    └── scan kv
      │    │         └── columns: k:1(int!null) v:2(int) w:3(int) s:4(string)
      │    └── aggregations
      │         ├── max [type=int]
      │         │    └── variable: k [type=int]
      │         ├── min [type=int]
      │         │    └── variable: v [type=int]
      │         └── max [type=int]
      │              └── variable: v [type=int]
      └── filters
           └── gt [type=bool]
                ├── variable: max [type=int]
                └── const: 2 [type=int]

build
SELECT max(k), min(v) FROM kv HAVING max(min(v)) > 2
----
error: max(): min(): aggregate function calls cannot be nested

build
SELECT max(k), min(v) FROM kv HAVING k
----
error (42804): argument of HAVING must be type bool, not type int

# Expressions listed in the HAVING clause must conform to same validation as the SELECT clause (grouped or aggregated).
build
SELECT 3 FROM kv GROUP BY v HAVING k > 5
----
error (42803): column "k" must appear in the GROUP BY clause or be used in an aggregate function

# pg has a special case for grouping on primary key, which would allow this, but we do not.
# See http://www.postgresql.org/docs/current/static/sql-select.html#SQL-GROUPBY
build
SELECT 3 FROM kv GROUP BY k HAVING v > 2
----
error (42803): column "v" must appear in the GROUP BY clause or be used in an aggregate function

build
SELECT k FROM kv HAVING k > 7
----
error (42803): column "k" must appear in the GROUP BY clause or be used in an aggregate function

build
SELECT count(*), k+w AS r FROM kv GROUP BY k+w HAVING (k+w) > 5
----
select
 ├── columns: count:5(int) r:6(int!null)
 ├── group-by
 │    ├── columns: count_rows:5(int) column6:6(int)
 │    ├── grouping columns: column6:6(int)
 │    ├── project
 │    │    ├── columns: column6:6(int)
 │    │    ├── scan kv
 │    │    │    └── columns: k:1(int!null) v:2(int) w:3(int) s:4(string)
 │    │    └── projections
 │    │         └── plus [type=int]
 │    │              ├── variable: k [type=int]
 │    │              └── variable: w [type=int]
 │    └── aggregations
 │         └── count-rows [type=int]
 └── filters
      └── gt [type=bool]
           ├── variable: column6 [type=int]
           └── const: 5 [type=int]

build
SELECT count(*), k+w FROM kv GROUP BY k+w HAVING (k+v) > 5
----
error (42803): column "k" must appear in the GROUP BY clause or be used in an aggregate function

# Check that everything still works with differently qualified names
build
SELECT max(kv.v) FROM kv GROUP BY v HAVING kv.v > 5
----
project
 ├── columns: max:5(int)
 └── select
      ├── columns: v:2(int!null) max:5(int)
      ├── group-by
      │    ├── columns: v:2(int) max:5(int)
      │    ├── grouping columns: v:2(int)
      │    ├── project
      │    │    ├── columns: v:2(int)
      │    │    └── scan kv
      │    │         └── columns: k:1(int!null) v:2(int) w:3(int) s:4(string)
      │    └── aggregations
      │         └── max [type=int]
      │              └── variable: v [type=int]
      └── filters
           └── gt [type=bool]
                ├── variable: v [type=int]
                └── const: 5 [type=int]

build
SELECT sum(kv.w) FROM kv GROUP BY lower(s) HAVING lower(kv.s) LIKE 'test%'
----
project
 ├── columns: sum:5(decimal)
 └── select
      ├── columns: sum:5(decimal) column6:6(string!null)
      ├── group-by
      │    ├── columns: sum:5(decimal) column6:6(string)
      │    ├── grouping columns: column6:6(string)
      │    ├── project
      │    │    ├── columns: column6:6(string) w:3(int)
      │    │    ├── scan kv
      │    │    │    └── columns: k:1(int!null) v:2(int) w:3(int) s:4(string)
      │    │    └── projections
      │    │         └── function: lower [type=string]
      │    │              └── variable: s [type=string]
      │    └── aggregations
      │         └── sum [type=decimal]
      │              └── variable: w [type=int]
      └── filters
           └── like [type=bool]
                ├── variable: column6 [type=string]
                └── const: 'test%' [type=string]

build
SELECT sum(kv.w) FROM kv GROUP BY lower(s) HAVING sum(w) IN (4, 5, 6)
----
project
 ├── columns: sum:5(decimal!null)
 └── select
      ├── columns: sum:5(decimal!null) column6:6(string)
      ├── group-by
      │    ├── columns: sum:5(decimal) column6:6(string)
      │    ├── grouping columns: column6:6(string)
      │    ├── project
      │    │    ├── columns: column6:6(string) w:3(int)
      │    │    ├── scan kv
      │    │    │    └── columns: k:1(int!null) v:2(int) w:3(int) s:4(string)
      │    │    └── projections
      │    │         └── function: lower [type=string]
      │    │              └── variable: s [type=string]
      │    └── aggregations
      │         └── sum [type=decimal]
      │              └── variable: w [type=int]
      └── filters
           └── in [type=bool]
                ├── variable: sum [type=decimal]
                └── tuple [type=tuple{decimal, decimal, decimal}]
                     ├── const: 4 [type=decimal]
                     ├── const: 5 [type=decimal]
                     └── const: 6 [type=decimal]

build fully-qualify-names
SELECT t.kv.v FROM t.kv GROUP BY v, kv.k * w HAVING k * kv.w > 5
----
project
 ├── columns: v:2(int)
 └── select
      ├── columns: t.public.kv.v:2(int) column5:5(int!null)
      ├── group-by
      │    ├── columns: t.public.kv.v:2(int) column5:5(int)
      │    ├── grouping columns: t.public.kv.v:2(int) column5:5(int)
      │    └── project
      │         ├── columns: column5:5(int) t.public.kv.v:2(int)
      │         ├── scan t.public.kv
      │         │    └── columns: t.public.kv.k:1(int!null) t.public.kv.v:2(int) t.public.kv.w:3(int) t.public.kv.s:4(string)
      │         └── projections
      │              └── mult [type=int]
      │                   ├── variable: t.public.kv.k [type=int]
      │                   └── variable: t.public.kv.w [type=int]
      └── filters
           └── gt [type=bool]
                ├── variable: column5 [type=int]
                └── const: 5 [type=int]

build fully-qualify-names
SELECT t.kv.v FROM t.kv GROUP BY v, kv.k * w HAVING w > 5
----
error (42803): column "w" must appear in the GROUP BY clause or be used in an aggregate function

build fully-qualify-names
SELECT upper(s), count(s), count(upper(s)) FROM t.kv GROUP BY upper(s) HAVING count(s) > 1
----
select
 ├── columns: upper:6(string) count:5(int!null) count:7(int)
 ├── group-by
 │    ├── columns: count:5(int) column6:6(string) count:7(int)
 │    ├── grouping columns: column6:6(string)
 │    ├── project
 │    │    ├── columns: column6:6(string) t.public.kv.s:4(string)
 │    │    ├── scan t.public.kv
 │    │    │    └── columns: t.public.kv.k:1(int!null) t.public.kv.v:2(int) t.public.kv.w:3(int) t.public.kv.s:4(string)
 │    │    └── projections
 │    │         └── function: upper [type=string]
 │    │              └── variable: t.public.kv.s [type=string]
 │    └── aggregations
 │         ├── count [type=int]
 │         │    └── variable: t.public.kv.s [type=string]
 │         └── count [type=int]
 │              └── variable: column6 [type=string]
 └── filters
      └── gt [type=bool]
           ├── variable: count [type=int]
           └── const: 1 [type=int]

# Check that ordering by an alias of an aggregate works when HAVING is present.
build
SELECT sum(k) AS mk FROM kv GROUP BY v HAVING sum(k)=10 ORDER BY mk
----
project
 ├── columns: mk:5(decimal!null)
 ├── ordering: +5
 └── select
      ├── columns: v:2(int) sum:5(decimal!null)
      ├── group-by
      │    ├── columns: v:2(int) sum:5(decimal)
      │    ├── grouping columns: v:2(int)
      │    ├── project
      │    │    ├── columns: k:1(int!null) v:2(int)
      │    │    └── scan kv
      │    │         └── columns: k:1(int!null) v:2(int) w:3(int) s:4(string)
      │    └── aggregations
      │         └── sum [type=decimal]
      │              └── variable: k [type=int]
      └── filters
           └── eq [type=bool]
                ├── variable: sum [type=decimal]
                └── const: 10 [type=decimal]

build
SELECT sum(k) AS mk FROM kv GROUP BY v HAVING max(k) > 10 ORDER BY mk
----
sort
 ├── columns: mk:5(decimal)
 ├── ordering: +5
 └── project
      ├── columns: sum:5(decimal)
      └── select
           ├── columns: v:2(int) sum:5(decimal) max:6(int!null)
           ├── group-by
           │    ├── columns: v:2(int) sum:5(decimal) max:6(int)
           │    ├── grouping columns: v:2(int)
           │    ├── project
           │    │    ├── columns: k:1(int!null) v:2(int)
           │    │    └── scan kv
           │    │         └── columns: k:1(int!null) v:2(int) w:3(int) s:4(string)
           │    └── aggregations
           │         ├── sum [type=decimal]
           │         │    └── variable: k [type=int]
           │         └── max [type=int]
           │              └── variable: k [type=int]
           └── filters
                └── gt [type=bool]
                     ├── variable: max [type=int]
                     └── const: 10 [type=int]

build
SELECT sum(k) AS mk FROM kv GROUP BY v HAVING v > 10 ORDER BY mk
----
sort
 ├── columns: mk:5(decimal)
 ├── ordering: +5
 └── project
      ├── columns: sum:5(decimal)
      └── select
           ├── columns: v:2(int!null) sum:5(decimal)
           ├── group-by
           │    ├── columns: v:2(int) sum:5(decimal)
           │    ├── grouping columns: v:2(int)
           │    ├── project
           │    │    ├── columns: k:1(int!null) v:2(int)
           │    │    └── scan kv
           │    │         └── columns: k:1(int!null) v:2(int) w:3(int) s:4(string)
           │    └── aggregations
           │         └── sum [type=decimal]
           │              └── variable: k [type=int]
           └── filters
                └── gt [type=bool]
                     ├── variable: v [type=int]
                     └── const: 10 [type=int]

build
SELECT max(k) AS mk1, max(k) AS mk2 FROM kv GROUP BY v HAVING max(k) > 10 ORDER BY mk1
----
sort
 ├── columns: mk1:5(int!null) mk2:5(int!null)
 ├── ordering: +5
 └── project
      ├── columns: max:5(int!null)
      └── select
           ├── columns: v:2(int) max:5(int!null)
           ├── group-by
           │    ├── columns: v:2(int) max:5(int)
           │    ├── grouping columns: v:2(int)
           │    ├── project
           │    │    ├── columns: k:1(int!null) v:2(int)
           │    │    └── scan kv
           │    │         └── columns: k:1(int!null) v:2(int) w:3(int) s:4(string)
           │    └── aggregations
           │         └── max [type=int]
           │              └── variable: k [type=int]
           └── filters
                └── gt [type=bool]
                     ├── variable: max [type=int]
                     └── const: 10 [type=int]

build
SELECT max(k) AS mk1, max(k) AS mk2 FROM kv GROUP BY v HAVING max(k) > 10 ORDER BY mk2
----
sort
 ├── columns: mk1:5(int!null) mk2:5(int!null)
 ├── ordering: +5
 └── project
      ├── columns: max:5(int!null)
      └── select
           ├── columns: v:2(int) max:5(int!null)
           ├── group-by
           │    ├── columns: v:2(int) max:5(int)
           │    ├── grouping columns: v:2(int)
           │    ├── project
           │    │    ├── columns: k:1(int!null) v:2(int)
           │    │    └── scan kv
           │    │         └── columns: k:1(int!null) v:2(int) w:3(int) s:4(string)
           │    └── aggregations
           │         └── max [type=int]
           │              └── variable: k [type=int]
           └── filters
                └── gt [type=bool]
                     ├── variable: max [type=int]
                     └── const: 10 [type=int]
