subtest generate_series

query I
SELECT * FROM generate_series(1, NULL)
----

query I colnames,nosort
SELECT * FROM generate_series(1, 3)
----
generate_series
1
2
3

query T colnames,nosort
SELECT * FROM generate_series('2017-11-11 00:00:00'::TIMESTAMP, '2017-11-11 03:00:00'::TIMESTAMP, '1 hour')
----
generate_series
2017-11-11 00:00:00 +0000 +0000
2017-11-11 01:00:00 +0000 +0000
2017-11-11 02:00:00 +0000 +0000
2017-11-11 03:00:00 +0000 +0000

query T colnames,nosort
SELECT * FROM generate_series('2017-11-11 03:00:00'::TIMESTAMP, '2017-11-11 00:00:00'::TIMESTAMP, '-1 hour')
----
generate_series
2017-11-11 03:00:00 +0000 +0000
2017-11-11 02:00:00 +0000 +0000
2017-11-11 01:00:00 +0000 +0000
2017-11-11 00:00:00 +0000 +0000

query T colnames,nosort
SELECT * FROM generate_series('2017-11-11 03:00:00'::TIMESTAMP, '2017-11-15 00:00:00'::TIMESTAMP, '1 day')
----
generate_series
2017-11-11 03:00:00 +0000 +0000
2017-11-12 03:00:00 +0000 +0000
2017-11-13 03:00:00 +0000 +0000
2017-11-14 03:00:00 +0000 +0000

query T colnames,nosort
SELECT * FROM generate_series('2017-01-15 03:00:00'::TIMESTAMP, '2017-12-15 00:00:00'::TIMESTAMP, '1 month')
----
generate_series
2017-01-15 03:00:00 +0000 +0000
2017-02-15 03:00:00 +0000 +0000
2017-03-15 03:00:00 +0000 +0000
2017-04-15 03:00:00 +0000 +0000
2017-05-15 03:00:00 +0000 +0000
2017-06-15 03:00:00 +0000 +0000
2017-07-15 03:00:00 +0000 +0000
2017-08-15 03:00:00 +0000 +0000
2017-09-15 03:00:00 +0000 +0000
2017-10-15 03:00:00 +0000 +0000
2017-11-15 03:00:00 +0000 +0000

# Check what happens when we step through February in a leap year, starting on Jan 31.
# This output is consistent with PostgreSQL 10.
query T colnames,nosort
SELECT * FROM generate_series('2016-01-31 03:00:00'::TIMESTAMP, '2016-12-31 00:00:00'::TIMESTAMP, '1 month')
----
generate_series
2016-01-31 03:00:00 +0000 +0000
2016-02-29 03:00:00 +0000 +0000
2016-03-29 03:00:00 +0000 +0000
2016-04-29 03:00:00 +0000 +0000
2016-05-29 03:00:00 +0000 +0000
2016-06-29 03:00:00 +0000 +0000
2016-07-29 03:00:00 +0000 +0000
2016-08-29 03:00:00 +0000 +0000
2016-09-29 03:00:00 +0000 +0000
2016-10-29 03:00:00 +0000 +0000
2016-11-29 03:00:00 +0000 +0000
2016-12-29 03:00:00 +0000 +0000

# Similar to the previous, but we don't hit a 30-day month until July.
query T colnames,nosort
SELECT * FROM generate_series('2016-01-31 03:00:00'::TIMESTAMP, '2016-12-31 00:00:00'::TIMESTAMP, '2 month')
----
generate_series
2016-01-31 03:00:00 +0000 +0000
2016-03-31 03:00:00 +0000 +0000
2016-05-31 03:00:00 +0000 +0000
2016-07-31 03:00:00 +0000 +0000
2016-09-30 03:00:00 +0000 +0000
2016-11-30 03:00:00 +0000 +0000

# Verify rollover when we're adding by months, days, and hours
query T colnames,nosort
SELECT * FROM generate_series('2016-01-30 22:00:00'::TIMESTAMP, '2016-12-31 00:00:00'::TIMESTAMP, '1 month 1 day 1 hour')
----
generate_series
2016-01-30 22:00:00 +0000 +0000
2016-03-01 23:00:00 +0000 +0000
2016-04-03 00:00:00 +0000 +0000
2016-05-04 01:00:00 +0000 +0000
2016-06-05 02:00:00 +0000 +0000
2016-07-06 03:00:00 +0000 +0000
2016-08-07 04:00:00 +0000 +0000
2016-09-08 05:00:00 +0000 +0000
2016-10-09 06:00:00 +0000 +0000
2016-11-10 07:00:00 +0000 +0000
2016-12-11 08:00:00 +0000 +0000

query T colnames,nosort
SELECT * FROM generate_series('1996-02-29 22:00:00'::TIMESTAMP, '2004-03-01 00:00:00'::TIMESTAMP, '4 year')
----
generate_series
1996-02-29 22:00:00 +0000 +0000
2000-02-29 22:00:00 +0000 +0000
2004-02-29 22:00:00 +0000 +0000

query T colnames
SELECT * FROM generate_series('2017-11-11 00:00:00'::TIMESTAMP, '2017-11-11 03:00:00'::TIMESTAMP, '-1 hour')
----
generate_series

query II colnames,rowsort
SELECT * FROM generate_series(1, 2), generate_series(1, 2)
----
generate_series  generate_series
1                1
1                2
2                1
2                2

query I colnames,nosort
SELECT * FROM generate_series(3, 1, -1)
----
generate_series
3
2
1

query I colnames
SELECT * FROM generate_series(3, 1)
----
generate_series

query error step cannot be 0
SELECT * FROM generate_series(1, 3, 0)

query I colnames,nosort
SELECT * FROM PG_CATALOG.generate_series(1, 3)
----
generate_series
1
2
3

query I colnames
SELECT * FROM generate_series(1, 1) AS c(x)
----
x
1

query II colnames
SELECT * FROM generate_series(1, 1) WITH ORDINALITY
----
generate_series  ordinality
1                1

query II colnames
SELECT * FROM generate_series(1, 1) WITH ORDINALITY AS c(x, y)
----
x y
1 1

query error set-returning functions are not allowed in LIMIT
SELECT * FROM (VALUES (1)) LIMIT generate_series(1, 3)

query I colnames,nosort
SELECT generate_series(1, 2)
----
generate_series
1
2

subtest multiple_SRFs

query II colnames,nosort
SELECT generate_series(1, 2), generate_series(3, 4)
----
generate_series             generate_series
1                           3
2                           4

query II nosort
SELECT generate_series(1, 2), generate_series(3, 4)
----
1  3
2  4

statement ok
CREATE TABLE t (a string)

statement ok
CREATE TABLE u (b string)

statement ok
INSERT INTO t VALUES ('cat')

statement ok
INSERT INTO u VALUES ('bird')

query TTII colnames,rowsort
SELECT t.*, u.*, generate_series(1,2), generate_series(3, 4) FROM t, u
----
a    b     generate_series generate_series
cat  bird  1               3
cat  bird  2               4

query TTII colnames,rowsort
SELECT t.*, u.*, a.*, b.* FROM t, u, generate_series(1, 2) AS a, generate_series(3, 4) AS b
----
a    b     a  b
cat  bird  1  3
cat  bird  1  4
cat  bird  2  3
cat  bird  2  4

query I colnames,nosort
SELECT 3 + x AS r FROM generate_series(1,2) AS a(x)
----
r
4
5

query I colnames,nosort
SELECT 3 + generate_series(1,2) AS r
----
r
4
5

query I colnames,nosort
SELECT 3 + (3 * generate_series(1,3)) AS r
----
r
6
9
12

subtest srf_ordering

statement ok
CREATE TABLE ordered_t(x INT PRIMARY KEY);
  INSERT INTO ordered_t VALUES (0), (1)

query II colnames
SELECT x, generate_series(3, x, -1) FROM ordered_t ORDER BY 1, 2;
----
x  generate_series
0  0
0  1
0  2
0  3
1  1
1  2
1  3

subtest unnest

statement error could not determine polymorphic type
SELECT * FROM unnest(NULL)

statement error could not determine polymorphic type
SELECT unnest(NULL)

query I colnames,nosort
SELECT * from unnest(ARRAY[1,2])
----
unnest
1
2

query IT nosort
SELECT unnest(ARRAY[1,2]), unnest(ARRAY['a', 'b'])
----
1  a
2  b

query I colnames,nosort
SELECT unnest(ARRAY[3,4]) - 2 AS r
----
r
1
2

query II colnames,nosort
SELECT 1 + generate_series(0, 1) AS r, unnest(ARRAY[2, 4]) - 1 AS t
----
r t
1 1
2 3

query II nosort
SELECT 1 + generate_series(0, 1), unnest(ARRAY[2, 4]) - 1
----
1  1
2  3

query I colnames,nosort
SELECT ascii(unnest(ARRAY['a', 'b', 'c']));
----
ascii
97
98
99

subtest nested_SRF
# See #20511

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

query I rowsort
SELECT generate_series(1, 3) + generate_series(1, 3)
----
2
4
6

query error pq: column "generate_series" does not exist
SELECT generate_series(1, 3) FROM t WHERE generate_series > 3

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

query T colnames
SELECT * from generate_series(1, (select * from generate_series(1, 0)))
----
generate_series

# 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.
query T colnames
SELECT unnest((SELECT current_schemas((SELECT isnan((SELECT round(3.4, (SELECT generate_series(1, 0)))))))));
----
unnest

query T colnames
SELECT information_schema._pg_expandarray((SELECT current_schemas((SELECT isnan((SELECT round(3.4, (SELECT generate_series(1, 0)))))))));
----
information_schema._pg_expandarray

# Regression for #18021.
query I colnames,nosort
SELECT generate_series(9223372036854775807::int, -9223372036854775807::int, -9223372036854775807::int)
----
generate_series
9223372036854775807
0
-9223372036854775807

subtest pg_get_keywords

# pg_get_keywords for compatibility (#10291)
query TTT colnames
SELECT * FROM pg_get_keywords() WHERE word IN ('alter', 'and', 'between', 'cross') ORDER BY word
----
word     catcode catdesc
alter    U       unreserved
and      R       reserved
between  C       unreserved (cannot be function or type name)
cross    T       reserved (can be function or type name)

# Postgres enables renaming both the source and the column name for
# single-column generators, but not for multi-column generators.
query IITTT colnames
SELECT a.*, b.*, c.* FROM generate_series(1,1) a, unnest(ARRAY[1]) b, pg_get_keywords() c LIMIT 0
----
a  b  word  catcode  catdesc

# Regression for #36501: the column from a single-column SRF should not be
# renamed because of a higher-level table alias.
query I colnames,nosort
SELECT * FROM (SELECT * FROM generate_series(1, 2)) AS a
----
generate_series
1
2

query I colnames
SELECT * FROM (SELECT unnest(ARRAY[1])) AS tablealias
----
unnest
1

query I colnames
SELECT * FROM (SELECT unnest(ARRAY[1]) AS colalias) AS tablealias
----
colalias
1

query II
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
----
1  1

# Beware of multi-valued SRFs in render position (#19149)
query TTT colnames
SELECT 'a' AS a, pg_get_keywords(), 'c' AS c LIMIT 1
----
a  pg_get_keywords       c
a  (abort,U,unreserved)  c

query TTT colnames
SELECT 'a' AS a, pg_get_keywords() AS b, 'c' AS c LIMIT 1
----
a  b                     c
a  (abort,U,unreserved)  c

subtest unary_table

query TTT colnames
SELECT 'a' AS a, crdb_internal.unary_table() AS b, 'c' AS c LIMIT 1
----
a  b   c
a  ()  c

subtest upper

# Regular scalar functions can be used as functions too. #22312
query T colnames
SELECT * FROM upper('abc')
----
upper
ABC

subtest current_schema

query TI colnames
SELECT * FROM current_schema() WITH ORDINALITY AS a(b)
----
b      ordinality
public 1

subtest expandArray

query error pq: unknown signature: information_schema._pg_expandarray()
SELECT information_schema._pg_expandarray()

query error pq: unknown signature: information_schema._pg_expandarray()
SELECT * FROM information_schema._pg_expandarray()

query error pq: information_schema\._pg_expandarray\(\): cannot determine type of empty array\. Consider casting to the desired type, for example ARRAY\[\]::int\[\]
SELECT information_schema._pg_expandarray(ARRAY[])

query error pq: information_schema\._pg_expandarray\(\): cannot determine type of empty array\. Consider casting to the desired type, for example ARRAY\[\]::int\[\]
SELECT * FROM information_schema._pg_expandarray(ARRAY[])

statement error could not determine polymorphic type
SELECT * FROM information_schema._pg_expandarray(NULL)

statement error could not determine polymorphic type
SELECT information_schema._pg_expandarray(NULL)

query I colnames
SELECT information_schema._pg_expandarray(ARRAY[]:::int[])
----
information_schema._pg_expandarray

query II colnames
SELECT * FROM information_schema._pg_expandarray(ARRAY[]:::int[])
----
x  n

query T colnames
SELECT information_schema._pg_expandarray(ARRAY[100])
----
information_schema._pg_expandarray
(100,1)

query II colnames
SELECT * FROM information_schema._pg_expandarray(ARRAY[100])
----
x   n
100 1

query T colnames,nosort
SELECT information_schema._pg_expandarray(ARRAY[2, 1])
----
information_schema._pg_expandarray
(2,1)
(1,2)

query II colnames,nosort
SELECT * FROM information_schema._pg_expandarray(ARRAY[2, 1])
----
x n
2 1
1 2

query T colnames,nosort
SELECT information_schema._pg_expandarray(ARRAY[3, 2, 1])
----
information_schema._pg_expandarray
(3,1)
(2,2)
(1,3)

query II colnames,nosort
SELECT * FROM information_schema._pg_expandarray(ARRAY[3, 2, 1])
----
x n
3 1
2 2
1 3

query T colnames
SELECT information_schema._pg_expandarray(ARRAY['a'])
----
information_schema._pg_expandarray
(a,1)

query TI colnames
SELECT * FROM information_schema._pg_expandarray(ARRAY['a'])
----
x n
a 1

query T colnames,nosort
SELECT information_schema._pg_expandarray(ARRAY['b', 'a'])
----
information_schema._pg_expandarray
(b,1)
(a,2)

query TI colnames,nosort
SELECT * FROM information_schema._pg_expandarray(ARRAY['b', 'a'])
----
x n
b 1
a 2

query T colnames,nosort
SELECT information_schema._pg_expandarray(ARRAY['c', 'b', 'a'])
----
information_schema._pg_expandarray
(c,1)
(b,2)
(a,3)

query TI colnames,nosort
SELECT * FROM information_schema._pg_expandarray(ARRAY['c', 'b', 'a'])
----
x n
c 1
b 2
a 3

subtest srf_accessor

query error pq: type int is not composite
SELECT (1).*

query error pq: type int is not composite
SELECT ((1)).*

query error pq: type int is not composite
SELECT (1).x

query error pq: type int is not composite
SELECT ((1)).x

query error pq: type string is not composite
SELECT ('a').*

query error pq: type string is not composite
SELECT (('a')).*

query error pq: type string is not composite
SELECT ('a').x

query error pq: type string is not composite
SELECT (('a')).x

query error pq: unnest\(\): cannot determine type of empty array. Consider casting to the desired type, for example ARRAY\[\]::int\[\]
SELECT (unnest(ARRAY[])).*

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

subtest multi_column

query TI colnames,nosort
SELECT (information_schema._pg_expandarray(ARRAY['c', 'b', 'a'])).*
----
x  n
c  1
b  2
a  3

query T colnames,nosort
SELECT (information_schema._pg_expandarray(ARRAY['c', 'b', 'a'])).x
----
x
c
b
a

query I colnames,nosort
SELECT (information_schema._pg_expandarray(ARRAY['c', 'b', 'a'])).n
----
n
1
2
3

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

query T colnames,nosort
SELECT temp.x from information_schema._pg_expandarray(array['c','b','a']) AS temp;
----
x
c
b
a

query I colnames,nosort
SELECT temp.n from information_schema._pg_expandarray(array['c','b','a']) AS temp;
----
n
1
2
3

query error pq: column "temp.other" does not exist
SELECT temp.other from information_schema._pg_expandarray(array['c','b','a']) AS temp;

query TI colnames,nosort
SELECT temp.* from information_schema._pg_expandarray(array['c','b','a']) AS temp;
----
x n
c 1
b 2
a 3

query TI colnames,nosort
SELECT * from information_schema._pg_expandarray(array['c','b','a']) AS temp;
----
x n
c 1
b 2
a 3

query I colnames,nosort
SELECT (i.keys).n FROM (SELECT information_schema._pg_expandarray(ARRAY[3,2,1]) AS keys) AS i
----
n
1
2
3

query II colnames,nosort
SELECT (i.keys).* FROM (SELECT information_schema._pg_expandarray(ARRAY[3,2,1]) AS keys) AS i
----
x  n
3  1
2  2
1  3

query T nosort
SELECT ((i.keys).*, 123) FROM (SELECT information_schema._pg_expandarray(ARRAY[3,2,1]) AS keys) AS i
----
("(3,1)",123)
("(2,2)",123)
("(1,3)",123)

subtest generate_subscripts

# Basic use cases

query I colnames,nosort
SELECT * FROM generate_subscripts(ARRAY[3,2,1])
----
generate_subscripts
1
2
3

query I colnames,nosort
SELECT * FROM generate_subscripts(ARRAY[3,2,1], 1)
----
generate_subscripts
1
2
3

query I colnames,nosort
SELECT * FROM generate_subscripts(ARRAY[3,2,1], 1, false)
----
generate_subscripts
1
2
3

query I colnames,nosort
SELECT * FROM generate_subscripts(ARRAY[3,2,1], 1, true)
----
generate_subscripts
3
2
1

query I colnames,nosort
SELECT generate_subscripts('{NULL,1,NULL,2}'::int[], 1) AS s
----
s
1
2
3
4

query I colnames,nosort
SELECT generate_subscripts('{NULL,1,NULL,2}'::int[], 1, true) AS s
----
s
4
3
2
1

# With a non-valid dimension (only 1 should return any rows)

query I colnames
SELECT * FROM generate_subscripts(ARRAY[3,2,1], 2)
----
generate_subscripts

query I colnames
SELECT * FROM generate_subscripts(ARRAY[3,2,1], 2, false)
----
generate_subscripts

query I colnames
SELECT * FROM generate_subscripts(ARRAY[3,2,1], 2, true)
----
generate_subscripts

query I colnames
SELECT * FROM generate_subscripts(ARRAY[3,2,1], 0)
----
generate_subscripts

query I colnames
SELECT * FROM generate_subscripts(ARRAY[3,2,1], 0, false)
----
generate_subscripts

query I colnames
SELECT * FROM generate_subscripts(ARRAY[3,2,1], 0, true)
----
generate_subscripts

query I colnames
SELECT * FROM generate_subscripts(ARRAY[3,2,1], -1)
----
generate_subscripts

query I colnames
SELECT * FROM generate_subscripts(ARRAY[3,2,1], -1, false)
----
generate_subscripts

query I colnames
SELECT * FROM generate_subscripts(ARRAY[3,2,1], -1, true)
----
generate_subscripts

# With an empty array
query I colnames
SELECT * FROM generate_subscripts(ARRAY[]:::int[])
----
generate_subscripts

query I colnames
SELECT * FROM generate_subscripts(ARRAY[]:::int[], 1)
----
generate_subscripts

query I colnames
SELECT * FROM generate_subscripts(ARRAY[]:::string[], 1, false)
----
generate_subscripts

query I colnames
SELECT * FROM generate_subscripts(ARRAY[]:::bool[], 1, true)
----
generate_subscripts

query I colnames
SELECT * FROM generate_subscripts(ARRAY[]:::int[], 0)
----
generate_subscripts

query I colnames
SELECT * FROM generate_subscripts(ARRAY[]:::string[], -1, false)
----
generate_subscripts

query I colnames
SELECT * FROM generate_subscripts(ARRAY[]:::bool[], 2, true)
----
generate_subscripts

# With an array with only one value
query I colnames
SELECT * FROM generate_subscripts(ARRAY[100])
----
generate_subscripts
1

query I colnames
SELECT * FROM generate_subscripts(ARRAY[100], 1)
----
generate_subscripts
1

query I colnames
SELECT * FROM generate_subscripts(ARRAY['b'], 1, false)
----
generate_subscripts
1

query I colnames
SELECT * FROM generate_subscripts(ARRAY[true], 1, true)
----
generate_subscripts
1

subtest srf_errors

query error set-returning functions are not allowed in ORDER BY
SELECT * FROM t ORDER BY generate_series(1, 3)

query error set-returning functions are not allowed in WHERE
SELECT * FROM t WHERE generate_series(1, 3) < 3

query error set-returning functions are not allowed in HAVING
SELECT * FROM t HAVING generate_series(1, 3) < 3

query error set-returning functions are not allowed in LIMIT
SELECT * FROM t LIMIT generate_series(1, 3)

query error set-returning functions are not allowed in OFFSET
SELECT * FROM t OFFSET generate_series(1, 3)

query error set-returning functions are not allowed in VALUES
VALUES (generate_series(1,3))

statement error set-returning functions are not allowed in DEFAULT
CREATE TABLE uu (x INT DEFAULT generate_series(1, 3))

statement error set-returning functions are not allowed in CHECK
CREATE TABLE uu (x INT CHECK (generate_series(1, 3) < 3))

statement error generate_series\(\): set-returning functions are not allowed in STORED COMPUTED COLUMN
CREATE TABLE uu (x INT AS (generate_series(1, 3)) STORED)

subtest correlated_srf

# Initially this table will have 3 columns:
# x, y, rowid
statement ok
CREATE TABLE vals (x INT, y INT, INDEX woo (x, y));

statement ok
ALTER TABLE vals DROP COLUMN y cascade;

# Once the second column is and added dropped this table will have the format:
# x, rowid, y
statement ok
ALTER TABLE vals ADD COLUMN y int;

statement ok
CREATE INDEX woo ON vals(x,y);

statement ok
INSERT INTO vals VALUES (3, 4), (NULL, NULL), (5, 6);

query III colnames
SELECT x, generate_series(1,x), generate_series(1,2) FROM vals ORDER BY 1,2,3
----
x     generate_series  generate_series
NULL  NULL             1
NULL  NULL             2
3     1                1
3     2                2
3     3                NULL
5     1                1
5     2                2
5     3                NULL
5     4                NULL
5     5                NULL

# Check that the expression is still valid if the dependent name
# is not otherwise rendered (needed column elision).
query I colnames,rowsort
SELECT generate_series(1,x) FROM vals
----
generate_series
1
2
3
1
2
3
4
5

# Check that the number of rows is still correct
# even if the SRF is not needed.
query I
SELECT count(*) FROM (SELECT generate_series(1,x) FROM vals)
----
8

query TI colnames
SELECT relname, unnest(indkey) FROM pg_class, pg_index WHERE pg_class.oid = pg_index.indrelid ORDER BY relname, unnest
----
relname    unnest
ordered_t  1
t          2
u          2
vals       1
vals       3
vals       4

# We are going to order by the relname, indexrelid (index's OID), x and n (from pg_expandarray)
query TT colnames
SELECT relname, information_schema._pg_expandarray(indkey) FROM pg_class, pg_index WHERE pg_class.oid = pg_index.indrelid ORDER BY relname, indexrelid, x, n
----
relname    information_schema._pg_expandarray
ordered_t  (1,1)
t          (2,1)
u          (2,1)
vals       (3,1)
vals       (1,1)
vals       (4,2)

# The following query needs indclass to become an oidvector.
# See bug #26504.
# query III
# SELECT
#     indexrelid,
#     (information_schema._pg_expandarray(indclass)).x AS operator_argument_type_oid,
#     (information_schema._pg_expandarray(indclass)).n AS operator_argument_position
# FROM
#     pg_index
# ----

subtest correlated_json_object_keys

statement ok
CREATE TABLE j(x INT PRIMARY KEY, y JSON);
  INSERT INTO j VALUES
     (1, '{"a":123,"b":456}'),
     (2, '{"c":111,"d":222}')

query IT rowsort
SELECT x, y->>json_object_keys(y) FROM j
----
1  123
1  456
2  111
2  222

subtest correlated_multi_column

query TTI colnames
SELECT tbl, idx, (i.keys).n
  FROM (SELECT ct.relname AS tbl, ct2.relname AS idx, information_schema._pg_expandarray(indkey) AS keys
          FROM pg_index ix
          JOIN pg_class ct ON ix.indrelid = ct.oid AND ct.relname = 'vals'
	  JOIN pg_class ct2 ON ix.indexrelid = ct2.oid) AS i
ORDER BY 1,2,3
----
tbl   idx        n
vals  vals_pkey  1
vals  woo        1
vals  woo        2

subtest dbviz_example_query

# DbVisualizer query from #24649 listed in #16971.
query TTI
SELECT   a.attname, a.atttypid, atttypmod
    FROM pg_catalog.pg_class ct
    JOIN pg_catalog.pg_attribute a ON (ct.oid = a.attrelid)
    JOIN pg_catalog.pg_namespace n ON (ct.relnamespace = n.oid)
    JOIN (
      SELECT i.indexrelid, i.indrelid, i.indisprimary,
             information_schema._pg_expandarray(i.indkey) AS keys
        FROM pg_catalog.pg_index i
        ) i ON (a.attnum = (i.keys).x AND a.attrelid = i.indrelid)
   WHERE true
     AND n.nspname = 'public'
     AND ct.relname = 'j'
     AND i.indisprimary
ORDER BY a.attnum
----
x  20  -1

subtest metabase_confluent_example_query

# Test from metabase listed on #16971.
# Also Kafka Confluent sink query from #25854.
query TTTTIT
SELECT NULL AS TABLE_CAT,
       n.nspname AS TABLE_SCHEM,
       ct.relname AS TABLE_NAME,
       a.attname AS COLUMN_NAME,
       (i.keys).n AS KEY_SEQ,
       ci.relname AS PK_NAME
    FROM pg_catalog.pg_class ct
    JOIN pg_catalog.pg_attribute a ON (ct.oid = a.attrelid)
    JOIN pg_catalog.pg_namespace n ON (ct.relnamespace = n.oid)
    JOIN (SELECT i.indexrelid,
                 i.indrelid,
             i.indisprimary,
             information_schema._pg_expandarray(i.indkey) AS keys
        FROM pg_catalog.pg_index i) i ON (a.attnum = (i.keys).x AND a.attrelid = i.indrelid)
    JOIN pg_catalog.pg_class ci ON (ci.oid = i.indexrelid)
   WHERE true AND ct.relname = 'j' AND i.indisprimary
ORDER BY table_name, pk_name, key_seq
----
NULL  public  j  x  1  j_pkey

subtest liquibase_example_query

# # Test from #24713 (Liquibase) listed on #16971.
# # TODO(knz) Needs support for pg_get_indexdef with 3 arguments,
# # see #26629.
# query TTTBTTIITTTTT
# SELECT NULL AS table_cat,
#        n.nspname AS table_schem,
#        ct.relname AS TABLE_NAME,
#        NOT i.indisunique AS non_unique,
#        NULL AS index_qualifier,
#        ci.relname AS index_name,
#        CASE i.indisclustered
#          WHEN TRUE THEN 1
#          ELSE CASE am.amname
#            WHEN 'hash' THEN 2
#            ELSE 3
#          END
#        END AS TYPE,
#        (i.KEYS).n AS ordinal_position,
#        trim(BOTH '"' FROM pg_catalog.pg_get_indexdef(ci.oid, (i.KEYS).n, FALSE)) AS COLUMN_NAME,
#        CASE am.amcanorder
#          WHEN TRUE THEN CASE i.indoption[(i.keys).n - 1] & 1
#            WHEN 1 THEN 'D'
#            ELSE 'A'
#          END
#          ELSE NULL
#        END AS asc_or_desc,
#        ci.reltuples AS CARDINALITY,
#        ci.relpages AS pages,
#        pg_catalog.pg_get_expr(i.indpred, i.indrelid) AS filter_condition
# FROM pg_catalog.pg_class ct
# JOIN pg_catalog.pg_namespace n ON (ct.relnamespace = n.oid)
# JOIN (
#   SELECT i.indexrelid,
#          i.indrelid,
#          i.indoption,
#          i.indisunique,
#          i.indisclustered,
#          i.indpred,
#          i.indexprs,
#          information_schema._pg_expandarray(i.indkey) AS KEYS
#   FROM pg_catalog.pg_index i
# ) i
#   ON (ct.oid = i.indrelid)
# JOIN pg_catalog.pg_class ci ON (ci.oid = i.indexrelid)
# JOIN pg_catalog.pg_am am ON (ci.relam = am.oid)
# WHERE TRUE
#   AND n.nspname = 'public'
#   AND ct.relname = 'j'
# ORDER BY non_unique,
#          TYPE,
#          index_name,
#          ordinal_position
# ----

subtest unnest_with_tuple_types

query T colnames,nosort
SELECT unnest(ARRAY[(1,2),(3,4)])
----
unnest
(1,2)
(3,4)

query II colnames,nosort
SELECT (unnest(ARRAY[(1,2),(3,4)])).*
----
?column?  ?column?
1         2
3         4

query T colnames,nosort
SELECT * FROM unnest(ARRAY[(1,2),(3,4)])
----
unnest
(1,2)
(3,4)

query T colnames,nosort
SELECT t.* FROM unnest(ARRAY[(1,2),(3,4)]) AS t
----
t
(1,2)
(3,4)


subtest variadic_unnest

query T nosort
SELECT unnest(ARRAY[1,2], ARRAY['a','b'])
----
(1,a)
(2,b)

query T nosort
SELECT unnest(ARRAY[1,2], ARRAY['a'], ARRAY[1.1, 2.2, 3.3])
----
(1,a,1.1)
(2,,2.2)
(,,3.3)

query IT colnames,nosort
SELECT * FROM unnest(ARRAY[1,2], ARRAY['a', 'b'])
----
unnest unnest
1  a
2  b

query ITT colnames,nosort
SELECT * FROM unnest(ARRAY[1,2], ARRAY['a'], ARRAY[1.1, 2.2, 3.3])
----
unnest unnest unnest
1    a    1.1
2    NULL 2.2
NULL NULL 3.3

query II colnames,nosort
SELECT * FROM unnest(array[1,2], array[3,4,5]) AS t(a, b);
----
a    b
1    3
2    4
NULL 5

query I rowsort
SELECT unnest(ARRAY[1,2,3]) FROM unnest(ARRAY[4,5,6])
----
1
1
1
2
2
2
3
3
3

query I rowsort
SELECT unnest(ARRAY[NULL,2,3]) FROM unnest(ARRAY[NULL,NULL,NULL])
----
NULL
NULL
NULL
2
2
2
3
3
3

query I rowsort
SELECT unnest(ARRAY[1,2,NULL]) FROM unnest(ARRAY[NULL,NULL,NULL])
----
1
1
1
2
2
2
NULL
NULL
NULL

query I rowsort
SELECT unnest(ARRAY[NULL,NULL,NULL]) FROM unnest(ARRAY[NULL,NULL,NULL])
----
NULL
NULL
NULL
NULL
NULL
NULL
NULL
NULL
NULL

statement ok
CREATE TABLE xy (x INT PRIMARY KEY, y INT)

statement ok
INSERT INTO xy (VALUES (1,1), (2,2), (3,4), (4,8), (5,NULL))

query II rowsort
SELECT * FROM xy WHERE x IN (SELECT unnest(ARRAY[NULL,x]))
----
1  1
2  2
3  4
4  8
5  NULL

query II rowsort
SELECT * FROM xy
WHERE EXISTS
(SELECT t
  FROM unnest(ARRAY[NULL,2,NULL,4,5,x])
  AS f(t)
  WHERE t=y
)
----
1  1
2  2
3  4

query IT rowsort
SELECT unnest(ARRAY[1,2,3,4]), unnest(ARRAY['one','two'])
----
1  one
2  two
3  NULL
4  NULL

query error expected 1 to be of type varbit, found type int
SELECT unnest(ARRAY[1,2,3::varbit(3)])

query error expected 2 to be of type varbit, found type int
SELECT unnest(ARRAY[NULL,2,3::varbit(3)])

query error pq: could not determine polymorphic type
SELECT unnest(NULL, NULL)

query error pq: could not determine polymorphic type
SELECT unnest(ARRAY[1,2], NULL)

query error pq: could not determine polymorphic type
SELECT * FROM unnest(NULL, NULL)

query error pq: column reference "unnest" is ambiguous
SELECT unnest FROM unnest(array[1,2], array[3,4,5])

# Regression test for #58438 - handle the case when unnest outputs a tuple with
# labels. The unnest should not panic.
statement ok
CREATE TABLE t58438(a INT, b INT);

statement ok
INSERT INTO t58438 VALUES (1, 2), (3, 4), (5, 6);

query T rowsort
SELECT unnest(ARRAY[t58438.*]) FROM t58438;
----
(1,2)
(3,4)
(5,6)

query II rowsort
SELECT (x).* FROM (SELECT unnest(ARRAY[t58438.*]) FROM t58438) v(x);
----
1  2
3  4
5  6

subtest redundant_zip_expression

statement ok
SET testing_optimizer_disable_rule_probability = 1.0;

statement ok
CREATE TABLE t95615 (c1 INET PRIMARY KEY)

statement ok
INSERT INTO t95615 VALUES ('192.168.0.1'::INET)

# Test that a redundant function call in a ProjectSet doesn't crash due to
# being built into more than one zip expression.
query TTTI
SELECT * FROM t95615, LATERAL ROWS FROM (hostmask(c1), hostmask(c1)) WITH ORDINALITY
----
192.168.0.1  0.0.0.0  0.0.0.0  1

statement ok
CREATE FUNCTION f95615() RETURNS FLOAT IMMUTABLE LEAKPROOF LANGUAGE SQL AS 'SELECT 1.1'

# A redundant UDF call should be added only once in a zip expression and not
# error out.
query TFFI
SELECT * FROM t95615, LATERAL ROWS FROM (f95615(), f95615()) WITH ORDINALITY
----
192.168.0.1  1.1  1.1  1

statement ok
RESET testing_optimizer_disable_rule_probability

# Regression test for issue #95315.
statement ok
CREATE TABLE t95315 (c1 INT, c2 FLOAT);

statement ok
INSERT INTO t95315 VALUES (1, 4.3), (2, 5.4), (3, 6), (4, 7);

# Regression test for issue #95315.
# A query which uses a project set involving simple column expressions does
# not error out. Results verified on postgres.
query IIF
SELECT 1,c1,c2 FROM t95315 JOIN ROWS FROM (CAST(c1 AS INT), CAST(c2 AS INT)) USING (c1, c2) ORDER BY 1,2,3;
----
1  3  6
1  4  7

subtest generator-syntax

# Regression test for #97119 and #94890 - return syntax error when CASE or
# COALESCE is used with a set-generating function as argument.
statement error pq: set-returning functions are not allowed in conditional expressions
SELECT CASE generate_series(1, 3) WHEN 3 THEN 0 ELSE 1 END;

statement error pq: set-returning functions are not allowed in conditional expressions
SELECT CASE WHEN true THEN generate_series(1, 3) ELSE 1 END;

statement error pq: set-returning functions are not allowed in conditional expressions
SELECT CASE WHEN false THEN 1 ELSE generate_series(1, 3) END;

statement error pq: set-returning functions are not allowed in conditional expressions
SELECT COALESCE(generate_series(1, 10));

# A subquery with a generator function is allowed within CASE and COALESCE.
query I rowsort
SELECT CASE WHEN true THEN (SELECT * FROM generate_series(1, 3) LIMIT 1) ELSE 1 END;
----
1

query I rowsort
SELECT COALESCE((SELECT * FROM generate_series(1, 3) LIMIT 1));
----
1

# Aggregate functions within CASE and COALESCE are allowed.
query R rowsort
SELECT CASE WHEN true THEN sum(x) ELSE 1 END FROM xy;
----
15

query R rowsort
SELECT COALESCE(sum(x)) FROM xy;
----
15

# Window functions within CASE and COALESCE are allowed.
query R rowsort
SELECT CASE WHEN true THEN sum(x) OVER () ELSE 1 END FROM xy;
----
15
15
15
15
15

query R rowsort
SELECT COALESCE(sum(x) OVER ()) FROM xy;
----
15
15
15
15
15

# IF does not allow generator functions.
statement error pq: set-returning functions are not allowed in conditional expressions
SELECT IF(x > y, generate_series(1, 3), 0) FROM xy;

# IFNULL does not allow generator functions. Note that the error mentions
# COALESCE because IFNULL is parsed directly as a COALESCE expression.
statement error pq: set-returning functions are not allowed in conditional expressions
SELECT IFNULL(1, generate_series(1, 2));

# NULLIF allows generator functions.
query I rowsort
SELECT NULLIF(generate_series(1, x), generate_series(1, 3)) from xy;
----
NULL
NULL
NULL
NULL
NULL
NULL
NULL
NULL
NULL
NULL
NULL
NULL
4
NULL
NULL
NULL
4
5

# Regression test for #110952 - providing invalid arguments to unnest should
# not trigger an internal error.
statement error pgcode 42804 pq: could not determine polymorphic type: unnest\(string\)
SELECT unnest('{}');

statement error pgcode 42804 pq: could not determine polymorphic type: unnest\(string, string, string\)
SELECT unnest('{}', '{}', '{}');

statement error pgcode 42883 pq: unknown signature: unnest\(int\)
SELECT unnest(1);

statement error pgcode 42883 pq: unknown signature: unnest\(int, int, int\)
SELECT unnest(1, 2, 3);

statement error pgcode 42804 pq: could not determine polymorphic type: unnest\(unknown\)
SELECT unnest(NULL);

statement error pgcode 42804 pq: could not determine polymorphic type: unnest\(unknown, unknown, unknown\)
SELECT unnest(NULL, NULL, NULL);

# pg_expandarray handles return types similarly to unnest.
statement error pgcode 42804 pq: could not determine polymorphic type: information_schema._pg_expandarray\(string\)
SELECT information_schema._pg_expandarray('{}');

query T
SELECT unnest('{1}'::int[], '{2}', '{3}');
----
(1,2,3)

query T
SELECT unnest('{1}'::int[], '{}', '{}');
----
(1,,)

query T
SELECT unnest('{1}', '{2}', '{3}'::int[]);
----
(1,2,3)

query T
SELECT unnest('{}', '{}', '{3}'::int[]);
----
(,,3)
