exec-ddl
CREATE TABLE abc (
  a INT PRIMARY KEY,
  b INT,
  c INT
)
----

# --------------------------------------------------
# UDFs without arguments.
# --------------------------------------------------

build
SELECT foo()
----
error (42883): unknown function: foo

exec-ddl
CREATE FUNCTION one() RETURNS INT LANGUAGE SQL AS 'SELECT 1';
----

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

build format=show-scalars
SELECT one()
----
project
 ├── columns: one:2
 ├── values
 │    └── tuple
 └── projections
      └── udf: one [as=one:2]
           └── body
                └── limit
                     ├── columns: "?column?":1!null
                     ├── project
                     │    ├── columns: "?column?":1!null
                     │    ├── values
                     │    │    └── tuple
                     │    └── projections
                     │         └── const: 1 [as="?column?":1]
                     └── const: 1

build format=show-scalars
SELECT *, one() FROM abc
----
project
 ├── columns: a:1!null b:2 c:3 one:7
 ├── scan abc
 │    └── columns: a:1!null b:2 c:3 crdb_internal_mvcc_timestamp:4 tableoid:5
 └── projections
      └── udf: one [as=one:7]
           └── body
                └── limit
                     ├── columns: "?column?":6!null
                     ├── project
                     │    ├── columns: "?column?":6!null
                     │    ├── values
                     │    │    └── tuple
                     │    └── projections
                     │         └── const: 1 [as="?column?":6]
                     └── const: 1

build format=show-scalars
SELECT * FROM abc WHERE one() = c
----
project
 ├── columns: a:1!null b:2 c:3
 └── select
      ├── columns: a:1!null b:2 c:3 crdb_internal_mvcc_timestamp:4 tableoid:5
      ├── scan abc
      │    └── columns: a:1!null b:2 c:3 crdb_internal_mvcc_timestamp:4 tableoid:5
      └── filters
           └── eq
                ├── udf: one
                │    └── body
                │         └── limit
                │              ├── columns: "?column?":6!null
                │              ├── project
                │              │    ├── columns: "?column?":6!null
                │              │    ├── values
                │              │    │    └── tuple
                │              │    └── projections
                │              │         └── const: 1 [as="?column?":6]
                │              └── const: 1
                └── variable: c:3

build format=show-scalars
SELECT a + one(), b + two() FROM abc WHERE c = two()
----
project
 ├── columns: "?column?":9 "?column?":12
 ├── select
 │    ├── columns: a:1!null b:2 c:3!null crdb_internal_mvcc_timestamp:4 tableoid:5
 │    ├── scan abc
 │    │    └── columns: a:1!null b:2 c:3 crdb_internal_mvcc_timestamp:4 tableoid:5
 │    └── filters
 │         └── eq
 │              ├── variable: c:3
 │              └── udf: two
 │                   └── body
 │                        ├── project
 │                        │    ├── columns: "?column?":6!null
 │                        │    ├── values
 │                        │    │    └── tuple
 │                        │    └── projections
 │                        │         └── const: 1 [as="?column?":6]
 │                        └── limit
 │                             ├── columns: "?column?":7!null
 │                             ├── project
 │                             │    ├── columns: "?column?":7!null
 │                             │    ├── values
 │                             │    │    └── tuple
 │                             │    └── projections
 │                             │         └── const: 2 [as="?column?":7]
 │                             └── const: 1
 └── projections
      ├── plus [as="?column?":9]
      │    ├── variable: a:1
      │    └── udf: one
      │         └── body
      │              └── limit
      │                   ├── columns: "?column?":8!null
      │                   ├── project
      │                   │    ├── columns: "?column?":8!null
      │                   │    ├── values
      │                   │    │    └── tuple
      │                   │    └── projections
      │                   │         └── const: 1 [as="?column?":8]
      │                   └── const: 1
      └── plus [as="?column?":12]
           ├── variable: b:2
           └── udf: two
                └── body
                     ├── project
                     │    ├── columns: "?column?":10!null
                     │    ├── values
                     │    │    └── tuple
                     │    └── projections
                     │         └── const: 1 [as="?column?":10]
                     └── limit
                          ├── columns: "?column?":11!null
                          ├── project
                          │    ├── columns: "?column?":11!null
                          │    ├── values
                          │    │    └── tuple
                          │    └── projections
                          │         └── const: 2 [as="?column?":11]
                          └── const: 1

exec-ddl
CREATE FUNCTION ordered() RETURNS INT LANGUAGE SQL AS $$
  SELECT a FROM abc ORDER BY b DESC
$$;
----

build format=show-scalars
SELECT ordered()
----
project
 ├── columns: ordered:6
 ├── values
 │    └── tuple
 └── projections
      └── udf: ordered [as=ordered:6]
           └── body
                └── limit
                     ├── columns: a:1!null b:2
                     ├── internal-ordering: -2
                     ├── project
                     │    ├── columns: a:1!null b:2
                     │    └── scan abc
                     │         └── columns: a:1!null b:2 c:3 crdb_internal_mvcc_timestamp:4 tableoid:5
                     └── const: 1


# --------------------------------------------------
# UDFs with named arguments.
# --------------------------------------------------

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

build format=show-scalars
SELECT add(1, 2)
----
project
 ├── columns: add:4
 ├── values
 │    └── tuple
 └── projections
      └── udf: add [as=add:4]
           ├── args
           │    ├── const: 1
           │    └── const: 2
           ├── params: x:1 y:2
           └── body
                └── limit
                     ├── columns: "?column?":3
                     ├── project
                     │    ├── columns: "?column?":3
                     │    ├── values
                     │    │    └── tuple
                     │    └── projections
                     │         └── plus [as="?column?":3]
                     │              ├── variable: x:1
                     │              └── variable: y:2
                     └── const: 1

build format=show-scalars
SELECT add(add(1, 2), 3)
----
project
 ├── columns: add:7
 ├── values
 │    └── tuple
 └── projections
      └── udf: add [as=add:7]
           ├── args
           │    ├── udf: add
           │    │    ├── args
           │    │    │    ├── const: 1
           │    │    │    └── const: 2
           │    │    ├── params: x:1 y:2
           │    │    └── body
           │    │         └── limit
           │    │              ├── columns: "?column?":3
           │    │              ├── project
           │    │              │    ├── columns: "?column?":3
           │    │              │    ├── values
           │    │              │    │    └── tuple
           │    │              │    └── projections
           │    │              │         └── plus [as="?column?":3]
           │    │              │              ├── variable: x:1
           │    │              │              └── variable: y:2
           │    │              └── const: 1
           │    └── const: 3
           ├── params: x:4 y:5
           └── body
                └── limit
                     ├── columns: "?column?":6
                     ├── project
                     │    ├── columns: "?column?":6
                     │    ├── values
                     │    │    └── tuple
                     │    └── projections
                     │         └── plus [as="?column?":6]
                     │              ├── variable: x:4
                     │              └── variable: y:5
                     └── const: 1

build format=show-scalars
SELECT add(a, b) FROM abc
----
project
 ├── columns: add:9
 ├── scan abc
 │    └── columns: a:1!null b:2 c:3 crdb_internal_mvcc_timestamp:4 tableoid:5
 └── projections
      └── udf: add [as=add:9]
           ├── args
           │    ├── variable: a:1
           │    └── variable: b:2
           ├── params: x:6 y:7
           └── body
                └── limit
                     ├── columns: "?column?":8
                     ├── project
                     │    ├── columns: "?column?":8
                     │    ├── values
                     │    │    └── tuple
                     │    └── projections
                     │         └── plus [as="?column?":8]
                     │              ├── variable: x:6
                     │              └── variable: y:7
                     └── const: 1

build format=show-scalars
SELECT * FROM abc WHERE a = add(b, c)
----
project
 ├── columns: a:1!null b:2 c:3
 └── select
      ├── columns: a:1!null b:2 c:3 crdb_internal_mvcc_timestamp:4 tableoid:5
      ├── scan abc
      │    └── columns: a:1!null b:2 c:3 crdb_internal_mvcc_timestamp:4 tableoid:5
      └── filters
           └── eq
                ├── variable: a:1
                └── udf: add
                     ├── args
                     │    ├── variable: b:2
                     │    └── variable: c:3
                     ├── params: x:6 y:7
                     └── body
                          └── limit
                               ├── columns: "?column?":8
                               ├── project
                               │    ├── columns: "?column?":8
                               │    ├── values
                               │    │    └── tuple
                               │    └── projections
                               │         └── plus [as="?column?":8]
                               │              ├── variable: x:6
                               │              └── variable: y:7
                               └── const: 1

build format=show-scalars
SELECT * FROM abc WHERE a = add(add(b, c), 3)
----
project
 ├── columns: a:1!null b:2 c:3
 └── select
      ├── columns: a:1!null b:2 c:3 crdb_internal_mvcc_timestamp:4 tableoid:5
      ├── scan abc
      │    └── columns: a:1!null b:2 c:3 crdb_internal_mvcc_timestamp:4 tableoid:5
      └── filters
           └── eq
                ├── variable: a:1
                └── udf: add
                     ├── args
                     │    ├── udf: add
                     │    │    ├── args
                     │    │    │    ├── variable: b:2
                     │    │    │    └── variable: c:3
                     │    │    ├── params: x:6 y:7
                     │    │    └── body
                     │    │         └── limit
                     │    │              ├── columns: "?column?":8
                     │    │              ├── project
                     │    │              │    ├── columns: "?column?":8
                     │    │              │    ├── values
                     │    │              │    │    └── tuple
                     │    │              │    └── projections
                     │    │              │         └── plus [as="?column?":8]
                     │    │              │              ├── variable: x:6
                     │    │              │              └── variable: y:7
                     │    │              └── const: 1
                     │    └── const: 3
                     ├── params: x:9 y:10
                     └── body
                          └── limit
                               ├── columns: "?column?":11
                               ├── project
                               │    ├── columns: "?column?":11
                               │    ├── values
                               │    │    └── tuple
                               │    └── projections
                               │         └── plus [as="?column?":11]
                               │              ├── variable: x:9
                               │              └── variable: y:10
                               └── const: 1

exec-ddl
CREATE FUNCTION fetch_b(a_arg INT) RETURNS INT LANGUAGE SQL AS $$
  SELECT b FROM abc WHERE a = a_arg
$$;
----

build format=show-scalars
SELECT fetch_b(1)
----
project
 ├── columns: fetch_b:7
 ├── values
 │    └── tuple
 └── projections
      └── udf: fetch_b [as=fetch_b:7]
           ├── args
           │    └── const: 1
           ├── params: a_arg:1
           └── body
                └── limit
                     ├── columns: b:3
                     ├── project
                     │    ├── columns: b:3
                     │    └── select
                     │         ├── columns: a:2!null b:3 c:4 crdb_internal_mvcc_timestamp:5 tableoid:6
                     │         ├── scan abc
                     │         │    └── columns: a:2!null b:3 c:4 crdb_internal_mvcc_timestamp:5 tableoid:6
                     │         └── filters
                     │              └── eq
                     │                   ├── variable: a:2
                     │                   └── variable: a_arg:1
                     └── const: 1

build format=show-scalars
SELECT fetch_b(add(1, 2))
----
project
 ├── columns: fetch_b:10
 ├── values
 │    └── tuple
 └── projections
      └── udf: fetch_b [as=fetch_b:10]
           ├── args
           │    └── udf: add
           │         ├── args
           │         │    ├── const: 1
           │         │    └── const: 2
           │         ├── params: x:1 y:2
           │         └── body
           │              └── limit
           │                   ├── columns: "?column?":3
           │                   ├── project
           │                   │    ├── columns: "?column?":3
           │                   │    ├── values
           │                   │    │    └── tuple
           │                   │    └── projections
           │                   │         └── plus [as="?column?":3]
           │                   │              ├── variable: x:1
           │                   │              └── variable: y:2
           │                   └── const: 1
           ├── params: a_arg:4
           └── body
                └── limit
                     ├── columns: b:6
                     ├── project
                     │    ├── columns: b:6
                     │    └── select
                     │         ├── columns: a:5!null b:6 c:7 crdb_internal_mvcc_timestamp:8 tableoid:9
                     │         ├── scan abc
                     │         │    └── columns: a:5!null b:6 c:7 crdb_internal_mvcc_timestamp:8 tableoid:9
                     │         └── filters
                     │              └── eq
                     │                   ├── variable: a:5
                     │                   └── variable: a_arg:4
                     └── const: 1

build format=show-scalars
SELECT * FROM abc WHERE b = fetch_b(a)
----
project
 ├── columns: a:1!null b:2!null c:3
 └── select
      ├── columns: a:1!null b:2!null c:3 crdb_internal_mvcc_timestamp:4 tableoid:5
      ├── scan abc
      │    └── columns: a:1!null b:2 c:3 crdb_internal_mvcc_timestamp:4 tableoid:5
      └── filters
           └── eq
                ├── variable: b:2
                └── udf: fetch_b
                     ├── args
                     │    └── variable: a:1
                     ├── params: a_arg:6
                     └── body
                          └── limit
                               ├── columns: b:8
                               ├── project
                               │    ├── columns: b:8
                               │    └── select
                               │         ├── columns: a:7!null b:8 c:9 crdb_internal_mvcc_timestamp:10 tableoid:11
                               │         ├── scan abc
                               │         │    └── columns: a:7!null b:8 c:9 crdb_internal_mvcc_timestamp:10 tableoid:11
                               │         └── filters
                               │              └── eq
                               │                   ├── variable: a:7
                               │                   └── variable: a_arg:6
                               └── const: 1

exec-ddl
CREATE FUNCTION shadowed_a(a INT) RETURNS INT LANGUAGE SQL AS $$
  SELECT c FROM abc WHERE abc.b = a
$$;
----

# The column "a" from the table takes precedence over the argument "a".
build format=show-scalars
SELECT shadowed_a(1)
----
project
 ├── columns: shadowed_a:7
 ├── values
 │    └── tuple
 └── projections
      └── udf: shadowed_a [as=shadowed_a:7]
           ├── args
           │    └── const: 1
           ├── params: a:1
           └── body
                └── limit
                     ├── columns: c:4
                     ├── project
                     │    ├── columns: c:4
                     │    └── select
                     │         ├── columns: abc.a:2!null b:3!null c:4 crdb_internal_mvcc_timestamp:5 tableoid:6
                     │         ├── scan abc
                     │         │    └── columns: abc.a:2!null b:3 c:4 crdb_internal_mvcc_timestamp:5 tableoid:6
                     │         └── filters
                     │              └── eq
                     │                   ├── variable: b:3
                     │                   └── variable: abc.a:2
                     └── const: 1

exec-ddl
CREATE FUNCTION add_num_args(x INT, y INT) RETURNS INT LANGUAGE SQL AS $$
  SELECT $1+$2;
$$;
----

build format=show-scalars
SELECT add_num_args(1, 2)
----
project
 ├── columns: add_num_args:4
 ├── values
 │    └── tuple
 └── projections
      └── udf: add_num_args [as=add_num_args:4]
           ├── args
           │    ├── const: 1
           │    └── const: 2
           ├── params: x:1 y:2
           └── body
                └── limit
                     ├── columns: "?column?":3
                     ├── project
                     │    ├── columns: "?column?":3
                     │    ├── values
                     │    │    └── tuple
                     │    └── projections
                     │         └── plus [as="?column?":3]
                     │              ├── variable: x:1
                     │              └── variable: y:2
                     └── const: 1

build format=show-scalars
SELECT add_num_args(add_num_args(1, 2), 3)
----
project
 ├── columns: add_num_args:7
 ├── values
 │    └── tuple
 └── projections
      └── udf: add_num_args [as=add_num_args:7]
           ├── args
           │    ├── udf: add_num_args
           │    │    ├── args
           │    │    │    ├── const: 1
           │    │    │    └── const: 2
           │    │    ├── params: x:1 y:2
           │    │    └── body
           │    │         └── limit
           │    │              ├── columns: "?column?":3
           │    │              ├── project
           │    │              │    ├── columns: "?column?":3
           │    │              │    ├── values
           │    │              │    │    └── tuple
           │    │              │    └── projections
           │    │              │         └── plus [as="?column?":3]
           │    │              │              ├── variable: x:1
           │    │              │              └── variable: y:2
           │    │              └── const: 1
           │    └── const: 3
           ├── params: x:4 y:5
           └── body
                └── limit
                     ├── columns: "?column?":6
                     ├── project
                     │    ├── columns: "?column?":6
                     │    ├── values
                     │    │    └── tuple
                     │    └── projections
                     │         └── plus [as="?column?":6]
                     │              ├── variable: x:4
                     │              └── variable: y:5
                     └── const: 1

build format=show-scalars
SELECT * FROM abc WHERE a = add_num_args(add_num_args(b, c), 3)
----
project
 ├── columns: a:1!null b:2 c:3
 └── select
      ├── columns: a:1!null b:2 c:3 crdb_internal_mvcc_timestamp:4 tableoid:5
      ├── scan abc
      │    └── columns: a:1!null b:2 c:3 crdb_internal_mvcc_timestamp:4 tableoid:5
      └── filters
           └── eq
                ├── variable: a:1
                └── udf: add_num_args
                     ├── args
                     │    ├── udf: add_num_args
                     │    │    ├── args
                     │    │    │    ├── variable: b:2
                     │    │    │    └── variable: c:3
                     │    │    ├── params: x:6 y:7
                     │    │    └── body
                     │    │         └── limit
                     │    │              ├── columns: "?column?":8
                     │    │              ├── project
                     │    │              │    ├── columns: "?column?":8
                     │    │              │    ├── values
                     │    │              │    │    └── tuple
                     │    │              │    └── projections
                     │    │              │         └── plus [as="?column?":8]
                     │    │              │              ├── variable: x:6
                     │    │              │              └── variable: y:7
                     │    │              └── const: 1
                     │    └── const: 3
                     ├── params: x:9 y:10
                     └── body
                          └── limit
                               ├── columns: "?column?":11
                               ├── project
                               │    ├── columns: "?column?":11
                               │    ├── values
                               │    │    └── tuple
                               │    └── projections
                               │         └── plus [as="?column?":11]
                               │              ├── variable: x:9
                               │              └── variable: y:10
                               └── const: 1

assign-placeholders-build query-args=(33) format=show-scalars
SELECT add_num_args(1, $1) FROM abc WHERE a = add_num_args($1, 2)
----
project
 ├── columns: add_num_args:12
 ├── select
 │    ├── columns: a:1!null b:2 c:3 crdb_internal_mvcc_timestamp:4 tableoid:5
 │    ├── scan abc
 │    │    └── columns: a:1!null b:2 c:3 crdb_internal_mvcc_timestamp:4 tableoid:5
 │    └── filters
 │         └── eq
 │              ├── variable: a:1
 │              └── udf: add_num_args
 │                   ├── args
 │                   │    ├── const: 33
 │                   │    └── const: 2
 │                   ├── params: x:6 y:7
 │                   └── body
 │                        └── limit
 │                             ├── columns: "?column?":8
 │                             ├── project
 │                             │    ├── columns: "?column?":8
 │                             │    ├── values
 │                             │    │    └── tuple
 │                             │    └── projections
 │                             │         └── plus [as="?column?":8]
 │                             │              ├── variable: x:6
 │                             │              └── variable: y:7
 │                             └── const: 1
 └── projections
      └── udf: add_num_args [as=add_num_args:12]
           ├── args
           │    ├── const: 1
           │    └── const: 33
           ├── params: x:9 y:10
           └── body
                └── limit
                     ├── columns: "?column?":11
                     ├── project
                     │    ├── columns: "?column?":11
                     │    ├── values
                     │    │    └── tuple
                     │    └── projections
                     │         └── plus [as="?column?":11]
                     │              ├── variable: x:9
                     │              └── variable: y:10
                     └── const: 1

# --------------------------------------------------
# UDFs with anonymous arguments.
# --------------------------------------------------

exec-ddl
CREATE FUNCTION add_anon(INT, INT) RETURNS INT LANGUAGE SQL AS $$
  SELECT $1+$2;
$$;
----

build format=show-scalars
SELECT add_anon(1, 2)
----
project
 ├── columns: add_anon:4
 ├── values
 │    └── tuple
 └── projections
      └── udf: add_anon [as=add_anon:4]
           ├── args
           │    ├── const: 1
           │    └── const: 2
           ├── params: arg1:1 arg2:2
           └── body
                └── limit
                     ├── columns: "?column?":3
                     ├── project
                     │    ├── columns: "?column?":3
                     │    ├── values
                     │    │    └── tuple
                     │    └── projections
                     │         └── plus [as="?column?":3]
                     │              ├── variable: arg1:1
                     │              └── variable: arg2:2
                     └── const: 1

build format=show-scalars
SELECT add_anon(add_anon(1, 2), 3)
----
project
 ├── columns: add_anon:7
 ├── values
 │    └── tuple
 └── projections
      └── udf: add_anon [as=add_anon:7]
           ├── args
           │    ├── udf: add_anon
           │    │    ├── args
           │    │    │    ├── const: 1
           │    │    │    └── const: 2
           │    │    ├── params: arg1:1 arg2:2
           │    │    └── body
           │    │         └── limit
           │    │              ├── columns: "?column?":3
           │    │              ├── project
           │    │              │    ├── columns: "?column?":3
           │    │              │    ├── values
           │    │              │    │    └── tuple
           │    │              │    └── projections
           │    │              │         └── plus [as="?column?":3]
           │    │              │              ├── variable: arg1:1
           │    │              │              └── variable: arg2:2
           │    │              └── const: 1
           │    └── const: 3
           ├── params: arg1:4 arg2:5
           └── body
                └── limit
                     ├── columns: "?column?":6
                     ├── project
                     │    ├── columns: "?column?":6
                     │    ├── values
                     │    │    └── tuple
                     │    └── projections
                     │         └── plus [as="?column?":6]
                     │              ├── variable: arg1:4
                     │              └── variable: arg2:5
                     └── const: 1

build format=show-scalars
SELECT * FROM abc WHERE a = add_anon(add_anon(b, c), 3)
----
project
 ├── columns: a:1!null b:2 c:3
 └── select
      ├── columns: a:1!null b:2 c:3 crdb_internal_mvcc_timestamp:4 tableoid:5
      ├── scan abc
      │    └── columns: a:1!null b:2 c:3 crdb_internal_mvcc_timestamp:4 tableoid:5
      └── filters
           └── eq
                ├── variable: a:1
                └── udf: add_anon
                     ├── args
                     │    ├── udf: add_anon
                     │    │    ├── args
                     │    │    │    ├── variable: b:2
                     │    │    │    └── variable: c:3
                     │    │    ├── params: arg1:6 arg2:7
                     │    │    └── body
                     │    │         └── limit
                     │    │              ├── columns: "?column?":8
                     │    │              ├── project
                     │    │              │    ├── columns: "?column?":8
                     │    │              │    ├── values
                     │    │              │    │    └── tuple
                     │    │              │    └── projections
                     │    │              │         └── plus [as="?column?":8]
                     │    │              │              ├── variable: arg1:6
                     │    │              │              └── variable: arg2:7
                     │    │              └── const: 1
                     │    └── const: 3
                     ├── params: arg1:9 arg2:10
                     └── body
                          └── limit
                               ├── columns: "?column?":11
                               ├── project
                               │    ├── columns: "?column?":11
                               │    ├── values
                               │    │    └── tuple
                               │    └── projections
                               │         └── plus [as="?column?":11]
                               │              ├── variable: arg1:9
                               │              └── variable: arg2:10
                               └── const: 1

assign-placeholders-build query-args=(33) format=show-scalars
SELECT add_anon(1, $1) FROM abc WHERE a = add_anon($1, 2)
----
project
 ├── columns: add_anon:12
 ├── select
 │    ├── columns: a:1!null b:2 c:3 crdb_internal_mvcc_timestamp:4 tableoid:5
 │    ├── scan abc
 │    │    └── columns: a:1!null b:2 c:3 crdb_internal_mvcc_timestamp:4 tableoid:5
 │    └── filters
 │         └── eq
 │              ├── variable: a:1
 │              └── udf: add_anon
 │                   ├── args
 │                   │    ├── const: 33
 │                   │    └── const: 2
 │                   ├── params: arg1:6 arg2:7
 │                   └── body
 │                        └── limit
 │                             ├── columns: "?column?":8
 │                             ├── project
 │                             │    ├── columns: "?column?":8
 │                             │    ├── values
 │                             │    │    └── tuple
 │                             │    └── projections
 │                             │         └── plus [as="?column?":8]
 │                             │              ├── variable: arg1:6
 │                             │              └── variable: arg2:7
 │                             └── const: 1
 └── projections
      └── udf: add_anon [as=add_anon:12]
           ├── args
           │    ├── const: 1
           │    └── const: 33
           ├── params: arg1:9 arg2:10
           └── body
                └── limit
                     ├── columns: "?column?":11
                     ├── project
                     │    ├── columns: "?column?":11
                     │    ├── values
                     │    │    └── tuple
                     │    └── projections
                     │         └── plus [as="?column?":11]
                     │              ├── variable: arg1:9
                     │              └── variable: arg2:10
                     └── const: 1


# --------------------------------------------------
# UDFs with implicit record types.
# --------------------------------------------------

exec-ddl
CREATE FUNCTION get_abc(i INT) RETURNS abc LANGUAGE SQL AS $$
  SELECT a, b, c FROM abc WHERE c > i ORDER BY b DESC
$$;
----

build format=show-scalars
SELECT get_abc(3)
----
project
 ├── columns: get_abc:9
 ├── values
 │    └── tuple
 └── projections
      └── udf: get_abc [as=get_abc:9]
           ├── args
           │    └── const: 3
           ├── params: i:1
           └── body
                └── project
                     ├── columns: column8:8
                     ├── project
                     │    ├── columns: column7:7
                     │    ├── limit
                     │    │    ├── columns: a:2!null b:3 c:4!null
                     │    │    ├── internal-ordering: -3
                     │    │    ├── project
                     │    │    │    ├── columns: a:2!null b:3 c:4!null
                     │    │    │    └── select
                     │    │    │         ├── columns: a:2!null b:3 c:4!null crdb_internal_mvcc_timestamp:5 tableoid:6
                     │    │    │         ├── scan abc
                     │    │    │         │    └── columns: a:2!null b:3 c:4 crdb_internal_mvcc_timestamp:5 tableoid:6
                     │    │    │         └── filters
                     │    │    │              └── gt
                     │    │    │                   ├── variable: c:4
                     │    │    │                   └── variable: i:1
                     │    │    └── const: 1
                     │    └── projections
                     │         └── tuple [as=column7:7]
                     │              ├── variable: a:2
                     │              ├── variable: b:3
                     │              └── variable: c:4
                     └── projections
                          └── assignment-cast: RECORD [as=column8:8]
                               └── variable: column7:7

exec-ddl
CREATE FUNCTION get_abc_star(i INT) RETURNS abc LANGUAGE SQL AS $$
  SELECT * FROM abc WHERE c > i ORDER BY b DESC
$$;
----

build format=show-scalars
SELECT get_abc_star(3)
----
project
 ├── columns: get_abc_star:9
 ├── values
 │    └── tuple
 └── projections
      └── udf: get_abc_star [as=get_abc_star:9]
           ├── args
           │    └── const: 3
           ├── params: i:1
           └── body
                └── project
                     ├── columns: column8:8
                     ├── project
                     │    ├── columns: column7:7
                     │    ├── limit
                     │    │    ├── columns: a:2!null b:3 c:4!null
                     │    │    ├── internal-ordering: -3
                     │    │    ├── project
                     │    │    │    ├── columns: a:2!null b:3 c:4!null
                     │    │    │    └── select
                     │    │    │         ├── columns: a:2!null b:3 c:4!null crdb_internal_mvcc_timestamp:5 tableoid:6
                     │    │    │         ├── scan abc
                     │    │    │         │    └── columns: a:2!null b:3 c:4 crdb_internal_mvcc_timestamp:5 tableoid:6
                     │    │    │         └── filters
                     │    │    │              └── gt
                     │    │    │                   ├── variable: c:4
                     │    │    │                   └── variable: i:1
                     │    │    └── const: 1
                     │    └── projections
                     │         └── tuple [as=column7:7]
                     │              ├── variable: a:2
                     │              ├── variable: b:3
                     │              └── variable: c:4
                     └── projections
                          └── assignment-cast: RECORD [as=column8:8]
                               └── variable: column7:7

exec-ddl
CREATE FUNCTION abc_b(i abc) RETURNS INT LANGUAGE SQL AS $$
  SELECT (i).b
$$;
----

build format=show-scalars
SELECT abc_b((1,2,3)::abc)
----
project
 ├── columns: abc_b:3
 ├── values
 │    └── tuple
 └── projections
      └── udf: abc_b [as=abc_b:3]
           ├── args
           │    └── cast: RECORD
           │         └── tuple
           │              ├── const: 1
           │              ├── const: 2
           │              └── const: 3
           ├── params: i:1
           └── body
                └── limit
                     ├── columns: b:2
                     ├── project
                     │    ├── columns: b:2
                     │    ├── values
                     │    │    └── tuple
                     │    └── projections
                     │         └── column-access: 1 [as=b:2]
                     │              └── variable: i:1
                     └── const: 1


# --------------------------------------------------
# UDFs that cast return values.
# --------------------------------------------------

exec-ddl
CREATE FUNCTION itof(i INT) RETURNS FLOAT8 LANGUAGE SQL AS 'SELECT i'
----

build format=show-scalars
SELECT itof(123)
----
project
 ├── columns: itof:4
 ├── values
 │    └── tuple
 └── projections
      └── udf: itof [as=itof:4]
           ├── args
           │    └── const: 123
           ├── params: i:1
           └── body
                └── project
                     ├── columns: column3:3
                     ├── limit
                     │    ├── columns: i:2
                     │    ├── project
                     │    │    ├── columns: i:2
                     │    │    ├── values
                     │    │    │    └── tuple
                     │    │    └── projections
                     │    │         └── variable: i:1 [as=i:2]
                     │    └── const: 1
                     └── projections
                          └── assignment-cast: FLOAT8 [as=column3:3]
                               └── variable: i:2

exec-ddl
CREATE FUNCTION stoc(s STRING) RETURNS CHAR LANGUAGE SQL AS 'SELECT s'
----

build format=show-scalars
SELECT stoc('a')
----
project
 ├── columns: stoc:4
 ├── values
 │    └── tuple
 └── projections
      └── udf: stoc [as=stoc:4]
           ├── args
           │    └── const: 'a'
           ├── params: s:1
           └── body
                └── project
                     ├── columns: column3:3
                     ├── limit
                     │    ├── columns: s:2
                     │    ├── project
                     │    │    ├── columns: s:2
                     │    │    ├── values
                     │    │    │    └── tuple
                     │    │    └── projections
                     │    │         └── variable: s:1 [as=s:2]
                     │    └── const: 1
                     └── projections
                          └── assignment-cast: CHAR [as=column3:3]
                               └── variable: s:2


# --------------------------------------------------
# UDFs with VOID return type.
# --------------------------------------------------

exec-ddl
CREATE FUNCTION retvoid(i INT) RETURNS VOID LANGUAGE SQL AS 'SELECT i'
----

build format=show-scalars
SELECT retvoid(1)
----
project
 ├── columns: retvoid:4
 ├── values
 │    └── tuple
 └── projections
      └── udf: retvoid [as=retvoid:4]
           ├── args
           │    └── const: 1
           ├── params: i:1
           └── body
                ├── project
                │    ├── columns: i:2
                │    ├── values
                │    │    └── tuple
                │    └── projections
                │         └── variable: i:1 [as=i:2]
                └── limit
                     ├── columns: column1:3
                     ├── values
                     │    ├── columns: column1:3
                     │    └── tuple
                     │         └── null
                     └── const: 1


# --------------------------------------------------
# UDFs that are STRICT/RETURNS NULL ON NULL INPUT.
# --------------------------------------------------

exec-ddl
CREATE FUNCTION strict_fn(i INT, t TEXT, b BOOl) RETURNS INT STRICT LANGUAGE SQL AS 'SELECT i'
----

build format=show-scalars
SELECT strict_fn(1, 'foo', false)
----
project
 ├── columns: strict_fn:5
 ├── values
 │    └── tuple
 └── projections
      └── udf: strict_fn [as=strict_fn:5]
           ├── strict
           ├── args
           │    ├── const: 1
           │    ├── const: 'foo'
           │    └── false
           ├── params: i:1 t:2 b:3
           └── body
                └── limit
                     ├── columns: i:4
                     ├── project
                     │    ├── columns: i:4
                     │    ├── values
                     │    │    └── tuple
                     │    └── projections
                     │         └── variable: i:1 [as=i:4]
                     └── const: 1

build format=show-scalars
SELECT strict_fn(a, b::TEXT, false) FROM abc WHERE strict_fn(a+1+2, b::TEXT, false) = 10
----
project
 ├── columns: strict_fn:14
 ├── select
 │    ├── columns: a:1!null abc.b:2 c:3 crdb_internal_mvcc_timestamp:4 tableoid:5
 │    ├── scan abc
 │    │    └── columns: a:1!null abc.b:2 c:3 crdb_internal_mvcc_timestamp:4 tableoid:5
 │    └── filters
 │         └── eq
 │              ├── udf: strict_fn
 │              │    ├── strict
 │              │    ├── args
 │              │    │    ├── plus
 │              │    │    │    ├── plus
 │              │    │    │    │    ├── variable: a:1
 │              │    │    │    │    └── const: 1
 │              │    │    │    └── const: 2
 │              │    │    ├── cast: STRING
 │              │    │    │    └── variable: abc.b:2
 │              │    │    └── false
 │              │    ├── params: i:6 t:7 b:8
 │              │    └── body
 │              │         └── limit
 │              │              ├── columns: i:9
 │              │              ├── project
 │              │              │    ├── columns: i:9
 │              │              │    ├── values
 │              │              │    │    └── tuple
 │              │              │    └── projections
 │              │              │         └── variable: i:6 [as=i:9]
 │              │              └── const: 1
 │              └── const: 10
 └── projections
      └── udf: strict_fn [as=strict_fn:14]
           ├── strict
           ├── args
           │    ├── variable: a:1
           │    ├── cast: STRING
           │    │    └── variable: abc.b:2
           │    └── false
           ├── params: i:10 t:11 b:12
           └── body
                └── limit
                     ├── columns: i:13
                     ├── project
                     │    ├── columns: i:13
                     │    ├── values
                     │    │    └── tuple
                     │    └── projections
                     │         └── variable: i:10 [as=i:13]
                     └── const: 1

exec-ddl
CREATE TABLE t101516 (i INT)
----

exec-ddl
CREATE FUNCTION f101516(x INT) RETURNS INT STRICT LANGUAGE SQL AS 'SELECT 1'
----

# Regression test for #101516. Subquery arguments should not be duplicated in a
# CASE expression for STRICT UDFs. This can cause intersecting columns in the
# left and right children of a join after hoisting the subquery. We use the norm
# directive here so that the subqueries are hoisted.
norm format=show-scalars
SELECT f101516((SELECT t1.i FROM t101516 t2 JOIN t101516 t3 ON t2.i = t3.i)) FROM t101516 t1
----
project
 ├── columns: f101516:16
 ├── scan t101516 [as=t1]
 │    └── columns: t1.i:1
 └── projections
      └── udf: f101516 [as=f101516:16]
           ├── strict
           ├── args
           │    └── subquery
           │         └── max1-row
           │              ├── columns: i:13
           │              └── project
           │                   ├── columns: i:13
           │                   ├── inner-join (hash)
           │                   │    ├── columns: t2.i:5!null t3.i:9!null
           │                   │    ├── scan t101516 [as=t2]
           │                   │    │    └── columns: t2.i:5
           │                   │    ├── scan t101516 [as=t3]
           │                   │    │    └── columns: t3.i:9
           │                   │    └── filters
           │                   │         └── eq
           │                   │              ├── variable: t2.i:5
           │                   │              └── variable: t3.i:9
           │                   └── projections
           │                        └── variable: t1.i:1 [as=i:13]
           ├── params: x:14
           └── body
                └── values
                     ├── columns: "?column?":15!null
                     └── tuple
                          └── const: 1

exec-ddl
CREATE FUNCTION strict_fn_record(i INT, t TEXT, b BOOl) RETURNS RECORD STRICT LANGUAGE SQL AS 'SELECT i, t, b'
----

build format=show-scalars
SELECT * FROM strict_fn_record(1, 'foo', false) as bar(i INT, t TEXT, b BOOl)
----
project-set
 ├── columns: i:7 t:8 b:9
 ├── values
 │    └── tuple
 └── zip
      └── udf: strict_fn_record
           ├── strict
           ├── args
           │    ├── const: 1
           │    ├── const: 'foo'
           │    └── false
           ├── params: i:1 t:2 b:3
           └── body
                └── limit
                     ├── columns: i:4 t:5 b:6
                     ├── project
                     │    ├── columns: i:4 t:5 b:6
                     │    ├── values
                     │    │    └── tuple
                     │    └── projections
                     │         ├── variable: i:1 [as=i:4]
                     │         ├── variable: t:2 [as=t:5]
                     │         └── variable: b:3 [as=b:6]
                     └── const: 1

build format=show-scalars
SELECT * FROM (SELECT strict_fn_record(1, 'foo', false)) as bar;
----
project
 ├── columns: strict_fn_record:9
 ├── values
 │    └── tuple
 └── projections
      └── udf: strict_fn_record [as=strict_fn_record:9]
           ├── strict
           ├── args
           │    ├── const: 1
           │    ├── const: 'foo'
           │    └── false
           ├── params: i:1 t:2 b:3
           └── body
                └── project
                     ├── columns: column8:8
                     ├── project
                     │    ├── columns: column7:7
                     │    ├── limit
                     │    │    ├── columns: i:4 t:5 b:6
                     │    │    ├── project
                     │    │    │    ├── columns: i:4 t:5 b:6
                     │    │    │    ├── values
                     │    │    │    │    └── tuple
                     │    │    │    └── projections
                     │    │    │         ├── variable: i:1 [as=i:4]
                     │    │    │         ├── variable: t:2 [as=t:5]
                     │    │    │         └── variable: b:3 [as=b:6]
                     │    │    └── const: 1
                     │    └── projections
                     │         └── tuple [as=column7:7]
                     │              ├── variable: i:4
                     │              ├── variable: t:5
                     │              └── variable: b:6
                     └── projections
                          └── assignment-cast: RECORD [as=column8:8]
                               └── variable: column7:7


# --------------------------------------------------
# UDFs with * expressions.
# --------------------------------------------------

exec-ddl
CREATE TABLE tstar (
  a INT
)
----

exec-ddl
CREATE FUNCTION fn_star() RETURNS INT LANGUAGE SQL AS 'SELECT * FROM tstar'
----

build format=show-scalars
SELECT fn_star()
----
project
 ├── columns: fn_star:5
 ├── values
 │    └── tuple
 └── projections
      └── udf: fn_star [as=fn_star:5]
           └── body
                └── limit
                     ├── columns: a:1
                     ├── project
                     │    ├── columns: a:1
                     │    └── scan tstar
                     │         └── columns: a:1 rowid:2!null crdb_internal_mvcc_timestamp:3 tableoid:4
                     └── const: 1

exec-ddl
CREATE TABLE tstar2 (
  a INT,
  b INT
)
----

exec-ddl
CREATE FUNCTION fn_star2() RETURNS RECORD LANGUAGE SQL AS 'SELECT * FROM tstar, tstar2 WHERE tstar.a = tstar2.b'
----

build format=show-scalars
SELECT fn_star2()
----
project
 ├── columns: fn_star2:12
 ├── values
 │    └── tuple
 └── projections
      └── udf: fn_star2 [as=fn_star2:12]
           └── body
                └── project
                     ├── columns: column11:11
                     ├── project
                     │    ├── columns: column10:10
                     │    ├── limit
                     │    │    ├── columns: tstar.a:1!null tstar2.a:5 b:6!null
                     │    │    ├── project
                     │    │    │    ├── columns: tstar.a:1!null tstar2.a:5 b:6!null
                     │    │    │    └── select
                     │    │    │         ├── columns: tstar.a:1!null tstar.rowid:2!null tstar.crdb_internal_mvcc_timestamp:3 tstar.tableoid:4 tstar2.a:5 b:6!null tstar2.rowid:7!null tstar2.crdb_internal_mvcc_timestamp:8 tstar2.tableoid:9
                     │    │    │         ├── inner-join (cross)
                     │    │    │         │    ├── columns: tstar.a:1 tstar.rowid:2!null tstar.crdb_internal_mvcc_timestamp:3 tstar.tableoid:4 tstar2.a:5 b:6 tstar2.rowid:7!null tstar2.crdb_internal_mvcc_timestamp:8 tstar2.tableoid:9
                     │    │    │         │    ├── scan tstar
                     │    │    │         │    │    └── columns: tstar.a:1 tstar.rowid:2!null tstar.crdb_internal_mvcc_timestamp:3 tstar.tableoid:4
                     │    │    │         │    ├── scan tstar2
                     │    │    │         │    │    └── columns: tstar2.a:5 b:6 tstar2.rowid:7!null tstar2.crdb_internal_mvcc_timestamp:8 tstar2.tableoid:9
                     │    │    │         │    └── filters (true)
                     │    │    │         └── filters
                     │    │    │              └── eq
                     │    │    │                   ├── variable: tstar.a:1
                     │    │    │                   └── variable: b:6
                     │    │    └── const: 1
                     │    └── projections
                     │         └── tuple [as=column10:10]
                     │              ├── variable: tstar.a:1
                     │              ├── variable: tstar2.a:5
                     │              └── variable: b:6
                     └── projections
                          └── assignment-cast: RECORD [as=column11:11]
                               └── variable: column10:10


# --------------------------------------------------
# Set-returning UDFs.
# --------------------------------------------------

exec-ddl
CREATE FUNCTION set_fn(i INT) RETURNS SETOF INT LANGUAGE SQL AS 'SELECT b FROM abc WHERE a > i'
----

build format=show-scalars
SELECT set_fn(1)
----
project-set
 ├── columns: set_fn:7
 ├── values
 │    └── tuple
 └── zip
      └── udf: set_fn
           ├── args
           │    └── const: 1
           ├── params: i:1
           └── body
                └── project
                     ├── columns: b:3
                     └── select
                          ├── columns: a:2!null b:3 c:4 crdb_internal_mvcc_timestamp:5 tableoid:6
                          ├── scan abc
                          │    └── columns: a:2!null b:3 c:4 crdb_internal_mvcc_timestamp:5 tableoid:6
                          └── filters
                               └── gt
                                    ├── variable: a:2
                                    └── variable: i:1

build format=show-scalars
SELECT * FROM set_fn(1)
----
project-set
 ├── columns: set_fn:7
 ├── values
 │    └── tuple
 └── zip
      └── udf: set_fn
           ├── args
           │    └── const: 1
           ├── params: i:1
           └── body
                └── project
                     ├── columns: b:3
                     └── select
                          ├── columns: a:2!null b:3 c:4 crdb_internal_mvcc_timestamp:5 tableoid:6
                          ├── scan abc
                          │    └── columns: a:2!null b:3 c:4 crdb_internal_mvcc_timestamp:5 tableoid:6
                          └── filters
                               └── gt
                                    ├── variable: a:2
                                    └── variable: i:1

build format=show-scalars
SELECT a, set_fn(a) FROM abc
----
project
 ├── columns: a:1!null set_fn:12
 └── project-set
      ├── columns: a:1!null b:2 c:3 crdb_internal_mvcc_timestamp:4 tableoid:5 set_fn:12
      ├── scan abc
      │    └── columns: a:1!null b:2 c:3 crdb_internal_mvcc_timestamp:4 tableoid:5
      └── zip
           └── udf: set_fn
                ├── args
                │    └── variable: a:1
                ├── params: i:6
                └── body
                     └── project
                          ├── columns: b:8
                          └── select
                               ├── columns: a:7!null b:8 c:9 crdb_internal_mvcc_timestamp:10 tableoid:11
                               ├── scan abc
                               │    └── columns: a:7!null b:8 c:9 crdb_internal_mvcc_timestamp:10 tableoid:11
                               └── filters
                                    └── gt
                                         ├── variable: a:7
                                         └── variable: i:6


# --------------------------------------------------
# UDFs with ANY/ALL expressions.
# --------------------------------------------------

exec-ddl
CREATE FUNCTION any_fn(i INT) RETURNS BOOL LANGUAGE SQL AS 'SELECT i = ANY(SELECT a FROM abc)'
----

build format=show-scalars
SELECT any_fn(10)
----
project
 ├── columns: any_fn:11
 ├── values
 │    └── tuple
 └── projections
      └── udf: any_fn [as=any_fn:11]
           ├── args
           │    └── const: 10
           ├── params: i:1
           └── body
                └── limit
                     ├── columns: "?column?":10
                     ├── project
                     │    ├── columns: "?column?":10
                     │    ├── values
                     │    │    └── tuple
                     │    └── projections
                     │         └── subquery [as="?column?":10]
                     │              └── project
                     │                   ├── columns: case:9
                     │                   ├── scalar-group-by
                     │                   │    ├── columns: bool_or:8
                     │                   │    ├── project
                     │                   │    │    ├── columns: notnull:7!null
                     │                   │    │    ├── select
                     │                   │    │    │    ├── columns: a:2!null
                     │                   │    │    │    ├── project
                     │                   │    │    │    │    ├── columns: a:2!null
                     │                   │    │    │    │    └── scan abc
                     │                   │    │    │    │         └── columns: a:2!null b:3 c:4 crdb_internal_mvcc_timestamp:5 tableoid:6
                     │                   │    │    │    └── filters
                     │                   │    │    │         └── is-not
                     │                   │    │    │              ├── eq
                     │                   │    │    │              │    ├── variable: i:1
                     │                   │    │    │              │    └── variable: a:2
                     │                   │    │    │              └── false
                     │                   │    │    └── projections
                     │                   │    │         └── is-not [as=notnull:7]
                     │                   │    │              ├── variable: a:2
                     │                   │    │              └── null
                     │                   │    └── aggregations
                     │                   │         └── bool-or [as=bool_or:8]
                     │                   │              └── variable: notnull:7
                     │                   └── projections
                     │                        └── case [as=case:9]
                     │                             ├── true
                     │                             ├── when
                     │                             │    ├── and
                     │                             │    │    ├── variable: bool_or:8
                     │                             │    │    └── is-not
                     │                             │    │         ├── variable: i:1
                     │                             │    │         └── null
                     │                             │    └── true
                     │                             ├── when
                     │                             │    ├── is
                     │                             │    │    ├── variable: bool_or:8
                     │                             │    │    └── null
                     │                             │    └── false
                     │                             └── null
                     └── const: 1

exec-ddl
CREATE FUNCTION all_fn(i INT) RETURNS BOOL LANGUAGE SQL AS 'SELECT i < ALL(SELECT a FROM abc WHERE b > i)'
----

build format=show-scalars
SELECT all_fn(10)
----
project
 ├── columns: all_fn:11
 ├── values
 │    └── tuple
 └── projections
      └── udf: all_fn [as=all_fn:11]
           ├── args
           │    └── const: 10
           ├── params: i:1
           └── body
                └── limit
                     ├── columns: "?column?":10
                     ├── project
                     │    ├── columns: "?column?":10
                     │    ├── values
                     │    │    └── tuple
                     │    └── projections
                     │         └── not [as="?column?":10]
                     │              └── subquery
                     │                   └── project
                     │                        ├── columns: case:9
                     │                        ├── scalar-group-by
                     │                        │    ├── columns: bool_or:8
                     │                        │    ├── project
                     │                        │    │    ├── columns: notnull:7!null
                     │                        │    │    ├── select
                     │                        │    │    │    ├── columns: a:2!null
                     │                        │    │    │    ├── project
                     │                        │    │    │    │    ├── columns: a:2!null
                     │                        │    │    │    │    └── select
                     │                        │    │    │    │         ├── columns: a:2!null b:3!null c:4 crdb_internal_mvcc_timestamp:5 tableoid:6
                     │                        │    │    │    │         ├── scan abc
                     │                        │    │    │    │         │    └── columns: a:2!null b:3 c:4 crdb_internal_mvcc_timestamp:5 tableoid:6
                     │                        │    │    │    │         └── filters
                     │                        │    │    │    │              └── gt
                     │                        │    │    │    │                   ├── variable: b:3
                     │                        │    │    │    │                   └── variable: i:1
                     │                        │    │    │    └── filters
                     │                        │    │    │         └── is-not
                     │                        │    │    │              ├── ge
                     │                        │    │    │              │    ├── variable: i:1
                     │                        │    │    │              │    └── variable: a:2
                     │                        │    │    │              └── false
                     │                        │    │    └── projections
                     │                        │    │         └── is-not [as=notnull:7]
                     │                        │    │              ├── variable: a:2
                     │                        │    │              └── null
                     │                        │    └── aggregations
                     │                        │         └── bool-or [as=bool_or:8]
                     │                        │              └── variable: notnull:7
                     │                        └── projections
                     │                             └── case [as=case:9]
                     │                                  ├── true
                     │                                  ├── when
                     │                                  │    ├── and
                     │                                  │    │    ├── variable: bool_or:8
                     │                                  │    │    └── is-not
                     │                                  │    │         ├── variable: i:1
                     │                                  │    │         └── null
                     │                                  │    └── true
                     │                                  ├── when
                     │                                  │    ├── is
                     │                                  │    │    ├── variable: bool_or:8
                     │                                  │    │    └── null
                     │                                  │    └── false
                     │                                  └── null
                     └── const: 1

exec-ddl
CREATE FUNCTION any_fn_tuple(i INT, j INT) RETURNS BOOL LANGUAGE SQL AS 'SELECT (i, j) = ANY(SELECT a, b FROM abc)'
----

build format=show-scalars
SELECT any_fn_tuple(10, 20)
----
project
 ├── columns: any_fn_tuple:13
 ├── values
 │    └── tuple
 └── projections
      └── udf: any_fn_tuple [as=any_fn_tuple:13]
           ├── args
           │    ├── const: 10
           │    └── const: 20
           ├── params: i:1 j:2
           └── body
                └── limit
                     ├── columns: "?column?":12
                     ├── project
                     │    ├── columns: "?column?":12
                     │    ├── values
                     │    │    └── tuple
                     │    └── projections
                     │         └── subquery [as="?column?":12]
                     │              └── project
                     │                   ├── columns: case:11
                     │                   ├── scalar-group-by
                     │                   │    ├── columns: bool_or:10
                     │                   │    ├── project
                     │                   │    │    ├── columns: notnull:9!null
                     │                   │    │    ├── select
                     │                   │    │    │    ├── columns: column8:8
                     │                   │    │    │    ├── project
                     │                   │    │    │    │    ├── columns: column8:8
                     │                   │    │    │    │    ├── project
                     │                   │    │    │    │    │    ├── columns: a:3!null b:4
                     │                   │    │    │    │    │    └── scan abc
                     │                   │    │    │    │    │         └── columns: a:3!null b:4 c:5 crdb_internal_mvcc_timestamp:6 tableoid:7
                     │                   │    │    │    │    └── projections
                     │                   │    │    │    │         └── tuple [as=column8:8]
                     │                   │    │    │    │              ├── variable: a:3
                     │                   │    │    │    │              └── variable: b:4
                     │                   │    │    │    └── filters
                     │                   │    │    │         └── is-not
                     │                   │    │    │              ├── eq
                     │                   │    │    │              │    ├── tuple
                     │                   │    │    │              │    │    ├── variable: i:1
                     │                   │    │    │              │    │    └── variable: j:2
                     │                   │    │    │              │    └── variable: column8:8
                     │                   │    │    │              └── false
                     │                   │    │    └── projections
                     │                   │    │         └── is-tuple-not-null [as=notnull:9]
                     │                   │    │              └── variable: column8:8
                     │                   │    └── aggregations
                     │                   │         └── bool-or [as=bool_or:10]
                     │                   │              └── variable: notnull:9
                     │                   └── projections
                     │                        └── case [as=case:11]
                     │                             ├── true
                     │                             ├── when
                     │                             │    ├── and
                     │                             │    │    ├── variable: bool_or:10
                     │                             │    │    └── is-tuple-not-null
                     │                             │    │         └── tuple
                     │                             │    │              ├── variable: i:1
                     │                             │    │              └── variable: j:2
                     │                             │    └── true
                     │                             ├── when
                     │                             │    ├── is
                     │                             │    │    ├── variable: bool_or:10
                     │                             │    │    └── null
                     │                             │    └── false
                     │                             └── null
                     └── const: 1


# --------------------------------------------------
# UDFs with mutations.
# --------------------------------------------------

exec-ddl
CREATE FUNCTION ups(x INT, y INT, z INT) RETURNS BOOL LANGUAGE SQL AS $$
  UPSERT INTO abc VALUES (x, y, z);
  SELECT true;
$$
----

# A single UPSERT to abc is allowed.
build format=hide-all
SELECT ups(1, 2, 3)
----
project
 ├── values
 │    └── ()
 └── projections
      └── ups(1, 2, 3)

# Multiple mutations to abc by the root statement and the UDF.
build
UPDATE abc SET c = 3 WHERE ups(1, 2, 3)
----
error (0A000): multiple mutations of the same table "abc" are not supported unless they all use INSERT without ON CONFLICT; this is to prevent data corruption, see documentation of sql.multiple_modifications_of_table.enabled

# Multiple mutations to abc by the root statement and the UDF is allowed with
# enable_multiple_modifications_of_table enabled.
build set=enable_multiple_modifications_of_table=true
UPDATE abc SET c = 3 WHERE ups(1, 2, 3)
----
update abc
 ├── columns: <none>
 ├── fetch columns: a:6 b:7 c:8
 ├── update-mapping:
 │    └── c_new:23 => c:3
 └── project
      ├── columns: c_new:23!null a:6!null b:7 c:8 crdb_internal_mvcc_timestamp:9 tableoid:10
      ├── select
      │    ├── columns: a:6!null b:7 c:8 crdb_internal_mvcc_timestamp:9 tableoid:10
      │    ├── scan abc
      │    │    ├── columns: a:6!null b:7 c:8 crdb_internal_mvcc_timestamp:9 tableoid:10
      │    │    └── flags: avoid-full-scan
      │    └── filters
      │         └── ups(1, 2, 3)
      └── projections
           └── 3 [as=c_new:23]

# Multiple mutations to abc by the root statement and the UDF.
build
WITH x AS (
  SELECT a FROM abc WHERE ups(1, 2, 3)
), y AS (
  UPSERT INTO abc VALUES (4, 5, 6) RETURNING j
)
SELECT * FROM x
----
error (0A000): multiple mutations of the same table "abc" are not supported unless they all use INSERT without ON CONFLICT; this is to prevent data corruption, see documentation of sql.multiple_modifications_of_table.enabled

exec-ddl
CREATE FUNCTION upd_ups(x INT, y INT, z INT) RETURNS VOID LANGUAGE SQL AS $$
  UPDATE abc SET c = 3 WHERE ups(x, y, z);
$$
----

# Multiple mutations to abc by the two UDFs invoked.
build
SELECT upd_ups(1, 2, 3)
----
error (0A000): multiple mutations of the same table "abc" are not supported unless they all use INSERT without ON CONFLICT; this is to prevent data corruption, see documentation of sql.multiple_modifications_of_table.enabled

# Multiple mutations to abc by the two UDFs invoked is allowed with
# enabled_multiple_modifications_of_table enabled.
build set=enable_multiple_modifications_of_table=true
SELECT upd_ups(1, 2, 3)
----
project
 ├── columns: upd_ups:28
 ├── values
 │    └── ()
 └── projections
      └── upd_ups(1, 2, 3) [as=upd_ups:28]

exec-ddl
CREATE FUNCTION ups2(a1 INT, b1 INT, c1 INT, a2 INT, b2 INT, c2 INT) RETURNS BOOL LANGUAGE SQL AS $$
  UPSERT INTO abc VALUES (a1, b1, c1);
  UPSERT INTO abc VALUES (a2, b2, c2);
  SELECT true;
$$
----

# Multiple mutations to abc in sibling statements in the UDF is allowed.
build format=hide-all
SELECT ups2(1, 2, 3, 4, 5, 6)
----
project
 ├── values
 │    └── ()
 └── projections
      └── ups2(1, 2, 3, 4, 5, 6)

exec-ddl
CREATE FUNCTION ups3(a1 INT, b1 INT, c1 INT, a2 INT, b2 INT, c2 INT) RETURNS BOOL LANGUAGE SQL AS $$
  UPSERT INTO abc VALUES (a1, b1, c1);
  SELECT ups(a2, b2, c2);
$$
----

# Multiple mutations to abc in sibling statements in the UDF is allowed.
build format=hide-all
SELECT ups3(1, 2, 3, 4, 5, 6)
----
project
 ├── values
 │    └── ()
 └── projections
      └── ups3(1, 2, 3, 4, 5, 6)

# --------------------------------------------------
# UDFs with foreign key constraints.
# --------------------------------------------------

exec-ddl
CREATE TABLE parent (p INT PRIMARY KEY);
----

exec-ddl
CREATE TABLE child (c INT PRIMARY KEY, p INT NOT NULL REFERENCES parent(p));
----

exec-ddl
CREATE FUNCTION f_fk(k INT, r INT) RETURNS RECORD AS $$
  INSERT INTO child VALUES (k,r) RETURNING *;
$$ LANGUAGE SQL;
----

opt format=show-scalars
SELECT f_fk(100, 1), f_fk(101, 2);
----
values
 ├── columns: f_fk:15 f_fk:30
 └── tuple
      ├── udf: f_fk
      │    ├── args
      │    │    ├── const: 100
      │    │    └── const: 1
      │    ├── params: k:1 r:2
      │    └── body
      │         └── project
      │              ├── columns: column14:14!null
      │              ├── insert child
      │              │    ├── columns: c:3!null child.p:4!null
      │              │    ├── insert-mapping:
      │              │    │    ├── column1:7 => c:3
      │              │    │    └── column2:8 => child.p:4
      │              │    ├── return-mapping:
      │              │    │    ├── column1:7 => c:3
      │              │    │    └── column2:8 => child.p:4
      │              │    ├── input binding: &1
      │              │    ├── values
      │              │    │    ├── columns: column1:7 column2:8
      │              │    │    └── tuple
      │              │    │         ├── variable: k:1
      │              │    │         └── variable: r:2
      │              │    └── f-k-checks
      │              │         └── f-k-checks-item: child(p) -> parent(p)
      │              │              └── anti-join (hash)
      │              │                   ├── columns: p:9
      │              │                   ├── with-scan &1
      │              │                   │    ├── columns: p:9
      │              │                   │    └── mapping:
      │              │                   │         └──  column2:8 => p:9
      │              │                   ├── scan parent
      │              │                   │    ├── columns: parent.p:10!null
      │              │                   │    └── flags: avoid-full-scan disabled not visible index feature
      │              │                   └── filters
      │              │                        └── eq
      │              │                             ├── variable: p:9
      │              │                             └── variable: parent.p:10
      │              └── projections
      │                   └── assignment-cast: RECORD [as=column14:14]
      │                        └── tuple
      │                             ├── variable: c:3
      │                             └── variable: child.p:4
      └── udf: f_fk
           ├── args
           │    ├── const: 101
           │    └── const: 2
           ├── params: k:16 r:17
           └── body
                └── project
                     ├── columns: column29:29!null
                     ├── insert child
                     │    ├── columns: c:18!null child.p:19!null
                     │    ├── insert-mapping:
                     │    │    ├── column1:22 => c:18
                     │    │    └── column2:23 => child.p:19
                     │    ├── return-mapping:
                     │    │    ├── column1:22 => c:18
                     │    │    └── column2:23 => child.p:19
                     │    ├── input binding: &2
                     │    ├── values
                     │    │    ├── columns: column1:22 column2:23
                     │    │    └── tuple
                     │    │         ├── variable: k:16
                     │    │         └── variable: r:17
                     │    └── f-k-checks
                     │         └── f-k-checks-item: child(p) -> parent(p)
                     │              └── anti-join (hash)
                     │                   ├── columns: p:24
                     │                   ├── with-scan &2
                     │                   │    ├── columns: p:24
                     │                   │    └── mapping:
                     │                   │         └──  column2:23 => p:24
                     │                   ├── scan parent
                     │                   │    ├── columns: parent.p:25!null
                     │                   │    └── flags: avoid-full-scan disabled not visible index feature
                     │                   └── filters
                     │                        └── eq
                     │                             ├── variable: p:24
                     │                             └── variable: parent.p:25
                     └── projections
                          └── assignment-cast: RECORD [as=column29:29]
                               └── tuple
                                    ├── variable: c:18
                                    └── variable: child.p:19
