# tests adapted from logictest -- srfs

# generate_series

build
SELECT * FROM generate_series(1, 3)
----
project-set
 ├── columns: generate_series:1(int)
 ├── values
 │    └── tuple [type=tuple]
 └── zip
      └── 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)
 ├── project-set
 │    ├── columns: generate_series:1(int)
 │    ├── values
 │    │    └── tuple [type=tuple]
 │    └── zip
 │         └── function: generate_series [type=int]
 │              ├── const: 1 [type=int]
 │              └── const: 2 [type=int]
 ├── project-set
 │    ├── columns: generate_series:2(int)
 │    ├── values
 │    │    └── tuple [type=tuple]
 │    └── zip
 │         └── function: generate_series [type=int]
 │              ├── const: 1 [type=int]
 │              └── const: 2 [type=int]
 └── filters (true)

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

build
SELECT * FROM generate_series(1, 1) AS c(x)
----
project-set
 ├── columns: x:1(int)
 ├── values
 │    └── tuple [type=tuple]
 └── zip
      └── 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)
 └── project-set
      ├── columns: generate_series:1(int)
      ├── values
      │    └── tuple [type=tuple]
      └── zip
           └── 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)
----
project-set
 ├── columns: generate_series:1(int) generate_series:2(int)
 ├── values
 │    └── tuple [type=tuple]
 └── zip
      ├── 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]

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)
      │    │    ├── project-set
      │    │    │    ├── columns: generate_series:5(int)
      │    │    │    ├── values
      │    │    │    │    └── tuple [type=tuple]
      │    │    │    └── zip
      │    │    │         └── function: generate_series [type=int]
      │    │    │              ├── const: 1 [type=int]
      │    │    │              └── const: 2 [type=int]
      │    │    ├── project-set
      │    │    │    ├── columns: generate_series:6(int)
      │    │    │    ├── values
      │    │    │    │    └── tuple [type=tuple]
      │    │    │    └── zip
      │    │    │         └── function: generate_series [type=int]
      │    │    │              ├── const: 3 [type=int]
      │    │    │              └── const: 4 [type=int]
      │    │    └── filters (true)
      │    └── filters (true)
      └── filters (true)

build
SELECT 3 + x FROM generate_series(1,2) AS a(x)
----
project
 ├── columns: "?column?":2(int)
 ├── project-set
 │    ├── columns: generate_series:1(int)
 │    ├── values
 │    │    └── tuple [type=tuple]
 │    └── zip
 │         └── 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)
 ├── project-set
 │    ├── columns: generate_series:1(int)
 │    ├── values
 │    │    └── tuple [type=tuple]
 │    └── zip
 │         └── function: generate_series [type=int]
 │              ├── const: 1 [type=int]
 │              └── const: 3 [type=int]
 └── 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])
----
project-set
 ├── columns: unnest:1(int)
 ├── values
 │    └── tuple [type=tuple]
 └── zip
      └── 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'])
----
project-set
 ├── columns: unnest:1(int) unnest:2(string)
 ├── values
 │    └── tuple [type=tuple]
 └── zip
      ├── 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]

build
SELECT unnest(ARRAY[3,4]) - 2
----
project
 ├── columns: "?column?":2(int)
 ├── project-set
 │    ├── columns: unnest:1(int)
 │    ├── values
 │    │    └── tuple [type=tuple]
 │    └── zip
 │         └── function: unnest [type=int]
 │              └── array: [type=int[]]
 │                   ├── const: 3 [type=int]
 │                   └── const: 4 [type=int]
 └── 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)
 ├── project-set
 │    ├── columns: generate_series:1(int) unnest:2(int)
 │    ├── values
 │    │    └── tuple [type=tuple]
 │    └── zip
 │         ├── 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]
 └── 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)
 ├── project-set
 │    ├── columns: unnest:1(string)
 │    ├── values
 │    │    └── tuple [type=tuple]
 │    └── zip
 │         └── function: unnest [type=string]
 │              └── array: [type=string[]]
 │                   ├── const: 'a' [type=string]
 │                   ├── const: 'b' [type=string]
 │                   └── const: 'c' [type=string]
 └── projections
      └── function: ascii [type=int]
           └── variable: unnest [type=string]

# Regression test for #36501: don't rename the SRF column because of a
# higher-level table alias.
build
SELECT * FROM (SELECT unnest(ARRAY[1])) AS tablealias
----
project-set
 ├── columns: unnest:1(int)
 ├── values
 │    └── tuple [type=tuple]
 └── zip
      └── function: unnest [type=int]
           └── array: [type=int[]]
                └── const: 1 [type=int]

build
SELECT * FROM (SELECT unnest(ARRAY[1]) AS colalias) AS tablealias
----
project-set
 ├── columns: colalias:1(int)
 ├── values
 │    └── tuple [type=tuple]
 └── zip
      └── function: unnest [type=int]
           └── array: [type=int[]]
                └── const: 1 [type=int]

build
SELECT * FROM
  (SELECT unnest(ARRAY[1]) AS filter_id2) AS uq
JOIN
  (SELECT unnest(ARRAY[1]) AS filter_id) AS ab
ON uq.filter_id2 = ab.filter_id
----
inner-join
 ├── columns: filter_id2:1(int!null) filter_id:2(int!null)
 ├── project-set
 │    ├── columns: unnest:1(int)
 │    ├── values
 │    │    └── tuple [type=tuple]
 │    └── zip
 │         └── function: unnest [type=int]
 │              └── array: [type=int[]]
 │                   └── const: 1 [type=int]
 ├── project-set
 │    ├── columns: unnest:2(int)
 │    ├── values
 │    │    └── tuple [type=tuple]
 │    └── zip
 │         └── function: unnest [type=int]
 │              └── array: [type=int[]]
 │                   └── const: 1 [type=int]
 └── filters
      └── eq [type=bool]
           ├── variable: unnest [type=int]
           └── variable: unnest [type=int]


# 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)
 ├── project-set
 │    ├── columns: generate_series:1(int) generate_series:2(int)
 │    ├── values
 │    │    └── tuple [type=tuple]
 │    └── zip
 │         ├── 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]
 └── 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)))
----
project-set
 ├── columns: generate_series:2(int)
 ├── values
 │    └── tuple [type=tuple]
 └── zip
      └── function: generate_series [type=int]
           ├── const: 1 [type=int]
           └── subquery [type=int]
                └── max1-row
                     ├── columns: generate_series:1(int)
                     └── project-set
                          ├── columns: generate_series:1(int)
                          ├── values
                          │    └── tuple [type=tuple]
                          └── zip
                               └── 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)))))))));
----
project-set
 ├── columns: unnest:5(string)
 ├── values
 │    └── tuple [type=tuple]
 └── zip
      └── 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)
                                                                                                └── project-set
                                                                                                     ├── columns: generate_series:1(int)
                                                                                                     ├── values
                                                                                                     │    └── tuple [type=tuple]
                                                                                                     └── zip
                                                                                                          └── function: generate_series [type=int]
                                                                                                               ├── const: 1 [type=int]
                                                                                                               └── const: 0 [type=int]

# 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)
      ├── project-set
      │    ├── columns: word:1(string) catcode:2(string) catdesc:3(string)
      │    ├── values
      │    │    └── tuple [type=tuple]
      │    └── zip
      │         └── function: pg_get_keywords [type=tuple{string AS word, string AS catcode, string AS catdesc}]
      └── filters
           └── 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)
 │    ├── project-set
 │    │    ├── columns: generate_series:1(int)
 │    │    ├── values
 │    │    │    └── tuple [type=tuple]
 │    │    └── zip
 │    │         └── 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)
 │    │    ├── project-set
 │    │    │    ├── columns: unnest:2(int)
 │    │    │    ├── values
 │    │    │    │    └── tuple [type=tuple]
 │    │    │    └── zip
 │    │    │         └── function: unnest [type=int]
 │    │    │              └── array: [type=int[]]
 │    │    │                   └── const: 1 [type=int]
 │    │    ├── project-set
 │    │    │    ├── columns: word:3(string) catcode:4(string) catdesc:5(string)
 │    │    │    ├── values
 │    │    │    │    └── tuple [type=tuple]
 │    │    │    └── zip
 │    │    │         └── function: pg_get_keywords [type=tuple{string AS word, string AS catcode, string AS catdesc}]
 │    │    └── filters (true)
 │    └── filters (true)
 └── 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)
 │    ├── project-set
 │    │    ├── columns: word:1(string) catcode:2(string) catdesc:3(string)
 │    │    ├── values
 │    │    │    └── tuple [type=tuple]
 │    │    └── zip
 │    │         └── function: pg_get_keywords [type=tuple{string AS word, string AS catcode, string AS catdesc}]
 │    └── 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)
 │    ├── project-set
 │    │    ├── columns: word:1(string) catcode:2(string) catdesc:3(string)
 │    │    ├── values
 │    │    │    └── tuple [type=tuple]
 │    │    └── zip
 │    │         └── function: pg_get_keywords [type=tuple{string AS word, string AS catcode, string AS catdesc}]
 │    └── 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)
 │    ├── project-set
 │    │    ├── values
 │    │    │    └── tuple [type=tuple]
 │    │    └── zip
 │    │         └── function: crdb_internal.unary_table [type=tuple]
 │    └── 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')
----
project-set
 ├── columns: upper:1(string)
 ├── values
 │    └── tuple [type=tuple]
 └── zip
      └── 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)
 └── project-set
      ├── columns: current_schema:1(string)
      ├── values
      │    └── tuple [type=tuple]
      └── zip
           └── 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})
 ├── project-set
 │    ├── columns: x:1(string) n:2(int)
 │    ├── values
 │    │    └── tuple [type=tuple]
 │    └── zip
 │         └── function: information_schema._pg_expandarray [type=tuple{string AS x, int AS n}]
 │              └── array: [type=string[]]
 │                   ├── const: 'b' [type=string]
 │                   └── const: 'a' [type=string]
 └── 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'])
----
project-set
 ├── columns: x:1(string) n:2(int)
 ├── values
 │    └── tuple [type=tuple]
 └── zip
      └── 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)
 ├── project-set
 │    ├── columns: x:1(string) n:2(int)
 │    ├── values
 │    │    └── tuple [type=tuple]
 │    └── zip
 │         └── 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]
 └── 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)
 ├── project-set
 │    ├── columns: x:1(string) n:2(int)
 │    ├── values
 │    │    └── tuple [type=tuple]
 │    └── zip
 │         └── 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]
 └── 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)
 └── project-set
      ├── columns: x:1(string) n:2(int)
      ├── values
      │    └── tuple [type=tuple]
      └── zip
           └── 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;
----
project-set
 ├── columns: x:1(string) n:2(int)
 ├── values
 │    └── tuple [type=tuple]
 └── zip
      └── 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;
----
project-set
 ├── columns: x:1(string) n:2(int)
 ├── values
 │    └── tuple [type=tuple]
 └── zip
      └── 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])
----
project-set
 ├── columns: generate_subscripts:1(int)
 ├── values
 │    └── tuple [type=tuple]
 └── zip
      └── 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']))
----
project-set
 ├── columns: generate_series:1(int) generate_series:2(int) word:3(string) catcode:4(string) catdesc:5(string) unnest:6(string)
 ├── values
 │    └── tuple [type=tuple]
 └── zip
      ├── 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)
 │    ├── project-set
 │    │    ├── columns: upper:1(string)
 │    │    ├── values
 │    │    │    └── tuple [type=tuple]
 │    │    └── zip
 │    │         └── function: upper [type=string]
 │    │              └── const: 'abc' [type=string]
 │    ├── project-set
 │    │    ├── columns: upper:2(string) generate_series:3(int)
 │    │    ├── values
 │    │    │    └── tuple [type=tuple]
 │    │    └── zip
 │    │         ├── function: upper [type=string]
 │    │         │    └── const: 'def' [type=string]
 │    │         └── function: generate_series [type=int]
 │    │              ├── const: 1 [type=int]
 │    │              └── const: 3 [type=int]
 │    └── filters
 │         └── true [type=bool]
 ├── project-set
 │    ├── columns: generate_series:4(int)
 │    ├── values
 │    │    └── tuple [type=tuple]
 │    └── zip
 │         └── function: generate_series [type=int]
 │              ├── const: 1 [type=int]
 │              └── const: 4 [type=int]
 └── filters
      └── 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: INT8 [type=int]
      │    │              └── variable: a [type=string]
      │    └── aggregations
      │         ├── max [type=string]
      │         │    └── variable: a [type=string]
      │         └── max [type=int]
      │              └── variable: column4 [type=int]
      └── filters
           └── 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)
                               │    └── project-set
                               │         ├── 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
                               │              └── function: generate_series [type=int]
                               │                   ├── const: 0 [type=int]
                               │                   └── cast: INT8 [type=int]
                               │                        └── variable: b [type=string]
                               └── 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)
 └── project-set
      ├── columns: a:1(string) t.rowid:2(int!null) generate_series:8(int)
      ├── scan t
      │    └── columns: a:1(string) t.rowid:2(int!null)
      └── zip
           └── function: generate_series [type=int]
                ├── subquery [type=int]
                │    └── max1-row
                │         ├── columns: generate_subscripts:7(int)
                │         └── project
                │              ├── columns: generate_subscripts:7(int)
                │              └── project-set
                │                   ├── columns: a:3(string) t.rowid:4(int!null) b:5(string) u.rowid:6(int!null) generate_subscripts:7(int)
                │                   ├── inner-join
                │                   │    ├── columns: a:3(string) t.rowid:4(int!null) b:5(string) u.rowid:6(int!null)
                │                   │    ├── scan t
                │                   │    │    └── columns: a:3(string) t.rowid:4(int!null)
                │                   │    ├── scan u
                │                   │    │    └── columns: b:5(string) u.rowid:6(int!null)
                │                   │    └── filters (true)
                │                   └── zip
                │                        └── function: generate_subscripts [type=int]
                │                             └── array: [type=string[]]
                │                                  ├── variable: a [type=string]
                │                                  └── concat [type=string]
                │                                       ├── variable: a [type=string]
                │                                       └── variable: b [type=string]
                └── const: 100 [type=int]

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)
 ├── project-set
 │    ├── columns: x:1(int!null) j:2(jsonb) k:3(jsonb) m:4(jsonb) n:5(jsonb) json_array_elements:6(jsonb)
 │    ├── scan a
 │    │    └── columns: x:1(int!null) j:2(jsonb) k:3(jsonb) m:4(jsonb) n:5(jsonb)
 │    └── zip
 │         └── function: json_array_elements [type=jsonb]
 │              └── variable: j [type=jsonb]
 └── 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})
      │              ├── project-set
      │              │    ├── columns: key:7(string) value:8(jsonb)
      │              │    ├── values
      │              │    │    └── tuple [type=tuple]
      │              │    └── zip
      │              │         └── function: jsonb_each [type=tuple{string AS key, jsonb AS value}]
      │              │              └── variable: k [type=jsonb]
      │              └── 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)
      │              └── project-set
      │                   ├── columns: x:10(int!null) j:11(jsonb) k:12(jsonb) m:13(jsonb) n:14(jsonb) jsonb_object_keys:15(string)
      │                   ├── scan a
      │                   │    └── columns: x:10(int!null) j:11(jsonb) k:12(jsonb) m:13(jsonb) n:14(jsonb)
      │                   └── zip
      │                        └── function: jsonb_object_keys [type=string]
      │                             └── variable: m [type=jsonb]
      └── subquery [type=int]
           └── max1-row
                ├── columns: generate_series:18(int)
                └── project-set
                     ├── columns: generate_series:18(int)
                     ├── values
                     │    └── tuple [type=tuple]
                     └── zip
                          └── function: generate_series [type=int]
                               ├── subquery [type=int]
                               │    └── max1-row
                               │         ├── columns: generate_series:17(int)
                               │         └── project
                               │              ├── columns: generate_series:17(int)
                               │              └── project-set
                               │                   ├── columns: jsonb_array_elements_text:16(string) generate_series:17(int)
                               │                   ├── project-set
                               │                   │    ├── columns: jsonb_array_elements_text:16(string)
                               │                   │    ├── values
                               │                   │    │    └── tuple [type=tuple]
                               │                   │    └── zip
                               │                   │         └── function: jsonb_array_elements_text [type=string]
                               │                   │              └── variable: n [type=jsonb]
                               │                   └── zip
                               │                        └── function: generate_series [type=int]
                               │                             ├── variable: x [type=int]
                               │                             └── const: 100 [type=int]
                               └── const: 1000 [type=int]

# 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
----
project-set
 ├── columns: ident:1(int[])
 ├── values
 │    └── tuple [type=tuple]
 └── zip
      └── cast: SERIAL2[] [type=int[]]
           └── const: 'string' [type=string]
