# tests adapted from logictest -- aggregate

exec-ddl
CREATE TABLE kv (
  k INT PRIMARY KEY,
  v INT,
  w INT,
  s STRING
)
----

# 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:7!null
 ├── select
 │    ├── scalar-group-by
 │    │    └── project
 │    │         └── scan kv
 │    │              └── columns: k:1!null v:2 w:3 s:4 crdb_internal_mvcc_timestamp:5 tableoid:6
 │    └── filters
 │         └── true
 └── projections
      └── 3 [as=r:7]

build
SELECT s, count(*) FROM kv GROUP BY s HAVING count(*) > 1
----
select
 ├── columns: s:4 count:7!null
 ├── group-by (hash)
 │    ├── columns: s:4 count_rows:7!null
 │    ├── grouping columns: s:4
 │    ├── project
 │    │    ├── columns: s:4
 │    │    └── scan kv
 │    │         └── columns: k:1!null v:2 w:3 s:4 crdb_internal_mvcc_timestamp:5 tableoid:6
 │    └── aggregations
 │         └── count-rows [as=count_rows:7]
 └── filters
      └── count_rows:7 > 1

build
SELECT max(k), min(v) FROM kv HAVING min(v) > 2
----
select
 ├── columns: max:7 min:8!null
 ├── scalar-group-by
 │    ├── columns: max:7 min:8
 │    ├── project
 │    │    ├── columns: k:1!null v:2
 │    │    └── scan kv
 │    │         └── columns: k:1!null v:2 w:3 s:4 crdb_internal_mvcc_timestamp:5 tableoid:6
 │    └── aggregations
 │         ├── max [as=max:7]
 │         │    └── k:1
 │         └── min [as=min:8]
 │              └── v:2
 └── filters
      └── min:8 > 2

build
SELECT max(k), min(v) FROM kv HAVING max(v) > 2
----
project
 ├── columns: max:7 min:8
 └── select
      ├── columns: max:7 min:8 max:9!null
      ├── scalar-group-by
      │    ├── columns: max:7 min:8 max:9
      │    ├── project
      │    │    ├── columns: k:1!null v:2
      │    │    └── scan kv
      │    │         └── columns: k:1!null v:2 w:3 s:4 crdb_internal_mvcc_timestamp:5 tableoid:6
      │    └── aggregations
      │         ├── max [as=max:7]
      │         │    └── k:1
      │         ├── min [as=min:8]
      │         │    └── v:2
      │         └── max [as=max:9]
      │              └── v:2
      └── filters
           └── max:9 > 2

build
SELECT max(k), min(v) FROM kv HAVING max(min(v)) > 2
----
error (42803): 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

# Special case for grouping on primary key.
build
SELECT 3 FROM kv GROUP BY k HAVING v > 2
----
project
 ├── columns: "?column?":7!null
 ├── select
 │    ├── columns: k:1!null v:2!null
 │    ├── group-by (hash)
 │    │    ├── columns: k:1!null v:2
 │    │    ├── grouping columns: k:1!null v:2
 │    │    └── project
 │    │         ├── columns: k:1!null v:2
 │    │         └── scan kv
 │    │              └── columns: k:1!null v:2 w:3 s:4 crdb_internal_mvcc_timestamp:5 tableoid:6
 │    └── filters
 │         └── v:2 > 2
 └── projections
      └── 3 [as="?column?":7]

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:7!null r:8!null
 ├── group-by (hash)
 │    ├── columns: count_rows:7!null column8:8
 │    ├── grouping columns: column8:8
 │    ├── project
 │    │    ├── columns: column8:8
 │    │    ├── scan kv
 │    │    │    └── columns: k:1!null v:2 w:3 s:4 crdb_internal_mvcc_timestamp:5 tableoid:6
 │    │    └── projections
 │    │         └── k:1 + w:3 [as=column8:8]
 │    └── aggregations
 │         └── count-rows [as=count_rows:7]
 └── filters
      └── column8:8 > 5

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:7
 └── select
      ├── columns: v:2!null max:7
      ├── group-by (hash)
      │    ├── columns: v:2 max:7
      │    ├── grouping columns: v:2
      │    ├── project
      │    │    ├── columns: v:2
      │    │    └── scan kv
      │    │         └── columns: k:1!null v:2 w:3 s:4 crdb_internal_mvcc_timestamp:5 tableoid:6
      │    └── aggregations
      │         └── max [as=max:7]
      │              └── v:2
      └── filters
           └── v:2 > 5

build
SELECT sum(kv.w) FROM kv GROUP BY lower(s) HAVING lower(kv.s) LIKE 'test%'
----
project
 ├── columns: sum:7
 └── select
      ├── columns: sum:7 column8:8!null
      ├── group-by (hash)
      │    ├── columns: sum:7 column8:8
      │    ├── grouping columns: column8:8
      │    ├── project
      │    │    ├── columns: column8:8 w:3
      │    │    ├── scan kv
      │    │    │    └── columns: k:1!null v:2 w:3 s:4 crdb_internal_mvcc_timestamp:5 tableoid:6
      │    │    └── projections
      │    │         └── lower(s:4) [as=column8:8]
      │    └── aggregations
      │         └── sum [as=sum:7]
      │              └── w:3
      └── filters
           └── column8:8 LIKE 'test%'

build
SELECT sum(kv.w) FROM kv GROUP BY lower(s) HAVING sum(w) IN (4, 5, 6)
----
project
 ├── columns: sum:7!null
 └── select
      ├── columns: sum:7!null column8:8
      ├── group-by (hash)
      │    ├── columns: sum:7 column8:8
      │    ├── grouping columns: column8:8
      │    ├── project
      │    │    ├── columns: column8:8 w:3
      │    │    ├── scan kv
      │    │    │    └── columns: k:1!null v:2 w:3 s:4 crdb_internal_mvcc_timestamp:5 tableoid:6
      │    │    └── projections
      │    │         └── lower(s:4) [as=column8:8]
      │    └── aggregations
      │         └── sum [as=sum:7]
      │              └── w:3
      └── filters
           └── sum:7 IN (4, 5, 6)

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
 └── select
      ├── columns: t.public.kv.v:2 column7:7!null
      ├── group-by (hash)
      │    ├── columns: t.public.kv.v:2 column7:7
      │    ├── grouping columns: t.public.kv.v:2 column7:7
      │    └── project
      │         ├── columns: column7:7 t.public.kv.v:2
      │         ├── scan t.public.kv
      │         │    └── columns: t.public.kv.k:1!null t.public.kv.v:2 t.public.kv.w:3 t.public.kv.s:4 t.public.kv.crdb_internal_mvcc_timestamp:5 t.public.kv.tableoid:6
      │         └── projections
      │              └── t.public.kv.k:1 * t.public.kv.w:3 [as=column7:7]
      └── filters
           └── column7:7 > 5

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:8 count:7!null count:9!null
 ├── group-by (hash)
 │    ├── columns: count:7!null column8:8 count:9!null
 │    ├── grouping columns: column8:8
 │    ├── project
 │    │    ├── columns: column8:8 t.public.kv.s:4
 │    │    ├── scan t.public.kv
 │    │    │    └── columns: t.public.kv.k:1!null t.public.kv.v:2 t.public.kv.w:3 t.public.kv.s:4 t.public.kv.crdb_internal_mvcc_timestamp:5 t.public.kv.tableoid:6
 │    │    └── projections
 │    │         └── upper(t.public.kv.s:4) [as=column8:8]
 │    └── aggregations
 │         ├── count [as=count:7]
 │         │    └── t.public.kv.s:4
 │         └── count [as=count:9]
 │              └── column8:8
 └── filters
      └── count:7 > 1

# 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:7!null
 ├── ordering: +7
 └── select
      ├── columns: v:2 sum:7!null
      ├── group-by (hash)
      │    ├── columns: v:2 sum:7!null
      │    ├── grouping columns: v:2
      │    ├── project
      │    │    ├── columns: k:1!null v:2
      │    │    └── scan kv
      │    │         └── columns: k:1!null v:2 w:3 s:4 crdb_internal_mvcc_timestamp:5 tableoid:6
      │    └── aggregations
      │         └── sum [as=sum:7]
      │              └── k:1
      └── filters
           └── sum:7 = 10

build
SELECT sum(k) AS mk FROM kv GROUP BY v HAVING max(k) > 10 ORDER BY mk
----
sort
 ├── columns: mk:7!null
 ├── ordering: +7
 └── project
      ├── columns: sum:7!null
      └── select
           ├── columns: v:2 sum:7!null max:8!null
           ├── group-by (hash)
           │    ├── columns: v:2 sum:7!null max:8!null
           │    ├── grouping columns: v:2
           │    ├── project
           │    │    ├── columns: k:1!null v:2
           │    │    └── scan kv
           │    │         └── columns: k:1!null v:2 w:3 s:4 crdb_internal_mvcc_timestamp:5 tableoid:6
           │    └── aggregations
           │         ├── sum [as=sum:7]
           │         │    └── k:1
           │         └── max [as=max:8]
           │              └── k:1
           └── filters
                └── max:8 > 10

build
SELECT sum(k) AS mk FROM kv GROUP BY v HAVING v > 10 ORDER BY mk
----
sort
 ├── columns: mk:7!null
 ├── ordering: +7
 └── project
      ├── columns: sum:7!null
      └── select
           ├── columns: v:2!null sum:7!null
           ├── group-by (hash)
           │    ├── columns: v:2 sum:7!null
           │    ├── grouping columns: v:2
           │    ├── project
           │    │    ├── columns: k:1!null v:2
           │    │    └── scan kv
           │    │         └── columns: k:1!null v:2 w:3 s:4 crdb_internal_mvcc_timestamp:5 tableoid:6
           │    └── aggregations
           │         └── sum [as=sum:7]
           │              └── k:1
           └── filters
                └── v:2 > 10

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:7!null mk2:7!null
 ├── ordering: +7
 └── project
      ├── columns: max:7!null
      └── select
           ├── columns: v:2 max:7!null
           ├── group-by (hash)
           │    ├── columns: v:2 max:7!null
           │    ├── grouping columns: v:2
           │    ├── project
           │    │    ├── columns: k:1!null v:2
           │    │    └── scan kv
           │    │         └── columns: k:1!null v:2 w:3 s:4 crdb_internal_mvcc_timestamp:5 tableoid:6
           │    └── aggregations
           │         └── max [as=max:7]
           │              └── k:1
           └── filters
                └── max:7 > 10

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:7!null mk2:7!null
 ├── ordering: +7
 └── project
      ├── columns: max:7!null
      └── select
           ├── columns: v:2 max:7!null
           ├── group-by (hash)
           │    ├── columns: v:2 max:7!null
           │    ├── grouping columns: v:2
           │    ├── project
           │    │    ├── columns: k:1!null v:2
           │    │    └── scan kv
           │    │         └── columns: k:1!null v:2 w:3 s:4 crdb_internal_mvcc_timestamp:5 tableoid:6
           │    └── aggregations
           │         └── max [as=max:7]
           │              └── k:1
           └── filters
                └── max:7 > 10
