# --------------------------------------------------
# FoldArray
# --------------------------------------------------

exec-ddl
CREATE TABLE t (
  x INT PRIMARY KEY
)
----
TABLE t
 ├── x int not null
 └── INDEX primary
      └── x int not null

opt expect=FoldArray
SELECT ARRAY[1, 2, 3] FROM t
----
project
 ├── columns: array:2(int[]!null)
 ├── fd: ()-->(2)
 ├── scan t
 └── projections
      └── const: ARRAY[1,2,3] [type=int[]]

# Do not fold if there is a non-constant element.
opt expect-not=FoldArray
SELECT ARRAY[1, 2, 3, x] FROM t
----
project
 ├── columns: array:2(int[])
 ├── scan t
 │    ├── columns: x:1(int!null)
 │    └── key: (1)
 └── projections
      └── ARRAY[1, 2, 3, x] [type=int[], outer=(1)]

opt expect=FoldArray
SELECT ARRAY['foo', 'bar']
----
values
 ├── columns: array:1(string[])
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (ARRAY['foo','bar'],) [type=tuple{string[]}]

# --------------------------------------------------
# FoldBinary
# --------------------------------------------------

# Fold constant.
opt expect=FoldBinary
SELECT 1::INT + 2::DECIMAL
----
values
 ├── columns: "?column?":1(decimal)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (3,) [type=tuple{decimal}]

# Don't fold: out of range error.
opt expect-not=FoldBinary
SELECT 9223372036854775800::INT + 9223372036854775800::INT
----
values
 ├── columns: "?column?":1(int)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (9223372036854775800 + 9223372036854775800,) [type=tuple{int}]

# Fold constant.
opt expect=FoldBinary
SELECT 1::INT - 2::INT
----
values
 ├── columns: "?column?":1(int)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (-1,) [type=tuple{int}]

# Don't fold: out of range error.
opt expect-not=FoldBinary
SELECT (-9223372036854775800)::INT - 9223372036854775800::INT
----
values
 ├── columns: "?column?":1(int)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (-9223372036854775800 - 9223372036854775800,) [type=tuple{int}]

# Fold constant.
opt expect=FoldBinary
SELECT 4::INT * 2::INT
----
values
 ├── columns: "?column?":1(int)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (8,) [type=tuple{int}]

# Don't fold: out of range error.
opt expect-not=FoldBinary
SELECT 9223372036854775800::INT * 9223372036854775800::INT
----
values
 ├── columns: "?column?":1(int)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (9223372036854775800 * 9223372036854775800,) [type=tuple{int}]

# Fold constant.
opt expect=FoldBinary
SELECT 1::FLOAT / 2::FLOAT
----
values
 ├── columns: "?column?":1(float)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (0.5,) [type=tuple{float}]

# Don't fold: divide by zero error.
opt expect-not=FoldBinary
SELECT 1::INT / 0::INT
----
values
 ├── columns: "?column?":1(decimal)
 ├── cardinality: [1 - 1]
 ├── side-effects
 ├── key: ()
 ├── fd: ()-->(1)
 └── (1 / 0,) [type=tuple{decimal}]

# Fold constant.
opt expect=FoldBinary
SELECT B'01' # B'11'
----
values
 ├── columns: "?column?":1(varbit)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (B'10',) [type=tuple{varbit}]

# Don't fold: cannot mix bit array sizes error.
opt expect-not=FoldBinary
SELECT B'01' # B'11001001010101'
----
values
 ├── columns: "?column?":1(varbit)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (B'01' # B'11001001010101',) [type=tuple{varbit}]

# Fold constant.
opt expect=FoldBinary
SELECT B'01' | B'11'
----
values
 ├── columns: "?column?":1(varbit)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (B'11',) [type=tuple{varbit}]

# Don't fold: cannot mix bit array sizes error.
opt expect-not=FoldBinary
SELECT B'01' | B'11001001010101'
----
values
 ├── columns: "?column?":1(varbit)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (B'01' | B'11001001010101',) [type=tuple{varbit}]

# Fold constant.
opt expect=FoldBinary
SELECT '2000-05-05 10:00:00+03':::TIMESTAMP - '2000-05-06 10:00:00+03':::TIMESTAMP
----
values
 ├── columns: "?column?":1(interval)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── ('-24:00:00',) [type=tuple{interval}]

# Fold constant.
opt expect=FoldBinary
SELECT '2000-05-05 10:00:00+03':::TIMESTAMP - '2000-05-06 10:00:00+03':::TIMESTAMPTZ
----
values
 ├── columns: "?column?":1(interval)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── ('-21:00:00',) [type=tuple{interval}]

# Fold constant.
opt expect=FoldBinary
SELECT ARRAY['a','b','c'] || 'd'
----
values
 ├── columns: "?column?":1(string[])
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (ARRAY['a','b','c','d'],) [type=tuple{string[]}]

# Fold constant.
opt expect=FoldBinary
SELECT ARRAY['a','b','c'] || ARRAY['d','e','f']
----
values
 ├── columns: "?column?":1(string[])
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (ARRAY['a','b','c','d','e','f'],) [type=tuple{string[]}]

# NULL should not be added to the array.
opt expect=FoldBinary
SELECT ARRAY[1,2,3] || NULL
----
values
 ├── columns: "?column?":1(int[])
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (ARRAY[1,2,3],) [type=tuple{int[]}]

# Regression test for #34270.
opt expect=FoldBinary
VALUES ((e'{}' ->> 0) || (e'{}' ->> 0))
----
values
 ├── columns: column1:1(string)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (NULL,) [type=tuple{string}]

# --------------------------------------------------
# FoldUnary
# --------------------------------------------------
opt expect=FoldUnary
SELECT -(1:::int)
----
values
 ├── columns: "?column?":1(int)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (-1,) [type=tuple{int}]

opt expect=FoldUnary
SELECT -(1:::float)
----
values
 ├── columns: "?column?":1(float)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (-1.0,) [type=tuple{float}]

# TODO(justin): it would be better if this produced an error in the optimizer
# rather than falling back to execution to error.
opt expect-not=FoldUnary format=show-all
SELECT -((-9223372036854775808)::int)
----
values
 ├── columns: "?column?":1(int)
 ├── cardinality: [1 - 1]
 ├── stats: [rows=1]
 ├── cost: 0.02
 ├── key: ()
 ├── fd: ()-->(1)
 ├── prune: (1)
 └── tuple [type=tuple{int}]
      └── unary-minus [type=int]
           └── const: -9223372036854775808 [type=int]

opt expect=FoldUnary format=show-all
SELECT -(1:::decimal)
----
values
 ├── columns: "?column?":1(decimal)
 ├── cardinality: [1 - 1]
 ├── stats: [rows=1]
 ├── cost: 0.02
 ├── key: ()
 ├── fd: ()-->(1)
 ├── prune: (1)
 └── tuple [type=tuple{decimal}]
      └── const: -1 [type=decimal]

opt expect=FoldUnary format=show-all
SELECT -('-1d'::interval);
----
values
 ├── columns: "?column?":1(interval)
 ├── cardinality: [1 - 1]
 ├── stats: [rows=1]
 ├── cost: 0.02
 ├── key: ()
 ├── fd: ()-->(1)
 ├── prune: (1)
 └── tuple [type=tuple{interval}]
      └── const: '1 day' [type=interval]

# TODO(justin): this seems incorrect but it's consistent with the existing
# planner. Revisit this: #26932.
opt expect=FoldUnary
SELECT -('-9223372036854775808d'::interval);
----
values
 ├── columns: "?column?":1(interval)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── ('-9223372036854775808 days',) [type=tuple{interval}]

# Fold constant.
opt expect=FoldUnary
SELECT ~(500::INT)
----
values
 ├── columns: "?column?":1(int)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (-501,) [type=tuple{int}]

# Fold constant.
opt expect=FoldUnary
SELECT ~('35.231.178.195'::INET)
----
values
 ├── columns: "?column?":1(inet)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── ('220.24.77.60',) [type=tuple{inet}]

# --------------------------------------------------
# FoldComparison
# --------------------------------------------------

opt expect=FoldComparison
SELECT 1::INT < 2::INT
----
values
 ├── columns: "?column?":1(bool)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (true,) [type=tuple{bool}]

opt expect=FoldComparison
SELECT 1::INT > 2::INT
----
values
 ├── columns: "?column?":1(bool)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (false,) [type=tuple{bool}]

opt expect=FoldComparison
SELECT 10.0::FLOAT <= 20.0::FLOAT
----
values
 ├── columns: "?column?":1(bool)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (true,) [type=tuple{bool}]

opt expect=FoldComparison
SELECT 10.0::FLOAT >= 20.0::FLOAT
----
values
 ├── columns: "?column?":1(bool)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (false,) [type=tuple{bool}]

opt expect=FoldComparison
SELECT 2.0::DECIMAL = 2::INT
----
values
 ├── columns: "?column?":1(bool)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (true,) [type=tuple{bool}]

opt expect=FoldComparison
SELECT 2.0::DECIMAL != 2::INT
----
values
 ├── columns: "?column?":1(bool)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (false,) [type=tuple{bool}]

opt expect=FoldComparison
SELECT 100 IS NOT DISTINCT FROM 200
----
values
 ├── columns: "?column?":1(bool)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (false,) [type=tuple{bool}]

opt expect=FoldComparison
SELECT 100 IS DISTINCT FROM 200
----
values
 ├── columns: "?column?":1(bool)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (true,) [type=tuple{bool}]

opt expect=FoldComparison
SELECT 'foo' IN ('a', 'b', 'c')
----
values
 ├── columns: "?column?":1(bool)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (false,) [type=tuple{bool}]

opt expect=FoldComparison
SELECT 'foo' NOT IN ('a', 'b', 'c')
----
values
 ├── columns: "?column?":1(bool)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (true,) [type=tuple{bool}]

opt expect=FoldComparison
SELECT 'foo' LIKE 'foobar'
----
values
 ├── columns: "?column?":1(bool)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (false,) [type=tuple{bool}]

opt expect=FoldComparison
SELECT 'foo' NOT LIKE 'foobar'
----
values
 ├── columns: "?column?":1(bool)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (true,) [type=tuple{bool}]

opt expect=FoldComparison
SELECT 'foo' ILIKE 'FOO%'
----
values
 ├── columns: "?column?":1(bool)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (true,) [type=tuple{bool}]

opt expect=FoldComparison
SELECT 'foo' NOT ILIKE 'FOO%'
----
values
 ├── columns: "?column?":1(bool)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (false,) [type=tuple{bool}]

opt expect=FoldComparison
SELECT 'monday' SIMILAR TO '_onday'
----
values
 ├── columns: "?column?":1(bool)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (true,) [type=tuple{bool}]

opt expect=FoldComparison
SELECT 'monday' NOT SIMILAR TO '_onday'
----
values
 ├── columns: "?column?":1(bool)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (false,) [type=tuple{bool}]

opt expect=FoldComparison
SELECT 'tuEsday' ~ 't[uU][eE]sday'
----
values
 ├── columns: "?column?":1(bool)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (true,) [type=tuple{bool}]

opt expect=FoldComparison
SELECT 'tuEsday' !~ 't[uU][eE]sday'
----
values
 ├── columns: "?column?":1(bool)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (false,) [type=tuple{bool}]

opt expect=FoldComparison
SELECT 'wednesday' ~* 'W.*y'
----
values
 ├── columns: "?column?":1(bool)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (true,) [type=tuple{bool}]

opt expect=FoldComparison
SELECT 'wednesday' !~* 'W.*y'
----
values
 ├── columns: "?column?":1(bool)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (false,) [type=tuple{bool}]

opt expect=FoldComparison
SELECT '[1, 2]'::JSONB <@ '[1, 2, 3]'::JSONB
----
values
 ├── columns: "?column?":1(bool)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (true,) [type=tuple{bool}]

opt expect=FoldComparison
SELECT ('a', 'b', 'c') = ('d', 'e', 'f')
----
values
 ├── columns: "?column?":1(bool)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (false,) [type=tuple{bool}]

# --------------------------------------------------
# FoldCast
# --------------------------------------------------

opt expect=FoldCast
SELECT 1::int/1
----
values
 ├── columns: "?column?":1(decimal)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 └── (1,) [type=tuple{decimal}]

# --------------------------------------------------
# FoldFunction
# --------------------------------------------------

opt expect=FoldFunction
SELECT length('abc'), upper('xyz'), lower('DEF')
----
values
 ├── columns: length:1(int) upper:2(string) lower:3(string)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1-3)
 └── (3, 'XYZ', 'def') [type=tuple{int, string, string}]

opt expect=FoldFunction
SELECT encode('abc', 'hex'), decode('616263', 'hex')
----
values
 ├── columns: encode:1(string) decode:2(bytes)
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(1,2)
 └── ('616263', '\x616263') [type=tuple{string, bytes}]

opt expect-not=FoldFunction
SELECT now(), current_user(), current_database()
----
values
 ├── columns: now:1(timestamptz) current_user:2(string) current_database:3(string)
 ├── cardinality: [1 - 1]
 ├── side-effects
 ├── key: ()
 ├── fd: ()-->(1-3)
 └── (now(), current_user(), current_database()) [type=tuple{timestamptz, string, string}]
