# LogicTest: local

statement ok
CREATE TYPE part_type AS ENUM ('one', 'two', 'three', 'four', 'five');

statement ok
SET experimental_enable_implicit_column_partitioning = true

statement ok
SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED

statement ok
CREATE TABLE t_double (
  pk INT PRIMARY KEY,
  a part_type,
  b part_type,
  c INT,
  UNIQUE INDEX (c)
) PARTITION ALL BY LIST (a, b) (
  PARTITION one VALUES IN (('one', 'one')),
  PARTITION two VALUES IN (('two', 'two'))
)

# Test that we don't allow writes to tables with multiple partition columns.
statement error pgcode 0A000 pq: unimplemented: unique without index constraint under non-serializable isolation levels
INSERT INTO t_double VALUES (1, 'one', 'one', 10), (2, 'two', 'two', 20)

statement ok
CREATE TABLE t_int (
  pk INT PRIMARY KEY,
  a INT NOT NULL,
  c INT,
  UNIQUE INDEX (c)
) PARTITION ALL BY LIST (a) (
  PARTITION one VALUES IN (1),
  PARTITION two VALUES IN (2)
)

# Test that we don't allow writes to tables with non-enum partition columns.
statement error pgcode 0A000 pq: unimplemented: unique without index constraint under non-serializable isolation levels
INSERT INTO t_int VALUES (1, 1, 10), (2, 2, 20)

statement ok
CREATE TABLE t (
  pk INT PRIMARY KEY,
  a part_type,
  b INT,
  c INT,
  d INT,
  j JSON,
  UNIQUE INDEX (c),
  FAMILY (pk, a, b, c, d, j)
) PARTITION ALL BY LIST(a) ( 
  PARTITION one VALUES IN ('one'),
  PARTITION two VALUES IN ('two'),
  PARTITION three VALUES IN ('three'),
  PARTITION four VALUES IN ('four'),
  PARTITION five VALUES IN ('five')
)

query T
SELECT create_statement FROM [SHOW CREATE TABLE t]
----
CREATE TABLE public.t (
  pk INT8 NOT NULL,
  a public.part_type NOT NULL,
  b INT8 NULL,
  c INT8 NULL,
  d INT8 NULL,
  j JSONB NULL,
  CONSTRAINT t_pkey PRIMARY KEY (pk ASC),
  UNIQUE INDEX t_c_key (c ASC),
  FAMILY fam_0_pk_a_b_c_d_j (pk, a, b, c, d, j)
) PARTITION ALL BY LIST (a) (
  PARTITION one VALUES IN (('one')),
  PARTITION two VALUES IN (('two')),
  PARTITION three VALUES IN (('three')),
  PARTITION four VALUES IN (('four')),
  PARTITION five VALUES IN (('five'))
)
-- Warning: Partitioned table with no zone configurations.

query T
EXPLAIN (OPT, CATALOG) SELECT * FROM t
----
TABLE t
 ├── pk int not null
 ├── a part_type not null
 ├── b int
 ├── c int
 ├── d int
 ├── j jsonb
 ├── crdb_internal_mvcc_timestamp decimal [hidden] [system]
 ├── tableoid oid [hidden] [system]
 ├── crdb_internal_origin_id int4 [hidden] [system]
 ├── crdb_internal_origin_timestamp decimal [hidden] [system]
 ├── FAMILY fam_0_pk_a_b_c_d_j (pk, a, b, c, d, j)
 ├── CHECK (a IN (x'20':::@100106, x'40':::@100106, x'80':::@100106, x'a0':::@100106, x'c0':::@100106))
 ├── PRIMARY INDEX t_pkey
 │    ├── a part_type not null (implicit)
 │    ├── pk int not null
 │    └── partitions
 │         ├── one
 │         │    └── partition by list prefixes
 │         │         └── ('one')
 │         ├── two
 │         │    └── partition by list prefixes
 │         │         └── ('two')
 │         ├── three
 │         │    └── partition by list prefixes
 │         │         └── ('three')
 │         ├── four
 │         │    └── partition by list prefixes
 │         │         └── ('four')
 │         └── five
 │              └── partition by list prefixes
 │                   └── ('five')
 ├── UNIQUE INDEX t_c_key
 │    ├── a part_type not null (implicit)
 │    ├── c int
 │    ├── pk int not null (storing)
 │    └── partitions
 │         ├── one
 │         │    └── partition by list prefixes
 │         │         └── ('one')
 │         ├── two
 │         │    └── partition by list prefixes
 │         │         └── ('two')
 │         ├── three
 │         │    └── partition by list prefixes
 │         │         └── ('three')
 │         ├── four
 │         │    └── partition by list prefixes
 │         │         └── ('four')
 │         └── five
 │              └── partition by list prefixes
 │                   └── ('five')
 ├── UNIQUE WITHOUT INDEX (pk)
 └── UNIQUE WITHOUT INDEX (c)
scan t
 └── check constraint expressions
      └── a IN ('one', 'two', 'three', 'four', 'five')

statement ok
CREATE TABLE overwrite (
  pk INT PRIMARY KEY,
  a part_type,
  b INT,
  FAMILY (pk, a, b)
) PARTITION ALL BY LIST(a) (
  PARTITION one VALUES IN ('one'),
  PARTITION two VALUES IN ('two'),
  PARTITION three VALUES IN ('three'),
  PARTITION four VALUES IN ('four'),
  PARTITION five VALUES IN ('five')
)

statement ok
SET tracing = kv

# Test a blind write.
statement ok
UPSERT INTO overwrite VALUES (1, 'two', 3)

# Test a blind rewrite. No tombstones because the PK doesn't change.
statement ok
UPSERT INTO overwrite VALUES (1, 'two', 4)

# Test a blind overwrite.
statement ok
UPSERT INTO overwrite VALUES (1, 'three', 5)

query T
SELECT message FROM [SHOW TRACE FOR SESSION] WHERE message LIKE 'CPut%'
----
CPut /Table/111/1/"@"/1/0 -> /TUPLE/3:3:Int/3
CPut /Table/111/1/" "/1/0 -> nil (tombstone)
CPut /Table/111/1/"\x80"/1/0 -> nil (tombstone)
CPut /Table/111/1/"\xa0"/1/0 -> nil (tombstone)
CPut /Table/111/1/"\xc0"/1/0 -> nil (tombstone)
CPut /Table/111/1/"\x80"/1/0 -> /TUPLE/3:3:Int/5
CPut /Table/111/1/" "/1/0 -> nil (tombstone)
CPut /Table/111/1/"@"/1/0 -> nil (tombstone)
CPut /Table/111/1/"\xa0"/1/0 -> nil (tombstone)
CPut /Table/111/1/"\xc0"/1/0 -> nil (tombstone)

query ITI
SELECT * FROM overwrite ORDER BY pk
----
1  three  5

query T
EXPLAIN INSERT INTO t VALUES (1, 'two', 3, 4, 5)
----
distribution: local
vectorized: true
·
• insert fast path
  into: t(pk, a, b, c, d, j)
  auto commit
  uniqueness checks (tombstones): t_pkey, t_c_key
  size: 7 columns, 1 row

query T
EXPLAIN (OPT) INSERT INTO t VALUES (1, 'two', 3, 4, 5)
----
insert t
 ├── unique w/tombstone indexes: t_pkey t_c_key
 └── values
      └── (1, 'two', 3, 4, 5, NULL, true)

statement ok
INSERT INTO t VALUES (1, 'two', 3, 4, 5)

statement error pgcode 23505 pq: duplicate key value violates unique constraint "t_pkey"
INSERT INTO t VALUES (1, 'one', 3, 6, 5)

statement error pgcode 23505 pq: duplicate key value violates unique constraint "t_c_key"
INSERT INTO t VALUES (2, 'three', 3, 4, 5)

statement ok
INSERT INTO t VALUES (2, 'four', 3, 6, 5)

statement error pgcode 23505 pq: duplicate key value violates unique constraint "t_pkey"
UPDATE t SET pk = 1 WHERE c = 6;

query T
EXPLAIN UPDATE t SET c = 4 WHERE pk = 2
----
distribution: local
vectorized: true
·
• update
│ table: t
│ uniqueness checks (tombstones): t_c_key
│ set: c
│ auto commit
│
└── • render
    │
    └── • scan
          missing stats
          table: t@t_pkey
          spans: [/'one'/2 - /'one'/2] [/'two'/2 - /'two'/2] [/'three'/2 - /'three'/2] [/'four'/2 - /'four'/2] … (1 more)
          locking strength: for update

query T
EXPLAIN (OPT) UPDATE t SET c = 4 WHERE pk = 2
----
update t
 ├── unique w/tombstone indexes: t_c_key
 └── project
      ├── scan t
      │    ├── constraint: /12/11
      │    │    ├── [/'one'/2 - /'one'/2]
      │    │    ├── [/'two'/2 - /'two'/2]
      │    │    ├── [/'three'/2 - /'three'/2]
      │    │    ├── [/'four'/2 - /'four'/2]
      │    │    └── [/'five'/2 - /'five'/2]
      │    └── flags: avoid-full-scan
      └── projections
           └── 4

statement error pgcode 23505 pq: duplicate key value violates unique constraint "t_c_key"
UPDATE t SET c = 4 WHERE pk = 2

query T
EXPLAIN UPSERT INTO t VALUES (1, 'five', 3, 4, 15)
----
distribution: local
vectorized: true
·
• upsert
│ into: t(pk, a, b, c, d, j)
│ auto commit
│ arbiter constraints: t_pkey
│ uniqueness checks (tombstones): t_pkey, t_c_key
│
└── • render
    │
    └── • lookup join (left outer)
        │ table: t@t_pkey
        │ equality cols are key
        │ lookup condition: (a IN ('one', 'two', __more1_10__, 'five')) AND (column1 = pk)
        │ locking strength: for update
        │ locking durability: guaranteed
        │
        └── • values
              size: 6 columns, 1 row

query T
EXPLAIN (OPT) UPSERT INTO t VALUES (1, 'five', 3, 4, 15)
----
upsert t
 ├── arbiter constraints: t_pkey
 ├── unique w/tombstone indexes: t_pkey t_c_key
 └── project
      ├── left-join (lookup t)
      │    ├── flags: prefer lookup join (into right side)
      │    ├── lookup columns are key
      │    ├── locking: for-update,durability-guaranteed
      │    ├── values
      │    │    └── (1, 'five', 3, 4, 15, NULL)
      │    └── filters (true)
      └── projections
           └── column2 IN ('one', 'two', 'three', 'four', 'five')

statement ok
UPSERT INTO t VALUES (1, 'five', 3, 4, 15)

query T
EXPLAIN INSERT INTO t VALUES (1, 'three', 3, 4, 15) ON CONFLICT DO NOTHING
----
distribution: local
vectorized: true
·
• insert
│ into: t(pk, a, b, c, d, j)
│ auto commit
│ arbiter constraints: t_pkey, t_c_key
│ uniqueness checks (tombstones): t_pkey, t_c_key
│
└── • render
    │
    └── • lookup join (anti)
        │ table: t@t_c_key
        │ equality cols are key
        │ lookup condition: (a IN ('one', 'two', __more1_10__, 'five')) AND (column4 = c)
        │ locking strength: for share
        │ locking durability: guaranteed
        │
        └── • lookup join (anti)
            │ table: t@t_pkey
            │ equality cols are key
            │ lookup condition: (a IN ('one', 'two', __more1_10__, 'five')) AND (column1 = pk)
            │ locking strength: for share
            │ locking durability: guaranteed
            │
            └── • values
                  size: 6 columns, 1 row

statement ok
INSERT INTO t VALUES (1, 'three', 3, 4, 15) ON CONFLICT DO NOTHING

query T
EXPLAIN INSERT INTO t VALUES (1, 'one', 3, 4, 5) ON CONFLICT (pk) DO UPDATE SET d = t.d + 10
----
distribution: local
vectorized: true
·
• upsert
│ into: t(pk, a, b, c, d, j)
│ auto commit
│ arbiter constraints: t_pkey
│ uniqueness checks (tombstones): t_pkey, t_c_key
│
└── • render
    │
    └── • lookup join (left outer)
        │ table: t@t_pkey
        │ equality cols are key
        │ lookup condition: (a IN ('one', 'two', __more1_10__, 'five')) AND (column1 = pk)
        │ locking strength: for update
        │ locking durability: guaranteed
        │
        └── • values
              size: 6 columns, 1 row

query T
EXPLAIN (OPT) INSERT INTO t VALUES (1, 'one', 3, 4, 5) ON CONFLICT (pk) DO UPDATE SET d = t.d + 10
----
upsert t
 ├── arbiter constraints: t_pkey
 ├── unique w/tombstone indexes: t_pkey t_c_key
 └── project
      ├── left-join (lookup t)
      │    ├── flags: prefer lookup join (into right side)
      │    ├── lookup columns are key
      │    ├── locking: for-update,durability-guaranteed
      │    ├── values
      │    │    └── (1, 'one', 3, 4, 5, NULL)
      │    └── filters (true)
      └── projections
           ├── CASE WHEN a IS NULL THEN column2 ELSE a END IN ('one', 'two', 'three', 'four', 'five')
           └── CASE WHEN a IS NULL THEN column5 ELSE d + 10 END

statement ok
INSERT INTO t VALUES (1, 'one', 3, 4, 5) ON CONFLICT (pk) DO UPDATE SET d = t.d + 10

query T
SELECT message FROM [SHOW TRACE FOR SESSION] WHERE message LIKE 'CPut%'
----
CPut /Table/111/1/"@"/1/0 -> /TUPLE/3:3:Int/3
CPut /Table/111/1/" "/1/0 -> nil (tombstone)
CPut /Table/111/1/"\x80"/1/0 -> nil (tombstone)
CPut /Table/111/1/"\xa0"/1/0 -> nil (tombstone)
CPut /Table/111/1/"\xc0"/1/0 -> nil (tombstone)
CPut /Table/111/1/"\x80"/1/0 -> /TUPLE/3:3:Int/5
CPut /Table/111/1/" "/1/0 -> nil (tombstone)
CPut /Table/111/1/"@"/1/0 -> nil (tombstone)
CPut /Table/111/1/"\xa0"/1/0 -> nil (tombstone)
CPut /Table/111/1/"\xc0"/1/0 -> nil (tombstone)
CPut /Table/110/1/"@"/1/0 -> /TUPLE/3:3:Int/3/1:4:Int/4/1:5:Int/5
CPut /Table/110/1/" "/1/0 -> nil (tombstone)
CPut /Table/110/1/"\x80"/1/0 -> nil (tombstone)
CPut /Table/110/1/"\xa0"/1/0 -> nil (tombstone)
CPut /Table/110/1/"\xc0"/1/0 -> nil (tombstone)
CPut /Table/110/2/" "/4/0 -> nil (tombstone)
CPut /Table/110/2/"\x80"/4/0 -> nil (tombstone)
CPut /Table/110/2/"\xa0"/4/0 -> nil (tombstone)
CPut /Table/110/2/"\xc0"/4/0 -> nil (tombstone)
CPut /Table/110/1/" "/1/0 -> /TUPLE/3:3:Int/3/1:4:Int/6/1:5:Int/5
CPut /Table/110/1/"@"/1/0 -> nil (tombstone)
CPut /Table/110/1/"\x80"/1/0 -> nil (tombstone)
CPut /Table/110/1/"\xa0"/1/0 -> nil (tombstone)
CPut /Table/110/1/"\xc0"/1/0 -> nil (tombstone)
CPut /Table/110/2/"@"/6/0 -> nil (tombstone)
CPut /Table/110/2/"\x80"/6/0 -> nil (tombstone)
CPut /Table/110/2/"\xa0"/6/0 -> nil (tombstone)
CPut /Table/110/2/"\xc0"/6/0 -> nil (tombstone)
CPut /Table/110/1/"\x80"/2/0 -> /TUPLE/3:3:Int/3/1:4:Int/4/1:5:Int/5
CPut /Table/110/1/" "/2/0 -> nil (tombstone)
CPut /Table/110/1/"@"/2/0 -> nil (tombstone)
CPut /Table/110/1/"\xa0"/2/0 -> nil (tombstone)
CPut /Table/110/1/"\xc0"/2/0 -> nil (tombstone)
CPut /Table/110/2/" "/4/0 -> nil (tombstone)
CPut /Table/110/2/"@"/4/0 -> nil (tombstone)
CPut /Table/110/2/"\xa0"/4/0 -> nil (tombstone)
CPut /Table/110/2/"\xc0"/4/0 -> nil (tombstone)
CPut /Table/110/1/"\xa0"/2/0 -> /TUPLE/3:3:Int/3/1:4:Int/6/1:5:Int/5
CPut /Table/110/1/" "/2/0 -> nil (tombstone)
CPut /Table/110/1/"@"/2/0 -> nil (tombstone)
CPut /Table/110/1/"\x80"/2/0 -> nil (tombstone)
CPut /Table/110/1/"\xc0"/2/0 -> nil (tombstone)
CPut /Table/110/2/" "/6/0 -> nil (tombstone)
CPut /Table/110/2/"@"/6/0 -> nil (tombstone)
CPut /Table/110/2/"\x80"/6/0 -> nil (tombstone)
CPut /Table/110/2/"\xc0"/6/0 -> nil (tombstone)
CPut /Table/110/1/"\xa0"/1/0 -> /TUPLE/3:3:Int/3/1:4:Int/6/1:5:Int/5
CPut /Table/110/1/" "/1/0 -> nil (tombstone)
CPut /Table/110/1/"@"/1/0 -> nil (tombstone)
CPut /Table/110/1/"\x80"/1/0 -> nil (tombstone)
CPut /Table/110/1/"\xc0"/1/0 -> nil (tombstone)
CPut /Table/110/2/"\xa0"/4/0 -> /BYTES/0x8a (expecting does not exist)
CPut /Table/110/2/" "/4/0 -> nil (tombstone)
CPut /Table/110/2/"@"/4/0 -> nil (tombstone)
CPut /Table/110/2/"\x80"/4/0 -> nil (tombstone)
CPut /Table/110/2/"\xc0"/4/0 -> nil (tombstone)
CPut /Table/110/1/"\xc0"/1/0 -> /TUPLE/3:3:Int/3/1:4:Int/4/1:5:Int/15
CPut /Table/110/1/" "/1/0 -> nil (tombstone)
CPut /Table/110/1/"@"/1/0 -> nil (tombstone)
CPut /Table/110/1/"\x80"/1/0 -> nil (tombstone)
CPut /Table/110/1/"\xa0"/1/0 -> nil (tombstone)
CPut /Table/110/2/" "/4/0 -> nil (tombstone)
CPut /Table/110/2/"@"/4/0 -> nil (tombstone)
CPut /Table/110/2/"\x80"/4/0 -> nil (tombstone)
CPut /Table/110/2/"\xa0"/4/0 -> nil (tombstone)

query ITIIIT
SELECT * FROM t ORDER BY pk
----
1  five  3  4  25  NULL
2  four  3  6  5   NULL
