exec-ddl
CREATE TABLE a (k INT PRIMARY KEY, i INT, f FLOAT, s STRING, j JSON)
----

exec-ddl
CREATE TABLE xy (x INT PRIMARY KEY, y INT)
----

exec-ddl
CREATE TABLE computed (a INT PRIMARY KEY, b INT, c INT AS (a+b+1) STORED)
----

exec-ddl
CREATE TABLE b (k INT PRIMARY KEY, i INT, f FLOAT, s STRING NOT NULL, j JSON)
----

exec-ddl
CREATE TABLE virt (
  k INT PRIMARY KEY,
  i INT,
  s STRING,
  j JSON,
  v STRING AS (lower(s)) VIRTUAL,
  x JSON AS (j->'x') VIRTUAL,
  INDEX (v),
  INVERTED INDEX (x)
)
----

# --------------------------------------------------
# InlineConstVar
# --------------------------------------------------

norm expect=InlineConstVar
SELECT k FROM b WHERE i=5 AND i IN (1, 2, 3, 4, 5)
----
project
 ├── columns: k:1!null
 ├── key: (1)
 └── select
      ├── columns: k:1!null i:2!null
      ├── key: (1)
      ├── fd: ()-->(2)
      ├── scan b
      │    ├── columns: k:1!null i:2
      │    ├── key: (1)
      │    └── fd: (1)-->(2)
      └── filters
           └── i:2 = 5 [outer=(2), constraints=(/2: [/5 - /5]; tight), fd=()-->(2)]

norm expect=InlineConstVar
SELECT k FROM b WHERE i=8 AND 3 = mod(i, 5)
----
project
 ├── columns: k:1!null
 ├── key: (1)
 └── select
      ├── columns: k:1!null i:2!null
      ├── key: (1)
      ├── fd: ()-->(2)
      ├── scan b
      │    ├── columns: k:1!null i:2
      │    ├── key: (1)
      │    └── fd: (1)-->(2)
      └── filters
           └── i:2 = 8 [outer=(2), constraints=(/2: [/8 - /8]; tight), fd=()-->(2)]

norm expect=InlineConstVar
SELECT k FROM b WHERE i=4 AND i IN (1, 2, 3, 4)
----
project
 ├── columns: k:1!null
 ├── key: (1)
 └── select
      ├── columns: k:1!null i:2!null
      ├── key: (1)
      ├── fd: ()-->(2)
      ├── scan b
      │    ├── columns: k:1!null i:2
      │    ├── key: (1)
      │    └── fd: (1)-->(2)
      └── filters
           └── i:2 = 4 [outer=(2), constraints=(/2: [/4 - /4]; tight), fd=()-->(2)]

# Case that requires multiple iterations to fully inline.
norm expect=InlineConstVar
SELECT * FROM xy WHERE x=y AND y=4 AND x IN (1, 2, 3, 4)
----
select
 ├── columns: x:1!null y:2!null
 ├── cardinality: [0 - 1]
 ├── key: ()
 ├── fd: ()-->(1,2)
 ├── scan xy
 │    ├── columns: x:1!null y:2
 │    ├── key: (1)
 │    └── fd: (1)-->(2)
 └── filters
      ├── x:1 = 4 [outer=(1), constraints=(/1: [/4 - /4]; tight), fd=()-->(1)]
      └── y:2 = 4 [outer=(2), constraints=(/2: [/4 - /4]; tight), fd=()-->(2)]

norm expect=InlineConstVar
SELECT * FROM xy WHERE x=y AND y=4 AND x=3
----
values
 ├── columns: x:1!null y:2!null
 ├── cardinality: [0 - 0]
 ├── key: ()
 └── fd: ()-->(1,2)

# Can't inline composite types.
norm expect-not=InlineConstVar
SELECT * FROM (VALUES (0.0), (0.00), (0.000)) AS v (x) WHERE x = 0 AND x::STRING = '0.00';
----
select
 ├── columns: x:1!null
 ├── cardinality: [0 - 3]
 ├── immutable
 ├── fd: ()-->(1)
 ├── values
 │    ├── columns: column1:1!null
 │    ├── cardinality: [3 - 3]
 │    ├── (0.0,)
 │    ├── (0.00,)
 │    └── (0.000,)
 └── filters
      ├── column1:1 = 0 [outer=(1), immutable, constraints=(/1: [/0 - /0]; tight), fd=()-->(1)]
      └── column1:1::STRING = '0.00' [outer=(1), immutable]

# The rule should trigger, but not inline the composite type.
norm expect=InlineConstVar
SELECT * FROM (VALUES (0.0, 'a'), (0.00, 'b'), (0.000, 'b')) AS v (x, y) WHERE x = 0 AND x::STRING = '0.00' AND y = 'b' AND y IN ('a', 'b');
----
select
 ├── columns: x:1!null y:2!null
 ├── cardinality: [0 - 3]
 ├── immutable
 ├── fd: ()-->(1,2)
 ├── values
 │    ├── columns: column1:1!null column2:2!null
 │    ├── cardinality: [3 - 3]
 │    ├── (0.0, 'a')
 │    ├── (0.00, 'b')
 │    └── (0.000, 'b')
 └── filters
      ├── column1:1 = 0 [outer=(1), immutable, constraints=(/1: [/0 - /0]; tight), fd=()-->(1)]
      ├── column1:1::STRING = '0.00' [outer=(1), immutable]
      └── column2:2 = 'b' [outer=(2), constraints=(/2: [/'b' - /'b']; tight), fd=()-->(2)]

# Ensure that InlineConstVar fires before filter pushdown rules.
norm expect=InlineConstVar
SELECT * FROM a INNER JOIN xy ON True WHERE y=10 AND i<y
----
inner-join (cross)
 ├── columns: k:1!null i:2!null f:3 s:4 j:5 x:8!null y:9!null
 ├── key: (1,8)
 ├── fd: ()-->(9), (1)-->(2-5)
 ├── select
 │    ├── columns: k:1!null i:2!null f:3 s:4 j:5
 │    ├── key: (1)
 │    ├── fd: (1)-->(2-5)
 │    ├── scan a
 │    │    ├── columns: k:1!null i:2 f:3 s:4 j:5
 │    │    ├── key: (1)
 │    │    └── fd: (1)-->(2-5)
 │    └── filters
 │         └── i:2 < 10 [outer=(2), constraints=(/2: (/NULL - /9]; tight)]
 ├── select
 │    ├── columns: x:8!null y:9!null
 │    ├── key: (8)
 │    ├── fd: ()-->(9)
 │    ├── scan xy
 │    │    ├── columns: x:8!null y:9
 │    │    ├── key: (8)
 │    │    └── fd: (8)-->(9)
 │    └── filters
 │         └── y:9 = 10 [outer=(9), constraints=(/9: [/10 - /10]; tight), fd=()-->(9)]
 └── filters (true)

# --------------------------------------------------
# InlineProjectConstants
# --------------------------------------------------

# Inline constants from Project expression.
norm expect=InlineProjectConstants
UPDATE computed SET a=1, b=2
----
update computed
 ├── columns: <none>
 ├── fetch columns: a:6 b:7 c:8
 ├── update-mapping:
 │    ├── a_new:11 => a:1
 │    ├── b_new:12 => b:2
 │    └── c_comp:13 => c:3
 ├── cardinality: [0 - 0]
 ├── volatile, mutations
 └── project
      ├── columns: c_comp:13!null a_new:11!null b_new:12!null a:6!null b:7 c:8
      ├── key: (6)
      ├── fd: ()-->(11-13), (6)-->(7,8)
      ├── scan computed
      │    ├── columns: a:6!null b:7 c:8
      │    ├── computed column expressions
      │    │    └── c:8
      │    │         └── (a:6 + b:7) + 1
      │    ├── flags: avoid-full-scan
      │    ├── key: (6)
      │    └── fd: (6)-->(7,8)
      └── projections
           ├── 4 [as=c_comp:13]
           ├── 1 [as=a_new:11]
           └── 2 [as=b_new:12]

# Inline constants from Values expression.
norm expect=InlineProjectConstants
SELECT one+two+three+four FROM (VALUES (1, $1:::int, 2, $2:::int)) AS t(one, two, three, four)
----
project
 ├── columns: "?column?":5
 ├── cardinality: [1 - 1]
 ├── immutable, has-placeholder
 ├── key: ()
 ├── fd: ()-->(5)
 ├── values
 │    ├── columns: column2:2 column4:4
 │    ├── cardinality: [1 - 1]
 │    ├── has-placeholder
 │    ├── key: ()
 │    ├── fd: ()-->(2,4)
 │    └── ($1, $2)
 └── projections
      └── column4:4 + ((column2:2 + 1) + 2) [as="?column?":5, outer=(2,4), immutable]

# Multiple constant columns, multiple refs to each, interspersed with other
# columns.
norm expect=InlineProjectConstants
SELECT one+two, x, one*two, y FROM (SELECT x, 1 AS one, y, 2 AS two FROM xy)
----
project
 ├── columns: "?column?":7!null x:1!null "?column?":8!null y:2
 ├── key: (1)
 ├── fd: ()-->(7,8), (1)-->(2)
 ├── scan xy
 │    ├── columns: x:1!null y:2
 │    ├── key: (1)
 │    └── fd: (1)-->(2)
 └── projections
      ├── 3 [as="?column?":7]
      └── 2 [as="?column?":8]

# Constant column reference within correlated subquery (which becomes
# uncorrelated as a result).
norm expect=InlineProjectConstants
SELECT EXISTS(SELECT * FROM a WHERE k=one AND i=two) FROM (VALUES (1, 2)) AS t(one, two)
----
values
 ├── columns: exists:11
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(11)
 └── tuple
      └── coalesce
           ├── subquery
           │    └── project
           │         ├── columns: column12:12!null
           │         ├── cardinality: [0 - 1]
           │         ├── key: ()
           │         ├── fd: ()-->(12)
           │         ├── select
           │         │    ├── columns: k:3!null i:4!null
           │         │    ├── cardinality: [0 - 1]
           │         │    ├── key: ()
           │         │    ├── fd: ()-->(3,4)
           │         │    ├── scan a
           │         │    │    ├── columns: k:3!null i:4
           │         │    │    ├── key: (3)
           │         │    │    └── fd: (3)-->(4)
           │         │    └── filters
           │         │         ├── k:3 = 1 [outer=(3), constraints=(/3: [/1 - /1]; tight), fd=()-->(3)]
           │         │         └── i:4 = 2 [outer=(4), constraints=(/4: [/2 - /2]; tight), fd=()-->(4)]
           │         └── projections
           │              └── true [as=column12:12]
           └── false

# Do not inline constants from Values expression with multiple rows.
norm expect-not=InlineProjectConstants
SELECT one+two FROM (VALUES (1, 2), (3, 4)) AS t(one, two)
----
project
 ├── columns: "?column?":3!null
 ├── cardinality: [2 - 2]
 ├── immutable
 ├── values
 │    ├── columns: column1:1!null column2:2!null
 │    ├── cardinality: [2 - 2]
 │    ├── (1, 2)
 │    └── (3, 4)
 └── projections
      └── column1:1 + column2:2 [as="?column?":3, outer=(1,2), immutable]

# --------------------------------------------------
# InlineSelectConstants
# --------------------------------------------------

# Inline constants from Project expression.
norm expect=InlineSelectConstants
SELECT * FROM (SELECT 1 AS one from xy) WHERE one > 0
----
project
 ├── columns: one:5!null
 ├── fd: ()-->(5)
 ├── scan xy
 └── projections
      └── 1 [as=one:5]

# Inline constants from Values expression.
norm expect=InlineSelectConstants
SELECT *
FROM (VALUES ($1:::int, 1, $2:::float, 2)) AS t(one, two, three, four)
WHERE one = two OR three = four
----
select
 ├── columns: one:1 two:2!null three:3 four:4!null
 ├── cardinality: [0 - 1]
 ├── has-placeholder
 ├── key: ()
 ├── fd: ()-->(1-4)
 ├── values
 │    ├── columns: column1:1 column2:2!null column3:3 column4:4!null
 │    ├── cardinality: [1 - 1]
 │    ├── has-placeholder
 │    ├── key: ()
 │    ├── fd: ()-->(1-4)
 │    └── ($1, 1, $2, 2)
 └── filters
      └── (column1:1 = 1) OR (column3:3 = 2.0) [outer=(1,3)]

# Multiple constant columns, multiple refs to each, interspersed with other
# columns.
norm expect=InlineSelectConstants
SELECT * FROM (SELECT x, 1 AS one, y, 2 AS two FROM xy) WHERE x=one AND y=two
----
project
 ├── columns: x:1!null one:5!null y:2!null two:6!null
 ├── cardinality: [0 - 1]
 ├── key: ()
 ├── fd: ()-->(1,2,5,6)
 ├── select
 │    ├── columns: x:1!null y:2!null
 │    ├── cardinality: [0 - 1]
 │    ├── key: ()
 │    ├── fd: ()-->(1,2)
 │    ├── scan xy
 │    │    ├── columns: x:1!null y:2
 │    │    ├── key: (1)
 │    │    └── fd: (1)-->(2)
 │    └── filters
 │         ├── x:1 = 1 [outer=(1), constraints=(/1: [/1 - /1]; tight), fd=()-->(1)]
 │         └── y:2 = 2 [outer=(2), constraints=(/2: [/2 - /2]; tight), fd=()-->(2)]
 └── projections
      ├── 1 [as=one:5]
      └── 2 [as=two:6]

# Do not inline constants from Values expression with multiple rows.
norm expect-not=InlineSelectConstants
SELECT * FROM (VALUES (1, 2), (3, 4)) AS t(one, two) WHERE one=two
----
select
 ├── columns: one:1!null two:2!null
 ├── cardinality: [0 - 2]
 ├── fd: (1)==(2), (2)==(1)
 ├── values
 │    ├── columns: column1:1!null column2:2!null
 │    ├── cardinality: [2 - 2]
 │    ├── (1, 2)
 │    └── (3, 4)
 └── filters
      └── column1:1 = column2:2 [outer=(1,2), constraints=(/1: (/NULL - ]; /2: (/NULL - ]), fd=(1)==(2), (2)==(1)]

# --------------------------------------------------
# InlineJoinConstantsLeft + InlineJoinConstantsRight
# --------------------------------------------------
norm expect=InlineJoinConstantsLeft
SELECT * FROM (SELECT 1 AS one) LEFT JOIN a ON k=one
----
left-join (cross)
 ├── columns: one:1!null k:2 i:3 f:4 s:5 j:6
 ├── cardinality: [1 - 1]
 ├── multiplicity: left-rows(exactly-one), right-rows(exactly-one)
 ├── key: ()
 ├── fd: ()-->(1-6)
 ├── values
 │    ├── columns: one:1!null
 │    ├── cardinality: [1 - 1]
 │    ├── key: ()
 │    ├── fd: ()-->(1)
 │    └── (1,)
 ├── select
 │    ├── columns: k:2!null i:3 f:4 s:5 j:6
 │    ├── cardinality: [0 - 1]
 │    ├── key: ()
 │    ├── fd: ()-->(2-6)
 │    ├── scan a
 │    │    ├── columns: k:2!null i:3 f:4 s:5 j:6
 │    │    ├── key: (2)
 │    │    └── fd: (2)-->(3-6)
 │    └── filters
 │         └── k:2 = 1 [outer=(2), constraints=(/2: [/1 - /1]; tight), fd=()-->(2)]
 └── filters (true)

norm expect=InlineJoinConstantsRight
SELECT * FROM a FULL JOIN (SELECT 1 AS one) ON k=one
----
full-join (cross)
 ├── columns: k:1 i:2 f:3 s:4 j:5 one:8
 ├── cardinality: [1 - ]
 ├── multiplicity: left-rows(exactly-one), right-rows(one-or-more)
 ├── key: (1)
 ├── fd: (1)-->(2-5,8)
 ├── scan a
 │    ├── columns: k:1!null i:2 f:3 s:4 j:5
 │    ├── key: (1)
 │    └── fd: (1)-->(2-5)
 ├── values
 │    ├── columns: one:8!null
 │    ├── cardinality: [1 - 1]
 │    ├── key: ()
 │    ├── fd: ()-->(8)
 │    └── (1,)
 └── filters
      └── k:1 = 1 [outer=(1), constraints=(/1: [/1 - /1]; tight), fd=()-->(1)]

norm expect=(InlineJoinConstantsLeft,InlineJoinConstantsRight)
SELECT * FROM (SELECT 1 AS one) INNER JOIN (SELECT 2 AS two) ON one=two
----
values
 ├── columns: one:1!null two:2!null
 ├── cardinality: [0 - 0]
 ├── key: ()
 └── fd: ()-->(1,2)

# Constant column exists in input, but is not referenced.
norm expect-not=(InlineJoinConstantsLeft,InlineJoinConstantsRight)
SELECT * FROM a INNER JOIN (SELECT 1 AS one, y FROM xy) ON k=y
----
inner-join (hash)
 ├── columns: k:1!null i:2 f:3 s:4 j:5 one:12!null y:9!null
 ├── multiplicity: left-rows(zero-or-more), right-rows(zero-or-one)
 ├── fd: ()-->(12), (1)-->(2-5), (1)==(9), (9)==(1)
 ├── scan a
 │    ├── columns: k:1!null i:2 f:3 s:4 j:5
 │    ├── key: (1)
 │    └── fd: (1)-->(2-5)
 ├── project
 │    ├── columns: one:12!null y:9
 │    ├── fd: ()-->(12)
 │    ├── scan xy
 │    │    └── columns: y:9
 │    └── projections
 │         └── 1 [as=one:12]
 └── filters
      └── k:1 = y:9 [outer=(1,9), constraints=(/1: (/NULL - ]; /9: (/NULL - ]), fd=(1)==(9), (9)==(1)]

# Regression test for #50841
exec-ddl
CREATE TABLE kv  (k  INT8 PRIMARY KEY, v  INT8);
----

exec-ddl
CREATE TABLE kv2 (k2 INT8 PRIMARY KEY, v2 INT8);
----

# Ensure that lookup joins are used.
opt expect-not=InlineJoinConstantsLeft format=hide-all
SELECT v, v2
FROM (SELECT unnest('{1}'::INT8[]) AS lookup_k)
INNER LOOKUP JOIN (SELECT k, v FROM kv) ON k = lookup_k
INNER LOOKUP JOIN (SELECT k2, v2 FROM kv2) ON k2 = lookup_k;
----
project
 └── inner-join (lookup kv2)
      ├── flags: force lookup join (into right side)
      ├── lookup columns are key
      ├── inner-join (lookup kv)
      │    ├── flags: force lookup join (into right side)
      │    ├── lookup columns are key
      │    ├── values
      │    │    └── (1,)
      │    └── filters (true)
      └── filters (true)

# Ensure that merge joins are used.
opt expect-not=InlineJoinConstantsLeft format=hide-all
SELECT v, v2
FROM (SELECT unnest('{1}'::INT8[]) AS lookup_k)
INNER MERGE JOIN (SELECT k, v FROM kv) ON k = lookup_k
INNER MERGE JOIN (SELECT k2, v2 FROM kv2) ON k2 = lookup_k;
----
project
 └── inner-join (merge)
      ├── flags: force merge join
      ├── inner-join (merge)
      │    ├── flags: force merge join
      │    ├── values
      │    │    └── (1,)
      │    ├── scan kv
      │    └── filters (true)
      ├── scan kv2
      └── filters (true)

# Ensure that merge joins are used.
opt expect-not=InlineJoinConstantsRight format=hide-all
SELECT v, v2
FROM (SELECT k, v FROM kv)
INNER MERGE JOIN (SELECT unnest('{1}'::INT8[]) AS lookup_k) ON k = lookup_k
INNER MERGE JOIN (SELECT k2, v2 FROM kv2) ON k2 = lookup_k;
----
project
 └── inner-join (merge)
      ├── flags: force merge join
      ├── project
      │    ├── scan kv
      │    │    └── constraint: /1: [/1 - /1]
      │    └── projections
      │         └── 1
      ├── scan kv2
      └── filters (true)

# --------------------------------------------------
# PushSelectIntoInlinableProject
# --------------------------------------------------

# Inline comparison.
norm expect=PushSelectIntoInlinableProject
SELECT * FROM (SELECT i=1 AS expr FROM a) a WHERE expr IS NULL
----
project
 ├── columns: expr:8
 ├── select
 │    ├── columns: i:2
 │    ├── scan a
 │    │    └── columns: i:2
 │    └── filters
 │         └── (i:2 = 1) IS NULL [outer=(2)]
 └── projections
      └── i:2 = 1 [as=expr:8, outer=(2)]

# Inline arithmetic.
norm expect=PushSelectIntoInlinableProject
SELECT * FROM (SELECT k*2+1 AS expr FROM a) a WHERE expr > 10
----
project
 ├── columns: expr:8!null
 ├── immutable
 ├── select
 │    ├── columns: k:1!null
 │    ├── immutable
 │    ├── key: (1)
 │    ├── scan a
 │    │    ├── columns: k:1!null
 │    │    └── key: (1)
 │    └── filters
 │         └── (k:1 * 2) > 9 [outer=(1), immutable]
 └── projections
      └── (k:1 * 2) + 1 [as=expr:8, outer=(1), immutable]

# Inline boolean logic.
norm expect=PushSelectIntoInlinableProject
SELECT * FROM (SELECT NOT(k>1 AND k<=5) AS expr FROM a) a WHERE expr
----
project
 ├── columns: expr:8!null
 ├── select
 │    ├── columns: k:1!null
 │    ├── key: (1)
 │    ├── scan a
 │    │    ├── columns: k:1!null
 │    │    └── key: (1)
 │    └── filters
 │         └── (k:1 <= 1) OR (k:1 > 5) [outer=(1), constraints=(/1: (/NULL - /1] [/6 - ]; tight)]
 └── projections
      └── (k:1 <= 1) OR (k:1 > 5) [as=expr:8, outer=(1)]

# Inline constants.
norm expect=PushSelectIntoInlinableProject
SELECT * FROM (SELECT (f IS NULL OR f != 10.5) AS expr FROM a) a WHERE expr
----
project
 ├── columns: expr:8
 ├── select
 │    ├── columns: f:3
 │    ├── scan a
 │    │    └── columns: f:3
 │    └── filters
 │         └── (f:3 IS NULL) OR (f:3 != 10.5) [outer=(3), constraints=(/3: [/NULL - /10.499999999999998] [/10.500000000000002 - ]; tight)]
 └── projections
      └── (f:3 IS NULL) OR (f:3 != 10.5) [as=expr:8, outer=(3)]

# Reference the expression to inline multiple times.
norm expect=PushSelectIntoInlinableProject
SELECT * FROM (SELECT f+1 AS expr FROM a) a WHERE expr=expr
----
project
 ├── columns: expr:8
 ├── immutable
 ├── select
 │    ├── columns: f:3
 │    ├── immutable
 │    ├── scan a
 │    │    └── columns: f:3
 │    └── filters
 │         └── (f:3 + 1.0) IS DISTINCT FROM CAST(NULL AS FLOAT8) [outer=(3), immutable]
 └── projections
      └── f:3 + 1.0 [as=expr:8, outer=(3), immutable]

# Use outer references in both inlined expression and in referencing expression.
norm expect=PushSelectIntoInlinableProject
SELECT * FROM a WHERE EXISTS(SELECT * FROM (SELECT (x-i) AS expr FROM xy) WHERE expr > i*i)
----
semi-join (cross)
 ├── columns: k:1!null i:2 f:3 s:4 j:5
 ├── immutable
 ├── key: (1)
 ├── fd: (1)-->(2-5)
 ├── scan a
 │    ├── columns: k:1!null i:2 f:3 s:4 j:5
 │    ├── key: (1)
 │    └── fd: (1)-->(2-5)
 ├── scan xy
 │    ├── columns: x:8!null
 │    └── key: (8)
 └── filters
      └── (x:8 - i:2) > (i:2 * i:2) [outer=(2,8), immutable]

exec-ddl
CREATE TABLE crdb_internal.zones (
    zone_id INT NOT NULL,
    cli_specifier STRING NULL,
    config_yaml BYTES NOT NULL,
    config_protobuf BYTES NOT NULL
)
----

# Regression test for #28827. Ensure that inlining is not applied when there
# is a correlated subquery in the filter.
norm
SELECT
  subq_0.c0 AS c0
FROM (SELECT zone_id+1 AS c0, zone_id+2 as c1 FROM crdb_internal.zones) AS subq_0
WHERE
  1
  >= CASE
    WHEN subq_0.c1 IS NOT NULL
    THEN pg_catalog.extract(
      CAST(
        CASE
        WHEN
        (
            EXISTS(
              SELECT
                ref_1.config_yaml AS c0,
                ref_1.config_yaml AS c1,
                subq_0.c0 AS c2,
                ref_1.config_yaml AS c3
              FROM
                crdb_internal.zones AS ref_1
              WHERE
                subq_0.c0 IS NOT NULL
              LIMIT
                52
            )
          )
        THEN pg_catalog.version()
        ELSE pg_catalog.version()
        END
          AS TEXT
      ),
      CAST(pg_catalog.current_date() AS DATE)
    )
    ELSE 1
    END
LIMIT
  107
----
project
 ├── columns: c0:8!null
 ├── cardinality: [0 - 107]
 ├── volatile
 └── limit
      ├── columns: c0:8!null c1:9!null
      ├── cardinality: [0 - 107]
      ├── volatile
      ├── select
      │    ├── columns: c0:8!null c1:9!null
      │    ├── volatile
      │    ├── limit hint: 107.00
      │    ├── project
      │    │    ├── columns: c0:8!null c1:9!null
      │    │    ├── immutable
      │    │    ├── limit hint: 321.00
      │    │    ├── scan zones
      │    │    │    ├── columns: crdb_internal.public.zones.zone_id:1!null
      │    │    │    └── limit hint: 321.00
      │    │    └── projections
      │    │         ├── crdb_internal.public.zones.zone_id:1 + 1 [as=c0:8, outer=(1), immutable]
      │    │         └── crdb_internal.public.zones.zone_id:1 + 2 [as=c1:9, outer=(1), immutable]
      │    └── filters
      │         └── le [outer=(8,9), volatile, correlated-subquery]
      │              ├── case
      │              │    ├── true
      │              │    ├── when
      │              │    │    ├── c1:9 IS NOT NULL
      │              │    │    └── function: extract
      │              │    │         ├── case
      │              │    │         │    ├── true
      │              │    │         │    ├── when
      │              │    │         │    │    ├── exists
      │              │    │         │    │    │    └── select
      │              │    │         │    │    │         ├── columns: ref_1.config_yaml:12!null
      │              │    │         │    │    │         ├── outer: (8)
      │              │    │         │    │    │         ├── scan zones [as=ref_1]
      │              │    │         │    │    │         │    └── columns: ref_1.config_yaml:12!null
      │              │    │         │    │    │         └── filters
      │              │    │         │    │    │              └── c0:8 IS NOT NULL [outer=(8), constraints=(/8: (/NULL - ]; tight)]
      │              │    │         │    │    └── version()
      │              │    │         │    └── version()
      │              │    │         └── '2017-05-10'
      │              │    └── 1.0
      │              └── 1.0
      └── 107

# --------------------------------------------------
# InlineSelectVirtualColumns
# --------------------------------------------------

# Inline indexed virtual columns in a Select below the Project.
norm expect=InlineSelectVirtualColumns
SELECT * FROM virt WHERE v = 'foo'
----
project
 ├── columns: k:1!null i:2 s:3 j:4 v:5 x:6
 ├── immutable
 ├── key: (1)
 ├── fd: (1)-->(2-4,6), (3)-->(5)
 ├── select
 │    ├── columns: k:1!null i:2 s:3 j:4
 │    ├── immutable
 │    ├── key: (1)
 │    ├── fd: (1)-->(2-4)
 │    ├── scan virt
 │    │    ├── columns: k:1!null i:2 s:3 j:4
 │    │    ├── computed column expressions
 │    │    │    ├── v:5
 │    │    │    │    └── lower(s:3)
 │    │    │    └── x:6
 │    │    │         └── j:4->'x'
 │    │    ├── key: (1)
 │    │    └── fd: (1)-->(2-4)
 │    └── filters
 │         └── lower(s:3) = 'foo' [outer=(3), immutable]
 └── projections
      ├── lower(s:3) [as=v:5, outer=(3), immutable]
      └── j:4->'x' [as=x:6, outer=(4), immutable]

# Inline inverted-indexed virtual columns.
norm expect=InlineSelectVirtualColumns
SELECT * FROM virt WHERE x @> '1'
----
project
 ├── columns: k:1!null i:2 s:3 j:4 v:5 x:6
 ├── immutable
 ├── key: (1)
 ├── fd: (1)-->(2-4,6), (3)-->(5)
 ├── select
 │    ├── columns: k:1!null i:2 s:3 j:4
 │    ├── immutable
 │    ├── key: (1)
 │    ├── fd: (1)-->(2-4)
 │    ├── scan virt
 │    │    ├── columns: k:1!null i:2 s:3 j:4
 │    │    ├── computed column expressions
 │    │    │    ├── v:5
 │    │    │    │    └── lower(s:3)
 │    │    │    └── x:6
 │    │    │         └── j:4->'x'
 │    │    ├── key: (1)
 │    │    └── fd: (1)-->(2-4)
 │    └── filters
 │         └── (j:4->'x') @> '1' [outer=(4), immutable]
 └── projections
      ├── lower(s:3) [as=v:5, outer=(3), immutable]
      └── j:4->'x' [as=x:6, outer=(4), immutable]

# Split the filters and inline only virtual columns.
norm expect=InlineSelectVirtualColumns
SELECT * FROM (
  SELECT i, v, upper(s) AS w FROM virt
) WHERE v = 'foo' AND w = 'FOO' AND i = 10
----
select
 ├── columns: i:2!null v:5 w:10!null
 ├── immutable
 ├── fd: ()-->(2,10)
 ├── project
 │    ├── columns: w:10 v:5 i:2!null
 │    ├── immutable
 │    ├── fd: ()-->(2)
 │    ├── select
 │    │    ├── columns: i:2!null s:3
 │    │    ├── immutable
 │    │    ├── fd: ()-->(2)
 │    │    ├── scan virt
 │    │    │    ├── columns: i:2 s:3
 │    │    │    └── computed column expressions
 │    │    │         ├── v:5
 │    │    │         │    └── lower(s:3)
 │    │    │         └── x:6
 │    │    │              └── j:4->'x'
 │    │    └── filters
 │    │         ├── lower(s:3) = 'foo' [outer=(3), immutable]
 │    │         └── i:2 = 10 [outer=(2), constraints=(/2: [/10 - /10]; tight), fd=()-->(2)]
 │    └── projections
 │         ├── upper(s:3) [as=w:10, outer=(3), immutable]
 │         └── lower(s:3) [as=v:5, outer=(3), immutable]
 └── filters
      └── w:10 = 'FOO' [outer=(10), constraints=(/10: [/'FOO' - /'FOO']; tight), fd=()-->(10)]

# Do not inline correlated subqueries.
norm expect-not=InlineSelectVirtualColumns
SELECT * FROM virt v1
WHERE EXISTS (
  SELECT * FROM virt v2 WHERE v1.v = v2.s
)
----
semi-join (hash)
 ├── columns: k:1!null i:2 s:3 j:4 v:5 x:6
 ├── immutable
 ├── key: (1)
 ├── fd: (1)-->(2-4,6), (3)-->(5)
 ├── project
 │    ├── columns: v:5 x:6 k:1!null i:2 s:3 j:4
 │    ├── immutable
 │    ├── key: (1)
 │    ├── fd: (1)-->(2-4,6), (3)-->(5)
 │    ├── scan virt
 │    │    ├── columns: k:1!null i:2 s:3 j:4
 │    │    ├── computed column expressions
 │    │    │    ├── v:5
 │    │    │    │    └── lower(s:3)
 │    │    │    └── x:6
 │    │    │         └── j:4->'x'
 │    │    ├── key: (1)
 │    │    └── fd: (1)-->(2-4)
 │    └── projections
 │         ├── lower(s:3) [as=v:5, outer=(3), immutable]
 │         └── j:4->'x' [as=x:6, outer=(4), immutable]
 ├── scan virt
 │    ├── columns: s:12
 │    └── computed column expressions
 │         ├── v:14
 │         │    └── lower(s:12)
 │         └── x:15
 │              └── j:13->'x'
 └── filters
      └── v:5 = s:12 [outer=(5,12), constraints=(/5: (/NULL - ]; /12: (/NULL - ]), fd=(5)==(12), (12)==(5)]

# Regression test for #63794. Inlining filters on virtual columns during
# exploration should not violate the ordering choice that all columns in an
# ordering column group should be equal according to the expression's FD.
exec-ddl
CREATE TABLE t63794_a (a INT)
----

exec-ddl
CREATE TABLE t63794_bc (b INT, c INT AS (b % 2) VIRTUAL, INDEX (b))
----

opt format=hide-all
SELECT a.a
FROM t63794_a AS a
  JOIN t63794_bc AS bc1
    JOIN t63794_bc AS bc2 ON true
  ON a.a = bc1.b AND
    bc1.b = bc2.b AND
    bc1.c = bc2.c
  JOIN t63794_bc AS bc3 ON
    bc1.b = bc3.b AND bc2.b = bc3.c
----
project
 └── inner-join (hash)
      ├── scan t63794_a [as=a]
      ├── inner-join (merge)
      │    ├── project
      │    │    ├── scan t63794_bc@t63794_bc_b_idx
      │    │    └── projections
      │    │         └── b % 2
      │    ├── inner-join (merge)
      │    │    ├── project
      │    │    │    ├── scan t63794_bc@t63794_bc_b_idx
      │    │    │    └── projections
      │    │    │         └── b % 2
      │    │    ├── project
      │    │    │    ├── scan t63794_bc@t63794_bc_b_idx
      │    │    │    └── projections
      │    │    │         └── b % 2
      │    │    └── filters (true)
      │    └── filters (true)
      └── filters
           └── a = b

# --------------------------------------------------
# InlineProjectInProject
# --------------------------------------------------
norm expect=InlineProjectInProject
SELECT NOT(expr), i+1 AS r FROM (SELECT k=1 AS expr, i FROM a)
----
project
 ├── columns: "?column?":9!null r:10
 ├── immutable
 ├── scan a
 │    ├── columns: k:1!null i:2
 │    ├── key: (1)
 │    └── fd: (1)-->(2)
 └── projections
      ├── k:1 != 1 [as="?column?":9, outer=(1)]
      └── i:2 + 1 [as=r:10, outer=(2), immutable]

# Multiple synthesized column references to same inner passthrough column
# (should still inline).
norm expect=InlineProjectInProject
SELECT x+1, x+2, y1+2 FROM (SELECT x, y+1 AS y1 FROM xy)
----
project
 ├── columns: "?column?":6!null "?column?":7!null "?column?":8
 ├── immutable
 ├── scan xy
 │    ├── columns: x:1!null y:2
 │    ├── key: (1)
 │    └── fd: (1)-->(2)
 └── projections
      ├── x:1 + 1 [as="?column?":6, outer=(1), immutable]
      ├── x:1 + 2 [as="?column?":7, outer=(1), immutable]
      └── (y:2 + 1) + 2 [as="?column?":8, outer=(2), immutable]

# Synthesized and passthrough references to same inner passthrough column
# (should still inline).
norm expect=InlineProjectInProject
SELECT x+y1 FROM (SELECT x, y+1 AS y1 FROM xy) ORDER BY x
----
project
 ├── columns: "?column?":6  [hidden: x:1!null]
 ├── immutable
 ├── key: (1)
 ├── fd: (1)-->(6)
 ├── ordering: +1
 ├── scan xy
 │    ├── columns: x:1!null y:2
 │    ├── key: (1)
 │    ├── fd: (1)-->(2)
 │    └── ordering: +1
 └── projections
      └── x:1 + (y:2 + 1) [as="?column?":6, outer=(1,2), immutable]

# Inline multiple expressions.
norm expect=InlineProjectInProject
SELECT expr+1 AS r, i, expr2 || 'bar' AS s FROM (SELECT k+1 AS expr, s || 'foo' AS expr2, i FROM a)
----
project
 ├── columns: r:10!null i:2 s:11
 ├── immutable
 ├── scan a
 │    ├── columns: k:1!null i:2 a.s:4
 │    ├── key: (1)
 │    └── fd: (1)-->(2,4)
 └── projections
      ├── (k:1 + 1) + 1 [as=r:10, outer=(1), immutable]
      └── (a.s:4 || 'foo') || 'bar' [as=s:11, outer=(4), immutable]

# Don't inline when there are multiple references.
norm expect-not=InlineProjectInProject
SELECT expr, expr*2 AS r FROM (SELECT k+1 AS expr FROM a)
----
project
 ├── columns: expr:8!null r:9!null
 ├── immutable
 ├── fd: (8)-->(9)
 ├── project
 │    ├── columns: expr:8!null
 │    ├── immutable
 │    ├── scan a
 │    │    ├── columns: k:1!null
 │    │    └── key: (1)
 │    └── projections
 │         └── k:1 + 1 [as=expr:8, outer=(1), immutable]
 └── projections
      └── expr:8 * 2 [as=r:9, outer=(8), immutable]

# Uncorrelated subquery should not block inlining.
norm expect=InlineProjectInProject
SELECT EXISTS(SELECT * FROM xy WHERE x=1 OR x=2), expr*2 AS r FROM (SELECT k+1 AS expr FROM a)
----
project
 ├── columns: exists:15 r:16!null
 ├── immutable
 ├── scan a
 │    ├── columns: k:1!null
 │    └── key: (1)
 └── projections
      ├── coalesce [as=exists:15, subquery]
      │    ├── subquery
      │    │    └── project
      │    │         ├── columns: column14:14!null
      │    │         ├── cardinality: [0 - 1]
      │    │         ├── key: ()
      │    │         ├── fd: ()-->(14)
      │    │         ├── limit
      │    │         │    ├── columns: x:9!null
      │    │         │    ├── cardinality: [0 - 1]
      │    │         │    ├── key: ()
      │    │         │    ├── fd: ()-->(9)
      │    │         │    ├── select
      │    │         │    │    ├── columns: x:9!null
      │    │         │    │    ├── cardinality: [0 - 2]
      │    │         │    │    ├── key: (9)
      │    │         │    │    ├── limit hint: 1.00
      │    │         │    │    ├── scan xy
      │    │         │    │    │    ├── columns: x:9!null
      │    │         │    │    │    ├── key: (9)
      │    │         │    │    │    └── limit hint: 500.00
      │    │         │    │    └── filters
      │    │         │    │         └── (x:9 = 1) OR (x:9 = 2) [outer=(9), constraints=(/9: [/1 - /1] [/2 - /2]; tight)]
      │    │         │    └── 1
      │    │         └── projections
      │    │              └── true [as=column14:14]
      │    └── false
      └── (k:1 + 1) * 2 [as=r:16, outer=(1), immutable]

# Correlated subquery should be hoisted as usual.
norm expect=InlineProjectInProject
SELECT EXISTS(SELECT * FROM xy WHERE expr<0) FROM (SELECT k+1 AS expr FROM a)
----
project
 ├── columns: exists:14!null
 ├── immutable
 ├── group-by (hash)
 │    ├── columns: k:1!null canary_agg:15
 │    ├── grouping columns: k:1!null
 │    ├── immutable
 │    ├── key: (1)
 │    ├── fd: (1)-->(15)
 │    ├── left-join (cross)
 │    │    ├── columns: k:1!null expr:8!null x:9
 │    │    ├── immutable
 │    │    ├── key: (1,9)
 │    │    ├── fd: (1)-->(8)
 │    │    ├── project
 │    │    │    ├── columns: expr:8!null k:1!null
 │    │    │    ├── immutable
 │    │    │    ├── key: (1)
 │    │    │    ├── fd: (1)-->(8)
 │    │    │    ├── scan a
 │    │    │    │    ├── columns: k:1!null
 │    │    │    │    └── key: (1)
 │    │    │    └── projections
 │    │    │         └── k:1 + 1 [as=expr:8, outer=(1), immutable]
 │    │    ├── scan xy
 │    │    │    ├── columns: x:9!null
 │    │    │    └── key: (9)
 │    │    └── filters
 │    │         └── expr:8 < 0 [outer=(8), constraints=(/8: (/NULL - /-1]; tight)]
 │    └── aggregations
 │         └── const-not-null-agg [as=canary_agg:15, outer=(9)]
 │              └── x:9
 └── projections
      └── canary_agg:15 IS NOT NULL [as=exists:14, outer=(15)]

# After c is replaced with k+2, (k+2) > 2 should be simplified to k > 0.
norm
SELECT c FROM (SELECT k+2 AS c FROM a) AS t WHERE c > 2;
----
project
 ├── columns: c:8!null
 ├── immutable
 ├── select
 │    ├── columns: k:1!null
 │    ├── key: (1)
 │    ├── scan a
 │    │    ├── columns: k:1!null
 │    │    └── key: (1)
 │    └── filters
 │         └── k:1 > 0 [outer=(1), constraints=(/1: [/1 - ]; tight)]
 └── projections
      └── k:1 + 2 [as=c:8, outer=(1), immutable]

exec-ddl
CREATE TABLE t136250 (
  col1_0 BOOL,
  col1_1 REFCURSOR,
  col1_2 PG_LSN,
  col1_3 BOX2D,
  col1_4 INT8,
  col1_5 STRING,
  col1_6 STRING,
  col1_7 INT8,
  col1_8 STRING AS (lower(NULL)) VIRTUAL,
  col1_9 STRING,
  foo_col DECIMAL,
  PRIMARY KEY (col1_8),
  INDEX (CAST(col1_3 AS STRING), CAST(col1_2 AS STRING))
);
----

# Regression test for #136250.
opt disable=(MergeProjects,PruneProjectCols) format=hide-all
SELECT NULL
  FROM t136250 AS t1
  JOIN t136250 AS t2 ON true
  FULL JOIN t136250 AS t3 ON true
  JOIN t136250 ON true
  JOIN t136250 AS t4 ON true
 WHERE NOT EXISTS (SELECT NULL FROM t136250 AS t5 JOIN t136250 ON true)
    OR NOT EXISTS (SELECT NULL FROM t136250 AS t6 JOIN t136250 AS t7 ON t6.col1_5 = t7.col1_5);
----
project
 ├── project
 │    ├── inner-join (cross)
 │    │    ├── select
 │    │    │    ├── scan t136250
 │    │    │    │    └── computed column expressions
 │    │    │    │         ├── col1_8
 │    │    │    │         │    └── CAST(NULL AS STRING)
 │    │    │    │         ├── crdb_internal_idx_expr
 │    │    │    │         │    └── col1_3::STRING
 │    │    │    │         └── crdb_internal_idx_expr_1
 │    │    │    │              └── col1_2::STRING
 │    │    │    └── filters
 │    │    │         └── or
 │    │    │              ├── not
 │    │    │              │    └── coalesce
 │    │    │              │         ├── subquery
 │    │    │              │         │    └── project
 │    │    │              │         │         ├── inner-join (cross)
 │    │    │              │         │         │    ├── project
 │    │    │              │         │         │    │    ├── scan t136250
 │    │    │              │         │         │    │    │    └── computed column expressions
 │    │    │              │         │         │    │    │         ├── col1_8
 │    │    │              │         │         │    │    │         │    └── CAST(NULL AS STRING)
 │    │    │              │         │         │    │    │         ├── crdb_internal_idx_expr
 │    │    │              │         │         │    │    │         │    └── col1_3::STRING
 │    │    │              │         │         │    │    │         └── crdb_internal_idx_expr_1
 │    │    │              │         │         │    │    │              └── col1_2::STRING
 │    │    │              │         │         │    │    └── projections
 │    │    │              │         │         │    │         ├── col1_3::STRING
 │    │    │              │         │         │    │         └── col1_2::STRING
 │    │    │              │         │         │    ├── project
 │    │    │              │         │         │    │    ├── scan t136250
 │    │    │              │         │         │    │    │    └── computed column expressions
 │    │    │              │         │         │    │    │         ├── col1_8
 │    │    │              │         │         │    │    │         │    └── CAST(NULL AS STRING)
 │    │    │              │         │         │    │    │         ├── crdb_internal_idx_expr
 │    │    │              │         │         │    │    │         │    └── col1_3::STRING
 │    │    │              │         │         │    │    │         └── crdb_internal_idx_expr_1
 │    │    │              │         │         │    │    │              └── col1_2::STRING
 │    │    │              │         │         │    │    └── projections
 │    │    │              │         │         │    │         ├── col1_3::STRING
 │    │    │              │         │         │    │         └── col1_2::STRING
 │    │    │              │         │         │    └── filters (true)
 │    │    │              │         │         └── projections
 │    │    │              │         │              └── true
 │    │    │              │         └── false
 │    │    │              └── not
 │    │    │                   └── coalesce
 │    │    │                        ├── subquery
 │    │    │                        │    └── project
 │    │    │                        │         ├── project
 │    │    │                        │         │    ├── project
 │    │    │                        │         │    │    ├── inner-join (lookup t136250)
 │    │    │                        │         │    │    │    ├── lookup columns are key
 │    │    │                        │         │    │    │    ├── project
 │    │    │                        │         │    │    │    │    ├── scan t136250
 │    │    │                        │         │    │    │    │    │    └── computed column expressions
 │    │    │                        │         │    │    │    │    │         ├── col1_8
 │    │    │                        │         │    │    │    │    │         │    └── CAST(NULL AS STRING)
 │    │    │                        │         │    │    │    │    │         ├── crdb_internal_idx_expr
 │    │    │                        │         │    │    │    │    │         │    └── col1_3::STRING
 │    │    │                        │         │    │    │    │    │         └── crdb_internal_idx_expr_1
 │    │    │                        │         │    │    │    │    │              └── col1_2::STRING
 │    │    │                        │         │    │    │    │    └── projections
 │    │    │                        │         │    │    │    │         └── CAST(NULL AS STRING)
 │    │    │                        │         │    │    │    └── filters
 │    │    │                        │         │    │    │         └── col1_5 = col1_5
 │    │    │                        │         │    │    └── projections
 │    │    │                        │         │    │         ├── col1_3::STRING
 │    │    │                        │         │    │         └── col1_2::STRING
 │    │    │                        │         │    └── projections
 │    │    │                        │         │         ├── col1_3::STRING
 │    │    │                        │         │         └── col1_2::STRING
 │    │    │                        │         └── projections
 │    │    │                        │              └── true
 │    │    │                        └── false
 │    │    ├── project
 │    │    │    ├── inner-join (cross)
 │    │    │    │    ├── select
 │    │    │    │    │    ├── full-join (cross)
 │    │    │    │    │    │    ├── inner-join (cross)
 │    │    │    │    │    │    │    ├── project
 │    │    │    │    │    │    │    │    ├── scan t136250
 │    │    │    │    │    │    │    │    │    └── computed column expressions
 │    │    │    │    │    │    │    │    │         ├── col1_8
 │    │    │    │    │    │    │    │    │         │    └── CAST(NULL AS STRING)
 │    │    │    │    │    │    │    │    │         ├── crdb_internal_idx_expr
 │    │    │    │    │    │    │    │    │         │    └── col1_3::STRING
 │    │    │    │    │    │    │    │    │         └── crdb_internal_idx_expr_1
 │    │    │    │    │    │    │    │    │              └── col1_2::STRING
 │    │    │    │    │    │    │    │    └── projections
 │    │    │    │    │    │    │    │         ├── col1_3::STRING
 │    │    │    │    │    │    │    │         └── col1_2::STRING
 │    │    │    │    │    │    │    ├── project
 │    │    │    │    │    │    │    │    ├── scan t136250
 │    │    │    │    │    │    │    │    │    └── computed column expressions
 │    │    │    │    │    │    │    │    │         ├── col1_8
 │    │    │    │    │    │    │    │    │         │    └── CAST(NULL AS STRING)
 │    │    │    │    │    │    │    │    │         ├── crdb_internal_idx_expr
 │    │    │    │    │    │    │    │    │         │    └── col1_3::STRING
 │    │    │    │    │    │    │    │    │         └── crdb_internal_idx_expr_1
 │    │    │    │    │    │    │    │    │              └── col1_2::STRING
 │    │    │    │    │    │    │    │    └── projections
 │    │    │    │    │    │    │    │         ├── col1_3::STRING
 │    │    │    │    │    │    │    │         └── col1_2::STRING
 │    │    │    │    │    │    │    └── filters (true)
 │    │    │    │    │    │    ├── project
 │    │    │    │    │    │    │    ├── scan t136250
 │    │    │    │    │    │    │    │    └── computed column expressions
 │    │    │    │    │    │    │    │         ├── col1_8
 │    │    │    │    │    │    │    │         │    └── CAST(NULL AS STRING)
 │    │    │    │    │    │    │    │         ├── crdb_internal_idx_expr
 │    │    │    │    │    │    │    │         │    └── col1_3::STRING
 │    │    │    │    │    │    │    │         └── crdb_internal_idx_expr_1
 │    │    │    │    │    │    │    │              └── col1_2::STRING
 │    │    │    │    │    │    │    └── projections
 │    │    │    │    │    │    │         ├── col1_3::STRING
 │    │    │    │    │    │    │         └── col1_2::STRING
 │    │    │    │    │    │    └── filters (true)
 │    │    │    │    │    └── filters
 │    │    │    │    │         └── or
 │    │    │    │    │              ├── not
 │    │    │    │    │              │    └── coalesce
 │    │    │    │    │              │         ├── subquery
 │    │    │    │    │              │         │    └── project
 │    │    │    │    │              │         │         ├── inner-join (cross)
 │    │    │    │    │              │         │         │    ├── project
 │    │    │    │    │              │         │         │    │    ├── scan t136250
 │    │    │    │    │              │         │         │    │    │    └── computed column expressions
 │    │    │    │    │              │         │         │    │    │         ├── col1_8
 │    │    │    │    │              │         │         │    │    │         │    └── CAST(NULL AS STRING)
 │    │    │    │    │              │         │         │    │    │         ├── crdb_internal_idx_expr
 │    │    │    │    │              │         │         │    │    │         │    └── col1_3::STRING
 │    │    │    │    │              │         │         │    │    │         └── crdb_internal_idx_expr_1
 │    │    │    │    │              │         │         │    │    │              └── col1_2::STRING
 │    │    │    │    │              │         │         │    │    └── projections
 │    │    │    │    │              │         │         │    │         ├── col1_3::STRING
 │    │    │    │    │              │         │         │    │         └── col1_2::STRING
 │    │    │    │    │              │         │         │    ├── project
 │    │    │    │    │              │         │         │    │    ├── scan t136250
 │    │    │    │    │              │         │         │    │    │    └── computed column expressions
 │    │    │    │    │              │         │         │    │    │         ├── col1_8
 │    │    │    │    │              │         │         │    │    │         │    └── CAST(NULL AS STRING)
 │    │    │    │    │              │         │         │    │    │         ├── crdb_internal_idx_expr
 │    │    │    │    │              │         │         │    │    │         │    └── col1_3::STRING
 │    │    │    │    │              │         │         │    │    │         └── crdb_internal_idx_expr_1
 │    │    │    │    │              │         │         │    │    │              └── col1_2::STRING
 │    │    │    │    │              │         │         │    │    └── projections
 │    │    │    │    │              │         │         │    │         ├── col1_3::STRING
 │    │    │    │    │              │         │         │    │         └── col1_2::STRING
 │    │    │    │    │              │         │         │    └── filters (true)
 │    │    │    │    │              │         │         └── projections
 │    │    │    │    │              │         │              └── true
 │    │    │    │    │              │         └── false
 │    │    │    │    │              └── not
 │    │    │    │    │                   └── coalesce
 │    │    │    │    │                        ├── subquery
 │    │    │    │    │                        │    └── project
 │    │    │    │    │                        │         ├── project
 │    │    │    │    │                        │         │    ├── project
 │    │    │    │    │                        │         │    │    ├── inner-join (lookup t136250)
 │    │    │    │    │                        │         │    │    │    ├── lookup columns are key
 │    │    │    │    │                        │         │    │    │    ├── project
 │    │    │    │    │                        │         │    │    │    │    ├── scan t136250
 │    │    │    │    │                        │         │    │    │    │    │    └── computed column expressions
 │    │    │    │    │                        │         │    │    │    │    │         ├── col1_8
 │    │    │    │    │                        │         │    │    │    │    │         │    └── CAST(NULL AS STRING)
 │    │    │    │    │                        │         │    │    │    │    │         ├── crdb_internal_idx_expr
 │    │    │    │    │                        │         │    │    │    │    │         │    └── col1_3::STRING
 │    │    │    │    │                        │         │    │    │    │    │         └── crdb_internal_idx_expr_1
 │    │    │    │    │                        │         │    │    │    │    │              └── col1_2::STRING
 │    │    │    │    │                        │         │    │    │    │    └── projections
 │    │    │    │    │                        │         │    │    │    │         └── CAST(NULL AS STRING)
 │    │    │    │    │                        │         │    │    │    └── filters
 │    │    │    │    │                        │         │    │    │         └── col1_5 = col1_5
 │    │    │    │    │                        │         │    │    └── projections
 │    │    │    │    │                        │         │    │         ├── col1_3::STRING
 │    │    │    │    │                        │         │    │         └── col1_2::STRING
 │    │    │    │    │                        │         │    └── projections
 │    │    │    │    │                        │         │         ├── col1_3::STRING
 │    │    │    │    │                        │         │         └── col1_2::STRING
 │    │    │    │    │                        │         └── projections
 │    │    │    │    │                        │              └── true
 │    │    │    │    │                        └── false
 │    │    │    │    ├── select
 │    │    │    │    │    ├── scan t136250
 │    │    │    │    │    │    └── computed column expressions
 │    │    │    │    │    │         ├── col1_8
 │    │    │    │    │    │         │    └── CAST(NULL AS STRING)
 │    │    │    │    │    │         ├── crdb_internal_idx_expr
 │    │    │    │    │    │         │    └── col1_3::STRING
 │    │    │    │    │    │         └── crdb_internal_idx_expr_1
 │    │    │    │    │    │              └── col1_2::STRING
 │    │    │    │    │    └── filters
 │    │    │    │    │         └── or
 │    │    │    │    │              ├── not
 │    │    │    │    │              │    └── coalesce
 │    │    │    │    │              │         ├── subquery
 │    │    │    │    │              │         │    └── project
 │    │    │    │    │              │         │         ├── inner-join (cross)
 │    │    │    │    │              │         │         │    ├── project
 │    │    │    │    │              │         │         │    │    ├── scan t136250
 │    │    │    │    │              │         │         │    │    │    └── computed column expressions
 │    │    │    │    │              │         │         │    │    │         ├── col1_8
 │    │    │    │    │              │         │         │    │    │         │    └── CAST(NULL AS STRING)
 │    │    │    │    │              │         │         │    │    │         ├── crdb_internal_idx_expr
 │    │    │    │    │              │         │         │    │    │         │    └── col1_3::STRING
 │    │    │    │    │              │         │         │    │    │         └── crdb_internal_idx_expr_1
 │    │    │    │    │              │         │         │    │    │              └── col1_2::STRING
 │    │    │    │    │              │         │         │    │    └── projections
 │    │    │    │    │              │         │         │    │         ├── col1_3::STRING
 │    │    │    │    │              │         │         │    │         └── col1_2::STRING
 │    │    │    │    │              │         │         │    ├── project
 │    │    │    │    │              │         │         │    │    ├── scan t136250
 │    │    │    │    │              │         │         │    │    │    └── computed column expressions
 │    │    │    │    │              │         │         │    │    │         ├── col1_8
 │    │    │    │    │              │         │         │    │    │         │    └── CAST(NULL AS STRING)
 │    │    │    │    │              │         │         │    │    │         ├── crdb_internal_idx_expr
 │    │    │    │    │              │         │         │    │    │         │    └── col1_3::STRING
 │    │    │    │    │              │         │         │    │    │         └── crdb_internal_idx_expr_1
 │    │    │    │    │              │         │         │    │    │              └── col1_2::STRING
 │    │    │    │    │              │         │         │    │    └── projections
 │    │    │    │    │              │         │         │    │         ├── col1_3::STRING
 │    │    │    │    │              │         │         │    │         └── col1_2::STRING
 │    │    │    │    │              │         │         │    └── filters (true)
 │    │    │    │    │              │         │         └── projections
 │    │    │    │    │              │         │              └── true
 │    │    │    │    │              │         └── false
 │    │    │    │    │              └── not
 │    │    │    │    │                   └── coalesce
 │    │    │    │    │                        ├── subquery
 │    │    │    │    │                        │    └── project
 │    │    │    │    │                        │         ├── project
 │    │    │    │    │                        │         │    ├── project
 │    │    │    │    │                        │         │    │    ├── inner-join (lookup t136250)
 │    │    │    │    │                        │         │    │    │    ├── lookup columns are key
 │    │    │    │    │                        │         │    │    │    ├── project
 │    │    │    │    │                        │         │    │    │    │    ├── scan t136250
 │    │    │    │    │                        │         │    │    │    │    │    └── computed column expressions
 │    │    │    │    │                        │         │    │    │    │    │         ├── col1_8
 │    │    │    │    │                        │         │    │    │    │    │         │    └── CAST(NULL AS STRING)
 │    │    │    │    │                        │         │    │    │    │    │         ├── crdb_internal_idx_expr
 │    │    │    │    │                        │         │    │    │    │    │         │    └── col1_3::STRING
 │    │    │    │    │                        │         │    │    │    │    │         └── crdb_internal_idx_expr_1
 │    │    │    │    │                        │         │    │    │    │    │              └── col1_2::STRING
 │    │    │    │    │                        │         │    │    │    │    └── projections
 │    │    │    │    │                        │         │    │    │    │         └── CAST(NULL AS STRING)
 │    │    │    │    │                        │         │    │    │    └── filters
 │    │    │    │    │                        │         │    │    │         └── col1_5 = col1_5
 │    │    │    │    │                        │         │    │    └── projections
 │    │    │    │    │                        │         │    │         ├── col1_3::STRING
 │    │    │    │    │                        │         │    │         └── col1_2::STRING
 │    │    │    │    │                        │         │    └── projections
 │    │    │    │    │                        │         │         ├── col1_3::STRING
 │    │    │    │    │                        │         │         └── col1_2::STRING
 │    │    │    │    │                        │         └── projections
 │    │    │    │    │                        │              └── true
 │    │    │    │    │                        └── false
 │    │    │    │    └── filters (true)
 │    │    │    └── projections
 │    │    │         ├── col1_3::STRING
 │    │    │         └── col1_2::STRING
 │    │    └── filters (true)
 │    └── projections
 │         ├── col1_3::STRING
 │         └── col1_2::STRING
 └── projections
      └── NULL

# --------------------------------------------------
# InlineUDF
# --------------------------------------------------

exec-ddl
CREATE FUNCTION add(x INT, y INT) RETURNS INT IMMUTABLE LANGUAGE SQL AS $$
  SELECT x + y
$$
----

exec-ddl
CREATE FUNCTION add_strict(x INT, y INT) RETURNS INT STRICT IMMUTABLE LANGUAGE SQL AS $$
  SELECT x + y
$$
----

exec-ddl
CREATE FUNCTION one_strict() RETURNS INT STRICT IMMUTABLE LANGUAGE SQL AS $$
  SELECT 1
$$
----

exec-ddl
CREATE FUNCTION rec(r RECORD) RETURNS RECORD IMMUTABLE LANGUAGE SQL AS $$
  SELECT r
$$
----

norm expect=InlineUDF
SELECT add(1, i) FROM (VALUES (1), (2), (3)) v(i)
----
project
 ├── columns: add:5!null
 ├── cardinality: [3 - 3]
 ├── immutable
 ├── values
 │    ├── columns: column1:1!null
 │    ├── cardinality: [3 - 3]
 │    ├── (1,)
 │    ├── (2,)
 │    └── (3,)
 └── projections
      └── column1:1 + 1 [as=add:5, outer=(1), immutable]

norm expect=InlineUDF
SELECT k FROM a WHERE add(i, 1) = 10
----
project
 ├── columns: k:1!null
 ├── key: (1)
 └── select
      ├── columns: k:1!null i:2!null
      ├── key: (1)
      ├── fd: ()-->(2)
      ├── scan a
      │    ├── columns: k:1!null i:2
      │    ├── key: (1)
      │    └── fd: (1)-->(2)
      └── filters
           └── i:2 = 9 [outer=(2), constraints=(/2: [/9 - /9]; tight), fd=()-->(2)]

# A UDF with a placeholder argument should be inlined.
norm expect=InlineUDF
SELECT add(1, $1)
----
values
 ├── columns: add:4
 ├── cardinality: [1 - 1]
 ├── immutable, has-placeholder
 ├── key: ()
 ├── fd: ()-->(4)
 └── tuple
      └── subquery
           └── values
                ├── columns: "?column?":3
                ├── cardinality: [1 - 1]
                ├── immutable, has-placeholder
                ├── key: ()
                ├── fd: ()-->(3)
                └── ($1 + 1,)

# A UDF with an argument that is a tuple of constants, variables, and
# placeholders should be inlined.
norm expect=InlineUDF
SELECT rec((1, i, $1::INT)) FROM a
----
project
 ├── columns: rec:10
 ├── has-placeholder
 ├── scan a
 │    └── columns: i:2
 └── projections
      └── (1, i:2, $1) [as=rec:10, outer=(2)]

# A strict UDF is inlined and wrapped in a CASE expression.
norm expect=InlineUDF
SELECT add_strict(1, i) FROM (VALUES (1), (2), (3)) v(i)
----
project
 ├── columns: add_strict:5
 ├── cardinality: [3 - 3]
 ├── immutable
 ├── values
 │    ├── columns: column1:1!null
 │    ├── cardinality: [3 - 3]
 │    ├── (1,)
 │    ├── (2,)
 │    └── (3,)
 └── projections
      └── case [as=add_strict:5, outer=(1), immutable, correlated-subquery]
           ├── true
           ├── when
           │    ├── column1:1 IS NULL
           │    └── CAST(NULL AS INT8)
           └── subquery
                └── values
                     ├── columns: "?column?":4
                     ├── outer: (1)
                     ├── cardinality: [1 - 1]
                     ├── immutable
                     ├── key: ()
                     ├── fd: ()-->(4)
                     └── (column1:1 + 1,)

# A strict non-set-returning UDF used as a datasource is inlined.
norm expect=InlineUDF
SELECT * FROM add_strict(1, $1)
----
project-set
 ├── columns: add_strict:4
 ├── immutable, has-placeholder
 ├── values
 │    ├── cardinality: [1 - 1]
 │    ├── key: ()
 │    └── ()
 └── zip
      └── case [immutable, subquery]
           ├── true
           ├── when
           │    ├── $1 IS NULL
           │    └── CAST(NULL AS INT8)
           └── subquery
                └── values
                     ├── columns: "?column?":3
                     ├── cardinality: [1 - 1]
                     ├── immutable, has-placeholder
                     ├── key: ()
                     ├── fd: ()-->(3)
                     └── ($1 + 1,)

# A strict UDF with zero arguments is inlined without a CASE expression.
norm expect=InlineUDF
SELECT one_strict() FROM (VALUES (1), (2), (3)) v(i)
----
project
 ├── columns: one_strict:3!null
 ├── cardinality: [3 - 3]
 ├── fd: ()-->(3)
 ├── values
 │    ├── cardinality: [3 - 3]
 │    ├── ()
 │    ├── ()
 │    └── ()
 └── projections
      └── 1 [as=one_strict:3]

# A UDF is not inlined when the arguments are not constants or either Variable
# or Const expressions.
norm expect-not=InlineUDF
SELECT add(1, i+10) FROM (VALUES (1), (2), (3)) v(i)
----
project
 ├── columns: add:5
 ├── cardinality: [3 - 3]
 ├── immutable
 ├── values
 │    ├── columns: column1:1!null
 │    ├── cardinality: [3 - 3]
 │    ├── (1,)
 │    ├── (2,)
 │    └── (3,)
 └── projections
      └── add(1, column1:1 + 10) [as=add:5, outer=(1), immutable, udf]

norm expect-not=InlineUDF
SELECT rec((1, i+10, $1::INT)) FROM a
----
project
 ├── columns: rec:10
 ├── immutable, has-placeholder
 ├── scan a
 │    └── columns: i:2
 └── projections
      └── rec((1, i:2 + 10, $1)) [as=rec:10, outer=(2), immutable, udf]

# Nested UDFs should be inlined.
norm expect=InlineUDF
SELECT add(10, add(i, 20)) FROM a WHERE add(k, add(10, f::INT)) = 100
----
project
 ├── columns: add:20
 ├── immutable
 ├── select
 │    ├── columns: k:1!null i:2 f:3
 │    ├── immutable
 │    ├── key: (1)
 │    ├── fd: (1)-->(2,3)
 │    ├── scan a
 │    │    ├── columns: k:1!null i:2 f:3
 │    │    ├── key: (1)
 │    │    └── fd: (1)-->(2,3)
 │    └── filters
 │         └── add(k:1, add(10, f:3::INT8)) = 100 [outer=(1,3), immutable, udf]
 └── projections
      └── u-d-f-call [as=add:20, outer=(2), immutable, correlated-subquery, udf]
           ├── 10
           └── subquery
                └── values
                     ├── columns: "?column?":16
                     ├── outer: (2)
                     ├── cardinality: [1 - 1]
                     ├── immutable
                     ├── key: ()
                     ├── fd: ()-->(16)
                     └── (i:2 + 20,)

exec-ddl
CREATE FUNCTION min_x() RETURNS INT STABLE LANGUAGE SQL AS $$
  SELECT x FROM xy ORDER BY x LIMIT 1
$$
----

# Stable UDFs should be inline. Presentation and ordering are preserved.
norm expect=InlineUDF
SELECT k, min_x() FROM a WHERE k = min_x()
----
project
 ├── columns: k:1!null min_x:16
 ├── cardinality: [0 - 1]
 ├── key: ()
 ├── fd: ()-->(1,16)
 ├── inner-join (hash)
 │    ├── columns: k:1!null x:8!null
 │    ├── cardinality: [0 - 1]
 │    ├── multiplicity: left-rows(zero-or-one), right-rows(zero-or-one)
 │    ├── key: ()
 │    ├── fd: ()-->(1,8), (1)==(8), (8)==(1)
 │    ├── scan a
 │    │    ├── columns: k:1!null
 │    │    └── key: (1)
 │    ├── limit
 │    │    ├── columns: x:8!null
 │    │    ├── internal-ordering: +8
 │    │    ├── cardinality: [0 - 1]
 │    │    ├── key: ()
 │    │    ├── fd: ()-->(8)
 │    │    ├── scan xy
 │    │    │    ├── columns: x:8!null
 │    │    │    ├── key: (8)
 │    │    │    ├── ordering: +8
 │    │    │    └── limit hint: 1.00
 │    │    └── 1
 │    └── filters
 │         └── k:1 = x:8 [outer=(1,8), constraints=(/1: (/NULL - ]; /8: (/NULL - ]), fd=(1)==(8), (8)==(1)]
 └── projections
      └── subquery [as=min_x:16, subquery]
           └── limit
                ├── columns: x:12!null
                ├── internal-ordering: +12
                ├── cardinality: [0 - 1]
                ├── key: ()
                ├── fd: ()-->(12)
                ├── scan xy
                │    ├── columns: x:12!null
                │    ├── key: (12)
                │    ├── ordering: +12
                │    └── limit hint: 1.00
                └── 1

exec-ddl
CREATE FUNCTION min_x_gt(i INT) RETURNS INT STABLE LANGUAGE SQL AS $$
  SELECT x FROM xy WHERE x > i ORDER BY x LIMIT 1
$$
----

# Only the inner stable UDF should be inlined.
norm expect=InlineUDF
SELECT k FROM a WHERE k = min_x_gt(min_x_gt(0))
----
select
 ├── columns: k:1!null
 ├── stable
 ├── key: (1)
 ├── scan a
 │    ├── columns: k:1!null
 │    └── key: (1)
 └── filters
      └── eq [outer=(1), stable, subquery, udf, constraints=(/1: (/NULL - ])]
           ├── k:1
           └── udf: min_x_gt
                ├── args
                │    └── subquery
                │         └── limit
                │              ├── columns: x:9!null
                │              ├── internal-ordering: +9
                │              ├── cardinality: [0 - 1]
                │              ├── key: ()
                │              ├── fd: ()-->(9)
                │              ├── select
                │              │    ├── columns: x:9!null
                │              │    ├── key: (9)
                │              │    ├── ordering: +9
                │              │    ├── limit hint: 1.00
                │              │    ├── scan xy
                │              │    │    ├── columns: x:9!null
                │              │    │    ├── key: (9)
                │              │    │    ├── ordering: +9
                │              │    │    └── limit hint: 3.00
                │              │    └── filters
                │              │         └── x:9 > 0 [outer=(9), constraints=(/9: [/1 - ]; tight)]
                │              └── 1
                ├── params: i:13
                └── body
                     └── limit
                          ├── columns: x:14!null
                          ├── internal-ordering: +14
                          ├── outer: (13)
                          ├── cardinality: [0 - 1]
                          ├── key: ()
                          ├── fd: ()-->(14)
                          ├── select
                          │    ├── columns: x:14!null
                          │    ├── outer: (13)
                          │    ├── key: (14)
                          │    ├── scan xy
                          │    │    ├── columns: x:14!null
                          │    │    └── key: (14)
                          │    └── filters
                          │         └── x:14 > i:13 [outer=(13,14), constraints=(/13: (/NULL - ]; /14: (/NULL - ])]
                          └── 1

# UDFs with volatile arguments are not inlined.
norm expect-not=InlineUDF
SELECT add((random()*10)::INT, i) FROM a
----
project
 ├── columns: add:11
 ├── volatile
 ├── scan a
 │    └── columns: i:2
 └── projections
      └── add((random() * 10.0)::INT8, i:2) [as=add:11, outer=(2), volatile, udf]

exec-ddl
CREATE FUNCTION vol() RETURNS INT VOLATILE LANGUAGE SQL AS $$
  SELECT 1;
$$
----

# Volatile UDFs are not inlined.
norm expect-not=InlineUDF
SELECT vol() FROM a
----
project
 ├── columns: vol:9
 ├── volatile
 ├── scan a
 └── projections
      └── vol() [as=vol:9, volatile, udf]

exec-ddl
CREATE FUNCTION set_fn(x INT) RETURNS SETOF INT IMMUTABLE LANGUAGE SQL AS $$
  SELECT i FROM a WHERE k > x
$$
----

# Set-returning UDFs are not inlined.
norm expect-not=InlineUDF
SELECT * FROM set_fn(0)
----
project-set
 ├── columns: set_fn:9
 ├── immutable
 ├── values
 │    ├── cardinality: [1 - 1]
 │    ├── key: ()
 │    └── ()
 └── zip
      └── set_fn(0) [immutable, udf]

exec-ddl
CREATE FUNCTION multi_stmt() RETURNS INT IMMUTABLE LANGUAGE SQL AS $$
  SELECT 1;
  SELECT 2;
$$
----

# Multi-statement UDFs are not inlined.
norm expect-not=InlineUDF
SELECT multi_stmt() FROM a
----
project
 ├── columns: multi_stmt:10
 ├── immutable
 ├── fd: ()-->(10)
 ├── scan a
 └── projections
      └── multi_stmt() [as=multi_stmt:10, immutable, udf]

exec-ddl
CREATE FUNCTION empty() RETURNS BOOL STABLE LANGUAGE SQL AS ''
----

# Empty UDFs are not inlined.
norm expect-not=InlineUDF
SELECT empty() FROM (VALUES (10), (20)) v(i)
----
project
 ├── columns: empty:2
 ├── cardinality: [2 - 2]
 ├── stable
 ├── fd: ()-->(2)
 ├── values
 │    ├── cardinality: [2 - 2]
 │    ├── ()
 │    └── ()
 └── projections
      └── empty() [as=empty:2, stable, udf]

exec-ddl
CREATE FUNCTION x_0_1_y_2(x INT, y INT) RETURNS BOOL IMMUTABLE LANGUAGE SQL AS $$
  SELECT x = 0 OR x = 1 OR y = 2
$$
----

# Do not inline a UDF when the parameter corresponding to a subquery argument is
# referenced multiple times.
# TODO(mgartner): Fix the formatting of subquery UDF arguments.
norm expect-not=InlineUDF
SELECT x_0_1_y_2((SELECT v FROM (VALUES (10), (20)) v(v) WHERE v > a.i), 10) FROM a
----
project
 ├── columns: x_0_1_y_2:12
 ├── immutable
 ├── scan a
 │    └── columns: i:2
 └── projections
      └── u-d-f-call [as=x_0_1_y_2:12, outer=(2), immutable, correlated-subquery, udf]
           ├── subquery
           │    └── max1-row
           │         ├── columns: column1:8!null
           │         ├── error: "more than one row returned by a subquery used as an expression"
           │         ├── outer: (2)
           │         ├── cardinality: [0 - 1]
           │         ├── key: ()
           │         ├── fd: ()-->(8)
           │         └── select
           │              ├── columns: column1:8!null
           │              ├── outer: (2)
           │              ├── cardinality: [0 - 2]
           │              ├── values
           │              │    ├── columns: column1:8!null
           │              │    ├── cardinality: [2 - 2]
           │              │    ├── (10,)
           │              │    └── (20,)
           │              └── filters
           │                   └── column1:8 > i:2 [outer=(2,8), constraints=(/2: (/NULL - ]; /8: (/NULL - ])]
           └── 10

exec-ddl
CREATE FUNCTION x_y(x INT, y INT) RETURNS RECORD IMMUTABLE LANGUAGE SQL AS $$
  SELECT x, y;
$$
----

# Do not inline a UDF that outputs multiple columns.
norm expect-not=InlineUDF
SELECT * FROM x_y(1, 2) AS f(x INT, y INT);
----
project-set
 ├── columns: x:5 y:6
 ├── immutable
 ├── values
 │    ├── cardinality: [1 - 1]
 │    ├── key: ()
 │    └── ()
 └── zip
      └── x_y(1, 2) [immutable, udf]
