# LogicTest: local-opt

# Prepare a trace to be inspected below.

statement ok
SET tracing = on; BEGIN; SELECT 1; COMMIT; SELECT 2; SET tracing = off

# Inspect the trace: we exclude messages containing newlines as these
# may contain non-deterministic txn object descriptions.
# This also checks that the span column properly reports separate
# SQL transactions.
# We replace the command position because the values depend on exactly
# how many commands we ran in the session.
query ITT
SELECT
  span, regexp_replace(message, 'pos:[0-9]*', 'pos:?'), operation
FROM [SHOW TRACE FOR SESSION]
WHERE message LIKE '%SPAN START%' OR message LIKE '%pos%executing%';
----
0  === SPAN START: session recording ===                session recording
0  [NoTxn pos:?] executing ExecStmt: BEGIN TRANSACTION  session recording
1  === SPAN START: sql txn ===                          sql txn
1  [Open pos:?] executing ExecStmt: SELECT 1            sql txn
2  === SPAN START: consuming rows ===                   consuming rows
3  === SPAN START: flow ===                             flow
1  [Open pos:?] executing ExecStmt: COMMIT TRANSACTION  sql txn
0  [NoTxn pos:?] executing ExecStmt: SELECT 2           session recording
4  === SPAN START: sql txn ===                          sql txn
4  [Open pos:?] executing ExecStmt: SELECT 2            sql txn
5  === SPAN START: consuming rows ===                   consuming rows
6  === SPAN START: flow ===                             flow
0  [NoTxn pos:?] executing ExecStmt: SET TRACING = off  session recording

# ------------------------------------------------------------------------------
# Numeric References Tests.
# These are put at the beginning of the file to ensure the numeric table
# reference is 53 (the numeric reference of the first table).
# If the numbering scheme in cockroach changes, this test will break.
# These tests replicate the tests at sql/table_ref_test.go. The reason
# for duplication is to include tests within the opt testing framework
# TODO(madhavsuresh): get the numeric reference ID in a less brittle fashion
# ------------------------------------------------------------------------------
statement ok
CREATE TABLE num_ref (a INT PRIMARY KEY, xx INT, b INT, c INT, INDEX bc (b,c))

statement ok
CREATE TABLE num_ref_hidden (a INT, b INT)

statement ok
ALTER TABLE num_ref RENAME COLUMN b TO d

statement ok
ALTER TABLE num_ref RENAME COLUMN a TO p

statement ok
ALTER TABLE num_ref DROP COLUMN xx

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53 AS num_ref_alias]
----
scan  ·      ·                (p, d, c)  ·
·     table  num_ref@primary  ·          ·
·     spans  ALL              ·          ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(4) AS num_ref_alias]
----
scan  ·      ·                (c)  ·
·     table  num_ref@primary  ·    ·
·     spans  ALL              ·    ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(1,4) AS num_ref_alias]
----
scan  ·      ·                (p, c)  ·
·     table  num_ref@primary  ·       ·
·     spans  ALL              ·       ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(1,3,4) AS num_ref_alias]
----
scan  ·      ·                (p, d, c)  ·
·     table  num_ref@primary  ·          ·
·     spans  ALL              ·          ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(4,3,1) AS num_ref_alias]
----
render     ·         ·                (c, d, p)  ·
 │         render 0  c                ·          ·
 │         render 1  d                ·          ·
 │         render 2  p                ·          ·
 └── scan  ·         ·                (p, d, c)  ·
·          table     num_ref@primary  ·          ·
·          spans     ALL              ·          ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(4,3,1) AS num_ref_alias(col1,col2,col3)]
----
render     ·         ·                (col1, col2, col3)  ·
 │         render 0  c                ·                   ·
 │         render 1  d                ·                   ·
 │         render 2  p                ·                   ·
 └── scan  ·         ·                (p, d, c)           ·
·          table     num_ref@primary  ·                   ·
·          spans     ALL              ·                   ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(4,3,1) AS num_ref_alias]@bc
----
render     ·         ·           (c, d, p)  ·
 │         render 0  c           ·          ·
 │         render 1  d           ·          ·
 │         render 2  p           ·          ·
 └── scan  ·         ·           (p, d, c)  ·
·          table     num_ref@bc  ·          ·
·          spans     ALL         ·          ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(4) AS num_ref_alias]@bc
----
scan  ·      ·           (c)  ·
·     table  num_ref@bc  ·    ·
·     spans  ALL         ·    ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(3) AS num_ref_alias]@bc
----
scan  ·      ·           (d)  ·
·     table  num_ref@bc  ·    ·
·     spans  ALL         ·    ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(1) AS num_ref_alias]@bc
----
scan  ·      ·           (p)  ·
·     table  num_ref@bc  ·    ·
·     spans  ALL         ·    ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(1) AS num_ref_alias]@[1]
----
scan  ·      ·                (p)  ·
·     table  num_ref@primary  ·    ·
·     spans  ALL              ·    ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(1) AS num_ref_alias]@[2]
----
scan  ·      ·           (p)  ·
·     table  num_ref@bc  ·    ·
·     spans  ALL         ·    ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(3) AS num_ref_alias]@[1]
----
scan  ·      ·                (d)  ·
·     table  num_ref@primary  ·    ·
·     spans  ALL              ·    ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(3) AS num_ref_alias]@[2]
----
scan  ·      ·           (d)  ·
·     table  num_ref@bc  ·    ·
·     spans  ALL         ·    ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(4) AS num_ref_alias]@[1]
----
scan  ·      ·                (c)  ·
·     table  num_ref@primary  ·    ·
·     spans  ALL              ·    ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [53(4) AS num_ref_alias]@[2]
----
scan  ·      ·           (c)  ·
·     table  num_ref@bc  ·    ·
·     spans  ALL         ·    ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [54(1,3) AS num_ref_alias]
----
scan  ·      ·                       (a)  ·
·     table  num_ref_hidden@primary  ·    ·
·     spans  ALL                     ·    ·


query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM [54(3) AS num_ref_alias]
----
scan  ·      ·                       ()  ·
·     table  num_ref_hidden@primary  ·   ·
·     spans  ALL                     ·   ·

query TTTTT
EXPLAIN (VERBOSE) SELECT rowid FROM [54(3) AS num_ref_alias]
----
scan  ·      ·                       (rowid[hidden])  ·
·     table  num_ref_hidden@primary  ·                ·
·     spans  ALL                     ·                ·

query error pq: \[666\(1\) AS num_ref_alias\]: relation \"\[666\]\" does not exist
EXPLAIN (VERBOSE) SELECT * FROM [666(1) AS num_ref_alias]

query error pq: column \[666\] does not exist
EXPLAIN (VERBOSE) SELECT * FROM [53(666) AS num_ref_alias]

query error pq: column \[2\] does not exist
EXPLAIN (VERBOSE) SELECT * FROM [53(2) AS num_ref_alias]

query error pq: an explicit list of column IDs must include at least one column
EXPLAIN (VERBOSE) SELECT * FROM [53() AS num_ref_alias]

query error pq: an explicit list of column IDs must include at least one column
EXPLAIN (VERBOSE) SELECT 1 FROM [53() as num_ref_alias]

statement ok
DROP TABLE num_ref

query error pq: \[53\(1\) AS num_ref_alias\]: table is being dropped
EXPLAIN (VERBOSE) SELECT * FROM [53(1) AS num_ref_alias]

# ------------------------------------------------------------------------------
# Basic filter combinations.
# ------------------------------------------------------------------------------
statement ok
CREATE TABLE a (x INT PRIMARY KEY, y INT);

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM a WHERE x > 1
----
scan  ·      ·          (x, y)  ·
·     table  a@primary  ·       ·
·     spans  /2-        ·       ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM a WHERE y > 10
----
scan  ·       ·          (x, y)  ·
·     table   a@primary  ·       ·
·     spans   ALL        ·       ·
·     filter  y > 10     ·       ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM a WHERE x > 1 AND x < 3
----
scan  ·      ·          (x, y)  ·
·     table  a@primary  ·       ·
·     spans  /2-/2/#    ·       ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM a WHERE x > 1 AND y < 30
----
scan  ·       ·          (x, y)  ·
·     table   a@primary  ·       ·
·     spans   /2-        ·       ·
·     filter  y < 30     ·       ·

query TTTTT
EXPLAIN (VERBOSE) SELECT x + 1 AS r FROM a
----
render     ·         ·          (r)  ·
 │         render 0  x + 1      ·    ·
 └── scan  ·         ·          (x)  ·
·          table     a@primary  ·    ·
·          spans     ALL        ·    ·

query TTTTT
EXPLAIN (VERBOSE) SELECT x AS a, x + 1 AS b, y, y + 1 AS c, x + y AS d FROM a
----
render     ·         ·          (a, b, y, c, d)  ·
 │         render 0  x          ·                ·
 │         render 1  x + 1      ·                ·
 │         render 2  y          ·                ·
 │         render 3  y + 1      ·                ·
 │         render 4  x + y      ·                ·
 └── scan  ·         ·          (x, y)           ·
·          table     a@primary  ·                ·
·          spans     ALL        ·                ·

query TTTTT
EXPLAIN (VERBOSE) SELECT u * v + v AS r FROM (SELECT x + 3, y + 10 FROM a) AS foo(u, v)
----
render          ·         ·                                       (r)                       ·
 │              render 0  "?column?" + ("?column?" * "?column?")  ·                         ·
 └── render     ·         ·                                       ("?column?", "?column?")  ·
      │         render 0  x + 3                                   ·                         ·
      │         render 1  y + 10                                  ·                         ·
      └── scan  ·         ·                                       (x, y)                    ·
·               table     a@primary                               ·                         ·
·               spans     ALL                                     ·                         ·

query TTTTT
EXPLAIN (VERBOSE) SELECT x, x, y, x FROM a
----
render     ·         ·          (x, x, y, x)  ·
 │         render 0  x          ·             ·
 │         render 1  x          ·             ·
 │         render 2  y          ·             ·
 │         render 3  x          ·             ·
 └── scan  ·         ·          (x, y)        ·
·          table     a@primary  ·             ·
·          spans     ALL        ·             ·

query TTTTT
EXPLAIN (VERBOSE) SELECT x + 1 AS a, x + y AS b FROM a WHERE x + y > 20
----
render     ·         ·             (a, b)  ·
 │         render 0  x + 1         ·       ·
 │         render 1  x + y         ·       ·
 └── scan  ·         ·             (x, y)  ·
·          table     a@primary     ·       ·
·          spans     ALL           ·       ·
·          filter    (x + y) > 20  ·       ·

statement ok
DROP TABLE a

# ------------------------------------------------------------------------------
# Test with a hidden column.
# ------------------------------------------------------------------------------
statement ok
CREATE TABLE b (x INT, y INT);

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM b
----
scan  ·      ·          (x, y)  ·
·     table  b@primary  ·       ·
·     spans  ALL        ·       ·

query TTTTT
EXPLAIN (VERBOSE) SELECT x, y, rowid FROM b WHERE rowid > 0
----
scan  ·      ·          (x, y, rowid[hidden])  ·
·     table  b@primary  ·                      ·
·     spans  /1-        ·                      ·

statement ok
DROP TABLE b

# ------------------------------------------------------------------------------
# Test with storing columns.
# ------------------------------------------------------------------------------
statement ok
CREATE TABLE t (
  a INT PRIMARY KEY,
  b INT,
  c INT,
  d INT,
  INDEX b_idx (b) STORING (c, d),
  UNIQUE INDEX c_idx (c) STORING (b, d)
)

query TTBITTBB colnames
SHOW INDEXES FROM t
----
table_name  index_name  non_unique  seq_in_index  column_name  direction  storing  implicit
t           primary     false       1             a            ASC        false    false
t           b_idx       true        1             b            ASC        false    false
t           b_idx       true        2             c            N/A        true     false
t           b_idx       true        3             d            N/A        true     false
t           b_idx       true        4             a            ASC        false    true
t           c_idx       false       1             c            ASC        false    false
t           c_idx       false       2             b            N/A        true     false
t           c_idx       false       3             d            N/A        true     false
t           c_idx       false       4             a            ASC        false    true

statement ok
INSERT INTO t VALUES (1, 2, 3, 4)

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

query T
SELECT message FROM [SHOW KV TRACE FOR SESSION]
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
----
fetched: /t/b_idx/2/1/c/d -> /3/4
output row: [1 2 3 4]

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

query T
SELECT message FROM [SHOW KV TRACE FOR SESSION]
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
----
fetched: /t/c_idx/3/b/d -> /2/4
output row: [1 2 3 4]

# Test index backfill for UNIQUE and non-UNIQUE indexes with STORING columns.

statement ok
CREATE INDEX d_idx ON t (d) STORING (b)

statement ok
SET tracing = on,kv,results; SELECT a, b, d FROM t@d_idx; SET tracing = off

query T
SELECT message FROM [SHOW KV TRACE FOR SESSION]
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
----
fetched: /t/d_idx/4/1/b -> /2
output row: [1 2 4]

statement ok
CREATE UNIQUE INDEX a_idx ON t (a) STORING (b)

statement ok
SET tracing = on,kv,results; SELECT a, b FROM t@a_idx; SET tracing = off

query T
SELECT message FROM [SHOW KV TRACE FOR SESSION]
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
----
fetched: /t/a_idx/1/b -> /2
output row: [1 2]

# Test that unspecified storing values are treated like NULL values.
statement ok
INSERT INTO t (a) VALUES (2)

statement ok
INSERT INTO t VALUES (3)

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

query T
SELECT message FROM [SHOW KV TRACE FOR SESSION]
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
----
fetched: /t/b_idx/NULL/2 -> NULL
output row: [2 NULL NULL NULL]
fetched: /t/b_idx/NULL/3 -> NULL
output row: [3 NULL NULL NULL]
fetched: /t/b_idx/2/1/c/d -> /3/4
output row: [1 2 3 4]

# Regression test for #14601.

statement ok
CREATE TABLE t14601 (a STRING, b BOOL)

statement ok
CREATE INDEX i14601 ON t14601 (a) STORING (b)

query TTT
EXPLAIN SELECT a FROM t14601 ORDER BY a
----
scan  ·      ·
·     table  t14601@i14601
·     spans  ALL

# Updates were broken too.

statement ok
CREATE TABLE t14601a (
  a STRING,
  b BOOL,
  c INT,
  FAMILY f1 (a),
  FAMILY f2 (b),
  FAMILY f3 (c)
)

statement ok
CREATE INDEX i14601a ON t14601a (a) STORING (b, c)

query TTT
EXPLAIN SELECT a, b FROM t14601a ORDER BY a
----
scan  ·      ·
·     table  t14601a@i14601a
·     spans  ALL

statement ok
DROP index i14601a

statement ok
CREATE UNIQUE INDEX i14601a ON t14601a (a) STORING (b)

query TTT
EXPLAIN SELECT a, b FROM t14601a ORDER BY a
----
scan  ·      ·
·     table  t14601a@i14601a
·     spans  ALL

statement ok
DROP TABLE t; DROP TABLE t14601; DROP TABLE t14601a

# ------------------------------------------------------------------------------
# String inequality filter.
# ------------------------------------------------------------------------------
statement ok
CREATE TABLE c (n INT PRIMARY KEY, str STRING, INDEX str(str DESC));

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM c WHERE str >= 'moo'
----
scan  ·      ·                  (n, str)  ·
·     table  c@str              ·         ·
·     spans  -/"moo"/PrefixEnd  ·         ·

statement ok
DROP TABLE c

# ------------------------------------------------------------------------------
# "*" must expand to zero columns if there are zero columns to select.
# ------------------------------------------------------------------------------
statement ok
CREATE TABLE nocols(x INT); ALTER TABLE nocols DROP COLUMN x

query TTTTT
EXPLAIN (VERBOSE) SELECT 1 AS a, * FROM nocols
----
render     ·         ·               (a)  ·
 │         render 0  1               ·    ·
 └── scan  ·         ·               ()   ·
·          table     nocols@primary  ·    ·
·          spans     ALL             ·    ·

statement ok
DROP TABLE nocols

# ------------------------------------------------------------------------------
# Ensure that index is used when indexed column has collation.
# ------------------------------------------------------------------------------
statement ok
CREATE TABLE coll (
  a STRING COLLATE da,
  b INT,
  c BOOL,
  PRIMARY KEY (a, b),
  INDEX (b, a) STORING (c)
)

query TTTTT
EXPLAIN (TYPES) SELECT a, b FROM coll ORDER BY a, b
----
scan  ·      ·             (a collatedstring{da}, b int)  +a,+b
·     table  coll@primary  ·                              ·
·     spans  ALL           ·                              ·

query TTTTT
EXPLAIN (TYPES) SELECT b, a FROM coll ORDER BY b, a
----
render     ·         ·                        (b int, a collatedstring{da})  ·
 │         render 0  (b)[int]                 ·                              ·
 │         render 1  (a)[collatedstring{da}]  ·                              ·
 └── scan  ·         ·                        (a collatedstring{da}, b int)  +b,+a
·          table     coll@coll_b_a_idx        ·                              ·
·          spans     ALL                      ·                              ·

statement ok
DROP TABLE coll

# ------------------------------------------------------------------------------
# Ensure correct index is used when indexed column is computed.
# ------------------------------------------------------------------------------
statement ok
CREATE TABLE computed (
  k INT PRIMARY KEY,
  a JSON,
  b TEXT AS (a->>'q') STORED,
  INDEX (b)
)

query TTTTT
EXPLAIN (TYPES) SELECT b FROM computed ORDER BY b
----
scan  ·      ·                        (b string)  +b
·     table  computed@computed_b_idx  ·           ·
·     spans  ALL                      ·           ·

statement ok
DROP TABLE computed

# ------------------------------------------------------------------------------
# Ensure that Select filter probes expected date/time key/values that are in
# different column families.
# ------------------------------------------------------------------------------
statement ok
CREATE TABLE dt (
  a TIMESTAMP PRIMARY KEY,
  b DATE,
  c INTERVAL,
  UNIQUE (b),
  UNIQUE (c),
  FAMILY (a),
  FAMILY (b),
  FAMILY (c)
)

statement ok
INSERT INTO dt VALUES
  ('2015-08-30 03:34:45.34567', '2015-08-30', '34h2s'),
  ('2015-08-25 04:45:45.53453', '2015-08-25', '2h45m2s234ms'),
  ('2015-08-29 23:10:09.98763', '2015-08-29', '234h45m2s234ms')

statement ok
SET tracing = on,kv,results; SELECT * FROM dt WHERE a = '2015-08-25 04:45:45.53453+02:00'::timestamp; SET tracing = off

query T
SELECT message FROM [SHOW KV TRACE FOR SESSION]
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
----
fetched: /dt/primary/'2015-08-25 04:45:45.53453+00:00' -> NULL
fetched: /dt/primary/'2015-08-25 04:45:45.53453+00:00'/b -> '2015-08-25'
fetched: /dt/primary/'2015-08-25 04:45:45.53453+00:00'/c -> '02:45:02.234'
output row: ['2015-08-25 04:45:45.53453+00:00' '2015-08-25' '02:45:02.234']

statement ok
SET tracing = on,kv,results; SELECT b FROM dt WHERE b < '2015-08-29'::date; SET tracing = off

query T
SELECT message FROM [SHOW KV TRACE FOR SESSION]
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
----
fetched: /dt/dt_b_key/'2015-08-25' -> /'2015-08-25 04:45:45.53453+00:00'
output row: ['2015-08-25']

statement ok
SET tracing = on,kv,results; SELECT c FROM dt WHERE c < '234h45m2s234ms'::interval; SET tracing = off

query T
SELECT message FROM [SHOW KV TRACE FOR SESSION]
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
----
fetched: /dt/dt_c_key/'02:45:02.234' -> /'2015-08-25 04:45:45.53453+00:00'
output row: ['02:45:02.234']
fetched: /dt/dt_c_key/'34:00:02' -> /'2015-08-30 03:34:45.34567+00:00'
output row: ['34:00:02']

statement ok
DROP TABLE dt

# ------------------------------------------------------------------------------
# Ensure that decimal values result in correct scan spans.
# ------------------------------------------------------------------------------
statement ok
CREATE TABLE dec (d decimal, v decimal(3, 1), primary key (d, v))

query TTTTT
EXPLAIN (TYPES) SELECT * FROM dec WHERE d IS NaN and v IS NaN
----
scan  ·      ·                    (d decimal, v decimal)  ·
·     table  dec@primary          ·                       ·
·     spans  /NaN/NaN-/NaN/NaN/#  ·                       ·

# The NaN suffix is decimalNaNDesc, not decimalNaN(Asc).
query TTTTT
EXPLAIN (TYPES) SELECT * FROM dec WHERE d = 'Infinity' and v = 'Infinity'
----
scan  ·      ·                                        (d decimal, v decimal)  ·
·     table  dec@primary                              ·                       ·
·     spans  /Infinity/Infinity-/Infinity/Infinity/#  ·                       ·

query TTTTT
EXPLAIN (TYPES) SELECT * FROM dec WHERE d = '-Infinity' and v = '-Infinity'
----
scan  ·      ·                                            (d decimal, v decimal)  ·
·     table  dec@primary                                  ·                       ·
·     spans  /-Infinity/-Infinity-/-Infinity/-Infinity/#  ·                       ·

statement ok
DROP TABLE dec

# Test composite encoding of DECIMAL type in indexes.
statement ok
CREATE TABLE c (
  a INT PRIMARY KEY,
  b DECIMAL(2,2),
  INDEX b_idx (b)
)

statement ok
INSERT INTO c VALUES(1, 0.4)

# Test that unspecifying b is like specifying NULL.
statement ok
INSERT INTO c (a) VALUES(2)

statement ok
INSERT INTO c VALUES(3)

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

query T
SELECT message FROM [SHOW KV TRACE FOR SESSION]
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
----
fetched: /c/b_idx/NULL/2 -> NULL
output row: [2 NULL]
fetched: /c/b_idx/NULL/3 -> NULL
output row: [3 NULL]
fetched: /c/b_idx/0.4/1/b -> /0.40
output row: [1 0.40]

# ------------------------------------------------------------------------------
# Verify that lookups for Decimal NaN use indices when possible:
# - `WHERE d IS NaN` should perform a point lookup.
# - `WHERE d = 'NaN'` should also perform a point lookup.
# - `WHERE isnan(d)` is a function so it can't perform a point lookup.
# ------------------------------------------------------------------------------
statement ok
CREATE TABLE dec2 (d decimal null, index (d))

query TTTTT
EXPLAIN (TYPES) SELECT * FROM dec2 WHERE d IS NaN
----
scan  ·      ·                (d decimal)  ·
·     table  dec2@dec2_d_idx  ·            ·
·     spans  /NaN-/-Infinity  ·            ·

query TTTTT
EXPLAIN (TYPES) SELECT * FROM dec2 WHERE d = 'NaN'
----
scan  ·      ·                (d decimal)  ·
·     table  dec2@dec2_d_idx  ·            ·
·     spans  /NaN-/-Infinity  ·            ·

query TTTTT
EXPLAIN (TYPES) SELECT * FROM dec2 WHERE isnan(d)
----
scan  ·       ·                            (d decimal)  ·
·     table   dec2@primary                 ·            ·
·     spans   ALL                          ·            ·
·     filter  (isnan((d)[decimal]))[bool]  ·            ·

statement ok
DROP TABLE dec2

# ------------------------------------------------------------------------------
# Verify that lookups for Float NaN use indices when possible:
# - `WHERE f IS NaN` should perform a point lookup.
# - `WHERE f = 'NaN'` should also perform a point lookup.
# - `WHERE isnan(f)` is a function so it can't perform a point lookup.
# ------------------------------------------------------------------------------
statement ok
CREATE TABLE flt (f float null, unique index (f))

query TTTTT
EXPLAIN (TYPES) SELECT * FROM flt WHERE f IS NaN
----
scan  ·      ·                    (f float)  ·
·     table  flt@flt_f_key        ·          ·
·     spans  /NaN-/NaN/PrefixEnd  ·          ·

query TTTTT
EXPLAIN (TYPES) SELECT * FROM flt WHERE f = 'NaN'
----
scan  ·      ·                    (f float)  ·
·     table  flt@flt_f_key        ·          ·
·     spans  /NaN-/NaN/PrefixEnd  ·          ·

query TTTTT
EXPLAIN (TYPES) SELECT * FROM flt WHERE isnan(f)
----
scan  ·       ·                          (f float)  ·
·     table   flt@primary                ·          ·
·     spans   ALL                        ·          ·
·     filter  (isnan((f)[float]))[bool]  ·          ·

statement ok
DROP TABLE flt

# ------------------------------------------------------------------------------
# Verify we create the correct spans for negative numbers with extra
# operations.
# ------------------------------------------------------------------------------

statement ok
CREATE TABLE num (
  i int null,
  unique index (i),
  f float null,
  unique index (f),
  d decimal null,
  unique index (d),
  n interval null,
  unique index (n)
)

query TTTTT
EXPLAIN (TYPES) SELECT i FROM num WHERE i = -1:::INT
----
scan  ·      ·              (i int)  ·
·     table  num@num_i_key  ·        ·
·     spans  /-1-/0         ·        ·

query TTTTT
EXPLAIN (TYPES) SELECT f FROM num WHERE f = -1:::FLOAT
----
scan  ·      ·                  (f float)  ·
·     table  num@num_f_key      ·          ·
·     spans  /-1-/-1/PrefixEnd  ·          ·

query TTTTT
EXPLAIN (TYPES) SELECT d FROM num WHERE d = -1:::DECIMAL
----
scan  ·      ·                  (d decimal)  ·
·     table  num@num_d_key      ·            ·
·     spans  /-1-/-1/PrefixEnd  ·            ·

query TTTTT
EXPLAIN (TYPES) SELECT n FROM num WHERE n = -'1h':::INTERVAL
----
scan  ·      ·                            (n interval)  ·
·     table  num@num_n_key                ·             ·
·     spans  /-01:00:00-/1 day -25:00:00  ·             ·

statement ok
DROP TABLE num

# ------------------------------------------------------------------------------
# ANY, ALL tests.
# ------------------------------------------------------------------------------
statement ok
CREATE TABLE abc (a INT, b INT, c INT)

statement ok
INSERT INTO abc VALUES (1, 10, 100), (2, 20, 200), (3, 30, 300)

query III
SELECT * FROM abc WHERE a = ANY(SELECT a FROM abc WHERE b = 10)
----
1 10 100

query III
SELECT * FROM abc WHERE a < ANY(SELECT a FROM abc WHERE b = 30) ORDER BY a
----
1 10 100
2 20 200

query III
SELECT * FROM abc WHERE a > ANY(SELECT a FROM abc WHERE b = 30)
----

query III
SELECT * FROM abc WHERE a < ALL(SELECT b FROM abc) ORDER BY a
----
1 10 100
2 20 200
3 30 300

query III
SELECT * FROM abc WHERE a < ALL(SELECT a FROM abc WHERE a >= 2)
----
1 10 100

query III
SELECT * FROM abc WHERE a < ALL(SELECT a FROM abc)
----

statement ok
DROP TABLE abc

# ------------------------------------------------------------------------------
# IN tests.
# ------------------------------------------------------------------------------
# Regression tests for #22670.
query B
SELECT 1 IN (1, 2)
----
true

query B
SELECT NULL IN (1, 2)
----
NULL

query B
SELECT 1 IN (1, NULL)
----
true

query B
SELECT 1 IN (NULL, 2)
----
NULL

query B
SELECT (1, NULL) IN ((1, 1))
----
NULL

query B
SELECT (2, NULL) IN ((1, 1))
----
false

query B
SELECT (1, 1) IN ((1, NULL))
----
NULL

query B
SELECT (1, 1) IN ((2, NULL))
----
false

# Tests with a tuple coming from a subquery.
query B
SELECT NULL::int IN (SELECT * FROM (VALUES (1)) AS t(a))
----
NULL

query B
SELECT (1, NULL::int) IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b))
----
NULL

query B
SELECT (2, NULL::int) IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b))
----
false

query B
SELECT (NULL::int, 1) IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b))
----
NULL

query B
SELECT (NULL::int, 2) IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b))
----
false

query B
SELECT (NULL::int, NULL::int) IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b))
----
NULL

query B
SELECT NULL::int NOT IN (SELECT * FROM (VALUES (1)) AS t(a))
----
NULL

query B
SELECT (1, NULL::int) NOT IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b))
----
NULL

query B
SELECT (2, NULL::int) NOT IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b))
----
true

query B
SELECT (NULL::int, 1) NOT IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b))
----
NULL

query B
SELECT (NULL::int, 2) NOT IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b))
----
true

query B
SELECT (NULL::int, NULL::int) NOT IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b))
----
NULL

# Tests with an empty IN tuple.
query B
SELECT NULL::int IN (SELECT * FROM (VALUES (1)) AS t(a) WHERE a > 1)
----
false

query B
SELECT (1, NULL::int) IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b) WHERE a > 1)
----
false

query B
SELECT (NULL::int, 1) IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b) WHERE a > 1)
----
false

query B
SELECT (NULL::int, NULL::int) IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b) WHERE a > 1)
----
false

query B
SELECT NULL::int NOT IN (SELECT * FROM (VALUES (1)) AS t(a) WHERE a > 1)
----
true

query B
SELECT (1, NULL::int) NOT IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b) WHERE a > 1)
----
true

query B
SELECT (NULL::int, 1) NOT IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b) WHERE a > 1)
----
true

query B
SELECT (NULL::int, NULL::int) NOT IN (SELECT * FROM (VALUES (1, 1)) AS t(a, b) WHERE a > 1)
----
true

statement ok
CREATE TABLE abcd (a INT, b INT, c INT, d INT, PRIMARY KEY (a, b))

# Ensure that (non-top-level) render nodes get populated with the correct ordering.
query TTTTT
EXPLAIN (VERBOSE) SELECT a + x FROM (SELECT a, b + c AS x FROM abcd) ORDER BY a
----
render     ·         ·             ("?column?")  ·
 │         render 0  a + (b + c)   ·             ·
 └── scan  ·         ·             (a, b, c)     +a
·          table     abcd@primary  ·             ·
·          spans     ALL           ·             ·

query TTTTT
EXPLAIN (VERBOSE) SELECT a + x FROM (SELECT a, b, a + b + c AS x FROM abcd) ORDER BY b
----
render               ·         ·                  ("?column?")     ·
 │                   render 0  "?column?"         ·                ·
 └── sort            ·         ·                  ("?column?", b)  +b
      │              order     +b                 ·                ·
      └── render     ·         ·                  ("?column?", b)  ·
           │         render 0  a + (c + (a + b))  ·                ·
           │         render 1  b                  ·                ·
           └── scan  ·         ·                  (a, b, c)        ·
·                    table     abcd@primary       ·                ·
·                    spans     ALL                ·                ·


query TTTTT
EXPLAIN (VERBOSE) SELECT a + x FROM (SELECT a, b, a + b + c AS x FROM abcd) ORDER BY a DESC, b DESC
----
render        ·         ·                  ("?column?")  ·
 │            render 0  a + (c + (a + b))  ·             ·
 └── revscan  ·         ·                  (a, b, c)     -a,-b
·             table     abcd@primary       ·             ·
·             spans     ALL                ·             ·

# Ensure that filter nodes (and filtered scan nodes) get populated with the correct ordering.
query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM abcd WHERE a > b ORDER BY a
----
scan  ·       ·             (a, b, c, d)  +a
·     table   abcd@primary  ·             ·
·     spans   ALL           ·             ·
·     filter  a > b         ·             ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM abcd WHERE a > b ORDER BY a DESC, b DESC
----
sort       ·       ·             (a, b, c, d)  -a,-b
 │         order   -a,-b         ·             ·
 └── scan  ·       ·             (a, b, c, d)  ·
·          table   abcd@primary  ·             ·
·          spans   ALL           ·             ·
·          filter  a > b         ·             ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM (SELECT a, b FROM abcd LIMIT 10) WHERE a > b ORDER BY a
----
filter     ·       ·             (a, b)  +a
 │         filter  a > b         ·       ·
 └── scan  ·       ·             (a, b)  +a
·          table   abcd@primary  ·       ·
·          spans   ALL           ·       ·
·          limit   10            ·       ·

query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM (SELECT a, a+b+c AS x FROM (SELECT * FROM abcd LIMIT 10)) WHERE x > 100 ORDER BY a
----
render          ·         ·                    (a, x)     ·
 │              render 0  a                    ·          ·
 │              render 1  c + (a + b)          ·          ·
 └── filter     ·         ·                    (a, b, c)  +a
      │         filter    (c + (a + b)) > 100  ·          ·
      └── scan  ·         ·                    (a, b, c)  +a
·               table     abcd@primary         ·          ·
·               spans     ALL                  ·          ·
·               limit     10                   ·          ·

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

# Verify the scan is configured with the correct ordering +x,+y,+z (#31882).
query TTTTT
EXPLAIN (VERBOSE) SELECT * FROM (SELECT * FROM xyz LIMIT 10) WHERE y = 1 ORDER BY x, y, z
----
filter     ·       ·                  (x, y, z)  +x,+z
 │         filter  y = 1              ·          ·
 └── scan  ·       ·                  (x, y, z)  +x,+y,+z
·          table   xyz@xyz_x_y_z_idx  ·          ·
·          spans   ALL                ·          ·
·          limit   10                 ·          ·

# ------------------------------------------------------
# Verify that multi-span point lookups are parallelized.
# ------------------------------------------------------
statement ok
CREATE TABLE a (a INT PRIMARY KEY, item STRING, price FLOAT, UNIQUE INDEX item (item), UNIQUE INDEX p (price))

statement ok
CREATE TABLE b (a INT, b INT, c INT NULL, d INT NULL, PRIMARY KEY (a, b))

# No parallel line printed out for single-span selects.
query TTT
EXPLAIN SELECT * FROM a WHERE a = 10
----
scan  ·         ·
·     table     a@primary
·     spans     /10-/10/#

query TTT
EXPLAIN SELECT * FROM a WHERE a = 10 OR a = 20
----
scan  ·         ·
·     table     a@primary
·     spans     /10-/10/# /20-/20/#
·     parallel  ·

query TTT
EXPLAIN SELECT * FROM a WHERE a IN (10, 20)
----
scan  ·         ·
·     table     a@primary
·     spans     /10-/10/# /20-/20/#
·     parallel  ·

# Verify that consolidated point spans are still parallelized.
query TTT
EXPLAIN SELECT * FROM a WHERE a in (10, 11)
----
scan  ·         ·
·     table     a@primary
·     spans     /10-/11/#
·     parallel  ·

query TTT
EXPLAIN SELECT * FROM a WHERE a > 10 AND a < 20
----
scan  ·         ·
·     table     a@primary
·     spans     /11-/19/#
·     parallel  ·

# This ticks all the boxes for parallelization apart from the fact that there
# is no end key in the span.
query TTT
EXPLAIN SELECT * FROM a WHERE a > 10
----
scan  ·         ·
·     table     a@primary
·     spans     /11-

# Test non-int types.

# Point queries on non-int types are parallel.
query TTT
EXPLAIN SELECT price FROM a WHERE item IN ('sock', 'ball')
----
render           ·         ·
 └── index-join  ·         ·
      │          table     a@primary
      └── scan   ·         ·
·                table     a@item
·                spans     /"ball"-/"ball"/PrefixEnd /"sock"-/"sock"/PrefixEnd
·                parallel  ·

# Range queries on non-int types are not parallel due to unbounded number of
# results.
query TTT
EXPLAIN SELECT item FROM a WHERE price > 5 AND price < 10 OR price > 20 AND price < 40
----
render           ·       ·
 └── index-join  ·       ·
      │          table   a@primary
      └── scan   ·       ·
·                table   a@p
·                spans   /5.000000000000001-/9.999999999999998/PrefixEnd /20.000000000000004-/39.99999999999999/PrefixEnd
·                filter  (price < 10.0) OR (price > 20.0)

statement ok
SET CLUSTER SETTING sql.parallel_scans.enabled = false

query TTT
EXPLAIN SELECT * FROM a WHERE a IN (10, 20)
----
scan  ·         ·
·     table     a@primary
·     spans     /10-/10/# /20-/20/#

statement ok
SET CLUSTER SETTING sql.parallel_scans.enabled = true

# TODO(radu): fix this testcase after #31614 is resolved. There should be no filter left.
query TTT
EXPLAIN SELECT * FROM b WHERE (a = 10 AND b = 10) OR (a = 20 AND b = 20)
----
scan  ·         ·
·     table     b@primary
·     spans     /10/10-/10/10/# /20/20-/20/20/#
·     parallel  ·
·     filter    ((a = 10) AND (b = 10)) OR ((a = 20) AND (b = 20))

# This one isn't parallelizable because it's not a point lookup - only part of
# the primary key is specified.
query TTT
EXPLAIN SELECT * FROM b WHERE a = 10 OR a = 20
----
scan  ·      ·
·     table  b@primary
·     spans  /10-/11 /20-/21

# This one isn't parallelizable because it has a LIMIT clause.
query TTT
EXPLAIN SELECT * FROM a WHERE a = 10 OR a = 20 LIMIT 1
----
scan  ·      ·
·     table  a@primary
·     spans  /10-/10/# /20-/20/#
·     limit  1

statement ok
CREATE INDEX on b(b) STORING (c)

# This one isn't parallelizable because its index isn't unique.
query TTT
EXPLAIN SELECT b FROM b WHERE b = 10 OR b = 20
----
scan  ·      ·
·     table  b@b_b_idx
·     spans  /10-/11 /20-/21

statement ok
CREATE UNIQUE INDEX on b(c)

# If the index has nullable values, parallelize only when the spans do not
# specify any nulls.
query TTT
EXPLAIN SELECT c FROM b WHERE c = 10 OR c = 20
----
scan  ·         ·
·     table     b@b_c_key
·     spans     /10-/11 /20-/21
·     parallel  ·

query TTT
EXPLAIN SELECT c FROM b WHERE c = 10 OR c < 2
----
scan  ·      ·
·     table  b@b_c_key
·     spans  /!NULL-/2 /10-/11

statement ok
CREATE UNIQUE INDEX on b(d DESC)

# This scan is not parallelizable because the second span has a null in its end
# key.
query TTT
EXPLAIN SELECT d FROM b WHERE d = 10 OR d < 2
----
scan  ·      ·
·     table  b@b_d_key
·     spans  /10-/9 /1-/NULL

statement ok
CREATE UNIQUE INDEX ON b(c, d)

# This scan is not parallelizable because although the second column is
# constrained, the first column is null.
query TTT
EXPLAIN SELECT d FROM b WHERE c = 10 AND d = 10 OR c IS NULL AND d > 0 AND d < 2
----
render     ·       ·
 └── scan  ·       ·
·          table   b@b_c_d_key
·          spans   /NULL/1-/NULL/2 /10/10-/10/11
·          filter  ((c = 10) AND (d = 10)) OR ((c IS NULL) AND (d < 2))

statement ok
DROP INDEX b_b_idx

statement ok
CREATE UNIQUE INDEX on b(b) STORING (c)

# This one is parallelizable because its index is unique and non-null.
query TTT
EXPLAIN SELECT b FROM b WHERE b = 10 OR b = 20
----
scan  ·         ·
·     table     b@b_b_key
·     spans     /10-/11 /20-/21
·     parallel  ·

statement ok
ALTER TABLE a SPLIT AT VALUES(5)

# Run a select to prime the range cache to simplify the trace below.
statement ok
SELECT * FROM a

# Make sure that the scan actually gets parallelized.
statement ok
SET tracing = on; SELECT * FROM a WHERE a = 0 OR a = 10; SET tracing = off

# The span "sending partial batch" means that the scan was parallelized.
# If this test is failing and doesn't have that span, it means that the scanNode
# was improperly configured to add a limit to the ScanRequest batch.
# See #30943 for more details.
query T
SELECT message FROM [SHOW TRACE FOR SESSION]
WHERE message IN
    ('querying next range at /Table/73/1/0',
     'querying next range at /Table/73/1/10',
     '=== SPAN START: kv.DistSender: sending partial batch ==='
    )
----
querying next range at /Table/73/1/0
=== SPAN START: kv.DistSender: sending partial batch ===
querying next range at /Table/73/1/10
