# LogicTest: 5node !metamorphic-batch-sizes

statement ok
SET experimental_enable_implicit_column_partitioning = true;

# Make sure foreign key references checked is planned
subtest test_fk_constraint

statement ok
CREATE TABLE t_parent (
  id INT PRIMARY KEY USING HASH,
  part STRING CHECK (part IN ('seattle', 'new york')),
  FAMILY fam_0 (id, part)
) PARTITION ALL BY LIST (part) (
   PARTITION us_west VALUES IN (('seattle')),
   PARTITION us_east VALUES IN (('new york'))
);

statement ok
CREATE TABLE t_child (
  id INT PRIMARY KEY,
  pid INT REFERENCES t_parent (id),
  FAMILY fam_0 (id, pid)
);

statement ok
CREATE TABLE t_child_partitioned (
  id INT PRIMARY KEY,
  pid INT REFERENCES t_parent (id),
  part STRING CHECK (part IN ('seattle', 'new york')),
  FAMILY fam_0 (id, pid, part)
) PARTITION ALL BY LIST (part) (
   PARTITION us_west VALUES IN (('seattle')),
   PARTITION us_east VALUES IN (('new york'))
);

query T
EXPLAIN (VERBOSE) INSERT INTO t_child VALUES (123, 321);
----
distribution: local
vectorized: true
·
• root
│ columns: ()
│
├── • insert
│   │ columns: ()
│   │ estimated row count: 0 (missing stats)
│   │ into: t_child(id, pid)
│   │
│   └── • buffer
│       │ columns: (column1, column2)
│       │ label: buffer 1
│       │
│       └── • values
│             columns: (column1, column2)
│             size: 2 columns, 1 row
│             row 0, expr 0: 123
│             row 0, expr 1: 321
│
└── • constraint-check
    │
    └── • error if rows
        │ columns: ()
        │
        └── • project
            │ columns: (pid)
            │
            └── • lookup join (anti)
                │ columns: (crdb_internal_id_shard_16_eq, pid)
                │ estimated row count: 0 (missing stats)
                │ table: t_parent@t_parent_pkey
                │ equality cols are key
                │ lookup condition: ((part IN ('new york', 'seattle')) AND (crdb_internal_id_shard_16_eq = crdb_internal_id_shard_16)) AND (pid = id)
                │
                └── • render
                    │ columns: (crdb_internal_id_shard_16_eq, pid)
                    │ render crdb_internal_id_shard_16_eq: mod(fnv32(md5(crdb_internal.datums_to_bytes(column2))), 16)
                    │ render pid: column2
                    │
                    └── • project
                        │ columns: (column2)
                        │
                        └── • scan buffer
                              columns: (column1, column2)
                              estimated row count: 1
                              label: buffer 1

query T
EXPLAIN (VERBOSE) INSERT INTO t_child_partitioned VALUES (123, 321, 'seattle');
----
distribution: local
vectorized: true
·
• root
│ columns: ()
│
├── • insert
│   │ columns: ()
│   │ estimated row count: 0 (missing stats)
│   │ into: t_child_partitioned(id, pid, part)
│   │
│   └── • buffer
│       │ columns: (column1, column2, column3, check1)
│       │ label: buffer 1
│       │
│       └── • values
│             columns: (column1, column2, column3, check1)
│             size: 4 columns, 1 row
│             row 0, expr 0: 123
│             row 0, expr 1: 321
│             row 0, expr 2: 'seattle'
│             row 0, expr 3: true
│
├── • constraint-check
│   │
│   └── • error if rows
│       │ columns: ()
│       │
│       └── • project
│           │ columns: (id)
│           │
│           └── • cross join (inner)
│               │ columns: (id, id, part)
│               │ estimated row count: 1 (missing stats)
│               │
│               ├── • values
│               │     columns: (id)
│               │     size: 1 column, 1 row
│               │     row 0, expr 0: 123
│               │
│               └── • scan
│                     columns: (id, part)
│                     estimated row count: 1 (missing stats)
│                     table: t_child_partitioned@t_child_partitioned_pkey
│                     spans: /"new york"/123/0
│                     limit: 1
│
└── • constraint-check
    │
    └── • error if rows
        │ columns: ()
        │
        └── • project
            │ columns: (pid)
            │
            └── • lookup join (anti)
                │ columns: (crdb_internal_id_shard_16_eq, pid)
                │ estimated row count: 0 (missing stats)
                │ table: t_parent@t_parent_pkey
                │ equality cols are key
                │ lookup condition: ((part IN ('new york', 'seattle')) AND (crdb_internal_id_shard_16_eq = crdb_internal_id_shard_16)) AND (pid = id)
                │
                └── • render
                    │ columns: (crdb_internal_id_shard_16_eq, pid)
                    │ render crdb_internal_id_shard_16_eq: mod(fnv32(md5(crdb_internal.datums_to_bytes(column2))), 16)
                    │ render pid: column2
                    │
                    └── • project
                        │ columns: (column2)
                        │
                        └── • scan buffer
                              columns: (column1, column2, column3, check1)
                              estimated row count: 1
                              label: buffer 1

subtest test_uniqueness_check_uuid

# Make sure uniqueness check is omitted with gen_random_uuid().
statement ok
CREATE TABLE t_gen_random_uuid (
  user_id UUID DEFAULT gen_random_uuid() PRIMARY KEY USING HASH,
  val STRING NOT NULL,
  part STRING CHECK (part IN ('seattle', 'new york')),
  FAMILY fam_0 (user_id, val, part)
) PARTITION ALL BY LIST (part) (
   PARTITION us_west VALUES IN (('seattle')),
   PARTITION us_east VALUES IN (('new york'))
);

query T
EXPLAIN (VERBOSE) INSERT INTO t_gen_random_uuid (val, part) VALUES (4321, 'seattle');
----
distribution: local
vectorized: true
·
• insert
│ columns: ()
│ estimated row count: 0 (missing stats)
│ into: t_gen_random_uuid(crdb_internal_user_id_shard_16, user_id, val, part)
│ auto commit
│
└── • render
    │ columns: (crdb_internal_user_id_shard_16_comp, user_id_default, val_cast, column2, check1, check2)
    │ render check1: column2 IN ('new york', 'seattle')
    │ render check2: crdb_internal_user_id_shard_16_comp IN (0, 1, __more10_100__, 15)
    │ render column2: column2
    │ render val_cast: val_cast
    │ render user_id_default: user_id_default
    │ render crdb_internal_user_id_shard_16_comp: crdb_internal_user_id_shard_16_comp
    │
    └── • render
        │ columns: (crdb_internal_user_id_shard_16_comp, column2, val_cast, user_id_default)
        │ render crdb_internal_user_id_shard_16_comp: mod(fnv32(md5(crdb_internal.datums_to_bytes(user_id_default))), 16)
        │ render column2: column2
        │ render val_cast: val_cast
        │ render user_id_default: user_id_default
        │
        └── • values
              columns: (column2, val_cast, user_id_default)
              size: 3 columns, 1 row
              row 0, expr 0: 'seattle'
              row 0, expr 1: '4321'
              row 0, expr 2: gen_random_uuid()

query T
EXPLAIN (VERBOSE) INSERT INTO t_gen_random_uuid (val, part) VALUES (4321, 'seattle') ON CONFLICT DO NOTHING;
----
distribution: local
vectorized: true
·
• insert
│ columns: ()
│ estimated row count: 0 (missing stats)
│ into: t_gen_random_uuid(crdb_internal_user_id_shard_16, user_id, val, part)
│ auto commit
│ arbiter constraints: t_gen_random_uuid_pkey
│
└── • render
    │ columns: (crdb_internal_user_id_shard_16_comp, user_id_default, val_cast, column2, check1, check2)
    │ render check1: column2 IN ('new york', 'seattle')
    │ render check2: crdb_internal_user_id_shard_16_comp IN (0, 1, __more10_100__, 15)
    │ render column2: column2
    │ render val_cast: val_cast
    │ render user_id_default: user_id_default
    │ render crdb_internal_user_id_shard_16_comp: crdb_internal_user_id_shard_16_comp
    │
    └── • project
        │ columns: (column2, val_cast, user_id_default, crdb_internal_user_id_shard_16_comp)
        │
        └── • lookup join (anti)
            │ columns: (crdb_internal_user_id_shard_16_eq, crdb_internal_user_id_shard_16_comp, column2, val_cast, user_id_default)
            │ estimated row count: 0 (missing stats)
            │ table: t_gen_random_uuid@t_gen_random_uuid_pkey
            │ equality cols are key
            │ lookup condition: ((part IN ('new york', 'seattle')) AND (crdb_internal_user_id_shard_16_eq = crdb_internal_user_id_shard_16)) AND (user_id_default = user_id)
            │
            └── • render
                │ columns: (crdb_internal_user_id_shard_16_eq, crdb_internal_user_id_shard_16_comp, column2, val_cast, user_id_default)
                │ render crdb_internal_user_id_shard_16_eq: mod(fnv32(md5(crdb_internal.datums_to_bytes(user_id_default))), 16)
                │ render crdb_internal_user_id_shard_16_comp: mod(fnv32(md5(crdb_internal.datums_to_bytes(user_id_default))), 16)
                │ render column2: column2
                │ render val_cast: val_cast
                │ render user_id_default: user_id_default
                │
                └── • values
                      columns: (column2, val_cast, user_id_default)
                      size: 3 columns, 1 row
                      row 0, expr 0: 'seattle'
                      row 0, expr 1: '4321'
                      row 0, expr 2: gen_random_uuid()

query T
EXPLAIN (VERBOSE) INSERT INTO t_gen_random_uuid (val, part) VALUES (4321, 'seattle'), (8765, 'new york') ON CONFLICT DO NOTHING;
----
distribution: local
vectorized: true
·
• insert
│ columns: ()
│ estimated row count: 0 (missing stats)
│ into: t_gen_random_uuid(crdb_internal_user_id_shard_16, user_id, val, part)
│ auto commit
│ arbiter constraints: t_gen_random_uuid_pkey
│
└── • render
    │ columns: (crdb_internal_user_id_shard_16_comp, user_id_default, val_cast, column2, check1, check2)
    │ render check1: column2 IN ('new york', 'seattle')
    │ render check2: crdb_internal_user_id_shard_16_comp IN (0, 1, __more10_100__, 15)
    │ render column2: column2
    │ render val_cast: val_cast
    │ render user_id_default: user_id_default
    │ render crdb_internal_user_id_shard_16_comp: crdb_internal_user_id_shard_16_comp
    │
    └── • distinct
        │ columns: (column2, val_cast, user_id_default, crdb_internal_user_id_shard_16_comp)
        │ estimated row count: 0 (missing stats)
        │ distinct on: user_id_default
        │ nulls are distinct
        │
        └── • project
            │ columns: (column2, val_cast, user_id_default, crdb_internal_user_id_shard_16_comp)
            │
            └── • lookup join (anti)
                │ columns: (crdb_internal_user_id_shard_16_eq, crdb_internal_user_id_shard_16_comp, column2, val_cast, user_id_default)
                │ estimated row count: 0 (missing stats)
                │ table: t_gen_random_uuid@t_gen_random_uuid_pkey
                │ equality cols are key
                │ lookup condition: ((part IN ('new york', 'seattle')) AND (crdb_internal_user_id_shard_16_eq = crdb_internal_user_id_shard_16)) AND (user_id_default = user_id)
                │
                └── • render
                    │ columns: (crdb_internal_user_id_shard_16_eq, crdb_internal_user_id_shard_16_comp, column2, val_cast, user_id_default)
                    │ render crdb_internal_user_id_shard_16_eq: mod(fnv32(md5(crdb_internal.datums_to_bytes(user_id_default))), 16)
                    │ render crdb_internal_user_id_shard_16_comp: mod(fnv32(md5(crdb_internal.datums_to_bytes(user_id_default))), 16)
                    │ render column2: column2
                    │ render val_cast: val_cast
                    │ render user_id_default: user_id_default
                    │
                    └── • render
                        │ columns: (user_id_default, column2, val_cast)
                        │ render user_id_default: gen_random_uuid()
                        │ render column2: column2
                        │ render val_cast: val_cast
                        │
                        └── • values
                              columns: (val_cast, column2)
                              size: 2 columns, 2 rows
                              row 0, expr 0: '4321'
                              row 0, expr 1: 'seattle'
                              row 1, expr 0: '8765'
                              row 1, expr 1: 'new york'

subtest test_uniqueness_check_pk

statement ok
CREATE TABLE t_unique_hash_pk (
  id INT PRIMARY KEY USING HASH,
  part STRING CHECK (part IN ('seattle', 'new york')),
  FAMILY fam_0 (id, part)
) PARTITION ALL BY LIST (part) (
  PARTITION us_west VALUES IN (('seattle')),
  PARTITION us_east VALUES IN (('new york'))
);

query T
EXPLAIN (VERBOSE) INSERT INTO t_unique_hash_pk (id, part) VALUES (4321, 'seattle');
----
distribution: local
vectorized: true
·
• insert fast path
  columns: ()
  estimated row count: 0 (missing stats)
  into: t_unique_hash_pk(crdb_internal_id_shard_16, id, part)
  auto commit
  uniqueness check: t_unique_hash_pk@t_unique_hash_pk_pkey
  size: 5 columns, 1 row
  row 0, expr 0: 11
  row 0, expr 1: 4321
  row 0, expr 2: 'seattle'
  row 0, expr 3: true
  row 0, expr 4: true

query T
EXPLAIN (VERBOSE) INSERT INTO t_unique_hash_pk (id, part) VALUES (4321, 'seattle') ON CONFLICT DO NOTHING;
----
distribution: local
vectorized: true
·
• insert
│ columns: ()
│ estimated row count: 0 (missing stats)
│ into: t_unique_hash_pk(crdb_internal_id_shard_16, id, part)
│ auto commit
│ arbiter constraints: t_unique_hash_pk_pkey
│
└── • render
    │ columns: (crdb_internal_id_shard_16_comp, column1, column2, check1, check2)
    │ render check1: column2 IN ('new york', 'seattle')
    │ render check2: crdb_internal_id_shard_16_comp IN (0, 1, __more10_100__, 15)
    │ render column1: column1
    │ render column2: column2
    │ render crdb_internal_id_shard_16_comp: crdb_internal_id_shard_16_comp
    │
    └── • cross join (anti)
        │ columns: (column1, column2, crdb_internal_id_shard_16_comp)
        │ estimated row count: 0 (missing stats)
        │
        ├── • values
        │     columns: (column1, column2, crdb_internal_id_shard_16_comp)
        │     size: 3 columns, 1 row
        │     row 0, expr 0: 4321
        │     row 0, expr 1: 'seattle'
        │     row 0, expr 2: 11
        │
        └── • scan
              columns: (id)
              estimated row count: 1 (missing stats)
              table: t_unique_hash_pk@t_unique_hash_pk_pkey
              spans: /"new york"/11/4321/0 /"seattle"/11/4321/0
              parallel

query T
EXPLAIN (VERBOSE) INSERT INTO t_unique_hash_pk (id, part) VALUES (4321, 'seattle'), (8765, 'new york') ON CONFLICT DO NOTHING;
----
distribution: local
vectorized: true
·
• insert
│ columns: ()
│ estimated row count: 0 (missing stats)
│ into: t_unique_hash_pk(crdb_internal_id_shard_16, id, part)
│ auto commit
│ arbiter constraints: t_unique_hash_pk_pkey
│
└── • render
    │ columns: (crdb_internal_id_shard_16_comp, column1, column2, check1, check2)
    │ render check1: column2 IN ('new york', 'seattle')
    │ render check2: crdb_internal_id_shard_16_comp IN (0, 1, __more10_100__, 15)
    │ render column1: column1
    │ render column2: column2
    │ render crdb_internal_id_shard_16_comp: crdb_internal_id_shard_16_comp
    │
    └── • project
        │ columns: (column1, column2, crdb_internal_id_shard_16_comp)
        │
        └── • lookup join (anti)
            │ columns: (crdb_internal_id_shard_16_eq, crdb_internal_id_shard_16_comp, column1, column2)
            │ estimated row count: 0 (missing stats)
            │ table: t_unique_hash_pk@t_unique_hash_pk_pkey
            │ equality cols are key
            │ lookup condition: ((part IN ('new york', 'seattle')) AND (crdb_internal_id_shard_16_eq = crdb_internal_id_shard_16)) AND (column1 = id)
            │
            └── • render
                │ columns: (crdb_internal_id_shard_16_eq, crdb_internal_id_shard_16_comp, column1, column2)
                │ render crdb_internal_id_shard_16_eq: mod(fnv32(md5(crdb_internal.datums_to_bytes(column1))), 16)
                │ render crdb_internal_id_shard_16_comp: mod(fnv32(md5(crdb_internal.datums_to_bytes(column1))), 16)
                │ render column1: column1
                │ render column2: column2
                │
                └── • values
                      columns: (column1, column2)
                      size: 2 columns, 2 rows
                      row 0, expr 0: 4321
                      row 0, expr 1: 'seattle'
                      row 1, expr 0: 8765
                      row 1, expr 1: 'new york'

query T
EXPLAIN (VERBOSE) INSERT INTO t_unique_hash_pk (id, part) VALUES (4321, 'seattle') ON CONFLICT (id) DO NOTHING;
----
distribution: local
vectorized: true
·
• insert
│ columns: ()
│ estimated row count: 0 (missing stats)
│ into: t_unique_hash_pk(crdb_internal_id_shard_16, id, part)
│ auto commit
│ arbiter constraints: t_unique_hash_pk_pkey
│
└── • render
    │ columns: (crdb_internal_id_shard_16_comp, column1, column2, check1, check2)
    │ render check1: column2 IN ('new york', 'seattle')
    │ render check2: crdb_internal_id_shard_16_comp IN (0, 1, __more10_100__, 15)
    │ render column1: column1
    │ render column2: column2
    │ render crdb_internal_id_shard_16_comp: crdb_internal_id_shard_16_comp
    │
    └── • cross join (anti)
        │ columns: (column1, column2, crdb_internal_id_shard_16_comp)
        │ estimated row count: 0 (missing stats)
        │
        ├── • values
        │     columns: (column1, column2, crdb_internal_id_shard_16_comp)
        │     size: 3 columns, 1 row
        │     row 0, expr 0: 4321
        │     row 0, expr 1: 'seattle'
        │     row 0, expr 2: 11
        │
        └── • scan
              columns: (id)
              estimated row count: 1 (missing stats)
              table: t_unique_hash_pk@t_unique_hash_pk_pkey
              spans: /"new york"/11/4321/0 /"seattle"/11/4321/0
              parallel

query T
EXPLAIN (VERBOSE) INSERT INTO t_unique_hash_pk (id, part) VALUES (4321, 'seattle'), (8765, 'new york') ON CONFLICT (id) DO NOTHING;
----
distribution: local
vectorized: true
·
• insert
│ columns: ()
│ estimated row count: 0 (missing stats)
│ into: t_unique_hash_pk(crdb_internal_id_shard_16, id, part)
│ auto commit
│ arbiter constraints: t_unique_hash_pk_pkey
│
└── • render
    │ columns: (crdb_internal_id_shard_16_comp, column1, column2, check1, check2)
    │ render check1: column2 IN ('new york', 'seattle')
    │ render check2: crdb_internal_id_shard_16_comp IN (0, 1, __more10_100__, 15)
    │ render column1: column1
    │ render column2: column2
    │ render crdb_internal_id_shard_16_comp: crdb_internal_id_shard_16_comp
    │
    └── • project
        │ columns: (column1, column2, crdb_internal_id_shard_16_comp)
        │
        └── • lookup join (anti)
            │ columns: (crdb_internal_id_shard_16_eq, crdb_internal_id_shard_16_comp, column1, column2)
            │ estimated row count: 0 (missing stats)
            │ table: t_unique_hash_pk@t_unique_hash_pk_pkey
            │ equality cols are key
            │ lookup condition: ((part IN ('new york', 'seattle')) AND (crdb_internal_id_shard_16_eq = crdb_internal_id_shard_16)) AND (column1 = id)
            │
            └── • render
                │ columns: (crdb_internal_id_shard_16_eq, crdb_internal_id_shard_16_comp, column1, column2)
                │ render crdb_internal_id_shard_16_eq: mod(fnv32(md5(crdb_internal.datums_to_bytes(column1))), 16)
                │ render crdb_internal_id_shard_16_comp: mod(fnv32(md5(crdb_internal.datums_to_bytes(column1))), 16)
                │ render column1: column1
                │ render column2: column2
                │
                └── • values
                      columns: (column1, column2)
                      size: 2 columns, 2 rows
                      row 0, expr 0: 4321
                      row 0, expr 1: 'seattle'
                      row 1, expr 0: 8765
                      row 1, expr 1: 'new york'

query T
EXPLAIN (VERBOSE) INSERT INTO t_unique_hash_pk (id, part) VALUES (4321, 'seattle') ON CONFLICT (id) DO UPDATE SET id = excluded.id
----
distribution: local
vectorized: true
·
• root
│ columns: ()
│
├── • upsert
│   │ columns: ()
│   │ estimated row count: 0 (missing stats)
│   │ into: t_unique_hash_pk(crdb_internal_id_shard_16, id, part)
│   │ arbiter constraints: t_unique_hash_pk_pkey
│   │
│   └── • buffer
│       │ columns: (crdb_internal_id_shard_16_comp, column1, column2, crdb_internal_id_shard_16, id, part, crdb_internal_id_shard_16_comp, column1, part, check1, check2, upsert_part)
│       │ label: buffer 1
│       │
│       └── • project
│           │ columns: (crdb_internal_id_shard_16_comp, column1, column2, crdb_internal_id_shard_16, id, part, crdb_internal_id_shard_16_comp, column1, part, check1, check2, upsert_part)
│           │
│           └── • render
│               │ columns: (check1, check2, column1, column2, crdb_internal_id_shard_16_comp, crdb_internal_id_shard_16, id, part, upsert_part)
│               │ render check1: upsert_part IN ('new york', 'seattle')
│               │ render check2: crdb_internal_id_shard_16_comp IN (0, 1, __more10_100__, 15)
│               │ render column1: column1
│               │ render column2: column2
│               │ render crdb_internal_id_shard_16_comp: crdb_internal_id_shard_16_comp
│               │ render crdb_internal_id_shard_16: crdb_internal_id_shard_16
│               │ render id: id
│               │ render part: part
│               │ render upsert_part: upsert_part
│               │
│               └── • render
│                   │ columns: (upsert_part, column1, column2, crdb_internal_id_shard_16_comp, crdb_internal_id_shard_16, id, part)
│                   │ render upsert_part: CASE WHEN part IS NULL THEN column2 ELSE part END
│                   │ render column1: column1
│                   │ render column2: column2
│                   │ render crdb_internal_id_shard_16_comp: crdb_internal_id_shard_16_comp
│                   │ render crdb_internal_id_shard_16: crdb_internal_id_shard_16
│                   │ render id: id
│                   │ render part: part
│                   │
│                   └── • cross join (left outer)
│                       │ columns: (column1, column2, crdb_internal_id_shard_16_comp, crdb_internal_id_shard_16, id, part)
│                       │ estimated row count: 1 (missing stats)
│                       │
│                       ├── • values
│                       │     columns: (column1, column2, crdb_internal_id_shard_16_comp)
│                       │     size: 3 columns, 1 row
│                       │     row 0, expr 0: 4321
│                       │     row 0, expr 1: 'seattle'
│                       │     row 0, expr 2: 11
│                       │
│                       └── • scan
│                             columns: (crdb_internal_id_shard_16, id, part)
│                             estimated row count: 1 (missing stats)
│                             table: t_unique_hash_pk@t_unique_hash_pk_pkey
│                             spans: /"new york"/11/4321/0 /"seattle"/11/4321/0
│                             parallel
│                             locking strength: for update
│
└── • constraint-check
    │
    └── • error if rows
        │ columns: ()
        │
        └── • project
            │ columns: (id)
            │
            └── • project
                │ columns: (crdb_internal_id_shard_16, id, part)
                │
                └── • lookup join (semi)
                    │ columns: (crdb_internal_id_shard_16_eq, crdb_internal_id_shard_16, id, part)
                    │ estimated row count: 0 (missing stats)
                    │ table: t_unique_hash_pk@t_unique_hash_pk_pkey
                    │ lookup condition: ((part IN ('new york', 'seattle')) AND (crdb_internal_id_shard_16_eq = crdb_internal_id_shard_16)) AND (id = id)
                    │ pred: (crdb_internal_id_shard_16 != crdb_internal_id_shard_16) OR (part != part)
                    │
                    └── • render
                        │ columns: (crdb_internal_id_shard_16_eq, crdb_internal_id_shard_16, id, part)
                        │ render crdb_internal_id_shard_16_eq: mod(fnv32(md5(crdb_internal.datums_to_bytes(column1))), 16)
                        │ render crdb_internal_id_shard_16: crdb_internal_id_shard_16_comp
                        │ render id: column1
                        │ render part: upsert_part
                        │
                        └── • project
                            │ columns: (crdb_internal_id_shard_16_comp, column1, upsert_part)
                            │
                            └── • scan buffer
                                  columns: (crdb_internal_id_shard_16_comp, column1, column2, crdb_internal_id_shard_16, id, part, crdb_internal_id_shard_16_comp, column1, part, check1, check2, upsert_part)
                                  estimated row count: 1 (missing stats)
                                  label: buffer 1

query T
EXPLAIN (VERBOSE) INSERT INTO t_unique_hash_pk (id, part) VALUES (4321, 'seattle'), (8765, 'new york') ON CONFLICT (id) DO UPDATE SET id = excluded.id
----
distribution: local
vectorized: true
·
• root
│ columns: ()
│
├── • upsert
│   │ columns: ()
│   │ estimated row count: 0 (missing stats)
│   │ into: t_unique_hash_pk(crdb_internal_id_shard_16, id, part)
│   │ arbiter constraints: t_unique_hash_pk_pkey
│   │
│   └── • buffer
│       │ columns: (crdb_internal_id_shard_16_comp, column1, column2, crdb_internal_id_shard_16, id, part, crdb_internal_id_shard_16_comp, column1, part, check1, check2, upsert_part)
│       │ label: buffer 1
│       │
│       └── • project
│           │ columns: (crdb_internal_id_shard_16_comp, column1, column2, crdb_internal_id_shard_16, id, part, crdb_internal_id_shard_16_comp, column1, part, check1, check2, upsert_part)
│           │
│           └── • render
│               │ columns: (check1, check2, column1, column2, crdb_internal_id_shard_16_comp, crdb_internal_id_shard_16, id, part, upsert_part)
│               │ render check1: upsert_part IN ('new york', 'seattle')
│               │ render check2: crdb_internal_id_shard_16_comp IN (0, 1, __more10_100__, 15)
│               │ render column1: column1
│               │ render column2: column2
│               │ render crdb_internal_id_shard_16_comp: crdb_internal_id_shard_16_comp
│               │ render crdb_internal_id_shard_16: crdb_internal_id_shard_16
│               │ render id: id
│               │ render part: part
│               │ render upsert_part: upsert_part
│               │
│               └── • render
│                   │ columns: (upsert_part, column1, column2, crdb_internal_id_shard_16_comp, crdb_internal_id_shard_16, id, part)
│                   │ render upsert_part: CASE WHEN part IS NULL THEN column2 ELSE part END
│                   │ render column1: column1
│                   │ render column2: column2
│                   │ render crdb_internal_id_shard_16_comp: crdb_internal_id_shard_16_comp
│                   │ render crdb_internal_id_shard_16: crdb_internal_id_shard_16
│                   │ render id: id
│                   │ render part: part
│                   │
│                   └── • project
│                       │ columns: (column1, column2, crdb_internal_id_shard_16_comp, crdb_internal_id_shard_16, id, part)
│                       │
│                       └── • lookup join (left outer)
│                           │ columns: (crdb_internal_id_shard_16_eq, crdb_internal_id_shard_16_comp, column1, column2, crdb_internal_id_shard_16, id, part)
│                           │ estimated row count: 2 (missing stats)
│                           │ table: t_unique_hash_pk@t_unique_hash_pk_pkey
│                           │ equality cols are key
│                           │ lookup condition: ((part IN ('new york', 'seattle')) AND (crdb_internal_id_shard_16_eq = crdb_internal_id_shard_16)) AND (column1 = id)
│                           │ locking strength: for update
│                           │
│                           └── • render
│                               │ columns: (crdb_internal_id_shard_16_eq, crdb_internal_id_shard_16_comp, column1, column2)
│                               │ render crdb_internal_id_shard_16_eq: mod(fnv32(md5(crdb_internal.datums_to_bytes(column1))), 16)
│                               │ render crdb_internal_id_shard_16_comp: mod(fnv32(md5(crdb_internal.datums_to_bytes(column1))), 16)
│                               │ render column1: column1
│                               │ render column2: column2
│                               │
│                               └── • values
│                                     columns: (column1, column2)
│                                     size: 2 columns, 2 rows
│                                     row 0, expr 0: 4321
│                                     row 0, expr 1: 'seattle'
│                                     row 1, expr 0: 8765
│                                     row 1, expr 1: 'new york'
│
└── • constraint-check
    │
    └── • error if rows
        │ columns: ()
        │
        └── • project
            │ columns: (id)
            │
            └── • project
                │ columns: (crdb_internal_id_shard_16, id, part)
                │
                └── • lookup join (semi)
                    │ columns: (crdb_internal_id_shard_16_eq, crdb_internal_id_shard_16, id, part)
                    │ estimated row count: 1 (missing stats)
                    │ table: t_unique_hash_pk@t_unique_hash_pk_pkey
                    │ lookup condition: ((part IN ('new york', 'seattle')) AND (crdb_internal_id_shard_16_eq = crdb_internal_id_shard_16)) AND (id = id)
                    │ pred: (crdb_internal_id_shard_16 != crdb_internal_id_shard_16) OR (part != part)
                    │
                    └── • render
                        │ columns: (crdb_internal_id_shard_16_eq, crdb_internal_id_shard_16, id, part)
                        │ render crdb_internal_id_shard_16_eq: mod(fnv32(md5(crdb_internal.datums_to_bytes(column1))), 16)
                        │ render crdb_internal_id_shard_16: crdb_internal_id_shard_16_comp
                        │ render id: column1
                        │ render part: upsert_part
                        │
                        └── • project
                            │ columns: (crdb_internal_id_shard_16_comp, column1, upsert_part)
                            │
                            └── • scan buffer
                                  columns: (crdb_internal_id_shard_16_comp, column1, column2, crdb_internal_id_shard_16, id, part, crdb_internal_id_shard_16_comp, column1, part, check1, check2, upsert_part)
                                  estimated row count: 2 (missing stats)
                                  label: buffer 1

query T
EXPLAIN (VERBOSE) UPSERT INTO t_unique_hash_pk (id, part) VALUES (4321, 'seattle');
----
distribution: local
vectorized: true
·
• upsert
│ columns: ()
│ estimated row count: 0 (missing stats)
│ into: t_unique_hash_pk(crdb_internal_id_shard_16, id, part)
│ auto commit
│ arbiter constraints: t_unique_hash_pk_pkey
│
└── • project
    │ columns: (crdb_internal_id_shard_16_comp, column1, column2, crdb_internal_id_shard_16, id, part, column2, part, check1, check2)
    │
    └── • render
        │ columns: (check1, check2, column1, column2, crdb_internal_id_shard_16_comp, crdb_internal_id_shard_16, id, part)
        │ render check1: column2 IN ('new york', 'seattle')
        │ render check2: CASE WHEN part IS NULL THEN crdb_internal_id_shard_16_comp ELSE crdb_internal_id_shard_16 END IN (0, 1, __more10_100__, 15)
        │ render column1: column1
        │ render column2: column2
        │ render crdb_internal_id_shard_16_comp: crdb_internal_id_shard_16_comp
        │ render crdb_internal_id_shard_16: crdb_internal_id_shard_16
        │ render id: id
        │ render part: part
        │
        └── • cross join (left outer)
            │ columns: (column1, column2, crdb_internal_id_shard_16_comp, crdb_internal_id_shard_16, id, part)
            │ estimated row count: 1 (missing stats)
            │
            ├── • values
            │     columns: (column1, column2, crdb_internal_id_shard_16_comp)
            │     size: 3 columns, 1 row
            │     row 0, expr 0: 4321
            │     row 0, expr 1: 'seattle'
            │     row 0, expr 2: 11
            │
            └── • scan
                  columns: (crdb_internal_id_shard_16, id, part)
                  estimated row count: 1 (missing stats)
                  table: t_unique_hash_pk@t_unique_hash_pk_pkey
                  spans: /"new york"/11/4321/0 /"seattle"/11/4321/0
                  parallel
                  locking strength: for update

query T
EXPLAIN (VERBOSE) UPSERT INTO t_unique_hash_pk (id, part) VALUES (4321, 'seattle'), (8765, 'new york');
----
distribution: local
vectorized: true
·
• upsert
│ columns: ()
│ estimated row count: 0 (missing stats)
│ into: t_unique_hash_pk(crdb_internal_id_shard_16, id, part)
│ auto commit
│ arbiter constraints: t_unique_hash_pk_pkey
│
└── • project
    │ columns: (crdb_internal_id_shard_16_comp, column1, column2, crdb_internal_id_shard_16, id, part, column2, part, check1, check2)
    │
    └── • render
        │ columns: (check1, check2, column1, column2, crdb_internal_id_shard_16_comp, crdb_internal_id_shard_16, id, part)
        │ render check1: column2 IN ('new york', 'seattle')
        │ render check2: CASE WHEN part IS NULL THEN crdb_internal_id_shard_16_comp ELSE crdb_internal_id_shard_16 END IN (0, 1, __more10_100__, 15)
        │ render column1: column1
        │ render column2: column2
        │ render crdb_internal_id_shard_16_comp: crdb_internal_id_shard_16_comp
        │ render crdb_internal_id_shard_16: crdb_internal_id_shard_16
        │ render id: id
        │ render part: part
        │
        └── • project
            │ columns: (column1, column2, crdb_internal_id_shard_16_comp, crdb_internal_id_shard_16, id, part)
            │
            └── • lookup join (left outer)
                │ columns: (crdb_internal_id_shard_16_eq, crdb_internal_id_shard_16_comp, column1, column2, crdb_internal_id_shard_16, id, part)
                │ estimated row count: 2 (missing stats)
                │ table: t_unique_hash_pk@t_unique_hash_pk_pkey
                │ equality cols are key
                │ lookup condition: ((part IN ('new york', 'seattle')) AND (crdb_internal_id_shard_16_eq = crdb_internal_id_shard_16)) AND (column1 = id)
                │ locking strength: for update
                │
                └── • render
                    │ columns: (crdb_internal_id_shard_16_eq, crdb_internal_id_shard_16_comp, column1, column2)
                    │ render crdb_internal_id_shard_16_eq: mod(fnv32(md5(crdb_internal.datums_to_bytes(column1))), 16)
                    │ render crdb_internal_id_shard_16_comp: mod(fnv32(md5(crdb_internal.datums_to_bytes(column1))), 16)
                    │ render column1: column1
                    │ render column2: column2
                    │
                    └── • values
                          columns: (column1, column2)
                          size: 2 columns, 2 rows
                          row 0, expr 0: 4321
                          row 0, expr 1: 'seattle'
                          row 1, expr 0: 8765
                          row 1, expr 1: 'new york'

query T
EXPLAIN (VERBOSE) UPDATE t_unique_hash_pk SET id = 1234 WHERE id = 4321;
----
distribution: local
vectorized: true
·
• root
│ columns: ()
│
├── • update
│   │ columns: ()
│   │ estimated row count: 0 (missing stats)
│   │ table: t_unique_hash_pk
│   │ set: crdb_internal_id_shard_16, id
│   │
│   └── • buffer
│       │ columns: (crdb_internal_id_shard_16, id, part, crdb_internal_id_shard_16_comp, id_new, check2)
│       │ label: buffer 1
│       │
│       └── • render
│           │ columns: (crdb_internal_id_shard_16, id, part, crdb_internal_id_shard_16_comp, id_new, check2)
│           │ render check2: true
│           │ render crdb_internal_id_shard_16_comp: 4
│           │ render id_new: 1234
│           │ render crdb_internal_id_shard_16: crdb_internal_id_shard_16
│           │ render id: id
│           │ render part: part
│           │
│           └── • scan
│                 columns: (crdb_internal_id_shard_16, id, part)
│                 estimated row count: 1 (missing stats)
│                 table: t_unique_hash_pk@t_unique_hash_pk_pkey
│                 spans: /"new york"/11/4321/0 /"seattle"/11/4321/0
│                 parallel
│                 locking strength: for update
│
└── • constraint-check
    │
    └── • error if rows
        │ columns: ()
        │
        └── • project
            │ columns: (id)
            │
            └── • project
                │ columns: (crdb_internal_id_shard_16, id, part)
                │
                └── • lookup join (semi)
                    │ columns: (crdb_internal_id_shard_16_eq, crdb_internal_id_shard_16, id, part)
                    │ estimated row count: 0 (missing stats)
                    │ table: t_unique_hash_pk@t_unique_hash_pk_pkey
                    │ lookup condition: ((part IN ('new york', 'seattle')) AND (crdb_internal_id_shard_16_eq = crdb_internal_id_shard_16)) AND (id = id)
                    │ pred: (crdb_internal_id_shard_16 != crdb_internal_id_shard_16) OR (part != part)
                    │
                    └── • render
                        │ columns: (crdb_internal_id_shard_16_eq, crdb_internal_id_shard_16, id, part)
                        │ render crdb_internal_id_shard_16_eq: mod(fnv32(md5(crdb_internal.datums_to_bytes(id_new))), 16)
                        │ render crdb_internal_id_shard_16: crdb_internal_id_shard_16_comp
                        │ render id: id_new
                        │ render part: part
                        │
                        └── • project
                            │ columns: (crdb_internal_id_shard_16_comp, id_new, part)
                            │
                            └── • scan buffer
                                  columns: (crdb_internal_id_shard_16, id, part, crdb_internal_id_shard_16_comp, id_new, check2)
                                  estimated row count: 1 (missing stats)
                                  label: buffer 1

subtest test_uniqueness_check_sec_key

statement ok
CREATE TABLE t_unique_hash_sec_key (
  id INT PRIMARY KEY,
  email STRING,
  part STRING CHECK (part IN ('seattle', 'new york')),
  FAMILY fam_0 (id, email, part)
) PARTITION ALL BY LIST (part) (
   PARTITION us_west VALUES IN (('seattle')),
   PARTITION us_east VALUES IN (('new york'))
);

statement ok
CREATE UNIQUE INDEX idx_uniq_hash_email ON t_unique_hash_sec_key (email) USING HASH;

query T
EXPLAIN (VERBOSE) INSERT INTO t_unique_hash_sec_key (id, email, part) VALUES (4321, 'some_email', 'seattle');
----
distribution: local
vectorized: true
·
• insert fast path
  columns: ()
  estimated row count: 0 (missing stats)
  into: t_unique_hash_sec_key(id, email, part, crdb_internal_email_shard_16)
  auto commit
  uniqueness check: t_unique_hash_sec_key@t_unique_hash_sec_key_pkey
  uniqueness check: t_unique_hash_sec_key@idx_uniq_hash_email
  size: 6 columns, 1 row
  row 0, expr 0: 4321
  row 0, expr 1: 'some_email'
  row 0, expr 2: 'seattle'
  row 0, expr 3: 1
  row 0, expr 4: true
  row 0, expr 5: true

query T
EXPLAIN (VERBOSE) INSERT INTO t_unique_hash_sec_key (id, email, part) VALUES (4321, 'some_email', 'seattle') ON CONFLICT DO NOTHING;
----
distribution: local
vectorized: true
·
• insert
│ columns: ()
│ estimated row count: 0 (missing stats)
│ into: t_unique_hash_sec_key(id, email, part, crdb_internal_email_shard_16)
│ auto commit
│ arbiter constraints: t_unique_hash_sec_key_pkey, idx_uniq_hash_email
│
└── • render
    │ columns: (column1, column2, column3, crdb_internal_email_shard_16_comp, check1, check2)
    │ render check1: column3 IN ('new york', 'seattle')
    │ render check2: crdb_internal_email_shard_16_comp IN (0, 1, __more10_100__, 15)
    │ render column1: column1
    │ render column2: column2
    │ render column3: column3
    │ render crdb_internal_email_shard_16_comp: crdb_internal_email_shard_16_comp
    │
    └── • project
        │ columns: (column1, column2, column3, crdb_internal_email_shard_16_comp)
        │
        └── • lookup join (anti)
            │ columns: (crdb_internal_email_shard_16_eq, column1, column2, column3, crdb_internal_email_shard_16_comp)
            │ estimated row count: 0 (missing stats)
            │ table: t_unique_hash_sec_key@idx_uniq_hash_email
            │ equality cols are key
            │ lookup condition: ((part IN ('new york', 'seattle')) AND (crdb_internal_email_shard_16_eq = crdb_internal_email_shard_16)) AND (column2 = email)
            │
            └── • render
                │ columns: (crdb_internal_email_shard_16_eq, column1, column2, column3, crdb_internal_email_shard_16_comp)
                │ render crdb_internal_email_shard_16_eq: mod(fnv32(md5(crdb_internal.datums_to_bytes(column2))), 16)
                │ render column1: column1
                │ render column2: column2
                │ render column3: column3
                │ render crdb_internal_email_shard_16_comp: crdb_internal_email_shard_16_comp
                │
                └── • cross join (anti)
                    │ columns: (column1, column2, column3, crdb_internal_email_shard_16_comp)
                    │ estimated row count: 0 (missing stats)
                    │
                    ├── • values
                    │     columns: (column1, column2, column3, crdb_internal_email_shard_16_comp)
                    │     size: 4 columns, 1 row
                    │     row 0, expr 0: 4321
                    │     row 0, expr 1: 'some_email'
                    │     row 0, expr 2: 'seattle'
                    │     row 0, expr 3: 1
                    │
                    └── • project
                        │ columns: ()
                        │
                        └── • scan
                              columns: (id)
                              estimated row count: 1 (missing stats)
                              table: t_unique_hash_sec_key@t_unique_hash_sec_key_pkey
                              spans: /"new york"/4321/0 /"seattle"/4321/0
                              parallel

query T
EXPLAIN (VERBOSE) INSERT INTO t_unique_hash_sec_key (id, email, part) VALUES (4321, 'some_email', 'seattle'), (8765, 'another_email', 'new york') ON CONFLICT DO NOTHING;
----
distribution: local
vectorized: true
·
• insert
│ columns: ()
│ estimated row count: 0 (missing stats)
│ into: t_unique_hash_sec_key(id, email, part, crdb_internal_email_shard_16)
│ auto commit
│ arbiter constraints: t_unique_hash_sec_key_pkey, idx_uniq_hash_email
│
└── • render
    │ columns: (column1, column2, column3, crdb_internal_email_shard_16_comp, check1, check2)
    │ render check1: column3 IN ('new york', 'seattle')
    │ render check2: crdb_internal_email_shard_16_comp IN (0, 1, __more10_100__, 15)
    │ render column1: column1
    │ render column2: column2
    │ render column3: column3
    │ render crdb_internal_email_shard_16_comp: crdb_internal_email_shard_16_comp
    │
    └── • project
        │ columns: (column1, column2, column3, crdb_internal_email_shard_16_comp)
        │
        └── • lookup join (anti)
            │ columns: (crdb_internal_email_shard_16_eq, column1, column2, column3, crdb_internal_email_shard_16_comp)
            │ estimated row count: 0 (missing stats)
            │ table: t_unique_hash_sec_key@idx_uniq_hash_email
            │ equality cols are key
            │ lookup condition: ((part IN ('new york', 'seattle')) AND (crdb_internal_email_shard_16_eq = crdb_internal_email_shard_16)) AND (column2 = email)
            │
            └── • render
                │ columns: (crdb_internal_email_shard_16_eq, column1, column2, column3, crdb_internal_email_shard_16_comp)
                │ render crdb_internal_email_shard_16_eq: mod(fnv32(md5(crdb_internal.datums_to_bytes(column2))), 16)
                │ render column1: column1
                │ render column2: column2
                │ render column3: column3
                │ render crdb_internal_email_shard_16_comp: crdb_internal_email_shard_16_comp
                │
                └── • lookup join (anti)
                    │ columns: (crdb_internal_email_shard_16_comp, column1, column2, column3)
                    │ estimated row count: 0 (missing stats)
                    │ table: t_unique_hash_sec_key@t_unique_hash_sec_key_pkey
                    │ equality cols are key
                    │ lookup condition: (part IN ('new york', 'seattle')) AND (column1 = id)
                    │
                    └── • render
                        │ columns: (crdb_internal_email_shard_16_comp, column1, column2, column3)
                        │ render crdb_internal_email_shard_16_comp: mod(fnv32(md5(crdb_internal.datums_to_bytes(column2))), 16)
                        │ render column1: column1
                        │ render column2: column2
                        │ render column3: column3
                        │
                        └── • values
                              columns: (column1, column2, column3)
                              size: 3 columns, 2 rows
                              row 0, expr 0: 4321
                              row 0, expr 1: 'some_email'
                              row 0, expr 2: 'seattle'
                              row 1, expr 0: 8765
                              row 1, expr 1: 'another_email'
                              row 1, expr 2: 'new york'

query T
EXPLAIN (VERBOSE) INSERT INTO t_unique_hash_sec_key (id, email, part) VALUES (4321, 'some_email', 'seattle') ON CONFLICT (email) DO NOTHING;
----
distribution: local
vectorized: true
·
• root
│ columns: ()
│
├── • insert
│   │ columns: ()
│   │ estimated row count: 0 (missing stats)
│   │ into: t_unique_hash_sec_key(id, email, part, crdb_internal_email_shard_16)
│   │ arbiter constraints: idx_uniq_hash_email
│   │
│   └── • render
│       │ columns: (column1, column2, column3, crdb_internal_email_shard_16_comp, check1, check2)
│       │ render check1: column3 IN ('new york', 'seattle')
│       │ render check2: crdb_internal_email_shard_16_comp IN (0, 1, __more10_100__, 15)
│       │ render column1: column1
│       │ render column2: column2
│       │ render column3: column3
│       │ render crdb_internal_email_shard_16_comp: crdb_internal_email_shard_16_comp
│       │
│       └── • cross join (anti)
│           │ columns: (column1, column2, column3, crdb_internal_email_shard_16_comp)
│           │ estimated row count: 0 (missing stats)
│           │
│           ├── • values
│           │     columns: (column1, column2, column3, crdb_internal_email_shard_16_comp)
│           │     size: 4 columns, 1 row
│           │     row 0, expr 0: 4321
│           │     row 0, expr 1: 'some_email'
│           │     row 0, expr 2: 'seattle'
│           │     row 0, expr 3: 1
│           │
│           └── • project
│               │ columns: ()
│               │
│               └── • scan
│                     columns: (email)
│                     estimated row count: 1 (missing stats)
│                     table: t_unique_hash_sec_key@idx_uniq_hash_email
│                     spans: /"new york"/1/"some_email"/0 /"seattle"/1/"some_email"/0
│                     parallel
│
└── • constraint-check
    │
    └── • error if rows
        │ columns: ()
        │
        └── • project
            │ columns: (id)
            │
            └── • cross join (inner)
                │ columns: (id, id, part)
                │ estimated row count: 1 (missing stats)
                │
                ├── • values
                │     columns: (id)
                │     size: 1 column, 1 row
                │     row 0, expr 0: 4321
                │
                └── • scan
                      columns: (id, part)
                      estimated row count: 1 (missing stats)
                      table: t_unique_hash_sec_key@t_unique_hash_sec_key_pkey
                      spans: /"new york"/4321/0
                      limit: 1

query T
EXPLAIN (VERBOSE) INSERT INTO t_unique_hash_sec_key (id, email, part) VALUES (4321, 'some_email', 'seattle'), (8765, 'another_email', 'new york') ON CONFLICT (email) DO NOTHING;
----
distribution: local
vectorized: true
·
• root
│ columns: ()
│
├── • insert
│   │ columns: ()
│   │ estimated row count: 0 (missing stats)
│   │ into: t_unique_hash_sec_key(id, email, part, crdb_internal_email_shard_16)
│   │ arbiter constraints: idx_uniq_hash_email
│   │
│   └── • buffer
│       │ columns: (column1, column2, column3, crdb_internal_email_shard_16_comp, check1, check2)
│       │ label: buffer 1
│       │
│       └── • render
│           │ columns: (column1, column2, column3, crdb_internal_email_shard_16_comp, check1, check2)
│           │ render check1: column3 IN ('new york', 'seattle')
│           │ render check2: crdb_internal_email_shard_16_comp IN (0, 1, __more10_100__, 15)
│           │ render column1: column1
│           │ render column2: column2
│           │ render column3: column3
│           │ render crdb_internal_email_shard_16_comp: crdb_internal_email_shard_16_comp
│           │
│           └── • project
│               │ columns: (column1, column2, column3, crdb_internal_email_shard_16_comp)
│               │
│               └── • lookup join (anti)
│                   │ columns: (crdb_internal_email_shard_16_eq, crdb_internal_email_shard_16_comp, column1, column2, column3)
│                   │ estimated row count: 0 (missing stats)
│                   │ table: t_unique_hash_sec_key@idx_uniq_hash_email
│                   │ equality cols are key
│                   │ lookup condition: ((part IN ('new york', 'seattle')) AND (crdb_internal_email_shard_16_eq = crdb_internal_email_shard_16)) AND (column2 = email)
│                   │
│                   └── • render
│                       │ columns: (crdb_internal_email_shard_16_eq, crdb_internal_email_shard_16_comp, column1, column2, column3)
│                       │ render crdb_internal_email_shard_16_eq: mod(fnv32(md5(crdb_internal.datums_to_bytes(column2))), 16)
│                       │ render crdb_internal_email_shard_16_comp: mod(fnv32(md5(crdb_internal.datums_to_bytes(column2))), 16)
│                       │ render column1: column1
│                       │ render column2: column2
│                       │ render column3: column3
│                       │
│                       └── • values
│                             columns: (column1, column2, column3)
│                             size: 3 columns, 2 rows
│                             row 0, expr 0: 4321
│                             row 0, expr 1: 'some_email'
│                             row 0, expr 2: 'seattle'
│                             row 1, expr 0: 8765
│                             row 1, expr 1: 'another_email'
│                             row 1, expr 2: 'new york'
│
└── • constraint-check
    │
    └── • error if rows
        │ columns: ()
        │
        └── • project
            │ columns: (column1)
            │
            └── • lookup join (semi)
                │ columns: (column1, column3)
                │ estimated row count: 0 (missing stats)
                │ table: t_unique_hash_sec_key@t_unique_hash_sec_key_pkey
                │ lookup condition: (part IN ('new york', 'seattle')) AND (column1 = id)
                │ pred: column3 != part
                │
                └── • project
                    │ columns: (column1, column3)
                    │
                    └── • scan buffer
                          columns: (column1, column2, column3, crdb_internal_email_shard_16_comp, check1, check2)
                          estimated row count: 0 (missing stats)
                          label: buffer 1

query T
EXPLAIN (VERBOSE) INSERT INTO t_unique_hash_sec_key (id, email, part) VALUES (4321, 'some_email', 'seattle') ON CONFLICT (email) DO UPDATE SET email = 'bad_email';
----
distribution: local
vectorized: true
·
• root
│ columns: ()
│
├── • upsert
│   │ columns: ()
│   │ estimated row count: 0 (missing stats)
│   │ into: t_unique_hash_sec_key(id, email, part, crdb_internal_email_shard_16)
│   │ arbiter constraints: idx_uniq_hash_email
│   │
│   └── • buffer
│       │ columns: (column1, column2, column3, crdb_internal_email_shard_16_comp, id, email, part, crdb_internal_email_shard_16, upsert_email, upsert_crdb_internal_email_shard_16, part, check1, check2, upsert_id, upsert_part)
│       │ label: buffer 1
│       │
│       └── • project
│           │ columns: (column1, column2, column3, crdb_internal_email_shard_16_comp, id, email, part, crdb_internal_email_shard_16, upsert_email, upsert_crdb_internal_email_shard_16, part, check1, check2, upsert_id, upsert_part)
│           │
│           └── • render
│               │ columns: (check1, check2, column1, column2, column3, crdb_internal_email_shard_16_comp, id, email, part, crdb_internal_email_shard_16, upsert_id, upsert_email, upsert_part, upsert_crdb_internal_email_shard_16)
│               │ render check1: upsert_part IN ('new york', 'seattle')
│               │ render check2: upsert_crdb_internal_email_shard_16 IN (0, 1, __more10_100__, 15)
│               │ render column1: column1
│               │ render column2: column2
│               │ render column3: column3
│               │ render crdb_internal_email_shard_16_comp: crdb_internal_email_shard_16_comp
│               │ render id: id
│               │ render email: email
│               │ render part: part
│               │ render crdb_internal_email_shard_16: crdb_internal_email_shard_16
│               │ render upsert_id: upsert_id
│               │ render upsert_email: upsert_email
│               │ render upsert_part: upsert_part
│               │ render upsert_crdb_internal_email_shard_16: upsert_crdb_internal_email_shard_16
│               │
│               └── • render
│                   │ columns: (upsert_id, upsert_email, upsert_part, upsert_crdb_internal_email_shard_16, column1, column2, column3, crdb_internal_email_shard_16_comp, id, email, part, crdb_internal_email_shard_16)
│                   │ render upsert_id: CASE WHEN part IS NULL THEN column1 ELSE id END
│                   │ render upsert_email: CASE WHEN part IS NULL THEN column2 ELSE 'bad_email' END
│                   │ render upsert_part: CASE WHEN part IS NULL THEN column3 ELSE part END
│                   │ render upsert_crdb_internal_email_shard_16: CASE WHEN part IS NULL THEN crdb_internal_email_shard_16_comp ELSE 9 END
│                   │ render column1: column1
│                   │ render column2: column2
│                   │ render column3: column3
│                   │ render crdb_internal_email_shard_16_comp: crdb_internal_email_shard_16_comp
│                   │ render id: id
│                   │ render email: email
│                   │ render part: part
│                   │ render crdb_internal_email_shard_16: crdb_internal_email_shard_16
│                   │
│                   └── • cross join (left outer)
│                       │ columns: (column1, column2, column3, crdb_internal_email_shard_16_comp, crdb_internal_email_shard_16, id, email, part)
│                       │ estimated row count: 1 (missing stats)
│                       │
│                       ├── • values
│                       │     columns: (column1, column2, column3, crdb_internal_email_shard_16_comp)
│                       │     size: 4 columns, 1 row
│                       │     row 0, expr 0: 4321
│                       │     row 0, expr 1: 'some_email'
│                       │     row 0, expr 2: 'seattle'
│                       │     row 0, expr 3: 1
│                       │
│                       └── • render
│                           │ columns: (crdb_internal_email_shard_16, id, email, part)
│                           │ render crdb_internal_email_shard_16: mod(fnv32(md5(crdb_internal.datums_to_bytes(email))), 16)
│                           │ render id: id
│                           │ render email: email
│                           │ render part: part
│                           │
│                           └── • scan
│                                 columns: (id, email, part)
│                                 estimated row count: 1 (missing stats)
│                                 table: t_unique_hash_sec_key@idx_uniq_hash_email
│                                 spans: /"new york"/1/"some_email"/0 /"seattle"/1/"some_email"/0
│                                 parallel
│
├── • constraint-check
│   │
│   └── • error if rows
│       │ columns: ()
│       │
│       └── • project
│           │ columns: (upsert_id)
│           │
│           └── • lookup join (semi)
│               │ columns: (upsert_id, upsert_part)
│               │ estimated row count: 0 (missing stats)
│               │ table: t_unique_hash_sec_key@t_unique_hash_sec_key_pkey
│               │ lookup condition: (part IN ('new york', 'seattle')) AND (upsert_id = id)
│               │ pred: upsert_part != part
│               │
│               └── • project
│                   │ columns: (upsert_id, upsert_part)
│                   │
│                   └── • scan buffer
│                         columns: (column1, column2, column3, crdb_internal_email_shard_16_comp, id, email, part, crdb_internal_email_shard_16, upsert_email, upsert_crdb_internal_email_shard_16, part, check1, check2, upsert_id, upsert_part)
│                         estimated row count: 1 (missing stats)
│                         label: buffer 1
│
└── • constraint-check
    │
    └── • error if rows
        │ columns: ()
        │
        └── • project
            │ columns: (email)
            │
            └── • project
                │ columns: (id, email, part)
                │
                └── • lookup join (semi)
                    │ columns: (crdb_internal_email_shard_16_eq, id, email, part)
                    │ estimated row count: 0 (missing stats)
                    │ table: t_unique_hash_sec_key@idx_uniq_hash_email
                    │ lookup condition: ((part IN ('new york', 'seattle')) AND (crdb_internal_email_shard_16_eq = crdb_internal_email_shard_16)) AND (email = email)
                    │ pred: (id != id) OR (part != part)
                    │
                    └── • render
                        │ columns: (crdb_internal_email_shard_16_eq, id, email, part)
                        │ render crdb_internal_email_shard_16_eq: mod(fnv32(md5(crdb_internal.datums_to_bytes(upsert_email))), 16)
                        │ render id: upsert_id
                        │ render email: upsert_email
                        │ render part: upsert_part
                        │
                        └── • project
                            │ columns: (upsert_id, upsert_email, upsert_part)
                            │
                            └── • scan buffer
                                  columns: (column1, column2, column3, crdb_internal_email_shard_16_comp, id, email, part, crdb_internal_email_shard_16, upsert_email, upsert_crdb_internal_email_shard_16, part, check1, check2, upsert_id, upsert_part)
                                  estimated row count: 1 (missing stats)
                                  label: buffer 1

query T
EXPLAIN (VERBOSE) INSERT INTO t_unique_hash_sec_key (id, email, part) VALUES (4321, 'some_email', 'seattle'), (8765, 'another_email', 'new york') ON CONFLICT (email) DO UPDATE SET email = 'bad_email';
----
distribution: local
vectorized: true
·
• root
│ columns: ()
│
├── • upsert
│   │ columns: ()
│   │ estimated row count: 0 (missing stats)
│   │ into: t_unique_hash_sec_key(id, email, part, crdb_internal_email_shard_16)
│   │ arbiter constraints: idx_uniq_hash_email
│   │
│   └── • buffer
│       │ columns: (column1, column2, column3, crdb_internal_email_shard_16_comp, id, email, part, crdb_internal_email_shard_16, upsert_email, upsert_crdb_internal_email_shard_16, part, check1, check2, upsert_id, upsert_part)
│       │ label: buffer 1
│       │
│       └── • project
│           │ columns: (column1, column2, column3, crdb_internal_email_shard_16_comp, id, email, part, crdb_internal_email_shard_16, upsert_email, upsert_crdb_internal_email_shard_16, part, check1, check2, upsert_id, upsert_part)
│           │
│           └── • render
│               │ columns: (check1, check2, column1, column2, column3, crdb_internal_email_shard_16_comp, id, email, part, crdb_internal_email_shard_16, upsert_id, upsert_email, upsert_part, upsert_crdb_internal_email_shard_16)
│               │ render check1: upsert_part IN ('new york', 'seattle')
│               │ render check2: upsert_crdb_internal_email_shard_16 IN (0, 1, __more10_100__, 15)
│               │ render column1: column1
│               │ render column2: column2
│               │ render column3: column3
│               │ render crdb_internal_email_shard_16_comp: crdb_internal_email_shard_16_comp
│               │ render id: id
│               │ render email: email
│               │ render part: part
│               │ render crdb_internal_email_shard_16: crdb_internal_email_shard_16
│               │ render upsert_id: upsert_id
│               │ render upsert_email: upsert_email
│               │ render upsert_part: upsert_part
│               │ render upsert_crdb_internal_email_shard_16: upsert_crdb_internal_email_shard_16
│               │
│               └── • render
│                   │ columns: (upsert_id, upsert_email, upsert_part, upsert_crdb_internal_email_shard_16, column1, column2, column3, crdb_internal_email_shard_16_comp, id, email, part, crdb_internal_email_shard_16)
│                   │ render upsert_id: CASE WHEN part IS NULL THEN column1 ELSE id END
│                   │ render upsert_email: CASE WHEN part IS NULL THEN column2 ELSE 'bad_email' END
│                   │ render upsert_part: CASE WHEN part IS NULL THEN column3 ELSE part END
│                   │ render upsert_crdb_internal_email_shard_16: CASE WHEN part IS NULL THEN crdb_internal_email_shard_16_comp ELSE 9 END
│                   │ render column1: column1
│                   │ render column2: column2
│                   │ render column3: column3
│                   │ render crdb_internal_email_shard_16_comp: crdb_internal_email_shard_16_comp
│                   │ render id: id
│                   │ render email: email
│                   │ render part: part
│                   │ render crdb_internal_email_shard_16: crdb_internal_email_shard_16
│                   │
│                   └── • render
│                       │ columns: (crdb_internal_email_shard_16, column1, column2, column3, crdb_internal_email_shard_16_comp, id, email, part)
│                       │ render crdb_internal_email_shard_16: CASE id IS NULL WHEN true THEN CAST(NULL AS INT8) ELSE mod(fnv32(md5(crdb_internal.datums_to_bytes(email))), 16) END
│                       │ render column1: column1
│                       │ render column2: column2
│                       │ render column3: column3
│                       │ render crdb_internal_email_shard_16_comp: crdb_internal_email_shard_16_comp
│                       │ render id: id
│                       │ render email: email
│                       │ render part: part
│                       │
│                       └── • project
│                           │ columns: (column1, column2, column3, crdb_internal_email_shard_16_comp, id, email, part)
│                           │
│                           └── • project
│                               │ columns: (column1, column2, column3, crdb_internal_email_shard_16_comp, id, email, part, crdb_internal_email_shard_16)
│                               │
│                               └── • lookup join (left outer)
│                                   │ columns: (crdb_internal_email_shard_16_eq, crdb_internal_email_shard_16_comp, column1, column2, column3, id, email, part, crdb_internal_email_shard_16)
│                                   │ estimated row count: 2 (missing stats)
│                                   │ table: t_unique_hash_sec_key@idx_uniq_hash_email
│                                   │ equality cols are key
│                                   │ lookup condition: ((part IN ('new york', 'seattle')) AND (crdb_internal_email_shard_16_eq = crdb_internal_email_shard_16)) AND (column2 = email)
│                                   │ locking strength: for update
│                                   │
│                                   └── • render
│                                       │ columns: (crdb_internal_email_shard_16_eq, crdb_internal_email_shard_16_comp, column1, column2, column3)
│                                       │ render crdb_internal_email_shard_16_eq: mod(fnv32(md5(crdb_internal.datums_to_bytes(column2))), 16)
│                                       │ render crdb_internal_email_shard_16_comp: mod(fnv32(md5(crdb_internal.datums_to_bytes(column2))), 16)
│                                       │ render column1: column1
│                                       │ render column2: column2
│                                       │ render column3: column3
│                                       │
│                                       └── • values
│                                             columns: (column1, column2, column3)
│                                             size: 3 columns, 2 rows
│                                             row 0, expr 0: 4321
│                                             row 0, expr 1: 'some_email'
│                                             row 0, expr 2: 'seattle'
│                                             row 1, expr 0: 8765
│                                             row 1, expr 1: 'another_email'
│                                             row 1, expr 2: 'new york'
│
├── • constraint-check
│   │
│   └── • error if rows
│       │ columns: ()
│       │
│       └── • project
│           │ columns: (upsert_id)
│           │
│           └── • lookup join (semi)
│               │ columns: (upsert_id, upsert_part)
│               │ estimated row count: 1 (missing stats)
│               │ table: t_unique_hash_sec_key@t_unique_hash_sec_key_pkey
│               │ lookup condition: (part IN ('new york', 'seattle')) AND (upsert_id = id)
│               │ pred: upsert_part != part
│               │
│               └── • project
│                   │ columns: (upsert_id, upsert_part)
│                   │
│                   └── • scan buffer
│                         columns: (column1, column2, column3, crdb_internal_email_shard_16_comp, id, email, part, crdb_internal_email_shard_16, upsert_email, upsert_crdb_internal_email_shard_16, part, check1, check2, upsert_id, upsert_part)
│                         estimated row count: 2 (missing stats)
│                         label: buffer 1
│
└── • constraint-check
    │
    └── • error if rows
        │ columns: ()
        │
        └── • project
            │ columns: (email)
            │
            └── • project
                │ columns: (id, email, part)
                │
                └── • lookup join (semi)
                    │ columns: (crdb_internal_email_shard_16_eq, id, email, part)
                    │ estimated row count: 1 (missing stats)
                    │ table: t_unique_hash_sec_key@idx_uniq_hash_email
                    │ lookup condition: ((part IN ('new york', 'seattle')) AND (crdb_internal_email_shard_16_eq = crdb_internal_email_shard_16)) AND (email = email)
                    │ pred: (id != id) OR (part != part)
                    │
                    └── • render
                        │ columns: (crdb_internal_email_shard_16_eq, id, email, part)
                        │ render crdb_internal_email_shard_16_eq: mod(fnv32(md5(crdb_internal.datums_to_bytes(upsert_email))), 16)
                        │ render id: upsert_id
                        │ render email: upsert_email
                        │ render part: upsert_part
                        │
                        └── • project
                            │ columns: (upsert_id, upsert_email, upsert_part)
                            │
                            └── • scan buffer
                                  columns: (column1, column2, column3, crdb_internal_email_shard_16_comp, id, email, part, crdb_internal_email_shard_16, upsert_email, upsert_crdb_internal_email_shard_16, part, check1, check2, upsert_id, upsert_part)
                                  estimated row count: 2 (missing stats)
                                  label: buffer 1

query T
EXPLAIN (VERBOSE) UPSERT INTO t_unique_hash_sec_key VALUES (1, 'email1', 'seattle');
----
distribution: local
vectorized: true
·
• root
│ columns: ()
│
├── • upsert
│   │ columns: ()
│   │ estimated row count: 0 (missing stats)
│   │ into: t_unique_hash_sec_key(id, email, part, crdb_internal_email_shard_16)
│   │ arbiter constraints: t_unique_hash_sec_key_pkey
│   │
│   └── • buffer
│       │ columns: (column1, column2, column3, crdb_internal_email_shard_16_comp, id, email, part, crdb_internal_email_shard_16, column2, column3, crdb_internal_email_shard_16_comp, part, check1, check2, upsert_id)
│       │ label: buffer 1
│       │
│       └── • project
│           │ columns: (column1, column2, column3, crdb_internal_email_shard_16_comp, id, email, part, crdb_internal_email_shard_16, column2, column3, crdb_internal_email_shard_16_comp, part, check1, check2, upsert_id)
│           │
│           └── • render
│               │ columns: (check1, check2, upsert_id, column1, column2, column3, crdb_internal_email_shard_16_comp, id, email, part, crdb_internal_email_shard_16)
│               │ render check1: column3 IN ('new york', 'seattle')
│               │ render check2: crdb_internal_email_shard_16_comp IN (0, 1, __more10_100__, 15)
│               │ render upsert_id: CASE WHEN part IS NULL THEN column1 ELSE id END
│               │ render column1: column1
│               │ render column2: column2
│               │ render column3: column3
│               │ render crdb_internal_email_shard_16_comp: crdb_internal_email_shard_16_comp
│               │ render id: id
│               │ render email: email
│               │ render part: part
│               │ render crdb_internal_email_shard_16: crdb_internal_email_shard_16
│               │
│               └── • cross join (left outer)
│                   │ columns: (column1, column2, column3, crdb_internal_email_shard_16_comp, crdb_internal_email_shard_16, id, email, part)
│                   │ estimated row count: 1 (missing stats)
│                   │
│                   ├── • values
│                   │     columns: (column1, column2, column3, crdb_internal_email_shard_16_comp)
│                   │     size: 4 columns, 1 row
│                   │     row 0, expr 0: 1
│                   │     row 0, expr 1: 'email1'
│                   │     row 0, expr 2: 'seattle'
│                   │     row 0, expr 3: 12
│                   │
│                   └── • render
│                       │ columns: (crdb_internal_email_shard_16, id, email, part)
│                       │ render crdb_internal_email_shard_16: mod(fnv32(md5(crdb_internal.datums_to_bytes(email))), 16)
│                       │ render id: id
│                       │ render email: email
│                       │ render part: part
│                       │
│                       └── • scan
│                             columns: (id, email, part)
│                             estimated row count: 1 (missing stats)
│                             table: t_unique_hash_sec_key@t_unique_hash_sec_key_pkey
│                             spans: /"new york"/1/0 /"seattle"/1/0
│                             parallel
│
└── • constraint-check
    │
    └── • error if rows
        │ columns: ()
        │
        └── • project
            │ columns: (email)
            │
            └── • project
                │ columns: (id, email, part)
                │
                └── • lookup join (semi)
                    │ columns: (crdb_internal_email_shard_16_eq, id, email, part)
                    │ estimated row count: 0 (missing stats)
                    │ table: t_unique_hash_sec_key@idx_uniq_hash_email
                    │ lookup condition: ((part IN ('new york', 'seattle')) AND (crdb_internal_email_shard_16_eq = crdb_internal_email_shard_16)) AND (email = email)
                    │ pred: (id != id) OR (part != part)
                    │
                    └── • render
                        │ columns: (crdb_internal_email_shard_16_eq, id, email, part)
                        │ render crdb_internal_email_shard_16_eq: mod(fnv32(md5(crdb_internal.datums_to_bytes(column2))), 16)
                        │ render id: upsert_id
                        │ render email: column2
                        │ render part: column3
                        │
                        └── • project
                            │ columns: (upsert_id, column2, column3)
                            │
                            └── • scan buffer
                                  columns: (column1, column2, column3, crdb_internal_email_shard_16_comp, id, email, part, crdb_internal_email_shard_16, column2, column3, crdb_internal_email_shard_16_comp, part, check1, check2, upsert_id)
                                  estimated row count: 1 (missing stats)
                                  label: buffer 1

query T
EXPLAIN (VERBOSE) UPSERT INTO t_unique_hash_sec_key VALUES (1, 'email1', 'seattle'), (8765, 'email2', 'new york');
----
distribution: local
vectorized: true
·
• root
│ columns: ()
│
├── • upsert
│   │ columns: ()
│   │ estimated row count: 0 (missing stats)
│   │ into: t_unique_hash_sec_key(id, email, part, crdb_internal_email_shard_16)
│   │ arbiter constraints: t_unique_hash_sec_key_pkey
│   │
│   └── • buffer
│       │ columns: (column1, column2, column3, crdb_internal_email_shard_16_comp, id, email, part, crdb_internal_email_shard_16, column2, column3, crdb_internal_email_shard_16_comp, part, check1, check2, upsert_id)
│       │ label: buffer 1
│       │
│       └── • project
│           │ columns: (column1, column2, column3, crdb_internal_email_shard_16_comp, id, email, part, crdb_internal_email_shard_16, column2, column3, crdb_internal_email_shard_16_comp, part, check1, check2, upsert_id)
│           │
│           └── • render
│               │ columns: (check1, check2, upsert_id, column1, column2, column3, crdb_internal_email_shard_16_comp, id, email, part, crdb_internal_email_shard_16)
│               │ render check1: column3 IN ('new york', 'seattle')
│               │ render check2: crdb_internal_email_shard_16_comp IN (0, 1, __more10_100__, 15)
│               │ render upsert_id: CASE WHEN part IS NULL THEN column1 ELSE id END
│               │ render column1: column1
│               │ render column2: column2
│               │ render column3: column3
│               │ render crdb_internal_email_shard_16_comp: crdb_internal_email_shard_16_comp
│               │ render id: id
│               │ render email: email
│               │ render part: part
│               │ render crdb_internal_email_shard_16: crdb_internal_email_shard_16
│               │
│               └── • render
│                   │ columns: (crdb_internal_email_shard_16, column1, column2, column3, crdb_internal_email_shard_16_comp, id, email, part)
│                   │ render crdb_internal_email_shard_16: CASE id IS NULL WHEN true THEN CAST(NULL AS INT8) ELSE mod(fnv32(md5(crdb_internal.datums_to_bytes(email))), 16) END
│                   │ render column1: column1
│                   │ render column2: column2
│                   │ render column3: column3
│                   │ render crdb_internal_email_shard_16_comp: crdb_internal_email_shard_16_comp
│                   │ render id: id
│                   │ render email: email
│                   │ render part: part
│                   │
│                   └── • lookup join (left outer)
│                       │ columns: (crdb_internal_email_shard_16_comp, column1, column2, column3, id, email, part)
│                       │ estimated row count: 2 (missing stats)
│                       │ table: t_unique_hash_sec_key@t_unique_hash_sec_key_pkey
│                       │ equality cols are key
│                       │ lookup condition: (part IN ('new york', 'seattle')) AND (column1 = id)
│                       │ locking strength: for update
│                       │
│                       └── • render
│                           │ columns: (crdb_internal_email_shard_16_comp, column1, column2, column3)
│                           │ render crdb_internal_email_shard_16_comp: mod(fnv32(md5(crdb_internal.datums_to_bytes(column2))), 16)
│                           │ render column1: column1
│                           │ render column2: column2
│                           │ render column3: column3
│                           │
│                           └── • values
│                                 columns: (column1, column2, column3)
│                                 size: 3 columns, 2 rows
│                                 row 0, expr 0: 1
│                                 row 0, expr 1: 'email1'
│                                 row 0, expr 2: 'seattle'
│                                 row 1, expr 0: 8765
│                                 row 1, expr 1: 'email2'
│                                 row 1, expr 2: 'new york'
│
└── • constraint-check
    │
    └── • error if rows
        │ columns: ()
        │
        └── • project
            │ columns: (email)
            │
            └── • project
                │ columns: (id, email, part)
                │
                └── • lookup join (semi)
                    │ columns: (crdb_internal_email_shard_16_eq, id, email, part)
                    │ estimated row count: 1 (missing stats)
                    │ table: t_unique_hash_sec_key@idx_uniq_hash_email
                    │ lookup condition: ((part IN ('new york', 'seattle')) AND (crdb_internal_email_shard_16_eq = crdb_internal_email_shard_16)) AND (email = email)
                    │ pred: (id != id) OR (part != part)
                    │
                    └── • render
                        │ columns: (crdb_internal_email_shard_16_eq, id, email, part)
                        │ render crdb_internal_email_shard_16_eq: mod(fnv32(md5(crdb_internal.datums_to_bytes(column2))), 16)
                        │ render id: upsert_id
                        │ render email: column2
                        │ render part: column3
                        │
                        └── • project
                            │ columns: (upsert_id, column2, column3)
                            │
                            └── • scan buffer
                                  columns: (column1, column2, column3, crdb_internal_email_shard_16_comp, id, email, part, crdb_internal_email_shard_16, column2, column3, crdb_internal_email_shard_16_comp, part, check1, check2, upsert_id)
                                  estimated row count: 2 (missing stats)
                                  label: buffer 1

query T
EXPLAIN (VERBOSE) UPDATE t_unique_hash_sec_key SET email = 'email1' WHERE id = 2;
----
distribution: local
vectorized: true
·
• root
│ columns: ()
│
├── • update
│   │ columns: ()
│   │ estimated row count: 0 (missing stats)
│   │ table: t_unique_hash_sec_key
│   │ set: email, crdb_internal_email_shard_16
│   │
│   └── • buffer
│       │ columns: (id, email, part, crdb_internal_email_shard_16, email_new, crdb_internal_email_shard_16_comp, check2)
│       │ label: buffer 1
│       │
│       └── • render
│           │ columns: (id, email, part, crdb_internal_email_shard_16, email_new, crdb_internal_email_shard_16_comp, check2)
│           │ render check2: true
│           │ render crdb_internal_email_shard_16_comp: 12
│           │ render email_new: 'email1'
│           │ render crdb_internal_email_shard_16: mod(fnv32(md5(crdb_internal.datums_to_bytes(email))), 16)
│           │ render id: id
│           │ render email: email
│           │ render part: part
│           │
│           └── • scan
│                 columns: (id, email, part)
│                 estimated row count: 1 (missing stats)
│                 table: t_unique_hash_sec_key@t_unique_hash_sec_key_pkey
│                 spans: /"new york"/2/0 /"seattle"/2/0
│                 parallel
│                 locking strength: for update
│
└── • constraint-check
    │
    └── • error if rows
        │ columns: ()
        │
        └── • project
            │ columns: (email)
            │
            └── • project
                │ columns: (id, email, part)
                │
                └── • lookup join (semi)
                    │ columns: (crdb_internal_email_shard_16_eq, id, email, part)
                    │ estimated row count: 0 (missing stats)
                    │ table: t_unique_hash_sec_key@idx_uniq_hash_email
                    │ lookup condition: ((part IN ('new york', 'seattle')) AND (crdb_internal_email_shard_16_eq = crdb_internal_email_shard_16)) AND (email = email)
                    │ pred: (id != id) OR (part != part)
                    │
                    └── • render
                        │ columns: (crdb_internal_email_shard_16_eq, id, email, part)
                        │ render crdb_internal_email_shard_16_eq: mod(fnv32(md5(crdb_internal.datums_to_bytes(email_new))), 16)
                        │ render id: id
                        │ render email: email_new
                        │ render part: part
                        │
                        └── • project
                            │ columns: (id, email_new, part)
                            │
                            └── • scan buffer
                                  columns: (id, email, part, crdb_internal_email_shard_16, email_new, crdb_internal_email_shard_16_comp, check2)
                                  estimated row count: 1 (missing stats)
                                  label: buffer 1
