# LogicTest: local

statement ok
CREATE TABLE kv (
  k VARCHAR PRIMARY KEY,
  v VARCHAR,
  UNIQUE INDEX a (v),
  FAMILY (k),
  FAMILY (v)
)

statement ok
INSERT INTO kv VALUES ('A');
INSERT INTO kv (k) VALUES ('nil1');
INSERT INTO kv (k) VALUES ('nil2');
INSERT INTO kv VALUES ('nil3', NULL);
INSERT INTO kv VALUES ('nil4', NULL);
INSERT INTO kv (k,v) VALUES ('a', 'b'), ('c', 'd');

query T rowsort
SELECT v || 'hello' FROM [INSERT INTO kv VALUES ('e', 'f'), ('g', '') RETURNING v]
----
fhello
hello

statement ok
SET tracing = on,kv,results; SELECT * FROM kv; SET tracing = off

query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 ORDER BY message LIKE 'fetched:%' DESC, ordinality ASC
----
fetched: /kv/kv_pkey/'A' -> <undecoded>
fetched: /kv/kv_pkey/'a' -> <undecoded>
fetched: /kv/kv_pkey/'a'/v -> 'b'
fetched: /kv/kv_pkey/'c' -> <undecoded>
fetched: /kv/kv_pkey/'c'/v -> 'd'
fetched: /kv/kv_pkey/'e' -> <undecoded>
fetched: /kv/kv_pkey/'e'/v -> 'f'
fetched: /kv/kv_pkey/'g' -> <undecoded>
fetched: /kv/kv_pkey/'g'/v -> ''
fetched: /kv/kv_pkey/'nil1' -> <undecoded>
fetched: /kv/kv_pkey/'nil2' -> <undecoded>
fetched: /kv/kv_pkey/'nil3' -> <undecoded>
fetched: /kv/kv_pkey/'nil4' -> <undecoded>
output row: ['A' NULL]
output row: ['a' 'b']
output row: ['c' 'd']
output row: ['e' 'f']
output row: ['g' '']
output row: ['nil1' NULL]
output row: ['nil2' NULL]
output row: ['nil3' NULL]
output row: ['nil4' NULL]

statement ok
SET tracing = on,kv,results; SELECT * FROM kv@a; SET tracing = off

query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 ORDER BY message LIKE 'fetched:%' DESC, ordinality ASC
----
fetched: /kv/a/NULL -> /'A'
fetched: /kv/a/NULL -> /'nil1'
fetched: /kv/a/NULL -> /'nil2'
fetched: /kv/a/NULL -> /'nil3'
fetched: /kv/a/NULL -> /'nil4'
fetched: /kv/a/'' -> /'g'
fetched: /kv/a/'b' -> /'a'
fetched: /kv/a/'d' -> /'c'
fetched: /kv/a/'f' -> /'e'
output row: ['A' NULL]
output row: ['nil1' NULL]
output row: ['nil2' NULL]
output row: ['nil3' NULL]
output row: ['nil4' NULL]
output row: ['g' '']
output row: ['a' 'b']
output row: ['c' 'd']
output row: ['e' 'f']

statement error pgcode 23505 duplicate key value violates unique constraint "a"\nDETAIL: Key \(v\)=\('f'\) already exists\.
INSERT INTO kv VALUES ('h', 'f')

statement ok
SET tracing = on,kv,results; SELECT * FROM kv; SET tracing = off

query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 ORDER BY message LIKE 'fetched:%' DESC, ordinality ASC
----
fetched: /kv/kv_pkey/'A' -> <undecoded>
fetched: /kv/kv_pkey/'a' -> <undecoded>
fetched: /kv/kv_pkey/'a'/v -> 'b'
fetched: /kv/kv_pkey/'c' -> <undecoded>
fetched: /kv/kv_pkey/'c'/v -> 'd'
fetched: /kv/kv_pkey/'e' -> <undecoded>
fetched: /kv/kv_pkey/'e'/v -> 'f'
fetched: /kv/kv_pkey/'g' -> <undecoded>
fetched: /kv/kv_pkey/'g'/v -> ''
fetched: /kv/kv_pkey/'nil1' -> <undecoded>
fetched: /kv/kv_pkey/'nil2' -> <undecoded>
fetched: /kv/kv_pkey/'nil3' -> <undecoded>
fetched: /kv/kv_pkey/'nil4' -> <undecoded>
output row: ['A' NULL]
output row: ['a' 'b']
output row: ['c' 'd']
output row: ['e' 'f']
output row: ['g' '']
output row: ['nil1' NULL]
output row: ['nil2' NULL]
output row: ['nil3' NULL]
output row: ['nil4' NULL]

statement ok
SET tracing = on,kv,results; SELECT * FROM kv@a; SET tracing = off

query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 ORDER BY message LIKE 'fetched:%' DESC, ordinality ASC
----
fetched: /kv/a/NULL -> /'A'
fetched: /kv/a/NULL -> /'nil1'
fetched: /kv/a/NULL -> /'nil2'
fetched: /kv/a/NULL -> /'nil3'
fetched: /kv/a/NULL -> /'nil4'
fetched: /kv/a/'' -> /'g'
fetched: /kv/a/'b' -> /'a'
fetched: /kv/a/'d' -> /'c'
fetched: /kv/a/'f' -> /'e'
output row: ['A' NULL]
output row: ['nil1' NULL]
output row: ['nil2' NULL]
output row: ['nil3' NULL]
output row: ['nil4' NULL]
output row: ['g' '']
output row: ['a' 'b']
output row: ['c' 'd']
output row: ['e' 'f']

statement ok
INSERT INTO kv VALUES ('f', 'g')

statement ok
SET tracing = on,kv,results; SELECT * FROM kv; SET tracing = off

query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 ORDER BY message LIKE 'fetched:%' DESC, ordinality ASC
----
fetched: /kv/kv_pkey/'A' -> <undecoded>
fetched: /kv/kv_pkey/'a' -> <undecoded>
fetched: /kv/kv_pkey/'a'/v -> 'b'
fetched: /kv/kv_pkey/'c' -> <undecoded>
fetched: /kv/kv_pkey/'c'/v -> 'd'
fetched: /kv/kv_pkey/'e' -> <undecoded>
fetched: /kv/kv_pkey/'e'/v -> 'f'
fetched: /kv/kv_pkey/'f' -> <undecoded>
fetched: /kv/kv_pkey/'f'/v -> 'g'
fetched: /kv/kv_pkey/'g' -> <undecoded>
fetched: /kv/kv_pkey/'g'/v -> ''
fetched: /kv/kv_pkey/'nil1' -> <undecoded>
fetched: /kv/kv_pkey/'nil2' -> <undecoded>
fetched: /kv/kv_pkey/'nil3' -> <undecoded>
fetched: /kv/kv_pkey/'nil4' -> <undecoded>
output row: ['A' NULL]
output row: ['a' 'b']
output row: ['c' 'd']
output row: ['e' 'f']
output row: ['f' 'g']
output row: ['g' '']
output row: ['nil1' NULL]
output row: ['nil2' NULL]
output row: ['nil3' NULL]
output row: ['nil4' NULL]

statement ok
SET tracing = on,kv,results; SELECT * FROM kv@a; SET tracing = off

query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 ORDER BY message LIKE 'fetched:%' DESC, ordinality ASC
----
fetched: /kv/a/NULL -> /'A'
fetched: /kv/a/NULL -> /'nil1'
fetched: /kv/a/NULL -> /'nil2'
fetched: /kv/a/NULL -> /'nil3'
fetched: /kv/a/NULL -> /'nil4'
fetched: /kv/a/'' -> /'g'
fetched: /kv/a/'b' -> /'a'
fetched: /kv/a/'d' -> /'c'
fetched: /kv/a/'f' -> /'e'
fetched: /kv/a/'g' -> /'f'
output row: ['A' NULL]
output row: ['nil1' NULL]
output row: ['nil2' NULL]
output row: ['nil3' NULL]
output row: ['nil4' NULL]
output row: ['g' '']
output row: ['a' 'b']
output row: ['c' 'd']
output row: ['e' 'f']
output row: ['f' 'g']

statement error duplicate key value violates unique constraint "a"\nDETAIL: Key \(v\)=\('g'\) already exists\.
INSERT INTO kv VALUES ('h', 'g')

statement ok
SET tracing = on,kv,results; SELECT * FROM kv; SET tracing = off

query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 ORDER BY message LIKE 'fetched:%' DESC, ordinality ASC
----
fetched: /kv/kv_pkey/'A' -> <undecoded>
fetched: /kv/kv_pkey/'a' -> <undecoded>
fetched: /kv/kv_pkey/'a'/v -> 'b'
fetched: /kv/kv_pkey/'c' -> <undecoded>
fetched: /kv/kv_pkey/'c'/v -> 'd'
fetched: /kv/kv_pkey/'e' -> <undecoded>
fetched: /kv/kv_pkey/'e'/v -> 'f'
fetched: /kv/kv_pkey/'f' -> <undecoded>
fetched: /kv/kv_pkey/'f'/v -> 'g'
fetched: /kv/kv_pkey/'g' -> <undecoded>
fetched: /kv/kv_pkey/'g'/v -> ''
fetched: /kv/kv_pkey/'nil1' -> <undecoded>
fetched: /kv/kv_pkey/'nil2' -> <undecoded>
fetched: /kv/kv_pkey/'nil3' -> <undecoded>
fetched: /kv/kv_pkey/'nil4' -> <undecoded>
output row: ['A' NULL]
output row: ['a' 'b']
output row: ['c' 'd']
output row: ['e' 'f']
output row: ['f' 'g']
output row: ['g' '']
output row: ['nil1' NULL]
output row: ['nil2' NULL]
output row: ['nil3' NULL]
output row: ['nil4' NULL]

statement ok
SET tracing = on,kv,results; SELECT * FROM kv@a; SET tracing = off

query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 ORDER BY message LIKE 'fetched:%' DESC, ordinality ASC
----
fetched: /kv/a/NULL -> /'A'
fetched: /kv/a/NULL -> /'nil1'
fetched: /kv/a/NULL -> /'nil2'
fetched: /kv/a/NULL -> /'nil3'
fetched: /kv/a/NULL -> /'nil4'
fetched: /kv/a/'' -> /'g'
fetched: /kv/a/'b' -> /'a'
fetched: /kv/a/'d' -> /'c'
fetched: /kv/a/'f' -> /'e'
fetched: /kv/a/'g' -> /'f'
output row: ['A' NULL]
output row: ['nil1' NULL]
output row: ['nil2' NULL]
output row: ['nil3' NULL]
output row: ['nil4' NULL]
output row: ['g' '']
output row: ['a' 'b']
output row: ['c' 'd']
output row: ['e' 'f']
output row: ['f' 'g']

statement ok
CREATE TABLE kv5 (
  k CHAR PRIMARY KEY,
  v CHAR,
  UNIQUE INDEX a (v, k)
)

statement ok
INSERT INTO kv5 VALUES ('a', NULL)

statement ok
SET tracing = on,kv,results; SELECT * FROM kv5@a; SET tracing = off

query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 ORDER BY message LIKE 'fetched:%' DESC, ordinality ASC
----
fetched: /kv5/a/NULL/'a' -> <undecoded>
output row: ['a' NULL]

statement ok
CREATE TABLE insert_t (x INT, v INT)

statement ok
CREATE TABLE select_t (x INT, v INT)

# Check that INSERT supports ORDER BY (MySQL extension)
query T
EXPLAIN (VERBOSE) INSERT INTO insert_t TABLE select_t ORDER BY v DESC LIMIT 10
----
distribution: local
vectorized: true
·
• insert
│ columns: ()
│ estimated row count: 0 (missing stats)
│ into: insert_t(x, v, rowid)
│ auto commit
│
└── • render
    │ columns: (x, v, rowid_default)
    │ render rowid_default: unique_rowid()
    │ render x: x
    │ render v: v
    │
    └── • top-k
        │ columns: (x, v)
        │ estimated row count: 10 (missing stats)
        │ order: -v
        │ k: 10
        │
        └── • scan
              columns: (x, v)
              estimated row count: 1,000 (missing stats)
              table: select_t@select_t_pkey
              spans: FULL SCAN

# Check that INSERT supports LIMIT (MySQL extension)
query T
EXPLAIN (VERBOSE) INSERT INTO insert_t SELECT * FROM select_t LIMIT 1
----
distribution: local
vectorized: true
·
• insert
│ columns: ()
│ estimated row count: 0 (missing stats)
│ into: insert_t(x, v, rowid)
│ auto commit
│
└── • render
    │ columns: (x, v, rowid_default)
    │ render rowid_default: unique_rowid()
    │ render x: x
    │ render v: v
    │
    └── • scan
          columns: (x, v)
          estimated row count: 1 (missing stats)
          table: select_t@select_t_pkey
          spans: LIMITED SCAN
          limit: 1

# Check the grouping of LIMIT and ORDER BY
query T
EXPLAIN (PLAN) INSERT INTO insert_t VALUES (1,1), (2,2) LIMIT 1
----
distribution: local
vectorized: true
·
• insert
│ into: insert_t(x, v, rowid)
│ auto commit
│
└── • render
    │
    └── • limit
        │ count: 1
        │
        └── • values
              size: 2 columns, 2 rows

query T
EXPLAIN (PLAN) INSERT INTO insert_t VALUES (1,1), (2,2) ORDER BY 2 LIMIT 1
----
distribution: local
vectorized: true
·
• insert
│ into: insert_t(x, v, rowid)
│ auto commit
│
└── • render
    │
    └── • top-k
        │ estimated row count: 1
        │ order: +column2
        │ k: 1
        │
        └── • values
              size: 2 columns, 2 rows

query T
EXPLAIN (PLAN) INSERT INTO insert_t (VALUES (1,1), (2,2) ORDER BY 2) LIMIT 1
----
distribution: local
vectorized: true
·
• insert
│ into: insert_t(x, v, rowid)
│ auto commit
│
└── • render
    │
    └── • top-k
        │ estimated row count: 1
        │ order: +column2
        │ k: 1
        │
        └── • values
              size: 2 columns, 2 rows

query T
EXPLAIN (PLAN) INSERT INTO insert_t (VALUES (1,1), (2,2) ORDER BY 2 LIMIT 1)
----
distribution: local
vectorized: true
·
• insert
│ into: insert_t(x, v, rowid)
│ auto commit
│
└── • render
    │
    └── • top-k
        │ estimated row count: 1
        │ order: +column2
        │ k: 1
        │
        └── • values
              size: 2 columns, 2 rows

# ORDER BY expression that's not inserted into table.
query T
EXPLAIN (VERBOSE)
INSERT INTO insert_t (SELECT length(k), 2 FROM kv ORDER BY k || v LIMIT 10) RETURNING x+v
----
distribution: local
vectorized: true
·
• render
│ columns: ("?column?")
│ render ?column?: x + v
│
└── • insert
    │ columns: (x, v, rowid)
    │ estimated row count: 10 (missing stats)
    │ into: insert_t(x, v, rowid)
    │
    └── • render
        │ columns: (length, "?column?", rowid_default)
        │ render rowid_default: unique_rowid()
        │ render length: length
        │ render ?column?: "?column?"
        │
        └── • top-k
            │ columns: (length, "?column?", column16)
            │ estimated row count: 10 (missing stats)
            │ order: +column16
            │ k: 10
            │
            └── • render
                │ columns: (length, "?column?", column16)
                │ render length: length(k)
                │ render ?column?: 2
                │ render column16: k || v
                │
                └── • scan
                      columns: (k, v)
                      estimated row count: 1,000 (missing stats)
                      table: kv@kv_pkey
                      spans: FULL SCAN

# Index hints should be a no-op for normal inserts without ON CONFLICT.
query T
EXPLAIN (PLAN) INSERT INTO kv@a VALUES (1,1), (2,2)
----
distribution: local
vectorized: true
·
• insert fast path
  into: kv(k, v)
  auto commit
  size: 2 columns, 2 rows

# ------------------------------------------------------------------------------
# Insert rows into table during schema changes.
# ------------------------------------------------------------------------------

statement ok
CREATE TABLE mutation(x INT, y INT NOT NULL DEFAULT(10)); INSERT INTO mutation VALUES (1, 1)

statement ok
BEGIN; ALTER TABLE mutation DROP COLUMN y

# Ensure that default value is still inserted into y, since y is write-only.
query T
EXPLAIN (VERBOSE) INSERT INTO mutation(x) VALUES (2) RETURNING *
----
distribution: local
vectorized: true
·
• project
│ columns: (x)
│
└── • insert fast path
      columns: (x, rowid)
      estimated row count: 1
      into: mutation(x, rowid, y)
      size: 3 columns, 1 row
      row 0, expr 0: 2
      row 0, expr 1: unique_rowid()
      row 0, expr 2: 10

statement ok
ROLLBACK

statement ok
BEGIN; ALTER TABLE mutation ADD COLUMN z INT AS (x + y) STORED

# Ensure that value is *not* inserted into z, since z is delete-only.
query T
EXPLAIN (VERBOSE) INSERT INTO mutation(x, y) VALUES (2, 2)
----
distribution: local
vectorized: true
·
• insert fast path
  columns: ()
  estimated row count: 0 (missing stats)
  into: mutation(x, y, rowid)
  size: 3 columns, 1 row
  row 0, expr 0: 2
  row 0, expr 1: 2
  row 0, expr 2: unique_rowid()

statement ok
ROLLBACK

# ------------------------------------------------------------------------------
# Insert fast path.
# ------------------------------------------------------------------------------

# Do not plan insert fast path when VALUES clause has a subquery.
# statement ok
query T
EXPLAIN INSERT INTO kv VALUES (1, (SELECT v FROM kv))
----
distribution: local
vectorized: true
·
• root
│
├── • insert
│   │ into: kv(k, v)
│   │ auto commit
│   │
│   └── • values
│         size: 2 columns, 1 row
│
└── • subquery
    │ id: @S1
    │ original sql: (SELECT v FROM kv)
    │ exec mode: one row
    │
    └── • max1row
        │ estimated row count: 1
        │
        └── • scan
              missing stats
              table: kv@kv_pkey
              spans: FULL SCAN

statement ok
CREATE FUNCTION foo() RETURNS VARCHAR LANGUAGE SQL AS 'SELECT v FROM kv'

# Do not plan insert fast path when VALUES clause invokes a UDF.
query T
EXPLAIN INSERT INTO kv VALUES (1, foo())
----
distribution: local
vectorized: true
·
• insert
│ into: kv(k, v)
│ auto commit
│
└── • values
      size: 2 columns, 1 row

# Regression test for #35564: make sure we use the Insert's input required
# ordering for the internal projection.

statement ok
CREATE TABLE abc (a INT, b INT, c INT, INDEX(c) STORING(a,b))

statement ok
CREATE TABLE xyz (x INT, y INT, z INT)

query T
EXPLAIN (VERBOSE) SELECT * FROM [INSERT INTO xyz SELECT a, b, c FROM abc RETURNING z] ORDER BY z
----
distribution: local
vectorized: true
·
• root
│ columns: (z)
│
├── • sort
│   │ columns: (z)
│   │ estimated row count: 1,000 (missing stats)
│   │ order: +z
│   │
│   └── • scan buffer
│         columns: (z)
│         estimated row count: 1,000 (missing stats)
│         label: buffer 1
│
└── • subquery
    │ id: @S1
    │ original sql: INSERT INTO xyz SELECT a, b, c FROM abc RETURNING z
    │ exec mode: discard all rows
    │
    └── • buffer
        │ columns: (z)
        │ label: buffer 1
        │
        └── • project
            │ columns: (z)
            │
            └── • insert
                │ columns: (z, rowid)
                │ estimated row count: 1,000 (missing stats)
                │ into: xyz(x, y, z, rowid)
                │
                └── • render
                    │ columns: (a, b, c, rowid_default)
                    │ render rowid_default: unique_rowid()
                    │ render a: a
                    │ render b: b
                    │ render c: c
                    │
                    └── • scan
                          columns: (a, b, c)
                          estimated row count: 1,000 (missing stats)
                          table: abc@abc_pkey
                          spans: FULL SCAN

# ------------------------------------------------------------------------------
# Regression for #35364. This tests behavior that is different between the CBO
# and the HP. The CBO will (deliberately) round any input columns *before*
# evaluating any computed columns, as well as rounding the output.
# ------------------------------------------------------------------------------

statement ok
CREATE TABLE t35364(
    x DECIMAL(10,0) CHECK(round(x) = x) PRIMARY KEY,
    y DECIMAL(10,0) DEFAULT (1.5),
    z DECIMAL(10,0) AS (x+y+2.5) STORED CHECK(z >= 7)
)

query TTT
INSERT INTO t35364 (x) VALUES (1.5) RETURNING *
----
2  2  7

# Regression test for #62270: make sure the fast path is used when not
# providing values for some columns.
statement ok
CREATE TABLE t62270_parent (id INT PRIMARY KEY);
CREATE TABLE t62270_child (c UUID DEFAULT (gen_random_uuid()), p INT REFERENCES t62270_parent (id));

query T
EXPLAIN (VERBOSE) INSERT INTO t62270_child (p) VALUES (1)
----
distribution: local
vectorized: true
·
• insert fast path
  columns: ()
  estimated row count: 0 (missing stats)
  into: t62270_child(c, p, rowid)
  auto commit
  FK check: t62270_parent@t62270_parent_pkey
  size: 3 columns, 1 row
  row 0, expr 0: gen_random_uuid()
  row 0, expr 1: 1
  row 0, expr 2: unique_rowid()
