# tests adapted from logictest -- srfs

# generate_series

build
SELECT * FROM generate_series(1, 3)
----
zip
 ├── columns: generate_series:1(int)
 └── function: generate_series [type=int]
      ├── const: 1 [type=int]
      └── const: 3 [type=int]

build
SELECT * FROM generate_series(1, 2), generate_series(1, 2)
----
inner-join
 ├── columns: generate_series:1(int) generate_series:2(int)
 ├── zip
 │    ├── columns: generate_series:1(int)
 │    └── function: generate_series [type=int]
 │         ├── const: 1 [type=int]
 │         └── const: 2 [type=int]
 ├── zip
 │    ├── columns: generate_series:2(int)
 │    └── function: generate_series [type=int]
 │         ├── const: 1 [type=int]
 │         └── const: 2 [type=int]
 └── true [type=bool]

build
SELECT * FROM pg_catalog.generate_series(1, 3)
----
zip
 ├── columns: generate_series:1(int)
 └── function: generate_series [type=int]
      ├── const: 1 [type=int]
      └── const: 3 [type=int]

build
SELECT * FROM generate_series(1, 1) AS c(x)
----
zip
 ├── columns: x:1(int)
 └── function: generate_series [type=int]
      ├── const: 1 [type=int]
      └── const: 1 [type=int]

build
SELECT * FROM generate_series(1, 1) WITH ORDINALITY AS c(x, y)
----
row-number
 ├── columns: x:1(int) y:2(int!null)
 └── zip
      ├── columns: generate_series:1(int)
      └── function: generate_series [type=int]
           ├── const: 1 [type=int]
           └── const: 1 [type=int]

build
SELECT * FROM (VALUES (1)) LIMIT generate_series(1, 3)
----
error: generate_series(): generator functions are not allowed in LIMIT

# multiple_SRFs

build
SELECT generate_series(1, 2), generate_series(3, 4)
----
inner-join-apply
 ├── columns: generate_series:1(int) generate_series:2(int)
 ├── values
 │    └── tuple [type=tuple]
 ├── zip
 │    ├── columns: generate_series:1(int) generate_series:2(int)
 │    ├── function: generate_series [type=int]
 │    │    ├── const: 1 [type=int]
 │    │    └── const: 2 [type=int]
 │    └── function: generate_series [type=int]
 │         ├── const: 3 [type=int]
 │         └── const: 4 [type=int]
 └── true [type=bool]

exec-ddl
CREATE TABLE t (a string)
----
TABLE t
 ├── a string
 ├── rowid int not null (hidden)
 └── INDEX primary
      └── rowid int not null (hidden)

exec-ddl
CREATE TABLE u (b string)
----
TABLE u
 ├── b string
 ├── rowid int not null (hidden)
 └── INDEX primary
      └── rowid int not null (hidden)

build
SELECT t.*, u.*, a.*, b.* FROM t, u, generate_series(1, 2) AS a, generate_series(3, 4) AS b
----
project
 ├── columns: a:1(string) b:3(string) a:5(int) b:6(int)
 └── inner-join
      ├── columns: a:1(string) t.rowid:2(int!null) b:3(string) u.rowid:4(int!null) generate_series:5(int) generate_series:6(int)
      ├── scan t
      │    └── columns: a:1(string) t.rowid:2(int!null)
      ├── inner-join
      │    ├── columns: b:3(string) u.rowid:4(int!null) generate_series:5(int) generate_series:6(int)
      │    ├── scan u
      │    │    └── columns: b:3(string) u.rowid:4(int!null)
      │    ├── inner-join
      │    │    ├── columns: generate_series:5(int) generate_series:6(int)
      │    │    ├── zip
      │    │    │    ├── columns: generate_series:5(int)
      │    │    │    └── function: generate_series [type=int]
      │    │    │         ├── const: 1 [type=int]
      │    │    │         └── const: 2 [type=int]
      │    │    ├── zip
      │    │    │    ├── columns: generate_series:6(int)
      │    │    │    └── function: generate_series [type=int]
      │    │    │         ├── const: 3 [type=int]
      │    │    │         └── const: 4 [type=int]
      │    │    └── true [type=bool]
      │    └── true [type=bool]
      └── true [type=bool]

build
SELECT 3 + x FROM generate_series(1,2) AS a(x)
----
project
 ├── columns: "?column?":2(int)
 ├── zip
 │    ├── columns: generate_series:1(int)
 │    └── function: generate_series [type=int]
 │         ├── const: 1 [type=int]
 │         └── const: 2 [type=int]
 └── projections
      └── plus [type=int]
           ├── const: 3 [type=int]
           └── variable: generate_series [type=int]

build
SELECT 3 + (3 * generate_series(1,3))
----
project
 ├── columns: "?column?":2(int)
 ├── inner-join-apply
 │    ├── columns: generate_series:1(int)
 │    ├── values
 │    │    └── tuple [type=tuple]
 │    ├── zip
 │    │    ├── columns: generate_series:1(int)
 │    │    └── function: generate_series [type=int]
 │    │         ├── const: 1 [type=int]
 │    │         └── const: 3 [type=int]
 │    └── true [type=bool]
 └── projections
      └── plus [type=int]
           ├── const: 3 [type=int]
           └── mult [type=int]
                ├── const: 3 [type=int]
                └── variable: generate_series [type=int]

# unnest

build
SELECT * from unnest(ARRAY[1,2])
----
zip
 ├── columns: unnest:1(int)
 └── function: unnest [type=int]
      └── array: [type=int[]]
           ├── const: 1 [type=int]
           └── const: 2 [type=int]

build
SELECT unnest(ARRAY[1,2]), unnest(ARRAY['a', 'b'])
----
inner-join-apply
 ├── columns: unnest:1(int) unnest:2(string)
 ├── values
 │    └── tuple [type=tuple]
 ├── zip
 │    ├── columns: unnest:1(int) unnest:2(string)
 │    ├── function: unnest [type=int]
 │    │    └── array: [type=int[]]
 │    │         ├── const: 1 [type=int]
 │    │         └── const: 2 [type=int]
 │    └── function: unnest [type=string]
 │         └── array: [type=string[]]
 │              ├── const: 'a' [type=string]
 │              └── const: 'b' [type=string]
 └── true [type=bool]

build
SELECT unnest(ARRAY[3,4]) - 2
----
project
 ├── columns: "?column?":2(int)
 ├── inner-join-apply
 │    ├── columns: unnest:1(int)
 │    ├── values
 │    │    └── tuple [type=tuple]
 │    ├── zip
 │    │    ├── columns: unnest:1(int)
 │    │    └── function: unnest [type=int]
 │    │         └── array: [type=int[]]
 │    │              ├── const: 3 [type=int]
 │    │              └── const: 4 [type=int]
 │    └── true [type=bool]
 └── projections
      └── minus [type=int]
           ├── variable: unnest [type=int]
           └── const: 2 [type=int]

build
SELECT 1 + generate_series(0, 1), unnest(ARRAY[2, 4]) - 1
----
project
 ├── columns: "?column?":3(int) "?column?":4(int)
 ├── inner-join-apply
 │    ├── columns: generate_series:1(int) unnest:2(int)
 │    ├── values
 │    │    └── tuple [type=tuple]
 │    ├── zip
 │    │    ├── columns: generate_series:1(int) unnest:2(int)
 │    │    ├── function: generate_series [type=int]
 │    │    │    ├── const: 0 [type=int]
 │    │    │    └── const: 1 [type=int]
 │    │    └── function: unnest [type=int]
 │    │         └── array: [type=int[]]
 │    │              ├── const: 2 [type=int]
 │    │              └── const: 4 [type=int]
 │    └── true [type=bool]
 └── projections
      ├── plus [type=int]
      │    ├── const: 1 [type=int]
      │    └── variable: generate_series [type=int]
      └── minus [type=int]
           ├── variable: unnest [type=int]
           └── const: 1 [type=int]

build
SELECT ascii(unnest(ARRAY['a', 'b', 'c']));
----
project
 ├── columns: ascii:2(int)
 ├── inner-join-apply
 │    ├── columns: unnest:1(string)
 │    ├── values
 │    │    └── tuple [type=tuple]
 │    ├── zip
 │    │    ├── columns: unnest:1(string)
 │    │    └── function: unnest [type=string]
 │    │         └── array: [type=string[]]
 │    │              ├── const: 'a' [type=string]
 │    │              ├── const: 'b' [type=string]
 │    │              └── const: 'c' [type=string]
 │    └── true [type=bool]
 └── projections
      └── function: ascii [type=int]
           └── variable: unnest [type=string]

# nested_SRF
# See #20511

build
SELECT generate_series(generate_series(1, 3), 3)
----
error: generate_series(): unimplemented: nested set-returning functions

build
SELECT generate_series(1, 3) + generate_series(1, 3)
----
project
 ├── columns: "?column?":3(int)
 ├── inner-join-apply
 │    ├── columns: generate_series:1(int) generate_series:2(int)
 │    ├── values
 │    │    └── tuple [type=tuple]
 │    ├── zip
 │    │    ├── columns: generate_series:1(int) generate_series:2(int)
 │    │    ├── function: generate_series [type=int]
 │    │    │    ├── const: 1 [type=int]
 │    │    │    └── const: 3 [type=int]
 │    │    └── function: generate_series [type=int]
 │    │         ├── const: 1 [type=int]
 │    │         └── const: 3 [type=int]
 │    └── true [type=bool]
 └── projections
      └── plus [type=int]
           ├── variable: generate_series [type=int]
           └── variable: generate_series [type=int]

build
SELECT generate_series(1, 3) FROM t WHERE generate_series > 3
----
error (42703): column "generate_series" does not exist

# Regressions for #15900: ensure that null parameters to generate_series don't
# cause issues.

build
SELECT * from generate_series(1, (select * from generate_series(1, 0)))
----
zip
 ├── columns: generate_series:2(int)
 └── function: generate_series [type=int]
      ├── const: 1 [type=int]
      └── subquery [type=int]
           └── max1-row
                ├── columns: generate_series:1(int)
                └── zip
                     ├── columns: generate_series:1(int)
                     └── function: generate_series [type=int]
                          ├── const: 1 [type=int]
                          └── const: 0 [type=int]

# The following query is designed to produce a null array argument to unnest
# in a way that the type system can't detect before evaluation.
build
SELECT unnest((SELECT current_schemas((SELECT isnan((SELECT round(3.4, (SELECT generate_series(1, 0)))))))));
----
inner-join-apply
 ├── columns: unnest:5(string)
 ├── values
 │    └── tuple [type=tuple]
 ├── zip
 │    ├── columns: unnest:5(string)
 │    └── function: unnest [type=string]
 │         └── subquery [type=string[]]
 │              └── max1-row
 │                   ├── columns: current_schemas:4(string[])
 │                   └── project
 │                        ├── columns: current_schemas:4(string[])
 │                        ├── values
 │                        │    └── tuple [type=tuple]
 │                        └── projections
 │                             └── function: current_schemas [type=string[]]
 │                                  └── subquery [type=bool]
 │                                       └── max1-row
 │                                            ├── columns: isnan:3(bool)
 │                                            └── project
 │                                                 ├── columns: isnan:3(bool)
 │                                                 ├── values
 │                                                 │    └── tuple [type=tuple]
 │                                                 └── projections
 │                                                      └── function: isnan [type=bool]
 │                                                           └── subquery [type=decimal]
 │                                                                └── max1-row
 │                                                                     ├── columns: round:2(decimal)
 │                                                                     └── project
 │                                                                          ├── columns: round:2(decimal)
 │                                                                          ├── values
 │                                                                          │    └── tuple [type=tuple]
 │                                                                          └── projections
 │                                                                               └── function: round [type=decimal]
 │                                                                                    ├── const: 3.4 [type=decimal]
 │                                                                                    └── subquery [type=int]
 │                                                                                         └── max1-row
 │                                                                                              ├── columns: generate_series:1(int)
 │                                                                                              └── inner-join-apply
 │                                                                                                   ├── columns: generate_series:1(int)
 │                                                                                                   ├── values
 │                                                                                                   │    └── tuple [type=tuple]
 │                                                                                                   ├── zip
 │                                                                                                   │    ├── columns: generate_series:1(int)
 │                                                                                                   │    └── function: generate_series [type=int]
 │                                                                                                   │         ├── const: 1 [type=int]
 │                                                                                                   │         └── const: 0 [type=int]
 │                                                                                                   └── true [type=bool]
 └── true [type=bool]

# pg_get_keywords

# pg_get_keywords for compatibility (#10291)
build
SELECT * FROM pg_get_keywords() WHERE word IN ('alter', 'and', 'between', 'cross') ORDER BY word
----
sort
 ├── columns: word:1(string!null) catcode:2(string) catdesc:3(string)
 ├── ordering: +1
 └── select
      ├── columns: word:1(string!null) catcode:2(string) catdesc:3(string)
      ├── zip
      │    ├── columns: word:1(string) catcode:2(string) catdesc:3(string)
      │    └── function: pg_get_keywords [type=tuple{string AS word, string AS catcode, string AS catdesc}]
      └── filters [type=bool]
           └── in [type=bool]
                ├── variable: word [type=string]
                └── tuple [type=tuple{string, string, string, string}]
                     ├── const: 'alter' [type=string]
                     ├── const: 'and' [type=string]
                     ├── const: 'between' [type=string]
                     └── const: 'cross' [type=string]

# Postgres enables renaming both the source and the column name for
# single-column generators, but not for multi-column generators.
build
SELECT a.*, b.*, c.* FROM generate_series(1,1) a, unnest(ARRAY[1]) b, pg_get_keywords() c LIMIT 0
----
limit
 ├── columns: a:1(int) b:2(int) word:3(string) catcode:4(string) catdesc:5(string)
 ├── inner-join
 │    ├── columns: generate_series:1(int) unnest:2(int) word:3(string) catcode:4(string) catdesc:5(string)
 │    ├── zip
 │    │    ├── columns: generate_series:1(int)
 │    │    └── function: generate_series [type=int]
 │    │         ├── const: 1 [type=int]
 │    │         └── const: 1 [type=int]
 │    ├── inner-join
 │    │    ├── columns: unnest:2(int) word:3(string) catcode:4(string) catdesc:5(string)
 │    │    ├── zip
 │    │    │    ├── columns: unnest:2(int)
 │    │    │    └── function: unnest [type=int]
 │    │    │         └── array: [type=int[]]
 │    │    │              └── const: 1 [type=int]
 │    │    ├── zip
 │    │    │    ├── columns: word:3(string) catcode:4(string) catdesc:5(string)
 │    │    │    └── function: pg_get_keywords [type=tuple{string AS word, string AS catcode, string AS catdesc}]
 │    │    └── true [type=bool]
 │    └── true [type=bool]
 └── const: 0 [type=int]

# Beware of multi-valued SRFs in render position (#19149)
build
SELECT 'a', pg_get_keywords(), 'c' LIMIT 1
----
limit
 ├── columns: "?column?":4(string!null) pg_get_keywords:5(tuple{string AS word, string AS catcode, string AS catdesc}) "?column?":6(string!null)
 ├── project
 │    ├── columns: "?column?":4(string!null) pg_get_keywords:5(tuple{string AS word, string AS catcode, string AS catdesc}) "?column?":6(string!null)
 │    ├── inner-join-apply
 │    │    ├── columns: word:1(string) catcode:2(string) catdesc:3(string)
 │    │    ├── values
 │    │    │    └── tuple [type=tuple]
 │    │    ├── zip
 │    │    │    ├── columns: word:1(string) catcode:2(string) catdesc:3(string)
 │    │    │    └── function: pg_get_keywords [type=tuple{string AS word, string AS catcode, string AS catdesc}]
 │    │    └── true [type=bool]
 │    └── projections
 │         ├── const: 'a' [type=string]
 │         ├── tuple [type=tuple{string AS word, string AS catcode, string AS catdesc}]
 │         │    ├── variable: word [type=string]
 │         │    ├── variable: catcode [type=string]
 │         │    └── variable: catdesc [type=string]
 │         └── const: 'c' [type=string]
 └── const: 1 [type=int]

build
SELECT 'a', pg_get_keywords() b, 'c' LIMIT 1
----
limit
 ├── columns: "?column?":4(string!null) b:5(tuple{string AS word, string AS catcode, string AS catdesc}) "?column?":6(string!null)
 ├── project
 │    ├── columns: "?column?":4(string!null) b:5(tuple{string AS word, string AS catcode, string AS catdesc}) "?column?":6(string!null)
 │    ├── inner-join-apply
 │    │    ├── columns: word:1(string) catcode:2(string) catdesc:3(string)
 │    │    ├── values
 │    │    │    └── tuple [type=tuple]
 │    │    ├── zip
 │    │    │    ├── columns: word:1(string) catcode:2(string) catdesc:3(string)
 │    │    │    └── function: pg_get_keywords [type=tuple{string AS word, string AS catcode, string AS catdesc}]
 │    │    └── true [type=bool]
 │    └── projections
 │         ├── const: 'a' [type=string]
 │         ├── tuple [type=tuple{string AS word, string AS catcode, string AS catdesc}]
 │         │    ├── variable: word [type=string]
 │         │    ├── variable: catcode [type=string]
 │         │    └── variable: catdesc [type=string]
 │         └── const: 'c' [type=string]
 └── const: 1 [type=int]

# unary_table

build
SELECT 'a', crdb_internal.unary_table() b, 'c' LIMIT 1
----
limit
 ├── columns: "?column?":1(string!null) b:2(tuple) "?column?":3(string!null)
 ├── project
 │    ├── columns: "?column?":1(string!null) b:2(tuple) "?column?":3(string!null)
 │    ├── inner-join-apply
 │    │    ├── values
 │    │    │    └── tuple [type=tuple]
 │    │    ├── zip
 │    │    │    └── function: crdb_internal.unary_table [type=tuple]
 │    │    └── true [type=bool]
 │    └── projections
 │         ├── const: 'a' [type=string]
 │         ├── tuple [type=tuple]
 │         └── const: 'c' [type=string]
 └── const: 1 [type=int]

# upper

# Regular scalar functions can be used as functions too. #22312
build
SELECT * FROM upper('abc')
----
zip
 ├── columns: upper:1(string)
 └── function: upper [type=string]
      └── const: 'abc' [type=string]

# current_schema

build
SELECT * FROM current_schema() WITH ORDINALITY AS a(b)
----
row-number
 ├── columns: b:1(string) ordinality:2(int!null)
 └── zip
      ├── columns: current_schema:1(string)
      └── function: current_schema [type=string]

# expandArray

build
SELECT information_schema._pg_expandarray(ARRAY['b', 'a'])
----
project
 ├── columns: information_schema._pg_expandarray:3(tuple{string AS x, int AS n})
 ├── inner-join-apply
 │    ├── columns: x:1(string) n:2(int)
 │    ├── values
 │    │    └── tuple [type=tuple]
 │    ├── zip
 │    │    ├── columns: x:1(string) n:2(int)
 │    │    └── function: information_schema._pg_expandarray [type=tuple{string AS x, int AS n}]
 │    │         └── array: [type=string[]]
 │    │              ├── const: 'b' [type=string]
 │    │              └── const: 'a' [type=string]
 │    └── true [type=bool]
 └── projections
      └── tuple [type=tuple{string AS x, int AS n}]
           ├── variable: x [type=string]
           └── variable: n [type=int]

build
SELECT * FROM information_schema._pg_expandarray(ARRAY['b', 'a'])
----
zip
 ├── columns: x:1(string) n:2(int)
 └── function: information_schema._pg_expandarray [type=tuple{string AS x, int AS n}]
      └── array: [type=string[]]
           ├── const: 'b' [type=string]
           └── const: 'a' [type=string]

# srf_accessor

build
SELECT (1).*
----
error (42809): type int is not composite

build
SELECT ('a').*
----
error (42809): type string is not composite

build
SELECT (unnest(ARRAY[]:::INT[])).*
----
error (42809): type int is not composite

build
SELECT (information_schema._pg_expandarray(ARRAY['c', 'b', 'a'])).*
----
project
 ├── columns: x:3(string) n:4(int)
 ├── inner-join-apply
 │    ├── columns: x:1(string) n:2(int)
 │    ├── values
 │    │    └── tuple [type=tuple]
 │    ├── zip
 │    │    ├── columns: x:1(string) n:2(int)
 │    │    └── function: information_schema._pg_expandarray [type=tuple{string AS x, int AS n}]
 │    │         └── array: [type=string[]]
 │    │              ├── const: 'c' [type=string]
 │    │              ├── const: 'b' [type=string]
 │    │              └── const: 'a' [type=string]
 │    └── true [type=bool]
 └── projections
      ├── column-access: 0 [type=string]
      │    └── tuple [type=tuple{string AS x, int AS n}]
      │         ├── variable: x [type=string]
      │         └── variable: n [type=int]
      └── column-access: 1 [type=int]
           └── tuple [type=tuple{string AS x, int AS n}]
                ├── variable: x [type=string]
                └── variable: n [type=int]

build
SELECT (information_schema._pg_expandarray(ARRAY['c', 'b', 'a'])).x
----
project
 ├── columns: x:3(string)
 ├── inner-join-apply
 │    ├── columns: x:1(string) n:2(int)
 │    ├── values
 │    │    └── tuple [type=tuple]
 │    ├── zip
 │    │    ├── columns: x:1(string) n:2(int)
 │    │    └── function: information_schema._pg_expandarray [type=tuple{string AS x, int AS n}]
 │    │         └── array: [type=string[]]
 │    │              ├── const: 'c' [type=string]
 │    │              ├── const: 'b' [type=string]
 │    │              └── const: 'a' [type=string]
 │    └── true [type=bool]
 └── projections
      └── column-access: 0 [type=string]
           └── tuple [type=tuple{string AS x, int AS n}]
                ├── variable: x [type=string]
                └── variable: n [type=int]

build
SELECT (information_schema._pg_expandarray(ARRAY['c', 'b', 'a'])).other
----
error (42804): could not identify column "other" in tuple{string AS x, int AS n}

build
SELECT temp.n from information_schema._pg_expandarray(ARRAY['c','b','a']) AS temp;
----
project
 ├── columns: n:2(int)
 └── zip
      ├── columns: x:1(string) n:2(int)
      └── function: information_schema._pg_expandarray [type=tuple{string AS x, int AS n}]
           └── array: [type=string[]]
                ├── const: 'c' [type=string]
                ├── const: 'b' [type=string]
                └── const: 'a' [type=string]

build
SELECT temp.* from information_schema._pg_expandarray(ARRAY['c','b','a']) AS temp;
----
zip
 ├── columns: x:1(string) n:2(int)
 └── function: information_schema._pg_expandarray [type=tuple{string AS x, int AS n}]
      └── array: [type=string[]]
           ├── const: 'c' [type=string]
           ├── const: 'b' [type=string]
           └── const: 'a' [type=string]

build
SELECT * from information_schema._pg_expandarray(ARRAY['c','b','a']) AS temp;
----
zip
 ├── columns: x:1(string) n:2(int)
 └── function: information_schema._pg_expandarray [type=tuple{string AS x, int AS n}]
      └── array: [type=string[]]
           ├── const: 'c' [type=string]
           ├── const: 'b' [type=string]
           └── const: 'a' [type=string]

# generate_subscripts

build
SELECT * FROM generate_subscripts(ARRAY[3,2,1])
----
zip
 ├── columns: generate_subscripts:1(int)
 └── function: generate_subscripts [type=int]
      └── array: [type=int[]]
           ├── const: 3 [type=int]
           ├── const: 2 [type=int]
           └── const: 1 [type=int]

# Zip with multiple SRFs.
build
SELECT * FROM
ROWS FROM (generate_series(0, 1), generate_series(1, 3), pg_get_keywords(), unnest(ARRAY['a', 'b', 'c']))
----
zip
 ├── columns: generate_series:1(int) generate_series:2(int) word:3(string) catcode:4(string) catdesc:5(string) unnest:6(string)
 ├── function: generate_series [type=int]
 │    ├── const: 0 [type=int]
 │    └── const: 1 [type=int]
 ├── function: generate_series [type=int]
 │    ├── const: 1 [type=int]
 │    └── const: 3 [type=int]
 ├── function: pg_get_keywords [type=tuple{string AS word, string AS catcode, string AS catdesc}]
 └── function: unnest [type=string]
      └── array: [type=string[]]
           ├── const: 'a' [type=string]
           ├── const: 'b' [type=string]
           └── const: 'c' [type=string]

# Don't rename columns if the zip contains two functions.
build
SELECT a.*, b.*, c.* FROM upper('abc') a
JOIN ROWS FROM (upper('def'), generate_series(1, 3)) b ON true
JOIN generate_series(1, 4) c ON true
----
inner-join
 ├── columns: a:1(string) upper:2(string) generate_series:3(int) c:4(int)
 ├── inner-join
 │    ├── columns: upper:1(string) upper:2(string) generate_series:3(int)
 │    ├── zip
 │    │    ├── columns: upper:1(string)
 │    │    └── function: upper [type=string]
 │    │         └── const: 'abc' [type=string]
 │    ├── zip
 │    │    ├── columns: upper:2(string) generate_series:3(int)
 │    │    ├── function: upper [type=string]
 │    │    │    └── const: 'def' [type=string]
 │    │    └── function: generate_series [type=int]
 │    │         ├── const: 1 [type=int]
 │    │         └── const: 3 [type=int]
 │    └── filters [type=bool]
 │         └── true [type=bool]
 ├── zip
 │    ├── columns: generate_series:4(int)
 │    └── function: generate_series [type=int]
 │         ├── const: 1 [type=int]
 │         └── const: 4 [type=int]
 └── filters [type=bool]
      └── true [type=bool]

build
SELECT * FROM ROWS FROM (generate_series(generate_series(1,2),3))
----
error: generate_series(): generate_series(): set-returning functions must appear at the top level of FROM

# SRFs not allowed in HAVING, unless they are part of a subquery.
build
SELECT max(a) FROM t HAVING max(a::int) > generate_series(0, a::int)
----
error: generate_series(): generator functions are not allowed in HAVING

build
SELECT max(a) FROM t HAVING max(a::int) > (SELECT generate_series(0, b::int) FROM u limit 1)
----
project
 ├── columns: max:3(string)
 └── select
      ├── columns: max:3(string) max:5(int!null)
      ├── scalar-group-by
      │    ├── columns: max:3(string) max:5(int)
      │    ├── project
      │    │    ├── columns: column4:4(int) a:1(string)
      │    │    ├── scan t
      │    │    │    └── columns: a:1(string) t.rowid:2(int!null)
      │    │    └── projections
      │    │         └── cast: INT [type=int]
      │    │              └── variable: a [type=string]
      │    └── aggregations
      │         ├── max [type=string]
      │         │    └── variable: a [type=string]
      │         └── max [type=int]
      │              └── variable: column4 [type=int]
      └── filters [type=bool]
           └── gt [type=bool]
                ├── variable: max [type=int]
                └── subquery [type=int]
                     └── max1-row
                          ├── columns: generate_series:8(int)
                          └── limit
                               ├── columns: generate_series:8(int)
                               ├── project
                               │    ├── columns: generate_series:8(int)
                               │    └── inner-join-apply
                               │         ├── columns: b:6(string) u.rowid:7(int!null) generate_series:8(int)
                               │         ├── scan u
                               │         │    └── columns: b:6(string) u.rowid:7(int!null)
                               │         ├── zip
                               │         │    ├── columns: generate_series:8(int)
                               │         │    └── function: generate_series [type=int]
                               │         │         ├── const: 0 [type=int]
                               │         │         └── cast: INT [type=int]
                               │         │              └── variable: b [type=string]
                               │         └── true [type=bool]
                               └── const: 1 [type=int]

build
SELECT generate_series((SELECT generate_subscripts(ARRAY[a, a||b]) FROM t, u), 100) FROM t
----
project
 ├── columns: generate_series:8(int)
 └── inner-join-apply
      ├── columns: t.a:1(string) t.rowid:2(int!null) generate_series:8(int)
      ├── scan t
      │    └── columns: t.a:1(string) t.rowid:2(int!null)
      ├── zip
      │    ├── columns: generate_series:8(int)
      │    └── function: generate_series [type=int]
      │         ├── subquery [type=int]
      │         │    └── max1-row
      │         │         ├── columns: generate_subscripts:7(int)
      │         │         └── project
      │         │              ├── columns: generate_subscripts:7(int)
      │         │              └── inner-join-apply
      │         │                   ├── columns: t.a:3(string) t.rowid:4(int!null) b:5(string) u.rowid:6(int!null) generate_subscripts:7(int)
      │         │                   ├── inner-join
      │         │                   │    ├── columns: t.a:3(string) t.rowid:4(int!null) b:5(string) u.rowid:6(int!null)
      │         │                   │    ├── scan t
      │         │                   │    │    └── columns: t.a:3(string) t.rowid:4(int!null)
      │         │                   │    ├── scan u
      │         │                   │    │    └── columns: b:5(string) u.rowid:6(int!null)
      │         │                   │    └── true [type=bool]
      │         │                   ├── zip
      │         │                   │    ├── columns: generate_subscripts:7(int)
      │         │                   │    └── function: generate_subscripts [type=int]
      │         │                   │         └── array: [type=string[]]
      │         │                   │              ├── variable: t.a [type=string]
      │         │                   │              └── concat [type=string]
      │         │                   │                   ├── variable: t.a [type=string]
      │         │                   │                   └── variable: b [type=string]
      │         │                   └── true [type=bool]
      │         └── const: 100 [type=int]
      └── true [type=bool]

exec-ddl
CREATE TABLE a (x INT PRIMARY KEY, j JSON, k JSON, m JSON, n JSON)
----
TABLE a
 ├── x int not null
 ├── j jsonb
 ├── k jsonb
 ├── m jsonb
 ├── n jsonb
 └── INDEX primary
      └── x int not null

build
SELECT
  json_array_elements(j),
  (SELECT jsonb_each(k)),
  (SELECT jsonb_object_keys(m) FROM a),
  (SELECT generate_series((SELECT generate_series(x, 100) FROM jsonb_array_elements_text(n)), 1000))
FROM a
----
project
 ├── columns: json_array_elements:6(jsonb) jsonb_each:19(tuple{string AS key, jsonb AS value}) jsonb_object_keys:20(string) generate_series:21(int)
 ├── inner-join-apply
 │    ├── columns: a.x:1(int!null) a.j:2(jsonb) a.k:3(jsonb) a.m:4(jsonb) a.n:5(jsonb) json_array_elements:6(jsonb)
 │    ├── scan a
 │    │    └── columns: a.x:1(int!null) a.j:2(jsonb) a.k:3(jsonb) a.m:4(jsonb) a.n:5(jsonb)
 │    ├── zip
 │    │    ├── columns: json_array_elements:6(jsonb)
 │    │    └── function: json_array_elements [type=jsonb]
 │    │         └── variable: a.j [type=jsonb]
 │    └── true [type=bool]
 └── projections
      ├── subquery [type=tuple{string AS key, jsonb AS value}]
      │    └── max1-row
      │         ├── columns: jsonb_each:9(tuple{string AS key, jsonb AS value})
      │         └── project
      │              ├── columns: jsonb_each:9(tuple{string AS key, jsonb AS value})
      │              ├── inner-join-apply
      │              │    ├── columns: key:7(string) value:8(jsonb)
      │              │    ├── values
      │              │    │    └── tuple [type=tuple]
      │              │    ├── zip
      │              │    │    ├── columns: key:7(string) value:8(jsonb)
      │              │    │    └── function: jsonb_each [type=tuple{string AS key, jsonb AS value}]
      │              │    │         └── variable: a.k [type=jsonb]
      │              │    └── true [type=bool]
      │              └── projections
      │                   └── tuple [type=tuple{string AS key, jsonb AS value}]
      │                        ├── variable: key [type=string]
      │                        └── variable: value [type=jsonb]
      ├── subquery [type=string]
      │    └── max1-row
      │         ├── columns: jsonb_object_keys:15(string)
      │         └── project
      │              ├── columns: jsonb_object_keys:15(string)
      │              └── inner-join-apply
      │                   ├── columns: a.x:10(int!null) a.j:11(jsonb) a.k:12(jsonb) a.m:13(jsonb) a.n:14(jsonb) jsonb_object_keys:15(string)
      │                   ├── scan a
      │                   │    └── columns: a.x:10(int!null) a.j:11(jsonb) a.k:12(jsonb) a.m:13(jsonb) a.n:14(jsonb)
      │                   ├── zip
      │                   │    ├── columns: jsonb_object_keys:15(string)
      │                   │    └── function: jsonb_object_keys [type=string]
      │                   │         └── variable: a.m [type=jsonb]
      │                   └── true [type=bool]
      └── subquery [type=int]
           └── max1-row
                ├── columns: generate_series:18(int)
                └── inner-join-apply
                     ├── columns: generate_series:18(int)
                     ├── values
                     │    └── tuple [type=tuple]
                     ├── zip
                     │    ├── columns: generate_series:18(int)
                     │    └── function: generate_series [type=int]
                     │         ├── subquery [type=int]
                     │         │    └── max1-row
                     │         │         ├── columns: generate_series:17(int)
                     │         │         └── project
                     │         │              ├── columns: generate_series:17(int)
                     │         │              └── inner-join-apply
                     │         │                   ├── columns: jsonb_array_elements_text:16(string) generate_series:17(int)
                     │         │                   ├── zip
                     │         │                   │    ├── columns: jsonb_array_elements_text:16(string)
                     │         │                   │    └── function: jsonb_array_elements_text [type=string]
                     │         │                   │         └── variable: a.n [type=jsonb]
                     │         │                   ├── zip
                     │         │                   │    ├── columns: generate_series:17(int)
                     │         │                   │    └── function: generate_series [type=int]
                     │         │                   │         ├── variable: a.x [type=int]
                     │         │                   │         └── const: 100 [type=int]
                     │         │                   └── true [type=bool]
                     │         └── const: 1000 [type=int]
                     └── true [type=bool]

# Regression test for #30412.
build
SELECT 0, unnest(ARRAY[0]) GROUP BY 1
----
error (42803): column "unnest" must appear in the GROUP BY clause or be used in an aggregate function

build
SELECT 0, unnest(ARRAY[0]) GROUP BY 1, 2
----
error: unnest(): generator functions are not allowed in GROUP BY

build
SELECT 0, information_schema._pg_expandarray(ARRAY[0]) GROUP BY 1
----
error (42803): column "x" must appear in the GROUP BY clause or be used in an aggregate function

# Regression test for #31755.
build
SELECT * FROM ROWS FROM (CAST('string' AS SERIAL2[])) AS ident
----
zip
 ├── columns: ident:1(int[])
 └── cast: SERIAL2[] [type=int[]]
      └── const: 'string' [type=string]
