exec-ddl
CREATE TABLE abc (
    a INT NOT NULL,
    b INT DEFAULT (10),
    c INT AS (abc.b + 1) STORED,
    UNIQUE(a),
    UNIQUE(b, c)
)
----
TABLE abc
 ├── a int not null
 ├── b int
 ├── c int
 ├── rowid int not null (hidden)
 ├── INDEX primary
 │    └── rowid int not null (hidden)
 ├── INDEX secondary
 │    ├── a int not null
 │    └── rowid int not null (hidden) (storing)
 └── INDEX secondary
      ├── b int
      ├── c int
      └── rowid int not null (hidden) (storing)

exec-ddl
CREATE TABLE xyz (
    x INT PRIMARY KEY,
    y INT,
    z INT,
    UNIQUE (y, z),
    UNIQUE (z, y),
    INDEX (y DESC)
)
----
TABLE xyz
 ├── x int not null
 ├── y int
 ├── z int
 ├── INDEX primary
 │    └── x int not null
 ├── INDEX secondary
 │    ├── y int
 │    ├── z int
 │    └── x int not null (storing)
 ├── INDEX secondary
 │    ├── z int
 │    ├── y int
 │    └── x int not null (storing)
 └── INDEX secondary
      ├── y int desc
      └── x int not null

exec-ddl
CREATE TABLE uv (
    u INT,
    v INT,
    PRIMARY KEY (u, v)
)
----
TABLE uv
 ├── u int not null
 ├── v int not null
 └── INDEX primary
      ├── u int not null
      └── v int not null

exec-ddl
CREATE TABLE noindex (
    x INT PRIMARY KEY,
    y INT,
    z INT
)
----
TABLE noindex
 ├── x int not null
 ├── y int
 ├── z int
 └── INDEX primary
      └── x int not null

exec-ddl
CREATE TABLE mutation (
    m INT PRIMARY KEY,
    n INT,
    "o:write-only" INT DEFAULT(10),
    "p:write-only" INT AS (o + n) STORED,
    "q:delete-only" INT AS (m * p) STORED,
    CHECK (m > 0)
)
----
TABLE mutation
 ├── m int not null
 ├── n int
 ├── o int (mutation)
 ├── p int (mutation)
 ├── q int (mutation)
 ├── INDEX primary
 │    └── m int not null
 └── CHECK (m > 0)

exec-ddl
CREATE TABLE checks (
	a INT PRIMARY KEY CHECK (a > 0),
	b INT,
	c INT,
    d INT AS (c + 1) STORED,
    CHECK (checks.b < d)
)
----
TABLE checks
 ├── a int not null
 ├── b int
 ├── c int
 ├── d int
 ├── INDEX primary
 │    └── a int not null
 ├── CHECK (checks.b < d)
 └── CHECK (a > 0)

exec-ddl
CREATE TABLE decimals (
    a DECIMAL(10,0) PRIMARY KEY CHECK (round(a) = a),
    b DECIMAL(5,1)[] CHECK (b[0] > 1),
    c DECIMAL(10,1) DEFAULT (1.23),
    d DECIMAL(10,1) AS (a+c) STORED
)
----
TABLE decimals
 ├── a decimal not null
 ├── b decimal[]
 ├── c decimal
 ├── d decimal
 ├── INDEX primary
 │    └── a decimal not null
 ├── CHECK (round(a) = a)
 └── CHECK (b[0] > 1)

# ------------------------------------------------------------------------------
# Basic tests.
# ------------------------------------------------------------------------------

# Set single column, single column conflict.
build
INSERT INTO abc (a, b)
SELECT x, y FROM xyz
ON CONFLICT (a) DO
UPDATE SET a=5
----
upsert abc
 ├── columns: <none>
 ├── canary column: 13
 ├── fetch columns: a:10(int) b:11(int) c:12(int) rowid:13(int)
 ├── insert-mapping:
 │    ├──  x:5 => a:1
 │    ├──  y:6 => b:2
 │    ├──  column9:9 => c:3
 │    └──  column8:8 => rowid:4
 ├── update-mapping:
 │    ├──  upsert_a:16 => a:1
 │    └──  upsert_c:18 => c:3
 └── project
      ├── columns: upsert_a:16(int) upsert_b:17(int) upsert_c:18(int) upsert_rowid:19(int) x:5(int!null) y:6(int) column8:8(int) column9:9(int) a:10(int) b:11(int) c:12(int) rowid:13(int) column14:14(int!null) column15:15(int)
      ├── project
      │    ├── columns: column15:15(int) x:5(int!null) y:6(int) column8:8(int) column9:9(int) a:10(int) b:11(int) c:12(int) rowid:13(int) column14:14(int!null)
      │    ├── project
      │    │    ├── columns: column14:14(int!null) x:5(int!null) y:6(int) column8:8(int) column9:9(int) a:10(int) b:11(int) c:12(int) rowid:13(int)
      │    │    ├── left-join
      │    │    │    ├── columns: x:5(int!null) y:6(int) column8:8(int) column9:9(int) a:10(int) b:11(int) c:12(int) rowid:13(int)
      │    │    │    ├── project
      │    │    │    │    ├── columns: column9:9(int) x:5(int!null) y:6(int) column8:8(int)
      │    │    │    │    ├── project
      │    │    │    │    │    ├── columns: column8:8(int) x:5(int!null) y:6(int)
      │    │    │    │    │    ├── project
      │    │    │    │    │    │    ├── columns: x:5(int!null) y:6(int)
      │    │    │    │    │    │    └── scan xyz
      │    │    │    │    │    │         └── columns: x:5(int!null) y:6(int) z:7(int)
      │    │    │    │    │    └── projections
      │    │    │    │    │         └── function: unique_rowid [type=int]
      │    │    │    │    └── projections
      │    │    │    │         └── plus [type=int]
      │    │    │    │              ├── variable: y [type=int]
      │    │    │    │              └── const: 1 [type=int]
      │    │    │    ├── scan abc
      │    │    │    │    └── columns: a:10(int!null) b:11(int) c:12(int) rowid:13(int!null)
      │    │    │    └── filters
      │    │    │         └── eq [type=bool]
      │    │    │              ├── variable: x [type=int]
      │    │    │              └── variable: a [type=int]
      │    │    └── projections
      │    │         └── const: 5 [type=int]
      │    └── projections
      │         └── plus [type=int]
      │              ├── variable: b [type=int]
      │              └── const: 1 [type=int]
      └── projections
           ├── case [type=int]
           │    ├── true [type=bool]
           │    ├── when [type=int]
           │    │    ├── is [type=bool]
           │    │    │    ├── variable: rowid [type=int]
           │    │    │    └── null [type=unknown]
           │    │    └── variable: x [type=int]
           │    └── variable: column14 [type=int]
           ├── case [type=int]
           │    ├── true [type=bool]
           │    ├── when [type=int]
           │    │    ├── is [type=bool]
           │    │    │    ├── variable: rowid [type=int]
           │    │    │    └── null [type=unknown]
           │    │    └── variable: y [type=int]
           │    └── variable: b [type=int]
           ├── case [type=int]
           │    ├── true [type=bool]
           │    ├── when [type=int]
           │    │    ├── is [type=bool]
           │    │    │    ├── variable: rowid [type=int]
           │    │    │    └── null [type=unknown]
           │    │    └── variable: column9 [type=int]
           │    └── variable: column15 [type=int]
           └── case [type=int]
                ├── true [type=bool]
                ├── when [type=int]
                │    ├── is [type=bool]
                │    │    ├── variable: rowid [type=int]
                │    │    └── null [type=unknown]
                │    └── variable: column8 [type=int]
                └── variable: rowid [type=int]

# Set all columns, multi-column conflict.
build
INSERT INTO abc (a, b, rowid)
SELECT x, y, z FROM xyz
ON CONFLICT (b, c) DO
UPDATE SET a=1, b=2, rowid=3
RETURNING *
----
project
 ├── columns: a:1(int!null) b:2(int) c:3(int)
 └── upsert abc
      ├── columns: a:1(int!null) b:2(int) c:3(int) rowid:4(int!null)
      ├── canary column: 12
      ├── fetch columns: a:9(int) b:10(int) c:11(int) rowid:12(int)
      ├── insert-mapping:
      │    ├──  x:5 => a:1
      │    ├──  y:6 => b:2
      │    ├──  column8:8 => c:3
      │    └──  z:7 => rowid:4
      ├── update-mapping:
      │    ├──  upsert_a:17 => a:1
      │    ├──  upsert_b:18 => b:2
      │    ├──  upsert_c:19 => c:3
      │    └──  upsert_rowid:20 => rowid:4
      ├── return-mapping:
      │    ├──  upsert_a:17 => a:1
      │    ├──  upsert_b:18 => b:2
      │    ├──  upsert_c:19 => c:3
      │    └──  upsert_rowid:20 => rowid:4
      └── project
           ├── columns: upsert_a:17(int) upsert_b:18(int) upsert_c:19(int) upsert_rowid:20(int) x:5(int!null) y:6(int) z:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) rowid:12(int) column13:13(int!null) column14:14(int!null) column15:15(int!null) column16:16(int)
           ├── project
           │    ├── columns: column16:16(int) x:5(int!null) y:6(int) z:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) rowid:12(int) column13:13(int!null) column14:14(int!null) column15:15(int!null)
           │    ├── project
           │    │    ├── columns: column13:13(int!null) column14:14(int!null) column15:15(int!null) x:5(int!null) y:6(int) z:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) rowid:12(int)
           │    │    ├── left-join
           │    │    │    ├── columns: x:5(int!null) y:6(int) z:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) rowid:12(int)
           │    │    │    ├── project
           │    │    │    │    ├── columns: column8:8(int) x:5(int!null) y:6(int) z:7(int)
           │    │    │    │    ├── scan xyz
           │    │    │    │    │    └── columns: x:5(int!null) y:6(int) z:7(int)
           │    │    │    │    └── projections
           │    │    │    │         └── plus [type=int]
           │    │    │    │              ├── variable: y [type=int]
           │    │    │    │              └── const: 1 [type=int]
           │    │    │    ├── scan abc
           │    │    │    │    └── columns: a:9(int!null) b:10(int) c:11(int) rowid:12(int!null)
           │    │    │    └── filters
           │    │    │         ├── eq [type=bool]
           │    │    │         │    ├── variable: y [type=int]
           │    │    │         │    └── variable: b [type=int]
           │    │    │         └── eq [type=bool]
           │    │    │              ├── variable: column8 [type=int]
           │    │    │              └── variable: c [type=int]
           │    │    └── projections
           │    │         ├── const: 1 [type=int]
           │    │         ├── const: 2 [type=int]
           │    │         └── const: 3 [type=int]
           │    └── projections
           │         └── plus [type=int]
           │              ├── variable: column14 [type=int]
           │              └── const: 1 [type=int]
           └── projections
                ├── case [type=int]
                │    ├── true [type=bool]
                │    ├── when [type=int]
                │    │    ├── is [type=bool]
                │    │    │    ├── variable: rowid [type=int]
                │    │    │    └── null [type=unknown]
                │    │    └── variable: x [type=int]
                │    └── variable: column13 [type=int]
                ├── case [type=int]
                │    ├── true [type=bool]
                │    ├── when [type=int]
                │    │    ├── is [type=bool]
                │    │    │    ├── variable: rowid [type=int]
                │    │    │    └── null [type=unknown]
                │    │    └── variable: y [type=int]
                │    └── variable: column14 [type=int]
                ├── case [type=int]
                │    ├── true [type=bool]
                │    ├── when [type=int]
                │    │    ├── is [type=bool]
                │    │    │    ├── variable: rowid [type=int]
                │    │    │    └── null [type=unknown]
                │    │    └── variable: column8 [type=int]
                │    └── variable: column16 [type=int]
                └── case [type=int]
                     ├── true [type=bool]
                     ├── when [type=int]
                     │    ├── is [type=bool]
                     │    │    ├── variable: rowid [type=int]
                     │    │    └── null [type=unknown]
                     │    └── variable: z [type=int]
                     └── variable: column15 [type=int]

# UPDATE + WHERE clause.
build
INSERT INTO abc
SELECT x, y FROM xyz
ON CONFLICT (a) DO
UPDATE SET b=10
WHERE abc.a>0
----
upsert abc
 ├── columns: <none>
 ├── canary column: 13
 ├── fetch columns: a:10(int) b:11(int) c:12(int) rowid:13(int)
 ├── insert-mapping:
 │    ├──  x:5 => a:1
 │    ├──  y:6 => b:2
 │    ├──  column9:9 => c:3
 │    └──  column8:8 => rowid:4
 ├── update-mapping:
 │    ├──  upsert_b:17 => b:2
 │    └──  upsert_c:18 => c:3
 └── project
      ├── columns: upsert_a:16(int) upsert_b:17(int) upsert_c:18(int) upsert_rowid:19(int) x:5(int!null) y:6(int) column8:8(int) column9:9(int) a:10(int) b:11(int) c:12(int) rowid:13(int) column14:14(int!null) column15:15(int)
      ├── project
      │    ├── columns: column15:15(int) x:5(int!null) y:6(int) column8:8(int) column9:9(int) a:10(int) b:11(int) c:12(int) rowid:13(int) column14:14(int!null)
      │    ├── project
      │    │    ├── columns: column14:14(int!null) x:5(int!null) y:6(int) column8:8(int) column9:9(int) a:10(int) b:11(int) c:12(int) rowid:13(int)
      │    │    ├── select
      │    │    │    ├── columns: x:5(int!null) y:6(int) column8:8(int) column9:9(int) a:10(int) b:11(int) c:12(int) rowid:13(int)
      │    │    │    ├── left-join
      │    │    │    │    ├── columns: x:5(int!null) y:6(int) column8:8(int) column9:9(int) a:10(int) b:11(int) c:12(int) rowid:13(int)
      │    │    │    │    ├── project
      │    │    │    │    │    ├── columns: column9:9(int) x:5(int!null) y:6(int) column8:8(int)
      │    │    │    │    │    ├── project
      │    │    │    │    │    │    ├── columns: column8:8(int) x:5(int!null) y:6(int)
      │    │    │    │    │    │    ├── project
      │    │    │    │    │    │    │    ├── columns: x:5(int!null) y:6(int)
      │    │    │    │    │    │    │    └── scan xyz
      │    │    │    │    │    │    │         └── columns: x:5(int!null) y:6(int) z:7(int)
      │    │    │    │    │    │    └── projections
      │    │    │    │    │    │         └── function: unique_rowid [type=int]
      │    │    │    │    │    └── projections
      │    │    │    │    │         └── plus [type=int]
      │    │    │    │    │              ├── variable: y [type=int]
      │    │    │    │    │              └── const: 1 [type=int]
      │    │    │    │    ├── scan abc
      │    │    │    │    │    └── columns: a:10(int!null) b:11(int) c:12(int) rowid:13(int!null)
      │    │    │    │    └── filters
      │    │    │    │         └── eq [type=bool]
      │    │    │    │              ├── variable: x [type=int]
      │    │    │    │              └── variable: a [type=int]
      │    │    │    └── filters
      │    │    │         └── or [type=bool]
      │    │    │              ├── is [type=bool]
      │    │    │              │    ├── variable: rowid [type=int]
      │    │    │              │    └── null [type=unknown]
      │    │    │              └── gt [type=bool]
      │    │    │                   ├── variable: a [type=int]
      │    │    │                   └── const: 0 [type=int]
      │    │    └── projections
      │    │         └── const: 10 [type=int]
      │    └── projections
      │         └── plus [type=int]
      │              ├── variable: column14 [type=int]
      │              └── const: 1 [type=int]
      └── projections
           ├── case [type=int]
           │    ├── true [type=bool]
           │    ├── when [type=int]
           │    │    ├── is [type=bool]
           │    │    │    ├── variable: rowid [type=int]
           │    │    │    └── null [type=unknown]
           │    │    └── variable: x [type=int]
           │    └── variable: a [type=int]
           ├── case [type=int]
           │    ├── true [type=bool]
           │    ├── when [type=int]
           │    │    ├── is [type=bool]
           │    │    │    ├── variable: rowid [type=int]
           │    │    │    └── null [type=unknown]
           │    │    └── variable: y [type=int]
           │    └── variable: column14 [type=int]
           ├── case [type=int]
           │    ├── true [type=bool]
           │    ├── when [type=int]
           │    │    ├── is [type=bool]
           │    │    │    ├── variable: rowid [type=int]
           │    │    │    └── null [type=unknown]
           │    │    └── variable: column9 [type=int]
           │    └── variable: column15 [type=int]
           └── case [type=int]
                ├── true [type=bool]
                ├── when [type=int]
                │    ├── is [type=bool]
                │    │    ├── variable: rowid [type=int]
                │    │    └── null [type=unknown]
                │    └── variable: column8 [type=int]
                └── variable: rowid [type=int]

# Use RETURNING INSERT..ON CONFLICT as a FROM clause.
build
SELECT *
FROM [INSERT INTO abc (a, b) VALUES (1,2), (3,4) ON CONFLICT (a) DO UPDATE SET b=1 RETURNING *]
ORDER BY a, b DESC
----
sort
 ├── columns: a:1(int!null) b:2(int) c:3(int)
 ├── ordering: +1,-2
 └── project
      ├── columns: a:1(int!null) b:2(int) c:3(int)
      └── upsert abc
           ├── columns: a:1(int!null) b:2(int) c:3(int) rowid:4(int!null)
           ├── canary column: 12
           ├── fetch columns: a:9(int) b:10(int) c:11(int) rowid:12(int)
           ├── insert-mapping:
           │    ├──  column1:5 => a:1
           │    ├──  column2:6 => b:2
           │    ├──  column8:8 => c:3
           │    └──  column7:7 => rowid:4
           ├── update-mapping:
           │    ├──  upsert_b:16 => b:2
           │    └──  upsert_c:17 => c:3
           ├── return-mapping:
           │    ├──  upsert_a:15 => a:1
           │    ├──  upsert_b:16 => b:2
           │    ├──  upsert_c:17 => c:3
           │    └──  upsert_rowid:18 => rowid:4
           └── project
                ├── columns: upsert_a:15(int) upsert_b:16(int) upsert_c:17(int) upsert_rowid:18(int) column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) rowid:12(int) column13:13(int!null) column14:14(int)
                ├── project
                │    ├── columns: column14:14(int) column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) rowid:12(int) column13:13(int!null)
                │    ├── project
                │    │    ├── columns: column13:13(int!null) column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) rowid:12(int)
                │    │    ├── left-join
                │    │    │    ├── columns: column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) rowid:12(int)
                │    │    │    ├── project
                │    │    │    │    ├── columns: column8:8(int) column1:5(int) column2:6(int) column7:7(int)
                │    │    │    │    ├── project
                │    │    │    │    │    ├── columns: column7:7(int) column1:5(int) column2:6(int)
                │    │    │    │    │    ├── values
                │    │    │    │    │    │    ├── columns: column1:5(int) column2:6(int)
                │    │    │    │    │    │    ├── tuple [type=tuple{int, int}]
                │    │    │    │    │    │    │    ├── const: 1 [type=int]
                │    │    │    │    │    │    │    └── const: 2 [type=int]
                │    │    │    │    │    │    └── tuple [type=tuple{int, int}]
                │    │    │    │    │    │         ├── const: 3 [type=int]
                │    │    │    │    │    │         └── const: 4 [type=int]
                │    │    │    │    │    └── projections
                │    │    │    │    │         └── function: unique_rowid [type=int]
                │    │    │    │    └── projections
                │    │    │    │         └── plus [type=int]
                │    │    │    │              ├── variable: column2 [type=int]
                │    │    │    │              └── const: 1 [type=int]
                │    │    │    ├── scan abc
                │    │    │    │    └── columns: a:9(int!null) b:10(int) c:11(int) rowid:12(int!null)
                │    │    │    └── filters
                │    │    │         └── eq [type=bool]
                │    │    │              ├── variable: column1 [type=int]
                │    │    │              └── variable: a [type=int]
                │    │    └── projections
                │    │         └── const: 1 [type=int]
                │    └── projections
                │         └── plus [type=int]
                │              ├── variable: column13 [type=int]
                │              └── const: 1 [type=int]
                └── projections
                     ├── case [type=int]
                     │    ├── true [type=bool]
                     │    ├── when [type=int]
                     │    │    ├── is [type=bool]
                     │    │    │    ├── variable: rowid [type=int]
                     │    │    │    └── null [type=unknown]
                     │    │    └── variable: column1 [type=int]
                     │    └── variable: a [type=int]
                     ├── case [type=int]
                     │    ├── true [type=bool]
                     │    ├── when [type=int]
                     │    │    ├── is [type=bool]
                     │    │    │    ├── variable: rowid [type=int]
                     │    │    │    └── null [type=unknown]
                     │    │    └── variable: column2 [type=int]
                     │    └── variable: column13 [type=int]
                     ├── case [type=int]
                     │    ├── true [type=bool]
                     │    ├── when [type=int]
                     │    │    ├── is [type=bool]
                     │    │    │    ├── variable: rowid [type=int]
                     │    │    │    └── null [type=unknown]
                     │    │    └── variable: column8 [type=int]
                     │    └── variable: column14 [type=int]
                     └── case [type=int]
                          ├── true [type=bool]
                          ├── when [type=int]
                          │    ├── is [type=bool]
                          │    │    ├── variable: rowid [type=int]
                          │    │    └── null [type=unknown]
                          │    └── variable: column7 [type=int]
                          └── variable: rowid [type=int]

# Use table alias.
build
INSERT INTO abc AS tab (a, b)
VALUES (1, 2)
ON CONFLICT (a) DO
UPDATE SET a=tab.a*excluded.a
----
upsert tab
 ├── columns: <none>
 ├── canary column: 12
 ├── fetch columns: a:9(int) b:10(int) c:11(int) rowid:12(int)
 ├── insert-mapping:
 │    ├──  column1:5 => a:1
 │    ├──  column2:6 => b:2
 │    ├──  column8:8 => c:3
 │    └──  column7:7 => rowid:4
 ├── update-mapping:
 │    ├──  upsert_a:15 => a:1
 │    └──  upsert_c:17 => c:3
 └── project
      ├── columns: upsert_a:15(int) upsert_b:16(int) upsert_c:17(int) upsert_rowid:18(int) column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) rowid:12(int) column13:13(int) column14:14(int)
      ├── project
      │    ├── columns: column14:14(int) column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) rowid:12(int) column13:13(int)
      │    ├── project
      │    │    ├── columns: column13:13(int) column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) rowid:12(int)
      │    │    ├── left-join
      │    │    │    ├── columns: column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) rowid:12(int)
      │    │    │    ├── project
      │    │    │    │    ├── columns: column8:8(int) column1:5(int) column2:6(int) column7:7(int)
      │    │    │    │    ├── project
      │    │    │    │    │    ├── columns: column7:7(int) column1:5(int) column2:6(int)
      │    │    │    │    │    ├── values
      │    │    │    │    │    │    ├── columns: column1:5(int) column2:6(int)
      │    │    │    │    │    │    └── tuple [type=tuple{int, int}]
      │    │    │    │    │    │         ├── const: 1 [type=int]
      │    │    │    │    │    │         └── const: 2 [type=int]
      │    │    │    │    │    └── projections
      │    │    │    │    │         └── function: unique_rowid [type=int]
      │    │    │    │    └── projections
      │    │    │    │         └── plus [type=int]
      │    │    │    │              ├── variable: column2 [type=int]
      │    │    │    │              └── const: 1 [type=int]
      │    │    │    ├── scan tab
      │    │    │    │    └── columns: a:9(int!null) b:10(int) c:11(int) rowid:12(int!null)
      │    │    │    └── filters
      │    │    │         └── eq [type=bool]
      │    │    │              ├── variable: column1 [type=int]
      │    │    │              └── variable: a [type=int]
      │    │    └── projections
      │    │         └── mult [type=int]
      │    │              ├── variable: a [type=int]
      │    │              └── variable: column1 [type=int]
      │    └── projections
      │         └── plus [type=int]
      │              ├── variable: b [type=int]
      │              └── const: 1 [type=int]
      └── projections
           ├── case [type=int]
           │    ├── true [type=bool]
           │    ├── when [type=int]
           │    │    ├── is [type=bool]
           │    │    │    ├── variable: rowid [type=int]
           │    │    │    └── null [type=unknown]
           │    │    └── variable: column1 [type=int]
           │    └── variable: column13 [type=int]
           ├── case [type=int]
           │    ├── true [type=bool]
           │    ├── when [type=int]
           │    │    ├── is [type=bool]
           │    │    │    ├── variable: rowid [type=int]
           │    │    │    └── null [type=unknown]
           │    │    └── variable: column2 [type=int]
           │    └── variable: b [type=int]
           ├── case [type=int]
           │    ├── true [type=bool]
           │    ├── when [type=int]
           │    │    ├── is [type=bool]
           │    │    │    ├── variable: rowid [type=int]
           │    │    │    └── null [type=unknown]
           │    │    └── variable: column8 [type=int]
           │    └── variable: column14 [type=int]
           └── case [type=int]
                ├── true [type=bool]
                ├── when [type=int]
                │    ├── is [type=bool]
                │    │    ├── variable: rowid [type=int]
                │    │    └── null [type=unknown]
                │    └── variable: column7 [type=int]
                └── variable: rowid [type=int]

# Conflict columns don't match unique index (too few columns).
build
INSERT INTO abc (a, b)
VALUES (1, 2)
ON CONFLICT (b) DO
UPDATE SET a=5
----
error (42P10): there is no unique or exclusion constraint matching the ON CONFLICT specification

# Conflict columns don't match unique index (too many columns).
build
INSERT INTO abc (a, b)
VALUES (1, 2)
ON CONFLICT (a, b) DO
UPDATE SET a=5
----
error (42P10): there is no unique or exclusion constraint matching the ON CONFLICT specification

# Conflict columns don't match unique index (wrong order).
build
INSERT INTO abc (a, b)
VALUES (1, 2)
ON CONFLICT (c, b) DO
UPDATE SET a=5
----
error (42P10): there is no unique or exclusion constraint matching the ON CONFLICT specification

# ------------------------------------------------------------------------------
# Test DO NOTHING.
# ------------------------------------------------------------------------------

# No conflict columns specified (all non-duplicate indexes must be checked).
build
INSERT INTO xyz
VALUES (1, 2, 3), (4, 5, 6)
ON CONFLICT DO NOTHING
----
insert xyz
 ├── columns: <none>
 ├── insert-mapping:
 │    ├──  column1:4 => xyz.x:1
 │    ├──  column2:5 => xyz.y:2
 │    └──  column3:6 => xyz.z:3
 └── project
      ├── columns: column1:4(int) column2:5(int) column3:6(int)
      └── select
           ├── columns: column1:4(int) column2:5(int) column3:6(int) xyz_3.x:13(int) xyz_3.y:14(int) xyz_3.z:15(int)
           ├── left-join
           │    ├── columns: column1:4(int) column2:5(int) column3:6(int) xyz_3.x:13(int) xyz_3.y:14(int) xyz_3.z:15(int)
           │    ├── project
           │    │    ├── columns: column1:4(int) column2:5(int) column3:6(int)
           │    │    └── select
           │    │         ├── columns: column1:4(int) column2:5(int) column3:6(int) xyz_2.x:10(int) xyz_2.y:11(int) xyz_2.z:12(int)
           │    │         ├── left-join
           │    │         │    ├── columns: column1:4(int) column2:5(int) column3:6(int) xyz_2.x:10(int) xyz_2.y:11(int) xyz_2.z:12(int)
           │    │         │    ├── project
           │    │         │    │    ├── columns: column1:4(int) column2:5(int) column3:6(int)
           │    │         │    │    └── select
           │    │         │    │         ├── columns: column1:4(int) column2:5(int) column3:6(int) xyz_1.x:7(int) xyz_1.y:8(int) xyz_1.z:9(int)
           │    │         │    │         ├── left-join
           │    │         │    │         │    ├── columns: column1:4(int) column2:5(int) column3:6(int) xyz_1.x:7(int) xyz_1.y:8(int) xyz_1.z:9(int)
           │    │         │    │         │    ├── values
           │    │         │    │         │    │    ├── columns: column1:4(int) column2:5(int) column3:6(int)
           │    │         │    │         │    │    ├── tuple [type=tuple{int, int, int}]
           │    │         │    │         │    │    │    ├── const: 1 [type=int]
           │    │         │    │         │    │    │    ├── const: 2 [type=int]
           │    │         │    │         │    │    │    └── const: 3 [type=int]
           │    │         │    │         │    │    └── tuple [type=tuple{int, int, int}]
           │    │         │    │         │    │         ├── const: 4 [type=int]
           │    │         │    │         │    │         ├── const: 5 [type=int]
           │    │         │    │         │    │         └── const: 6 [type=int]
           │    │         │    │         │    ├── scan xyz_1
           │    │         │    │         │    │    └── columns: xyz_1.x:7(int!null) xyz_1.y:8(int) xyz_1.z:9(int)
           │    │         │    │         │    └── filters
           │    │         │    │         │         └── eq [type=bool]
           │    │         │    │         │              ├── variable: column1 [type=int]
           │    │         │    │         │              └── variable: xyz_1.x [type=int]
           │    │         │    │         └── filters
           │    │         │    │              └── is [type=bool]
           │    │         │    │                   ├── variable: xyz_1.x [type=int]
           │    │         │    │                   └── null [type=unknown]
           │    │         │    ├── scan xyz_2
           │    │         │    │    └── columns: xyz_2.x:10(int!null) xyz_2.y:11(int) xyz_2.z:12(int)
           │    │         │    └── filters
           │    │         │         ├── eq [type=bool]
           │    │         │         │    ├── variable: column2 [type=int]
           │    │         │         │    └── variable: xyz_2.y [type=int]
           │    │         │         └── eq [type=bool]
           │    │         │              ├── variable: column3 [type=int]
           │    │         │              └── variable: xyz_2.z [type=int]
           │    │         └── filters
           │    │              └── is [type=bool]
           │    │                   ├── variable: xyz_2.x [type=int]
           │    │                   └── null [type=unknown]
           │    ├── scan xyz_3
           │    │    └── columns: xyz_3.x:13(int!null) xyz_3.y:14(int) xyz_3.z:15(int)
           │    └── filters
           │         ├── eq [type=bool]
           │         │    ├── variable: column3 [type=int]
           │         │    └── variable: xyz_3.z [type=int]
           │         └── eq [type=bool]
           │              ├── variable: column2 [type=int]
           │              └── variable: xyz_3.y [type=int]
           └── filters
                └── is [type=bool]
                     ├── variable: xyz_3.x [type=int]
                     └── null [type=unknown]

# Conflict columns are explicitly specified.
build
INSERT INTO xyz
VALUES (1, 2, 3), (4, 5, 6)
ON CONFLICT (y, z) DO NOTHING
----
insert xyz
 ├── columns: <none>
 ├── insert-mapping:
 │    ├──  column1:4 => xyz.x:1
 │    ├──  column2:5 => xyz.y:2
 │    └──  column3:6 => xyz.z:3
 └── project
      ├── columns: column1:4(int) column2:5(int) column3:6(int)
      └── select
           ├── columns: column1:4(int) column2:5(int) column3:6(int) xyz_2.x:7(int) xyz_2.y:8(int) xyz_2.z:9(int)
           ├── left-join
           │    ├── columns: column1:4(int) column2:5(int) column3:6(int) xyz_2.x:7(int) xyz_2.y:8(int) xyz_2.z:9(int)
           │    ├── values
           │    │    ├── columns: column1:4(int) column2:5(int) column3:6(int)
           │    │    ├── tuple [type=tuple{int, int, int}]
           │    │    │    ├── const: 1 [type=int]
           │    │    │    ├── const: 2 [type=int]
           │    │    │    └── const: 3 [type=int]
           │    │    └── tuple [type=tuple{int, int, int}]
           │    │         ├── const: 4 [type=int]
           │    │         ├── const: 5 [type=int]
           │    │         └── const: 6 [type=int]
           │    ├── scan xyz_2
           │    │    └── columns: xyz_2.x:7(int!null) xyz_2.y:8(int) xyz_2.z:9(int)
           │    └── filters
           │         ├── eq [type=bool]
           │         │    ├── variable: column2 [type=int]
           │         │    └── variable: xyz_2.y [type=int]
           │         └── eq [type=bool]
           │              ├── variable: column3 [type=int]
           │              └── variable: xyz_2.z [type=int]
           └── filters
                └── is [type=bool]
                     ├── variable: xyz_2.x [type=int]
                     └── null [type=unknown]

# ------------------------------------------------------------------------------
# Test excluded columns.
# ------------------------------------------------------------------------------

build
INSERT INTO xyz
VALUES (1, 2, 3), (-1, -1, -1)
ON CONFLICT (z, y) DO
UPDATE SET x=excluded.x+1, y=excluded.y*xyz.y, z=excluded.x-excluded.z
WHERE excluded.y>xyz.y
RETURNING xyz.x*2, y+z
----
project
 ├── columns: "?column?":16(int) "?column?":17(int)
 ├── upsert xyz
 │    ├── columns: x:1(int!null) y:2(int) z:3(int)
 │    ├── canary column: 7
 │    ├── fetch columns: x:7(int) y:8(int) z:9(int)
 │    ├── insert-mapping:
 │    │    ├──  column1:4 => x:1
 │    │    ├──  column2:5 => y:2
 │    │    └──  column3:6 => z:3
 │    ├── update-mapping:
 │    │    ├──  upsert_x:13 => x:1
 │    │    ├──  upsert_y:14 => y:2
 │    │    └──  upsert_z:15 => z:3
 │    ├── return-mapping:
 │    │    ├──  upsert_x:13 => x:1
 │    │    ├──  upsert_y:14 => y:2
 │    │    └──  upsert_z:15 => z:3
 │    └── project
 │         ├── columns: upsert_x:13(int) upsert_y:14(int) upsert_z:15(int) column1:4(int) column2:5(int) column3:6(int) x:7(int) y:8(int) z:9(int) column10:10(int) column11:11(int) column12:12(int)
 │         ├── project
 │         │    ├── columns: column10:10(int) column11:11(int) column12:12(int) column1:4(int) column2:5(int) column3:6(int) x:7(int) y:8(int) z:9(int)
 │         │    ├── select
 │         │    │    ├── columns: column1:4(int) column2:5(int) column3:6(int) x:7(int) y:8(int) z:9(int)
 │         │    │    ├── left-join
 │         │    │    │    ├── columns: column1:4(int) column2:5(int) column3:6(int) x:7(int) y:8(int) z:9(int)
 │         │    │    │    ├── values
 │         │    │    │    │    ├── columns: column1:4(int) column2:5(int) column3:6(int)
 │         │    │    │    │    ├── tuple [type=tuple{int, int, int}]
 │         │    │    │    │    │    ├── const: 1 [type=int]
 │         │    │    │    │    │    ├── const: 2 [type=int]
 │         │    │    │    │    │    └── const: 3 [type=int]
 │         │    │    │    │    └── tuple [type=tuple{int, int, int}]
 │         │    │    │    │         ├── const: -1 [type=int]
 │         │    │    │    │         ├── const: -1 [type=int]
 │         │    │    │    │         └── const: -1 [type=int]
 │         │    │    │    ├── scan xyz
 │         │    │    │    │    └── columns: x:7(int!null) y:8(int) z:9(int)
 │         │    │    │    └── filters
 │         │    │    │         ├── eq [type=bool]
 │         │    │    │         │    ├── variable: column3 [type=int]
 │         │    │    │         │    └── variable: z [type=int]
 │         │    │    │         └── eq [type=bool]
 │         │    │    │              ├── variable: column2 [type=int]
 │         │    │    │              └── variable: y [type=int]
 │         │    │    └── filters
 │         │    │         └── or [type=bool]
 │         │    │              ├── is [type=bool]
 │         │    │              │    ├── variable: x [type=int]
 │         │    │              │    └── null [type=unknown]
 │         │    │              └── gt [type=bool]
 │         │    │                   ├── variable: column2 [type=int]
 │         │    │                   └── variable: y [type=int]
 │         │    └── projections
 │         │         ├── plus [type=int]
 │         │         │    ├── variable: column1 [type=int]
 │         │         │    └── const: 1 [type=int]
 │         │         ├── mult [type=int]
 │         │         │    ├── variable: column2 [type=int]
 │         │         │    └── variable: y [type=int]
 │         │         └── minus [type=int]
 │         │              ├── variable: column1 [type=int]
 │         │              └── variable: column3 [type=int]
 │         └── projections
 │              ├── case [type=int]
 │              │    ├── true [type=bool]
 │              │    ├── when [type=int]
 │              │    │    ├── is [type=bool]
 │              │    │    │    ├── variable: x [type=int]
 │              │    │    │    └── null [type=unknown]
 │              │    │    └── variable: column1 [type=int]
 │              │    └── variable: column10 [type=int]
 │              ├── case [type=int]
 │              │    ├── true [type=bool]
 │              │    ├── when [type=int]
 │              │    │    ├── is [type=bool]
 │              │    │    │    ├── variable: x [type=int]
 │              │    │    │    └── null [type=unknown]
 │              │    │    └── variable: column2 [type=int]
 │              │    └── variable: column11 [type=int]
 │              └── case [type=int]
 │                   ├── true [type=bool]
 │                   ├── when [type=int]
 │                   │    ├── is [type=bool]
 │                   │    │    ├── variable: x [type=int]
 │                   │    │    └── null [type=unknown]
 │                   │    └── variable: column3 [type=int]
 │                   └── variable: column12 [type=int]
 └── projections
      ├── mult [type=int]
      │    ├── variable: x [type=int]
      │    └── const: 2 [type=int]
      └── plus [type=int]
           ├── variable: y [type=int]
           └── variable: z [type=int]

# Try to use excluded in RETURNING.
build
INSERT INTO xyz
VALUES (1, 2, 3)
ON CONFLICT (x) DO
UPDATE SET x=1
RETURNING excluded.x
----
error (42P01): no data source matches prefix: excluded

# Referencing column without "excluded" or "xyz" prefix is not allowed.
build
INSERT INTO xyz
VALUES (1, 2, 3)
ON CONFLICT (x) DO
UPDATE SET x=x+1
----
error (42702): column reference "x" is ambiguous (candidates: excluded.x, xyz.x)

# ------------------------------------------------------------------------------
# Test UPDATE SET expressions.
# ------------------------------------------------------------------------------

# Subquery.
build
INSERT INTO abc
VALUES (1, 2)
ON CONFLICT (a) DO
UPDATE SET (b, a)=(SELECT x, y+excluded.b FROM xyz WHERE x=excluded.a)
----
upsert abc
 ├── columns: <none>
 ├── canary column: 12
 ├── fetch columns: a:9(int) b:10(int) c:11(int) rowid:12(int)
 ├── insert-mapping:
 │    ├──  column1:5 => a:1
 │    ├──  column2:6 => b:2
 │    ├──  column8:8 => c:3
 │    └──  column7:7 => rowid:4
 ├── update-mapping:
 │    ├──  upsert_a:18 => a:1
 │    ├──  upsert_b:19 => b:2
 │    └──  upsert_c:20 => c:3
 └── project
      ├── columns: upsert_a:18(int) upsert_b:19(int) upsert_c:20(int) upsert_rowid:21(int) column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) rowid:12(int) x:13(int) "?column?":16(int) column17:17(int)
      ├── project
      │    ├── columns: column17:17(int) column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) rowid:12(int) x:13(int) "?column?":16(int)
      │    ├── left-join-apply
      │    │    ├── columns: column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) rowid:12(int) x:13(int) "?column?":16(int)
      │    │    ├── left-join
      │    │    │    ├── columns: column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) rowid:12(int)
      │    │    │    ├── project
      │    │    │    │    ├── columns: column8:8(int) column1:5(int) column2:6(int) column7:7(int)
      │    │    │    │    ├── project
      │    │    │    │    │    ├── columns: column7:7(int) column1:5(int) column2:6(int)
      │    │    │    │    │    ├── values
      │    │    │    │    │    │    ├── columns: column1:5(int) column2:6(int)
      │    │    │    │    │    │    └── tuple [type=tuple{int, int}]
      │    │    │    │    │    │         ├── const: 1 [type=int]
      │    │    │    │    │    │         └── const: 2 [type=int]
      │    │    │    │    │    └── projections
      │    │    │    │    │         └── function: unique_rowid [type=int]
      │    │    │    │    └── projections
      │    │    │    │         └── plus [type=int]
      │    │    │    │              ├── variable: column2 [type=int]
      │    │    │    │              └── const: 1 [type=int]
      │    │    │    ├── scan abc
      │    │    │    │    └── columns: a:9(int!null) b:10(int) c:11(int) rowid:12(int!null)
      │    │    │    └── filters
      │    │    │         └── eq [type=bool]
      │    │    │              ├── variable: column1 [type=int]
      │    │    │              └── variable: a [type=int]
      │    │    ├── max1-row
      │    │    │    ├── columns: x:13(int!null) "?column?":16(int)
      │    │    │    └── project
      │    │    │         ├── columns: "?column?":16(int) x:13(int!null)
      │    │    │         ├── select
      │    │    │         │    ├── columns: x:13(int!null) y:14(int) z:15(int)
      │    │    │         │    ├── scan xyz
      │    │    │         │    │    └── columns: x:13(int!null) y:14(int) z:15(int)
      │    │    │         │    └── filters
      │    │    │         │         └── eq [type=bool]
      │    │    │         │              ├── variable: x [type=int]
      │    │    │         │              └── variable: column1 [type=int]
      │    │    │         └── projections
      │    │    │              └── plus [type=int]
      │    │    │                   ├── variable: y [type=int]
      │    │    │                   └── variable: column2 [type=int]
      │    │    └── filters (true)
      │    └── projections
      │         └── plus [type=int]
      │              ├── variable: x [type=int]
      │              └── const: 1 [type=int]
      └── projections
           ├── case [type=int]
           │    ├── true [type=bool]
           │    ├── when [type=int]
           │    │    ├── is [type=bool]
           │    │    │    ├── variable: rowid [type=int]
           │    │    │    └── null [type=unknown]
           │    │    └── variable: column1 [type=int]
           │    └── variable: ?column? [type=int]
           ├── case [type=int]
           │    ├── true [type=bool]
           │    ├── when [type=int]
           │    │    ├── is [type=bool]
           │    │    │    ├── variable: rowid [type=int]
           │    │    │    └── null [type=unknown]
           │    │    └── variable: column2 [type=int]
           │    └── variable: x [type=int]
           ├── case [type=int]
           │    ├── true [type=bool]
           │    ├── when [type=int]
           │    │    ├── is [type=bool]
           │    │    │    ├── variable: rowid [type=int]
           │    │    │    └── null [type=unknown]
           │    │    └── variable: column8 [type=int]
           │    └── variable: column17 [type=int]
           └── case [type=int]
                ├── true [type=bool]
                ├── when [type=int]
                │    ├── is [type=bool]
                │    │    ├── variable: rowid [type=int]
                │    │    └── null [type=unknown]
                │    └── variable: column7 [type=int]
                └── variable: rowid [type=int]

# Default expressions.
build
INSERT INTO abc
VALUES (1, 2)
ON CONFLICT (a) DO
UPDATE SET a=DEFAULT, b=DEFAULT
----
upsert abc
 ├── columns: <none>
 ├── canary column: 12
 ├── fetch columns: a:9(int) b:10(int) c:11(int) rowid:12(int)
 ├── insert-mapping:
 │    ├──  column1:5 => a:1
 │    ├──  column2:6 => b:2
 │    ├──  column8:8 => c:3
 │    └──  column7:7 => rowid:4
 ├── update-mapping:
 │    ├──  upsert_a:16 => a:1
 │    ├──  upsert_b:17 => b:2
 │    └──  upsert_c:18 => c:3
 └── project
      ├── columns: upsert_a:16(int) upsert_b:17(int) upsert_c:18(int) upsert_rowid:19(int) column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) rowid:12(int) column13:13(int) column14:14(int!null) column15:15(int)
      ├── project
      │    ├── columns: column15:15(int) column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) rowid:12(int) column13:13(int) column14:14(int!null)
      │    ├── project
      │    │    ├── columns: column13:13(int) column14:14(int!null) column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) rowid:12(int)
      │    │    ├── left-join
      │    │    │    ├── columns: column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) rowid:12(int)
      │    │    │    ├── project
      │    │    │    │    ├── columns: column8:8(int) column1:5(int) column2:6(int) column7:7(int)
      │    │    │    │    ├── project
      │    │    │    │    │    ├── columns: column7:7(int) column1:5(int) column2:6(int)
      │    │    │    │    │    ├── values
      │    │    │    │    │    │    ├── columns: column1:5(int) column2:6(int)
      │    │    │    │    │    │    └── tuple [type=tuple{int, int}]
      │    │    │    │    │    │         ├── const: 1 [type=int]
      │    │    │    │    │    │         └── const: 2 [type=int]
      │    │    │    │    │    └── projections
      │    │    │    │    │         └── function: unique_rowid [type=int]
      │    │    │    │    └── projections
      │    │    │    │         └── plus [type=int]
      │    │    │    │              ├── variable: column2 [type=int]
      │    │    │    │              └── const: 1 [type=int]
      │    │    │    ├── scan abc
      │    │    │    │    └── columns: a:9(int!null) b:10(int) c:11(int) rowid:12(int!null)
      │    │    │    └── filters
      │    │    │         └── eq [type=bool]
      │    │    │              ├── variable: column1 [type=int]
      │    │    │              └── variable: a [type=int]
      │    │    └── projections
      │    │         ├── cast: INT8 [type=int]
      │    │         │    └── null [type=unknown]
      │    │         └── const: 10 [type=int]
      │    └── projections
      │         └── plus [type=int]
      │              ├── variable: column14 [type=int]
      │              └── const: 1 [type=int]
      └── projections
           ├── case [type=int]
           │    ├── true [type=bool]
           │    ├── when [type=int]
           │    │    ├── is [type=bool]
           │    │    │    ├── variable: rowid [type=int]
           │    │    │    └── null [type=unknown]
           │    │    └── variable: column1 [type=int]
           │    └── variable: column13 [type=int]
           ├── case [type=int]
           │    ├── true [type=bool]
           │    ├── when [type=int]
           │    │    ├── is [type=bool]
           │    │    │    ├── variable: rowid [type=int]
           │    │    │    └── null [type=unknown]
           │    │    └── variable: column2 [type=int]
           │    └── variable: column14 [type=int]
           ├── case [type=int]
           │    ├── true [type=bool]
           │    ├── when [type=int]
           │    │    ├── is [type=bool]
           │    │    │    ├── variable: rowid [type=int]
           │    │    │    └── null [type=unknown]
           │    │    └── variable: column8 [type=int]
           │    └── variable: column15 [type=int]
           └── case [type=int]
                ├── true [type=bool]
                ├── when [type=int]
                │    ├── is [type=bool]
                │    │    ├── variable: rowid [type=int]
                │    │    └── null [type=unknown]
                │    └── variable: column7 [type=int]
                └── variable: rowid [type=int]

# ------------------------------------------------------------------------------
# Test mutation columns.
# ------------------------------------------------------------------------------

build
INSERT INTO mutation (m, n)
VALUES (1, 2)
ON CONFLICT (m) DO
UPDATE SET m=mutation.m+1
----
upsert mutation
 ├── columns: <none>
 ├── canary column: 10
 ├── fetch columns: m:10(int) n:11(int) o:12(int) p:13(int) q:14(int)
 ├── insert-mapping:
 │    ├──  column1:6 => m:1
 │    ├──  column2:7 => n:2
 │    ├──  column8:8 => o:3
 │    └──  column9:9 => p:4
 ├── update-mapping:
 │    ├──  upsert_m:17 => m:1
 │    └──  upsert_p:20 => p:4
 ├── check columns: check1:21(bool)
 └── project
      ├── columns: check1:21(bool) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) column15:15(int) column16:16(int) upsert_m:17(int) upsert_n:18(int) upsert_o:19(int) upsert_p:20(int)
      ├── project
      │    ├── columns: upsert_m:17(int) upsert_n:18(int) upsert_o:19(int) upsert_p:20(int) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) column15:15(int) column16:16(int)
      │    ├── project
      │    │    ├── columns: column16:16(int) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) column15:15(int)
      │    │    ├── project
      │    │    │    ├── columns: column15:15(int) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int)
      │    │    │    ├── left-join
      │    │    │    │    ├── columns: column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int)
      │    │    │    │    ├── project
      │    │    │    │    │    ├── columns: column9:9(int) column1:6(int) column2:7(int) column8:8(int!null)
      │    │    │    │    │    ├── project
      │    │    │    │    │    │    ├── columns: column8:8(int!null) column1:6(int) column2:7(int)
      │    │    │    │    │    │    ├── values
      │    │    │    │    │    │    │    ├── columns: column1:6(int) column2:7(int)
      │    │    │    │    │    │    │    └── tuple [type=tuple{int, int}]
      │    │    │    │    │    │    │         ├── const: 1 [type=int]
      │    │    │    │    │    │    │         └── const: 2 [type=int]
      │    │    │    │    │    │    └── projections
      │    │    │    │    │    │         └── const: 10 [type=int]
      │    │    │    │    │    └── projections
      │    │    │    │    │         └── plus [type=int]
      │    │    │    │    │              ├── variable: column8 [type=int]
      │    │    │    │    │              └── variable: column2 [type=int]
      │    │    │    │    ├── scan mutation
      │    │    │    │    │    └── columns: m:10(int!null) n:11(int) o:12(int) p:13(int) q:14(int)
      │    │    │    │    └── filters
      │    │    │    │         └── eq [type=bool]
      │    │    │    │              ├── variable: column1 [type=int]
      │    │    │    │              └── variable: m [type=int]
      │    │    │    └── projections
      │    │    │         └── plus [type=int]
      │    │    │              ├── variable: m [type=int]
      │    │    │              └── const: 1 [type=int]
      │    │    └── projections
      │    │         └── plus [type=int]
      │    │              ├── variable: o [type=int]
      │    │              └── variable: n [type=int]
      │    └── projections
      │         ├── case [type=int]
      │         │    ├── true [type=bool]
      │         │    ├── when [type=int]
      │         │    │    ├── is [type=bool]
      │         │    │    │    ├── variable: m [type=int]
      │         │    │    │    └── null [type=unknown]
      │         │    │    └── variable: column1 [type=int]
      │         │    └── variable: column15 [type=int]
      │         ├── case [type=int]
      │         │    ├── true [type=bool]
      │         │    ├── when [type=int]
      │         │    │    ├── is [type=bool]
      │         │    │    │    ├── variable: m [type=int]
      │         │    │    │    └── null [type=unknown]
      │         │    │    └── variable: column2 [type=int]
      │         │    └── variable: n [type=int]
      │         ├── case [type=int]
      │         │    ├── true [type=bool]
      │         │    ├── when [type=int]
      │         │    │    ├── is [type=bool]
      │         │    │    │    ├── variable: m [type=int]
      │         │    │    │    └── null [type=unknown]
      │         │    │    └── variable: column8 [type=int]
      │         │    └── variable: o [type=int]
      │         └── case [type=int]
      │              ├── true [type=bool]
      │              ├── when [type=int]
      │              │    ├── is [type=bool]
      │              │    │    ├── variable: m [type=int]
      │              │    │    └── null [type=unknown]
      │              │    └── variable: column9 [type=int]
      │              └── variable: column16 [type=int]
      └── projections
           └── gt [type=bool]
                ├── variable: upsert_m [type=int]
                └── const: 0 [type=int]

# ------------------------------------------------------------------------------
# Test UPSERT.
# ------------------------------------------------------------------------------

# Single column primary key.
build
UPSERT INTO xyz VALUES (1)
----
upsert xyz
 ├── columns: <none>
 ├── canary column: 6
 ├── fetch columns: x:6(int) y:7(int) z:8(int)
 ├── insert-mapping:
 │    ├──  column1:4 => x:1
 │    ├──  column5:5 => y:2
 │    └──  column5:5 => z:3
 ├── update-mapping:
 │    ├──  column5:5 => y:2
 │    └──  column5:5 => z:3
 └── project
      ├── columns: upsert_x:9(int) column1:4(int) column5:5(int) x:6(int) y:7(int) z:8(int)
      ├── left-join
      │    ├── columns: column1:4(int) column5:5(int) x:6(int) y:7(int) z:8(int)
      │    ├── project
      │    │    ├── columns: column5:5(int) column1:4(int)
      │    │    ├── values
      │    │    │    ├── columns: column1:4(int)
      │    │    │    └── tuple [type=tuple{int}]
      │    │    │         └── const: 1 [type=int]
      │    │    └── projections
      │    │         └── cast: INT8 [type=int]
      │    │              └── null [type=unknown]
      │    ├── scan xyz
      │    │    └── columns: x:6(int!null) y:7(int) z:8(int)
      │    └── filters
      │         └── eq [type=bool]
      │              ├── variable: column1 [type=int]
      │              └── variable: x [type=int]
      └── projections
           └── case [type=int]
                ├── true [type=bool]
                ├── when [type=int]
                │    ├── is [type=bool]
                │    │    ├── variable: x [type=int]
                │    │    └── null [type=unknown]
                │    └── variable: column1 [type=int]
                └── variable: x [type=int]

# Test multi-column primary key that contains all columns in table.
build
UPSERT INTO uv VALUES (1, 2) RETURNING *
----
upsert uv
 ├── columns: u:1(int!null) v:2(int!null)
 ├── upsert-mapping:
 │    ├──  column1:3 => u:1
 │    └──  column2:4 => v:2
 └── values
      ├── columns: column1:3(int) column2:4(int)
      └── tuple [type=tuple{int, int}]
           ├── const: 1 [type=int]
           └── const: 2 [type=int]

# Use returning UPSERT as a FROM expression.
build
SELECT * FROM [UPSERT INTO abc VALUES (1, 2) RETURNING *]
----
project
 ├── columns: a:1(int!null) b:2(int) c:3(int)
 └── upsert abc
      ├── columns: a:1(int!null) b:2(int) c:3(int) rowid:4(int!null)
      ├── canary column: 12
      ├── fetch columns: a:9(int) b:10(int) c:11(int) rowid:12(int)
      ├── insert-mapping:
      │    ├──  column1:5 => a:1
      │    ├──  column2:6 => b:2
      │    ├──  column8:8 => c:3
      │    └──  column7:7 => rowid:4
      ├── update-mapping:
      │    ├──  column1:5 => a:1
      │    ├──  column2:6 => b:2
      │    └──  column8:8 => c:3
      ├── return-mapping:
      │    ├──  column1:5 => a:1
      │    ├──  column2:6 => b:2
      │    ├──  column8:8 => c:3
      │    └──  upsert_rowid:13 => rowid:4
      └── project
           ├── columns: upsert_rowid:13(int) column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) rowid:12(int)
           ├── left-join
           │    ├── columns: column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) rowid:12(int)
           │    ├── project
           │    │    ├── columns: column8:8(int) column1:5(int) column2:6(int) column7:7(int)
           │    │    ├── project
           │    │    │    ├── columns: column7:7(int) column1:5(int) column2:6(int)
           │    │    │    ├── values
           │    │    │    │    ├── columns: column1:5(int) column2:6(int)
           │    │    │    │    └── tuple [type=tuple{int, int}]
           │    │    │    │         ├── const: 1 [type=int]
           │    │    │    │         └── const: 2 [type=int]
           │    │    │    └── projections
           │    │    │         └── function: unique_rowid [type=int]
           │    │    └── projections
           │    │         └── plus [type=int]
           │    │              ├── variable: column2 [type=int]
           │    │              └── const: 1 [type=int]
           │    ├── scan abc
           │    │    └── columns: a:9(int!null) b:10(int) c:11(int) rowid:12(int!null)
           │    └── filters
           │         └── eq [type=bool]
           │              ├── variable: column7 [type=int]
           │              └── variable: rowid [type=int]
           └── projections
                └── case [type=int]
                     ├── true [type=bool]
                     ├── when [type=int]
                     │    ├── is [type=bool]
                     │    │    ├── variable: rowid [type=int]
                     │    │    └── null [type=unknown]
                     │    └── variable: column7 [type=int]
                     └── variable: rowid [type=int]

# Use explicitly specified column names with secondary indexes present. Existing
# values of other columns need to be fetched to delete existing index rows.
build
UPSERT INTO xyz (z, x, y) VALUES (1, 2, 3)
----
upsert xyz
 ├── columns: <none>
 ├── canary column: 7
 ├── fetch columns: x:7(int) y:8(int) z:9(int)
 ├── insert-mapping:
 │    ├──  column2:5 => x:1
 │    ├──  column3:6 => y:2
 │    └──  column1:4 => z:3
 ├── update-mapping:
 │    ├──  column3:6 => y:2
 │    └──  column1:4 => z:3
 └── project
      ├── columns: upsert_x:10(int) column1:4(int) column2:5(int) column3:6(int) x:7(int) y:8(int) z:9(int)
      ├── left-join
      │    ├── columns: column1:4(int) column2:5(int) column3:6(int) x:7(int) y:8(int) z:9(int)
      │    ├── values
      │    │    ├── columns: column1:4(int) column2:5(int) column3:6(int)
      │    │    └── tuple [type=tuple{int, int, int}]
      │    │         ├── const: 1 [type=int]
      │    │         ├── const: 2 [type=int]
      │    │         └── const: 3 [type=int]
      │    ├── scan xyz
      │    │    └── columns: x:7(int!null) y:8(int) z:9(int)
      │    └── filters
      │         └── eq [type=bool]
      │              ├── variable: column2 [type=int]
      │              └── variable: x [type=int]
      └── projections
           └── case [type=int]
                ├── true [type=bool]
                ├── when [type=int]
                │    ├── is [type=bool]
                │    │    ├── variable: x [type=int]
                │    │    └── null [type=unknown]
                │    └── variable: column2 [type=int]
                └── variable: x [type=int]

# Use explicitly specified column names with no secondary indexes present.
# Upsert implemented with blind Puts is possible.
build
UPSERT INTO noindex (x, y, z) VALUES (1, 2, 3)
----
upsert noindex
 ├── columns: <none>
 ├── upsert-mapping:
 │    ├──  column1:4 => x:1
 │    ├──  column2:5 => y:2
 │    └──  column3:6 => z:3
 └── values
      ├── columns: column1:4(int) column2:5(int) column3:6(int)
      └── tuple [type=tuple{int, int, int}]
           ├── const: 1 [type=int]
           ├── const: 2 [type=int]
           └── const: 3 [type=int]

# Use subset of explicitly specified column names with no secondary indexes
# present. Existing values of other columns need to be fetched to provide
# update values for unspecified columns.
build
UPSERT INTO checks (a, b, c) VALUES (1, 2, 3)
----
upsert checks
 ├── columns: <none>
 ├── canary column: 9
 ├── fetch columns: a:9(int) b:10(int) c:11(int) d:12(int)
 ├── insert-mapping:
 │    ├──  column1:5 => a:1
 │    ├──  column2:6 => b:2
 │    ├──  column3:7 => c:3
 │    └──  column8:8 => d:4
 ├── update-mapping:
 │    ├──  column2:6 => b:2
 │    ├──  column3:7 => c:3
 │    └──  column8:8 => d:4
 ├── check columns: check1:14(bool) check2:15(bool)
 └── project
      ├── columns: check1:14(bool) check2:15(bool) column1:5(int) column2:6(int) column3:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) d:12(int) upsert_a:13(int)
      ├── project
      │    ├── columns: upsert_a:13(int) column1:5(int) column2:6(int) column3:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) d:12(int)
      │    ├── left-join
      │    │    ├── columns: column1:5(int) column2:6(int) column3:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) d:12(int)
      │    │    ├── project
      │    │    │    ├── columns: column8:8(int) column1:5(int) column2:6(int) column3:7(int)
      │    │    │    ├── values
      │    │    │    │    ├── columns: column1:5(int) column2:6(int) column3:7(int)
      │    │    │    │    └── tuple [type=tuple{int, int, int}]
      │    │    │    │         ├── const: 1 [type=int]
      │    │    │    │         ├── const: 2 [type=int]
      │    │    │    │         └── const: 3 [type=int]
      │    │    │    └── projections
      │    │    │         └── plus [type=int]
      │    │    │              ├── variable: column3 [type=int]
      │    │    │              └── const: 1 [type=int]
      │    │    ├── scan checks
      │    │    │    └── columns: a:9(int!null) b:10(int) c:11(int) d:12(int)
      │    │    └── filters
      │    │         └── eq [type=bool]
      │    │              ├── variable: column1 [type=int]
      │    │              └── variable: a [type=int]
      │    └── projections
      │         └── case [type=int]
      │              ├── true [type=bool]
      │              ├── when [type=int]
      │              │    ├── is [type=bool]
      │              │    │    ├── variable: a [type=int]
      │              │    │    └── null [type=unknown]
      │              │    └── variable: column1 [type=int]
      │              └── variable: a [type=int]
      └── projections
           ├── lt [type=bool]
           │    ├── variable: column2 [type=int]
           │    └── variable: column8 [type=int]
           └── gt [type=bool]
                ├── variable: upsert_a [type=int]
                └── const: 0 [type=int]

# Don't directly update mutation columns. However, computed columns do need to
# be updated. Use explicit target columns.
build
UPSERT INTO mutation (m, n) VALUES (1, 2)
----
upsert mutation
 ├── columns: <none>
 ├── canary column: 10
 ├── fetch columns: m:10(int) n:11(int) o:12(int) p:13(int) q:14(int)
 ├── insert-mapping:
 │    ├──  column1:6 => m:1
 │    ├──  column2:7 => n:2
 │    ├──  column8:8 => o:3
 │    └──  column9:9 => p:4
 ├── update-mapping:
 │    ├──  column2:7 => n:2
 │    └──  upsert_p:18 => p:4
 ├── check columns: check1:19(bool)
 └── project
      ├── columns: check1:19(bool) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) column15:15(int) upsert_m:16(int) upsert_o:17(int) upsert_p:18(int)
      ├── project
      │    ├── columns: upsert_m:16(int) upsert_o:17(int) upsert_p:18(int) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) column15:15(int)
      │    ├── project
      │    │    ├── columns: column15:15(int) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int)
      │    │    ├── left-join
      │    │    │    ├── columns: column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int)
      │    │    │    ├── project
      │    │    │    │    ├── columns: column9:9(int) column1:6(int) column2:7(int) column8:8(int!null)
      │    │    │    │    ├── project
      │    │    │    │    │    ├── columns: column8:8(int!null) column1:6(int) column2:7(int)
      │    │    │    │    │    ├── values
      │    │    │    │    │    │    ├── columns: column1:6(int) column2:7(int)
      │    │    │    │    │    │    └── tuple [type=tuple{int, int}]
      │    │    │    │    │    │         ├── const: 1 [type=int]
      │    │    │    │    │    │         └── const: 2 [type=int]
      │    │    │    │    │    └── projections
      │    │    │    │    │         └── const: 10 [type=int]
      │    │    │    │    └── projections
      │    │    │    │         └── plus [type=int]
      │    │    │    │              ├── variable: column8 [type=int]
      │    │    │    │              └── variable: column2 [type=int]
      │    │    │    ├── scan mutation
      │    │    │    │    └── columns: m:10(int!null) n:11(int) o:12(int) p:13(int) q:14(int)
      │    │    │    └── filters
      │    │    │         └── eq [type=bool]
      │    │    │              ├── variable: column1 [type=int]
      │    │    │              └── variable: m [type=int]
      │    │    └── projections
      │    │         └── plus [type=int]
      │    │              ├── variable: o [type=int]
      │    │              └── variable: column2 [type=int]
      │    └── projections
      │         ├── case [type=int]
      │         │    ├── true [type=bool]
      │         │    ├── when [type=int]
      │         │    │    ├── is [type=bool]
      │         │    │    │    ├── variable: m [type=int]
      │         │    │    │    └── null [type=unknown]
      │         │    │    └── variable: column1 [type=int]
      │         │    └── variable: m [type=int]
      │         ├── case [type=int]
      │         │    ├── true [type=bool]
      │         │    ├── when [type=int]
      │         │    │    ├── is [type=bool]
      │         │    │    │    ├── variable: m [type=int]
      │         │    │    │    └── null [type=unknown]
      │         │    │    └── variable: column8 [type=int]
      │         │    └── variable: o [type=int]
      │         └── case [type=int]
      │              ├── true [type=bool]
      │              ├── when [type=int]
      │              │    ├── is [type=bool]
      │              │    │    ├── variable: m [type=int]
      │              │    │    └── null [type=unknown]
      │              │    └── variable: column9 [type=int]
      │              └── variable: column15 [type=int]
      └── projections
           └── gt [type=bool]
                ├── variable: upsert_m [type=int]
                └── const: 0 [type=int]

# Don't directly update mutation columns. However, computed columns do need to
# be updated. Use implicit target columns.
build
UPSERT INTO mutation VALUES (1, 2)
----
upsert mutation
 ├── columns: <none>
 ├── canary column: 10
 ├── fetch columns: m:10(int) n:11(int) o:12(int) p:13(int) q:14(int)
 ├── insert-mapping:
 │    ├──  column1:6 => m:1
 │    ├──  column2:7 => n:2
 │    ├──  column8:8 => o:3
 │    └──  column9:9 => p:4
 ├── update-mapping:
 │    ├──  column2:7 => n:2
 │    └──  upsert_p:18 => p:4
 ├── check columns: check1:19(bool)
 └── project
      ├── columns: check1:19(bool) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) column15:15(int) upsert_m:16(int) upsert_o:17(int) upsert_p:18(int)
      ├── project
      │    ├── columns: upsert_m:16(int) upsert_o:17(int) upsert_p:18(int) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int) column15:15(int)
      │    ├── project
      │    │    ├── columns: column15:15(int) column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int)
      │    │    ├── left-join
      │    │    │    ├── columns: column1:6(int) column2:7(int) column8:8(int!null) column9:9(int) m:10(int) n:11(int) o:12(int) p:13(int) q:14(int)
      │    │    │    ├── project
      │    │    │    │    ├── columns: column9:9(int) column1:6(int) column2:7(int) column8:8(int!null)
      │    │    │    │    ├── project
      │    │    │    │    │    ├── columns: column8:8(int!null) column1:6(int) column2:7(int)
      │    │    │    │    │    ├── values
      │    │    │    │    │    │    ├── columns: column1:6(int) column2:7(int)
      │    │    │    │    │    │    └── tuple [type=tuple{int, int}]
      │    │    │    │    │    │         ├── const: 1 [type=int]
      │    │    │    │    │    │         └── const: 2 [type=int]
      │    │    │    │    │    └── projections
      │    │    │    │    │         └── const: 10 [type=int]
      │    │    │    │    └── projections
      │    │    │    │         └── plus [type=int]
      │    │    │    │              ├── variable: column8 [type=int]
      │    │    │    │              └── variable: column2 [type=int]
      │    │    │    ├── scan mutation
      │    │    │    │    └── columns: m:10(int!null) n:11(int) o:12(int) p:13(int) q:14(int)
      │    │    │    └── filters
      │    │    │         └── eq [type=bool]
      │    │    │              ├── variable: column1 [type=int]
      │    │    │              └── variable: m [type=int]
      │    │    └── projections
      │    │         └── plus [type=int]
      │    │              ├── variable: o [type=int]
      │    │              └── variable: column2 [type=int]
      │    └── projections
      │         ├── case [type=int]
      │         │    ├── true [type=bool]
      │         │    ├── when [type=int]
      │         │    │    ├── is [type=bool]
      │         │    │    │    ├── variable: m [type=int]
      │         │    │    │    └── null [type=unknown]
      │         │    │    └── variable: column1 [type=int]
      │         │    └── variable: m [type=int]
      │         ├── case [type=int]
      │         │    ├── true [type=bool]
      │         │    ├── when [type=int]
      │         │    │    ├── is [type=bool]
      │         │    │    │    ├── variable: m [type=int]
      │         │    │    │    └── null [type=unknown]
      │         │    │    └── variable: column8 [type=int]
      │         │    └── variable: o [type=int]
      │         └── case [type=int]
      │              ├── true [type=bool]
      │              ├── when [type=int]
      │              │    ├── is [type=bool]
      │              │    │    ├── variable: m [type=int]
      │              │    │    └── null [type=unknown]
      │              │    └── variable: column9 [type=int]
      │              └── variable: column15 [type=int]
      └── projections
           └── gt [type=bool]
                ├── variable: upsert_m [type=int]
                └── const: 0 [type=int]

# Use unknown name in upsert column list.
build
UPSERT INTO xyz (x, unknown) VALUES (1)
----
error (42703): column "unknown" does not exist

# ------------------------------------------------------------------------------
# Test check constraints.
# ------------------------------------------------------------------------------

# INSERT..ON CONFLICT
build
INSERT INTO checks (a, b) VALUES (1, 2) ON CONFLICT (a) DO UPDATE SET b=3, c=4
----
upsert checks
 ├── columns: <none>
 ├── canary column: 9
 ├── fetch columns: a:9(int) b:10(int) c:11(int) d:12(int)
 ├── insert-mapping:
 │    ├──  column1:5 => a:1
 │    ├──  column2:6 => b:2
 │    ├──  column7:7 => c:3
 │    └──  column8:8 => d:4
 ├── update-mapping:
 │    ├──  upsert_b:17 => b:2
 │    ├──  upsert_c:18 => c:3
 │    └──  upsert_d:19 => d:4
 ├── check columns: check1:20(bool) check2:21(bool)
 └── project
      ├── columns: check1:20(bool) check2:21(bool) column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) d:12(int) column13:13(int!null) column14:14(int!null) column15:15(int) upsert_a:16(int) upsert_b:17(int) upsert_c:18(int) upsert_d:19(int)
      ├── project
      │    ├── columns: upsert_a:16(int) upsert_b:17(int) upsert_c:18(int) upsert_d:19(int) column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) d:12(int) column13:13(int!null) column14:14(int!null) column15:15(int)
      │    ├── project
      │    │    ├── columns: column15:15(int) column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) d:12(int) column13:13(int!null) column14:14(int!null)
      │    │    ├── project
      │    │    │    ├── columns: column13:13(int!null) column14:14(int!null) column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) d:12(int)
      │    │    │    ├── left-join
      │    │    │    │    ├── columns: column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) d:12(int)
      │    │    │    │    ├── project
      │    │    │    │    │    ├── columns: column8:8(int) column1:5(int) column2:6(int) column7:7(int)
      │    │    │    │    │    ├── project
      │    │    │    │    │    │    ├── columns: column7:7(int) column1:5(int) column2:6(int)
      │    │    │    │    │    │    ├── values
      │    │    │    │    │    │    │    ├── columns: column1:5(int) column2:6(int)
      │    │    │    │    │    │    │    └── tuple [type=tuple{int, int}]
      │    │    │    │    │    │    │         ├── const: 1 [type=int]
      │    │    │    │    │    │    │         └── const: 2 [type=int]
      │    │    │    │    │    │    └── projections
      │    │    │    │    │    │         └── cast: INT8 [type=int]
      │    │    │    │    │    │              └── null [type=unknown]
      │    │    │    │    │    └── projections
      │    │    │    │    │         └── plus [type=int]
      │    │    │    │    │              ├── variable: column7 [type=int]
      │    │    │    │    │              └── const: 1 [type=int]
      │    │    │    │    ├── scan checks
      │    │    │    │    │    └── columns: a:9(int!null) b:10(int) c:11(int) d:12(int)
      │    │    │    │    └── filters
      │    │    │    │         └── eq [type=bool]
      │    │    │    │              ├── variable: column1 [type=int]
      │    │    │    │              └── variable: a [type=int]
      │    │    │    └── projections
      │    │    │         ├── const: 3 [type=int]
      │    │    │         └── const: 4 [type=int]
      │    │    └── projections
      │    │         └── plus [type=int]
      │    │              ├── variable: column14 [type=int]
      │    │              └── const: 1 [type=int]
      │    └── projections
      │         ├── case [type=int]
      │         │    ├── true [type=bool]
      │         │    ├── when [type=int]
      │         │    │    ├── is [type=bool]
      │         │    │    │    ├── variable: a [type=int]
      │         │    │    │    └── null [type=unknown]
      │         │    │    └── variable: column1 [type=int]
      │         │    └── variable: a [type=int]
      │         ├── case [type=int]
      │         │    ├── true [type=bool]
      │         │    ├── when [type=int]
      │         │    │    ├── is [type=bool]
      │         │    │    │    ├── variable: a [type=int]
      │         │    │    │    └── null [type=unknown]
      │         │    │    └── variable: column2 [type=int]
      │         │    └── variable: column13 [type=int]
      │         ├── case [type=int]
      │         │    ├── true [type=bool]
      │         │    ├── when [type=int]
      │         │    │    ├── is [type=bool]
      │         │    │    │    ├── variable: a [type=int]
      │         │    │    │    └── null [type=unknown]
      │         │    │    └── variable: column7 [type=int]
      │         │    └── variable: column14 [type=int]
      │         └── case [type=int]
      │              ├── true [type=bool]
      │              ├── when [type=int]
      │              │    ├── is [type=bool]
      │              │    │    ├── variable: a [type=int]
      │              │    │    └── null [type=unknown]
      │              │    └── variable: column8 [type=int]
      │              └── variable: column15 [type=int]
      └── projections
           ├── lt [type=bool]
           │    ├── variable: upsert_b [type=int]
           │    └── variable: upsert_d [type=int]
           └── gt [type=bool]
                ├── variable: upsert_a [type=int]
                └── const: 0 [type=int]

# INSERT..ON CONFLICT DO NOTHING
build
INSERT INTO checks (a, b) VALUES (1, 2) ON CONFLICT (a) DO NOTHING
----
insert checks
 ├── columns: <none>
 ├── insert-mapping:
 │    ├──  column1:5 => checks.a:1
 │    ├──  column2:6 => checks.b:2
 │    ├──  column7:7 => checks.c:3
 │    └──  column8:8 => checks.d:4
 ├── check columns: check1:13(bool) check2:14(bool)
 └── project
      ├── columns: check1:13(bool) check2:14(bool) column1:5(int) column2:6(int) column7:7(int) column8:8(int)
      ├── project
      │    ├── columns: column1:5(int) column2:6(int) column7:7(int) column8:8(int)
      │    └── select
      │         ├── columns: column1:5(int) column2:6(int) column7:7(int) column8:8(int) checks_1.a:9(int) checks_1.b:10(int) checks_1.c:11(int) checks_1.d:12(int)
      │         ├── left-join
      │         │    ├── columns: column1:5(int) column2:6(int) column7:7(int) column8:8(int) checks_1.a:9(int) checks_1.b:10(int) checks_1.c:11(int) checks_1.d:12(int)
      │         │    ├── project
      │         │    │    ├── columns: column8:8(int) column1:5(int) column2:6(int) column7:7(int)
      │         │    │    ├── project
      │         │    │    │    ├── columns: column7:7(int) column1:5(int) column2:6(int)
      │         │    │    │    ├── values
      │         │    │    │    │    ├── columns: column1:5(int) column2:6(int)
      │         │    │    │    │    └── tuple [type=tuple{int, int}]
      │         │    │    │    │         ├── const: 1 [type=int]
      │         │    │    │    │         └── const: 2 [type=int]
      │         │    │    │    └── projections
      │         │    │    │         └── cast: INT8 [type=int]
      │         │    │    │              └── null [type=unknown]
      │         │    │    └── projections
      │         │    │         └── plus [type=int]
      │         │    │              ├── variable: column7 [type=int]
      │         │    │              └── const: 1 [type=int]
      │         │    ├── scan checks_1
      │         │    │    └── columns: checks_1.a:9(int!null) checks_1.b:10(int) checks_1.c:11(int) checks_1.d:12(int)
      │         │    └── filters
      │         │         └── eq [type=bool]
      │         │              ├── variable: column1 [type=int]
      │         │              └── variable: checks_1.a [type=int]
      │         └── filters
      │              └── is [type=bool]
      │                   ├── variable: checks_1.a [type=int]
      │                   └── null [type=unknown]
      └── projections
           ├── lt [type=bool]
           │    ├── variable: column2 [type=int]
           │    └── variable: column8 [type=int]
           └── gt [type=bool]
                ├── variable: column1 [type=int]
                └── const: 0 [type=int]

# UPSERT
build
UPSERT INTO checks (a, b) VALUES (1, 2)
----
upsert checks
 ├── columns: <none>
 ├── canary column: 9
 ├── fetch columns: a:9(int) b:10(int) c:11(int) d:12(int)
 ├── insert-mapping:
 │    ├──  column1:5 => a:1
 │    ├──  column2:6 => b:2
 │    ├──  column7:7 => c:3
 │    └──  column8:8 => d:4
 ├── update-mapping:
 │    ├──  column2:6 => b:2
 │    └──  upsert_d:16 => d:4
 ├── check columns: check1:17(bool) check2:18(bool)
 └── project
      ├── columns: check1:17(bool) check2:18(bool) column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) d:12(int) column13:13(int) upsert_a:14(int) upsert_c:15(int) upsert_d:16(int)
      ├── project
      │    ├── columns: upsert_a:14(int) upsert_c:15(int) upsert_d:16(int) column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) d:12(int) column13:13(int)
      │    ├── project
      │    │    ├── columns: column13:13(int) column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) d:12(int)
      │    │    ├── left-join
      │    │    │    ├── columns: column1:5(int) column2:6(int) column7:7(int) column8:8(int) a:9(int) b:10(int) c:11(int) d:12(int)
      │    │    │    ├── project
      │    │    │    │    ├── columns: column8:8(int) column1:5(int) column2:6(int) column7:7(int)
      │    │    │    │    ├── project
      │    │    │    │    │    ├── columns: column7:7(int) column1:5(int) column2:6(int)
      │    │    │    │    │    ├── values
      │    │    │    │    │    │    ├── columns: column1:5(int) column2:6(int)
      │    │    │    │    │    │    └── tuple [type=tuple{int, int}]
      │    │    │    │    │    │         ├── const: 1 [type=int]
      │    │    │    │    │    │         └── const: 2 [type=int]
      │    │    │    │    │    └── projections
      │    │    │    │    │         └── cast: INT8 [type=int]
      │    │    │    │    │              └── null [type=unknown]
      │    │    │    │    └── projections
      │    │    │    │         └── plus [type=int]
      │    │    │    │              ├── variable: column7 [type=int]
      │    │    │    │              └── const: 1 [type=int]
      │    │    │    ├── scan checks
      │    │    │    │    └── columns: a:9(int!null) b:10(int) c:11(int) d:12(int)
      │    │    │    └── filters
      │    │    │         └── eq [type=bool]
      │    │    │              ├── variable: column1 [type=int]
      │    │    │              └── variable: a [type=int]
      │    │    └── projections
      │    │         └── plus [type=int]
      │    │              ├── variable: c [type=int]
      │    │              └── const: 1 [type=int]
      │    └── projections
      │         ├── case [type=int]
      │         │    ├── true [type=bool]
      │         │    ├── when [type=int]
      │         │    │    ├── is [type=bool]
      │         │    │    │    ├── variable: a [type=int]
      │         │    │    │    └── null [type=unknown]
      │         │    │    └── variable: column1 [type=int]
      │         │    └── variable: a [type=int]
      │         ├── case [type=int]
      │         │    ├── true [type=bool]
      │         │    ├── when [type=int]
      │         │    │    ├── is [type=bool]
      │         │    │    │    ├── variable: a [type=int]
      │         │    │    │    └── null [type=unknown]
      │         │    │    └── variable: column7 [type=int]
      │         │    └── variable: c [type=int]
      │         └── case [type=int]
      │              ├── true [type=bool]
      │              ├── when [type=int]
      │              │    ├── is [type=bool]
      │              │    │    ├── variable: a [type=int]
      │              │    │    └── null [type=unknown]
      │              │    └── variable: column8 [type=int]
      │              └── variable: column13 [type=int]
      └── projections
           ├── lt [type=bool]
           │    ├── variable: column2 [type=int]
           │    └── variable: upsert_d [type=int]
           └── gt [type=bool]
                ├── variable: upsert_a [type=int]
                └── const: 0 [type=int]

# Use subqueries and excluded.
build
INSERT INTO checks
SELECT a, b FROM abc
ON CONFLICT (a) DO UPDATE SET a=excluded.a, b=(SELECT x FROM xyz WHERE x=checks.a)
----
upsert checks
 ├── columns: <none>
 ├── canary column: 11
 ├── fetch columns: checks.a:11(int) checks.b:12(int) checks.c:13(int) d:14(int)
 ├── insert-mapping:
 │    ├──  abc.a:5 => checks.a:1
 │    ├──  abc.b:6 => checks.b:2
 │    ├──  column9:9 => checks.c:3
 │    └──  column10:10 => d:4
 ├── update-mapping:
 │    ├──  abc.a:5 => checks.a:1
 │    ├──  upsert_b:20 => checks.b:2
 │    └──  upsert_d:22 => d:4
 ├── check columns: check1:23(bool) check2:24(bool)
 └── project
      ├── columns: check1:23(bool) check2:24(bool) abc.a:5(int!null) abc.b:6(int) column9:9(int) column10:10(int) checks.a:11(int) checks.b:12(int) checks.c:13(int) d:14(int) column18:18(int) column19:19(int) upsert_b:20(int) upsert_c:21(int) upsert_d:22(int)
      ├── project
      │    ├── columns: upsert_b:20(int) upsert_c:21(int) upsert_d:22(int) abc.a:5(int!null) abc.b:6(int) column9:9(int) column10:10(int) checks.a:11(int) checks.b:12(int) checks.c:13(int) d:14(int) column18:18(int) column19:19(int)
      │    ├── project
      │    │    ├── columns: column19:19(int) abc.a:5(int!null) abc.b:6(int) column9:9(int) column10:10(int) checks.a:11(int) checks.b:12(int) checks.c:13(int) d:14(int) column18:18(int)
      │    │    ├── project
      │    │    │    ├── columns: column18:18(int) abc.a:5(int!null) abc.b:6(int) column9:9(int) column10:10(int) checks.a:11(int) checks.b:12(int) checks.c:13(int) d:14(int)
      │    │    │    ├── left-join
      │    │    │    │    ├── columns: abc.a:5(int!null) abc.b:6(int) column9:9(int) column10:10(int) checks.a:11(int) checks.b:12(int) checks.c:13(int) d:14(int)
      │    │    │    │    ├── project
      │    │    │    │    │    ├── columns: column10:10(int) abc.a:5(int!null) abc.b:6(int) column9:9(int)
      │    │    │    │    │    ├── project
      │    │    │    │    │    │    ├── columns: column9:9(int) abc.a:5(int!null) abc.b:6(int)
      │    │    │    │    │    │    ├── project
      │    │    │    │    │    │    │    ├── columns: abc.a:5(int!null) abc.b:6(int)
      │    │    │    │    │    │    │    └── scan abc
      │    │    │    │    │    │    │         └── columns: abc.a:5(int!null) abc.b:6(int) abc.c:7(int) rowid:8(int!null)
      │    │    │    │    │    │    └── projections
      │    │    │    │    │    │         └── cast: INT8 [type=int]
      │    │    │    │    │    │              └── null [type=unknown]
      │    │    │    │    │    └── projections
      │    │    │    │    │         └── plus [type=int]
      │    │    │    │    │              ├── variable: column9 [type=int]
      │    │    │    │    │              └── const: 1 [type=int]
      │    │    │    │    ├── scan checks
      │    │    │    │    │    └── columns: checks.a:11(int!null) checks.b:12(int) checks.c:13(int) d:14(int)
      │    │    │    │    └── filters
      │    │    │    │         └── eq [type=bool]
      │    │    │    │              ├── variable: abc.a [type=int]
      │    │    │    │              └── variable: checks.a [type=int]
      │    │    │    └── projections
      │    │    │         └── subquery [type=int]
      │    │    │              └── max1-row
      │    │    │                   ├── columns: x:15(int!null)
      │    │    │                   └── project
      │    │    │                        ├── columns: x:15(int!null)
      │    │    │                        └── select
      │    │    │                             ├── columns: x:15(int!null) y:16(int) z:17(int)
      │    │    │                             ├── scan xyz
      │    │    │                             │    └── columns: x:15(int!null) y:16(int) z:17(int)
      │    │    │                             └── filters
      │    │    │                                  └── eq [type=bool]
      │    │    │                                       ├── variable: x [type=int]
      │    │    │                                       └── variable: checks.a [type=int]
      │    │    └── projections
      │    │         └── plus [type=int]
      │    │              ├── variable: checks.c [type=int]
      │    │              └── const: 1 [type=int]
      │    └── projections
      │         ├── case [type=int]
      │         │    ├── true [type=bool]
      │         │    ├── when [type=int]
      │         │    │    ├── is [type=bool]
      │         │    │    │    ├── variable: checks.a [type=int]
      │         │    │    │    └── null [type=unknown]
      │         │    │    └── variable: abc.b [type=int]
      │         │    └── variable: column18 [type=int]
      │         ├── case [type=int]
      │         │    ├── true [type=bool]
      │         │    ├── when [type=int]
      │         │    │    ├── is [type=bool]
      │         │    │    │    ├── variable: checks.a [type=int]
      │         │    │    │    └── null [type=unknown]
      │         │    │    └── variable: column9 [type=int]
      │         │    └── variable: checks.c [type=int]
      │         └── case [type=int]
      │              ├── true [type=bool]
      │              ├── when [type=int]
      │              │    ├── is [type=bool]
      │              │    │    ├── variable: checks.a [type=int]
      │              │    │    └── null [type=unknown]
      │              │    └── variable: column10 [type=int]
      │              └── variable: column19 [type=int]
      └── projections
           ├── lt [type=bool]
           │    ├── variable: upsert_b [type=int]
           │    └── variable: upsert_d [type=int]
           └── gt [type=bool]
                ├── variable: abc.a [type=int]
                └── const: 0 [type=int]

# ------------------------------------------------------------------------------
# Test decimal column truncation.
# ------------------------------------------------------------------------------

# Fast UPSERT case.
opt
UPSERT INTO decimals (a, b) VALUES (1.1, ARRAY[0.95])
----
upsert decimals
 ├── columns: <none>
 ├── canary column: 13
 ├── fetch columns: decimals.a:13(decimal) decimals.b:14(decimal[]) decimals.c:15(decimal) decimals.d:16(decimal)
 ├── insert-mapping:
 │    ├──  a:8 => decimals.a:1
 │    ├──  b:9 => decimals.b:2
 │    ├──  c:10 => decimals.c:3
 │    └──  d:12 => decimals.d:4
 ├── update-mapping:
 │    ├──  b:9 => decimals.b:2
 │    └──  upsert_d:21 => decimals.d:4
 ├── check columns: check1:22(bool) check2:23(bool)
 └── project
      ├── columns: check1:22(bool) check2:23(bool) a:8(decimal) b:9(decimal[]) c:10(decimal) d:12(decimal) decimals.a:13(decimal) decimals.b:14(decimal[]) decimals.c:15(decimal) decimals.d:16(decimal) upsert_d:21(decimal)
      ├── project
      │    ├── columns: upsert_a:19(decimal) upsert_d:21(decimal) a:8(decimal) b:9(decimal[]) c:10(decimal) d:12(decimal) decimals.a:13(decimal) decimals.b:14(decimal[]) decimals.c:15(decimal) decimals.d:16(decimal)
      │    ├── left-join (lookup decimals)
      │    │    ├── columns: a:8(decimal) b:9(decimal[]) c:10(decimal) d:12(decimal) decimals.a:13(decimal) decimals.b:14(decimal[]) decimals.c:15(decimal) decimals.d:16(decimal)
      │    │    ├── key columns: [8] = [13]
      │    │    ├── project
      │    │    │    ├── columns: d:12(decimal) a:8(decimal) b:9(decimal[]) c:10(decimal)
      │    │    │    ├── values
      │    │    │    │    ├── columns: a:8(decimal) b:9(decimal[]) c:10(decimal)
      │    │    │    │    └── tuple [type=tuple{decimal, decimal[], decimal}]
      │    │    │    │         ├── function: crdb_internal.round_decimal_values [type=decimal]
      │    │    │    │         │    ├── const: 1.1 [type=decimal]
      │    │    │    │         │    └── const: 0 [type=int]
      │    │    │    │         ├── function: crdb_internal.round_decimal_values [type=decimal[]]
      │    │    │    │         │    ├── const: ARRAY[0.95] [type=decimal[]]
      │    │    │    │         │    └── const: 1 [type=int]
      │    │    │    │         └── function: crdb_internal.round_decimal_values [type=decimal]
      │    │    │    │              ├── const: 1.23 [type=decimal]
      │    │    │    │              └── const: 1 [type=int]
      │    │    │    └── projections
      │    │    │         └── function: crdb_internal.round_decimal_values [type=decimal]
      │    │    │              ├── plus [type=decimal]
      │    │    │              │    ├── variable: a [type=decimal]
      │    │    │              │    └── variable: c [type=decimal]
      │    │    │              └── const: 1 [type=int]
      │    │    └── filters (true)
      │    └── projections
      │         ├── case [type=decimal]
      │         │    ├── true [type=bool]
      │         │    ├── when [type=decimal]
      │         │    │    ├── is [type=bool]
      │         │    │    │    ├── variable: decimals.a [type=decimal]
      │         │    │    │    └── null [type=unknown]
      │         │    │    └── variable: a [type=decimal]
      │         │    └── variable: decimals.a [type=decimal]
      │         └── case [type=decimal]
      │              ├── true [type=bool]
      │              ├── when [type=decimal]
      │              │    ├── is [type=bool]
      │              │    │    ├── variable: decimals.a [type=decimal]
      │              │    │    └── null [type=unknown]
      │              │    └── variable: d [type=decimal]
      │              └── function: crdb_internal.round_decimal_values [type=decimal]
      │                   ├── plus [type=decimal]
      │                   │    ├── variable: decimals.a [type=decimal]
      │                   │    └── variable: decimals.c [type=decimal]
      │                   └── const: 1 [type=int]
      └── projections
           ├── eq [type=bool]
           │    ├── variable: upsert_a [type=decimal]
           │    └── function: round [type=decimal]
           │         └── variable: upsert_a [type=decimal]
           └── gt [type=bool]
                ├── indirection [type=decimal]
                │    ├── variable: b [type=decimal[]]
                │    └── const: 0 [type=int]
                └── const: 1 [type=decimal]

# Regular UPSERT case.
opt
UPSERT INTO decimals (a) VALUES (1.1)
----
upsert decimals
 ├── columns: <none>
 ├── canary column: 13
 ├── fetch columns: decimals.a:13(decimal) decimals.b:14(decimal[]) decimals.c:15(decimal) decimals.d:16(decimal)
 ├── insert-mapping:
 │    ├──  a:8 => decimals.a:1
 │    ├──  b:9 => decimals.b:2
 │    ├──  c:10 => decimals.c:3
 │    └──  d:12 => decimals.d:4
 ├── update-mapping:
 │    └──  upsert_d:22 => decimals.d:4
 ├── check columns: check1:23(bool) check2:24(bool)
 └── project
      ├── columns: check1:23(bool) check2:24(bool) a:8(decimal) b:9(decimal[]) c:10(decimal) d:12(decimal) decimals.a:13(decimal) decimals.b:14(decimal[]) decimals.c:15(decimal) decimals.d:16(decimal) upsert_d:22(decimal)
      ├── project
      │    ├── columns: upsert_a:19(decimal) upsert_b:20(decimal[]) upsert_d:22(decimal) a:8(decimal) b:9(decimal[]) c:10(decimal) d:12(decimal) decimals.a:13(decimal) decimals.b:14(decimal[]) decimals.c:15(decimal) decimals.d:16(decimal)
      │    ├── left-join (lookup decimals)
      │    │    ├── columns: a:8(decimal) b:9(decimal[]) c:10(decimal) d:12(decimal) decimals.a:13(decimal) decimals.b:14(decimal[]) decimals.c:15(decimal) decimals.d:16(decimal)
      │    │    ├── key columns: [8] = [13]
      │    │    ├── project
      │    │    │    ├── columns: d:12(decimal) a:8(decimal) b:9(decimal[]) c:10(decimal)
      │    │    │    ├── values
      │    │    │    │    ├── columns: a:8(decimal) b:9(decimal[]) c:10(decimal)
      │    │    │    │    └── tuple [type=tuple{decimal, decimal[], decimal}]
      │    │    │    │         ├── function: crdb_internal.round_decimal_values [type=decimal]
      │    │    │    │         │    ├── const: 1.1 [type=decimal]
      │    │    │    │         │    └── const: 0 [type=int]
      │    │    │    │         ├── function: crdb_internal.round_decimal_values [type=decimal[]]
      │    │    │    │         │    ├── null [type=decimal[]]
      │    │    │    │         │    └── const: 1 [type=int]
      │    │    │    │         └── function: crdb_internal.round_decimal_values [type=decimal]
      │    │    │    │              ├── const: 1.23 [type=decimal]
      │    │    │    │              └── const: 1 [type=int]
      │    │    │    └── projections
      │    │    │         └── function: crdb_internal.round_decimal_values [type=decimal]
      │    │    │              ├── plus [type=decimal]
      │    │    │              │    ├── variable: a [type=decimal]
      │    │    │              │    └── variable: c [type=decimal]
      │    │    │              └── const: 1 [type=int]
      │    │    └── filters (true)
      │    └── projections
      │         ├── case [type=decimal]
      │         │    ├── true [type=bool]
      │         │    ├── when [type=decimal]
      │         │    │    ├── is [type=bool]
      │         │    │    │    ├── variable: decimals.a [type=decimal]
      │         │    │    │    └── null [type=unknown]
      │         │    │    └── variable: a [type=decimal]
      │         │    └── variable: decimals.a [type=decimal]
      │         ├── case [type=decimal[]]
      │         │    ├── true [type=bool]
      │         │    ├── when [type=decimal[]]
      │         │    │    ├── is [type=bool]
      │         │    │    │    ├── variable: decimals.a [type=decimal]
      │         │    │    │    └── null [type=unknown]
      │         │    │    └── variable: b [type=decimal[]]
      │         │    └── variable: decimals.b [type=decimal[]]
      │         └── case [type=decimal]
      │              ├── true [type=bool]
      │              ├── when [type=decimal]
      │              │    ├── is [type=bool]
      │              │    │    ├── variable: decimals.a [type=decimal]
      │              │    │    └── null [type=unknown]
      │              │    └── variable: d [type=decimal]
      │              └── function: crdb_internal.round_decimal_values [type=decimal]
      │                   ├── plus [type=decimal]
      │                   │    ├── variable: decimals.a [type=decimal]
      │                   │    └── variable: decimals.c [type=decimal]
      │                   └── const: 1 [type=int]
      └── projections
           ├── eq [type=bool]
           │    ├── variable: upsert_a [type=decimal]
           │    └── function: round [type=decimal]
           │         └── variable: upsert_a [type=decimal]
           └── gt [type=bool]
                ├── indirection [type=decimal]
                │    ├── variable: upsert_b [type=decimal[]]
                │    └── const: 0 [type=int]
                └── const: 1 [type=decimal]

# INSERT...ON CONFLICT case.
opt
INSERT INTO decimals (a, b) VALUES (1.1, ARRAY[0.95])
ON CONFLICT (a)
DO UPDATE SET b=ARRAY[0.99]
----
upsert decimals
 ├── columns: <none>
 ├── canary column: 13
 ├── fetch columns: decimals.a:13(decimal) decimals.b:14(decimal[]) decimals.c:15(decimal) decimals.d:16(decimal)
 ├── insert-mapping:
 │    ├──  a:8 => decimals.a:1
 │    ├──  b:9 => decimals.b:2
 │    ├──  c:10 => decimals.c:3
 │    └──  d:12 => decimals.d:4
 ├── update-mapping:
 │    ├──  upsert_b:22 => decimals.b:2
 │    └──  upsert_d:24 => decimals.d:4
 ├── check columns: check1:25(bool) check2:26(bool)
 └── project
      ├── columns: check1:25(bool) check2:26(bool) a:8(decimal) b:9(decimal[]) c:10(decimal) d:12(decimal) decimals.a:13(decimal) decimals.b:14(decimal[]) decimals.c:15(decimal) decimals.d:16(decimal) upsert_b:22(decimal[]) upsert_d:24(decimal)
      ├── project
      │    ├── columns: upsert_a:21(decimal) upsert_b:22(decimal[]) upsert_d:24(decimal) a:8(decimal) b:9(decimal[]) c:10(decimal) d:12(decimal) decimals.a:13(decimal) decimals.b:14(decimal[]) decimals.c:15(decimal) decimals.d:16(decimal)
      │    ├── left-join (lookup decimals)
      │    │    ├── columns: a:8(decimal) b:9(decimal[]) c:10(decimal) d:12(decimal) decimals.a:13(decimal) decimals.b:14(decimal[]) decimals.c:15(decimal) decimals.d:16(decimal)
      │    │    ├── key columns: [8] = [13]
      │    │    ├── project
      │    │    │    ├── columns: d:12(decimal) a:8(decimal) b:9(decimal[]) c:10(decimal)
      │    │    │    ├── values
      │    │    │    │    ├── columns: a:8(decimal) b:9(decimal[]) c:10(decimal)
      │    │    │    │    └── tuple [type=tuple{decimal, decimal[], decimal}]
      │    │    │    │         ├── function: crdb_internal.round_decimal_values [type=decimal]
      │    │    │    │         │    ├── const: 1.1 [type=decimal]
      │    │    │    │         │    └── const: 0 [type=int]
      │    │    │    │         ├── function: crdb_internal.round_decimal_values [type=decimal[]]
      │    │    │    │         │    ├── const: ARRAY[0.95] [type=decimal[]]
      │    │    │    │         │    └── const: 1 [type=int]
      │    │    │    │         └── function: crdb_internal.round_decimal_values [type=decimal]
      │    │    │    │              ├── const: 1.23 [type=decimal]
      │    │    │    │              └── const: 1 [type=int]
      │    │    │    └── projections
      │    │    │         └── function: crdb_internal.round_decimal_values [type=decimal]
      │    │    │              ├── plus [type=decimal]
      │    │    │              │    ├── variable: a [type=decimal]
      │    │    │              │    └── variable: c [type=decimal]
      │    │    │              └── const: 1 [type=int]
      │    │    └── filters (true)
      │    └── projections
      │         ├── case [type=decimal]
      │         │    ├── true [type=bool]
      │         │    ├── when [type=decimal]
      │         │    │    ├── is [type=bool]
      │         │    │    │    ├── variable: decimals.a [type=decimal]
      │         │    │    │    └── null [type=unknown]
      │         │    │    └── variable: a [type=decimal]
      │         │    └── variable: decimals.a [type=decimal]
      │         ├── case [type=decimal[]]
      │         │    ├── true [type=bool]
      │         │    ├── when [type=decimal[]]
      │         │    │    ├── is [type=bool]
      │         │    │    │    ├── variable: decimals.a [type=decimal]
      │         │    │    │    └── null [type=unknown]
      │         │    │    └── variable: b [type=decimal[]]
      │         │    └── function: crdb_internal.round_decimal_values [type=decimal[]]
      │         │         ├── const: ARRAY[0.99] [type=decimal[]]
      │         │         └── const: 1 [type=int]
      │         └── case [type=decimal]
      │              ├── true [type=bool]
      │              ├── when [type=decimal]
      │              │    ├── is [type=bool]
      │              │    │    ├── variable: decimals.a [type=decimal]
      │              │    │    └── null [type=unknown]
      │              │    └── variable: d [type=decimal]
      │              └── function: crdb_internal.round_decimal_values [type=decimal]
      │                   ├── plus [type=decimal]
      │                   │    ├── variable: decimals.a [type=decimal]
      │                   │    └── variable: decimals.c [type=decimal]
      │                   └── const: 1 [type=int]
      └── projections
           ├── eq [type=bool]
           │    ├── variable: upsert_a [type=decimal]
           │    └── function: round [type=decimal]
           │         └── variable: upsert_a [type=decimal]
           └── gt [type=bool]
                ├── indirection [type=decimal]
                │    ├── variable: upsert_b [type=decimal[]]
                │    └── const: 0 [type=int]
                └── const: 1 [type=decimal]
