# LogicTest: local

# Prepare a trace to be inspected below.

# TODO(yuzefovich): clean up the tracing in the vectorized engine and remove
# adjustment of vectorize mode (#55821).
statement ok
SET vectorize=off; SET tracing = on

statement ok
BEGIN; SELECT 1; COMMIT; SELECT 2

statement ok
SET tracing = off; RESET vectorize

# 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
1   === SPAN START: session tracing ===                  session tracing
1   [Open pos:?] executing Sync                          session tracing
2   === SPAN START: commit sql txn ===                   commit sql txn
0   [NoTxn pos:?] executing ExecStmt: BEGIN TRANSACTION  session recording
3   === SPAN START: sql txn ===                          sql txn
3   [Open pos:?] executing ExecStmt: SELECT 1            sql txn
4   === SPAN START: sql query ===                        sql query
5   === SPAN START: optimizer ===                        optimizer
6   === SPAN START: consuming rows ===                   consuming rows
7   === SPAN START: flow ===                             flow
8   === SPAN START: values ===                           values
3   [Open pos:?] executing ExecStmt: COMMIT TRANSACTION  sql txn
9   === SPAN START: sql query ===                        sql query
10  === SPAN START: commit sql txn ===                   commit sql txn
0   [NoTxn pos:?] executing ExecStmt: SELECT 2           session recording
11  === SPAN START: sql txn ===                          sql txn
11  [Open pos:?] executing ExecStmt: SELECT 2            sql txn
12  === SPAN START: sql query ===                        sql query
13  === SPAN START: optimizer ===                        optimizer
14  === SPAN START: consuming rows ===                   consuming rows
15  === SPAN START: flow ===                             flow
16  === SPAN START: values ===                           values
17  === SPAN START: commit sql txn ===                   commit sql txn
0   [NoTxn pos:?] executing Sync                         session recording
0   [NoTxn pos:?] executing ExecStmt: SET TRACING = off  session recording

statement ok
CREATE TABLE num_ref (a INT PRIMARY KEY, xx INT, b INT, c INT, INDEX bc (b,c))

let $t_id
SELECT id FROM system.namespace WHERE name='num_ref'

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

let $t_id2
SELECT id FROM system.namespace WHERE name='num_ref_hidden'

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 T
EXPLAIN (VERBOSE) SELECT * FROM [$t_id AS num_ref_alias]
----
distribution: local
vectorized: true
·
• scan
  columns: (p, d, c)
  estimated row count: 1,000 (missing stats)
  table: num_ref@num_ref_pkey
  spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT * FROM [$t_id(4) AS num_ref_alias]
----
distribution: local
vectorized: true
·
• scan
  columns: (c)
  estimated row count: 1,000 (missing stats)
  table: num_ref@num_ref_pkey
  spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT * FROM [$t_id(1,4) AS num_ref_alias]
----
distribution: local
vectorized: true
·
• scan
  columns: (p, c)
  estimated row count: 1,000 (missing stats)
  table: num_ref@num_ref_pkey
  spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT * FROM [$t_id(1,3,4) AS num_ref_alias]
----
distribution: local
vectorized: true
·
• scan
  columns: (p, d, c)
  estimated row count: 1,000 (missing stats)
  table: num_ref@num_ref_pkey
  spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT * FROM [$t_id(4,3,1) AS num_ref_alias]
----
distribution: local
vectorized: true
·
• scan
  columns: (c, d, p)
  estimated row count: 1,000 (missing stats)
  table: num_ref@num_ref_pkey
  spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT * FROM [$t_id(4,3,1) AS num_ref_alias(col1,col2,col3)]
----
distribution: local
vectorized: true
·
• scan
  columns: (col1, col2, col3)
  estimated row count: 1,000 (missing stats)
  table: num_ref@num_ref_pkey
  spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT * FROM [$t_id(4,3,1) AS num_ref_alias]@bc
----
distribution: local
vectorized: true
·
• scan
  columns: (c, d, p)
  estimated row count: 1,000 (missing stats)
  table: num_ref@bc
  spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT * FROM [$t_id(4) AS num_ref_alias]@bc
----
distribution: local
vectorized: true
·
• scan
  columns: (c)
  estimated row count: 1,000 (missing stats)
  table: num_ref@bc
  spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT * FROM [$t_id(3) AS num_ref_alias]@bc
----
distribution: local
vectorized: true
·
• scan
  columns: (d)
  estimated row count: 1,000 (missing stats)
  table: num_ref@bc
  spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT * FROM [$t_id(1) AS num_ref_alias]@bc
----
distribution: local
vectorized: true
·
• scan
  columns: (p)
  estimated row count: 1,000 (missing stats)
  table: num_ref@bc
  spans: FULL SCAN

let $num_ref_bc
SELECT index_id
  FROM crdb_internal.table_indexes
 WHERE descriptor_id = $t_id AND index_name = 'bc';

let $num_ref_pkey
SELECT index_id
  FROM crdb_internal.table_indexes
 WHERE descriptor_id = $t_id AND index_name = 'num_ref_pkey';

query T
EXPLAIN (VERBOSE) SELECT * FROM [$t_id(1) AS num_ref_alias]@[$num_ref_pkey]
----
distribution: local
vectorized: true
·
• scan
  columns: (p)
  estimated row count: 1,000 (missing stats)
  table: num_ref@num_ref_pkey
  spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT * FROM [$t_id(1) AS num_ref_alias]@[$num_ref_bc]
----
distribution: local
vectorized: true
·
• scan
  columns: (p)
  estimated row count: 1,000 (missing stats)
  table: num_ref@bc
  spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT * FROM [$t_id(3) AS num_ref_alias]@[$num_ref_pkey]
----
distribution: local
vectorized: true
·
• scan
  columns: (d)
  estimated row count: 1,000 (missing stats)
  table: num_ref@num_ref_pkey
  spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT * FROM [$t_id(3) AS num_ref_alias]@[$num_ref_bc]
----
distribution: local
vectorized: true
·
• scan
  columns: (d)
  estimated row count: 1,000 (missing stats)
  table: num_ref@bc
  spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT * FROM [$t_id(4) AS num_ref_alias]@[$num_ref_pkey]
----
distribution: local
vectorized: true
·
• scan
  columns: (c)
  estimated row count: 1,000 (missing stats)
  table: num_ref@num_ref_pkey
  spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT * FROM [$t_id(4) AS num_ref_alias]@[$num_ref_bc]
----
distribution: local
vectorized: true
·
• scan
  columns: (c)
  estimated row count: 1,000 (missing stats)
  table: num_ref@bc
  spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT * FROM [$t_id2(1,3) AS num_ref_alias]
----
distribution: local
vectorized: true
·
• scan
  columns: (a)
  estimated row count: 1,000 (missing stats)
  table: num_ref_hidden@num_ref_hidden_pkey
  spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT * FROM [$t_id2(3) AS num_ref_alias]
----
distribution: local
vectorized: true
·
• scan
  columns: ()
  estimated row count: 1,000 (missing stats)
  table: num_ref_hidden@num_ref_hidden_pkey
  spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT rowid FROM [$t_id2(3) AS num_ref_alias]
----
distribution: local
vectorized: true
·
• scan
  columns: (rowid)
  estimated row count: 1,000 (missing stats)
  table: num_ref_hidden@num_ref_hidden_pkey
  spans: FULL SCAN

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 [$t_id(666) AS num_ref_alias]

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

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

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

statement ok
DROP TABLE num_ref

query error pq: \[\d+\(1\) AS num_ref_alias\]: descriptor is being dropped
EXPLAIN (VERBOSE) SELECT * FROM [$t_id(1) AS num_ref_alias]

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

query T
EXPLAIN (VERBOSE) SELECT * FROM a WHERE x > 1
----
distribution: local
vectorized: true
·
• scan
  columns: (x, y)
  estimated row count: 333 (missing stats)
  table: a@a_pkey
  spans: /2-

query T
EXPLAIN (VERBOSE) SELECT * FROM a WHERE y > 10
----
distribution: local
vectorized: true
·
• filter
│ columns: (x, y)
│ estimated row count: 333 (missing stats)
│ filter: y > 10
│
└── • scan
      columns: (x, y)
      estimated row count: 1,000 (missing stats)
      table: a@a_pkey
      spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT * FROM a WHERE x > 1 AND x < 3
----
distribution: local
vectorized: true
·
• scan
  columns: (x, y)
  estimated row count: 1 (missing stats)
  table: a@a_pkey
  spans: /2/0

query T
EXPLAIN (VERBOSE) SELECT * FROM a WHERE x > 1 AND y < 30
----
distribution: local
vectorized: true
·
• filter
│ columns: (x, y)
│ estimated row count: 311 (missing stats)
│ filter: y < 30
│
└── • scan
      columns: (x, y)
      estimated row count: 333 (missing stats)
      table: a@a_pkey
      spans: /2-

query T
EXPLAIN (VERBOSE) SELECT x + 1 AS r FROM a
----
distribution: local
vectorized: true
·
• render
│ columns: (r)
│ render r: x + 1
│
└── • scan
      columns: (x)
      estimated row count: 1,000 (missing stats)
      table: a@a_pkey
      spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT x AS a, x + 1 AS b, y, y + 1 AS c, x + y AS d FROM a
----
distribution: local
vectorized: true
·
• render
│ columns: (a, b, y, c, d)
│ render b: x + 1
│ render c: y + 1
│ render d: x + y
│ render x: x
│ render y: y
│
└── • scan
      columns: (x, y)
      estimated row count: 1,000 (missing stats)
      table: a@a_pkey
      spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT u * v + v AS r FROM (SELECT x + 3, y + 10 FROM a) AS foo(u, v)
----
distribution: local
vectorized: true
·
• render
│ columns: (r)
│ render r: "?column?" + ("?column?" * "?column?")
│
└── • render
    │ columns: ("?column?", "?column?")
    │ render ?column?: x + 3
    │ render ?column?: y + 10
    │
    └── • scan
          columns: (x, y)
          estimated row count: 1,000 (missing stats)
          table: a@a_pkey
          spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT x, x, y, x FROM a
----
distribution: local
vectorized: true
·
• project
│ columns: (x, x, y, x)
│
└── • scan
      columns: (x, y)
      estimated row count: 1,000 (missing stats)
      table: a@a_pkey
      spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT x + 1 AS a, x + y AS b FROM a WHERE x + y > 20
----
distribution: local
vectorized: true
·
• render
│ columns: (a, b)
│ render a: x + 1
│ render b: x + y
│
└── • filter
    │ columns: (x, y)
    │ estimated row count: 333 (missing stats)
    │ filter: (x + y) > 20
    │
    └── • scan
          columns: (x, y)
          estimated row count: 1,000 (missing stats)
          table: a@a_pkey
          spans: FULL SCAN

statement ok
DROP TABLE a

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

query T
EXPLAIN (VERBOSE) SELECT * FROM b
----
distribution: local
vectorized: true
·
• scan
  columns: (x, y)
  estimated row count: 1,000 (missing stats)
  table: b@b_pkey
  spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT x, y, rowid FROM b WHERE rowid > 0
----
distribution: local
vectorized: true
·
• scan
  columns: (x, y, rowid)
  estimated row count: 333 (missing stats)
  table: b@b_pkey
  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),
  FAMILY (a, b, c, d)
)

query TTBITTTBBBF colnames,rowsort
SHOW INDEXES FROM t
----
table_name  index_name  non_unique  seq_in_index  column_name  definition  direction  storing  implicit  visible  visibility
t           b_idx       true        1             b            b           ASC        false    false     true     1
t           b_idx       true        2             c            c           N/A        true     false     true     1
t           b_idx       true        3             d            d           N/A        true     false     true     1
t           b_idx       true        4             a            a           ASC        false    true      true     1
t           c_idx       false       1             c            c           ASC        false    false     true     1
t           c_idx       false       2             b            b           N/A        true     false     true     1
t           c_idx       false       3             d            d           N/A        true     false     true     1
t           c_idx       false       4             a            a           ASC        true     true      true     1
t           t_pkey      false       1             a            a           ASC        false    false     true     1
t           t_pkey      false       2             b            b           N/A        true     false     true     1
t           t_pkey      false       3             c            c           N/A        true     false     true     1
t           t_pkey      false       4             d            d           N/A        true     false     true     1

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] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 ORDER BY message LIKE 'fetched:%' DESC, ordinality ASC
----
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] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 ORDER BY message LIKE 'fetched:%' DESC, ordinality ASC
----
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] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 ORDER BY message LIKE 'fetched:%' DESC, ordinality ASC
----
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] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 ORDER BY message LIKE 'fetched:%' DESC, ordinality ASC
----
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] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 ORDER BY message LIKE 'fetched:%' DESC, ordinality ASC
----
fetched: /t/b_idx/NULL/2 -> <undecoded>
fetched: /t/b_idx/NULL/3 -> <undecoded>
fetched: /t/b_idx/2/1/c/d -> /3/4
output row: [2 NULL NULL NULL]
output row: [3 NULL NULL NULL]
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 T
EXPLAIN SELECT a FROM t14601 ORDER BY a
----
distribution: local
vectorized: true
·
• scan
  missing stats
  table: t14601@i14601
  spans: FULL SCAN

# 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 T
EXPLAIN SELECT a, b FROM t14601a ORDER BY a
----
distribution: local
vectorized: true
·
• scan
  missing stats
  table: t14601a@i14601a
  spans: FULL SCAN

statement ok
DROP index i14601a

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

query T
EXPLAIN SELECT a, b FROM t14601a ORDER BY a
----
distribution: local
vectorized: true
·
• scan
  missing stats
  table: t14601a@i14601a
  spans: FULL SCAN

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 T
EXPLAIN (VERBOSE) SELECT * FROM c WHERE str >= 'moo'
----
distribution: local
vectorized: true
·
• scan
  columns: (n, str)
  estimated row count: 333 (missing stats)
  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 T
EXPLAIN (VERBOSE) SELECT 1 AS a, * FROM nocols
----
distribution: local
vectorized: true
·
• render
│ columns: (a)
│ render a: 1
│
└── • scan
      columns: ()
      estimated row count: 1,000 (missing stats)
      table: nocols@nocols_pkey
      spans: FULL SCAN

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 T
EXPLAIN (TYPES) SELECT a, b FROM coll ORDER BY a, b
----
distribution: local
vectorized: true
·
• scan
  columns: (a collatedstring{da}, b int)
  ordering: +a,+b
  estimated row count: 1,000 (missing stats)
  table: coll@coll_pkey
  spans: FULL SCAN

query T
EXPLAIN (TYPES) SELECT b, a FROM coll ORDER BY b, a
----
distribution: local
vectorized: true
·
• scan
  columns: (b int, a collatedstring{da})
  ordering: +b,+a
  estimated row count: 1,000 (missing stats)
  table: coll@coll_b_a_idx
  spans: FULL SCAN

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 T
EXPLAIN (TYPES) SELECT b FROM computed ORDER BY b
----
distribution: local
vectorized: true
·
• scan
  columns: (b string)
  ordering: +b
  estimated row count: 1,000 (missing stats)
  table: computed@computed_b_idx
  spans: FULL SCAN

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] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 ORDER BY message LIKE 'fetched:%' DESC, ordinality ASC
----
fetched: /dt/dt_pkey/'2015-08-25 04:45:45.53453' -> <undecoded>
fetched: /dt/dt_pkey/'2015-08-25 04:45:45.53453'/b -> '2015-08-25'
fetched: /dt/dt_pkey/'2015-08-25 04:45:45.53453'/c -> '02:45:02.234'
output row: ['2015-08-25 04:45:45.53453' '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] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 ORDER BY message LIKE 'fetched:%' DESC, ordinality ASC
----
fetched: /dt/dt_b_key/'2015-08-25' -> /?
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] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 ORDER BY message LIKE 'fetched:%' DESC, ordinality ASC
----
fetched: /dt/dt_c_key/'02:45:02.234' -> /?
fetched: /dt/dt_c_key/'34:00:02' -> /?
output row: ['02:45:02.234']
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), family(d, v))

query T
EXPLAIN (TYPES) SELECT * FROM dec WHERE d IS NaN and v IS NaN
----
distribution: local
vectorized: true
·
• scan
  columns: (d decimal, v decimal)
  estimated row count: 1 (missing stats)
  table: dec@dec_pkey
  spans: /NaN/NaN/0

# Test again with separate column families.

statement ok
CREATE TABLE decfam (d decimal, v decimal(3, 1), primary key (d, v), family(d), family(v))

query T
EXPLAIN (TYPES) SELECT * FROM decfam WHERE d IS NaN and v IS NaN
----
distribution: local
vectorized: true
·
• scan
  columns: (d decimal, v decimal)
  estimated row count: 1 (missing stats)
  table: decfam@decfam_pkey
  spans: /NaN/NaN-/NaN/-Infinity

# The NaN suffix is decimalNaNDesc, not decimalNaN(Asc).
query T
EXPLAIN (TYPES) SELECT * FROM dec WHERE d = 'Infinity' and v = 'Infinity'
----
distribution: local
vectorized: true
·
• scan
  columns: (d decimal, v decimal)
  estimated row count: 1 (missing stats)
  table: dec@dec_pkey
  spans: /Infinity/Infinity/0

query T
EXPLAIN (TYPES) SELECT * FROM dec WHERE d = '-Infinity' and v = '-Infinity'
----
distribution: local
vectorized: true
·
• scan
  columns: (d decimal, v decimal)
  estimated row count: 1 (missing stats)
  table: dec@dec_pkey
  spans: /-Infinity/-Infinity/0

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] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 ORDER BY message LIKE 'fetched:%' DESC, ordinality ASC
----
fetched: /c/b_idx/NULL/2 -> <undecoded>
fetched: /c/b_idx/NULL/3 -> <undecoded>
fetched: /c/b_idx/0.4/1/b -> /0.40
output row: [2 NULL]
output row: [3 NULL]
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 T
EXPLAIN (TYPES) SELECT * FROM dec2 WHERE d IS NaN
----
distribution: local
vectorized: true
·
• scan
  columns: (d decimal)
  estimated row count: 10 (missing stats)
  table: dec2@dec2_d_idx
  spans: /NaN-/-Infinity

query T
EXPLAIN (TYPES) SELECT * FROM dec2 WHERE d = 'NaN'
----
distribution: local
vectorized: true
·
• scan
  columns: (d decimal)
  estimated row count: 10 (missing stats)
  table: dec2@dec2_d_idx
  spans: /NaN-/-Infinity

query T
EXPLAIN (TYPES) SELECT * FROM dec2 WHERE isnan(d)
----
distribution: local
vectorized: true
·
• filter
│ columns: (d decimal)
│ estimated row count: 330 (missing stats)
│ filter: (isnan((d)[decimal]))[bool]
│
└── • scan
      columns: (d decimal)
      estimated row count: 1,000 (missing stats)
      table: dec2@dec2_pkey
      spans: FULL SCAN

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 T
EXPLAIN (TYPES) SELECT * FROM flt WHERE f IS NaN
----
distribution: local
vectorized: true
·
• scan
  columns: (f float)
  estimated row count: 1 (missing stats)
  table: flt@flt_f_key
  spans: /NaN/0

query T
EXPLAIN (TYPES) SELECT * FROM flt WHERE f = 'NaN'
----
distribution: local
vectorized: true
·
• scan
  columns: (f float)
  estimated row count: 1 (missing stats)
  table: flt@flt_f_key
  spans: /NaN/0

query T
EXPLAIN (TYPES) SELECT * FROM flt WHERE isnan(f)
----
distribution: local
vectorized: true
·
• filter
│ columns: (f float)
│ estimated row count: 330 (missing stats)
│ filter: (isnan((f)[float]))[bool]
│
└── • scan
      columns: (f float)
      estimated row count: 1,000 (missing stats)
      table: flt@flt_pkey
      spans: FULL SCAN

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 T
EXPLAIN (TYPES) SELECT i FROM num WHERE i = -1:::INT
----
distribution: local
vectorized: true
·
• scan
  columns: (i int)
  estimated row count: 1 (missing stats)
  table: num@num_i_key
  spans: /-1/0

query T
EXPLAIN (TYPES) SELECT f FROM num WHERE f = -1:::FLOAT
----
distribution: local
vectorized: true
·
• scan
  columns: (f float)
  estimated row count: 1 (missing stats)
  table: num@num_f_key
  spans: /-1/0

query T
EXPLAIN (TYPES) SELECT d FROM num WHERE d = -1:::DECIMAL
----
distribution: local
vectorized: true
·
• scan
  columns: (d decimal)
  estimated row count: 1 (missing stats)
  table: num@num_d_key
  spans: /-1/0

query T
EXPLAIN (TYPES) SELECT n FROM num WHERE n = -'1h':::INTERVAL
----
distribution: local
vectorized: true
·
• scan
  columns: (n interval)
  estimated row count: 1 (missing stats)
  table: num@num_n_key
  spans: /-01:00:00/0

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 T
EXPLAIN (VERBOSE) SELECT a + x FROM (SELECT a, b + c AS x FROM abcd) ORDER BY a
----
distribution: local
vectorized: true
·
• project
│ columns: ("?column?")
│
└── • render
    │ columns: ("?column?", a)
    │ ordering: +a
    │ render ?column?: a + (b + c)
    │ render a: a
    │
    └── • scan
          columns: (a, b, c)
          ordering: +a
          estimated row count: 1,000 (missing stats)
          table: abcd@abcd_pkey
          spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT a + x FROM (SELECT a, b, a + b + c AS x FROM abcd) ORDER BY b
----
distribution: local
vectorized: true
·
• project
│ columns: ("?column?")
│
└── • sort
    │ columns: ("?column?", b)
    │ estimated row count: 1,000 (missing stats)
    │ order: +b
    │
    └── • render
        │ columns: ("?column?", b)
        │ render ?column?: a + (c + (a + b))
        │ render b: b
        │
        └── • scan
              columns: (a, b, c)
              estimated row count: 1,000 (missing stats)
              table: abcd@abcd_pkey
              spans: FULL SCAN


query T
EXPLAIN (VERBOSE) SELECT a + x FROM (SELECT a, b, a + b + c AS x FROM abcd) ORDER BY a DESC, b DESC
----
distribution: local
vectorized: true
·
• project
│ columns: ("?column?")
│
└── • render
    │ columns: ("?column?", a, b)
    │ ordering: -a,-b
    │ render ?column?: a + (c + (a + b))
    │ render a: a
    │ render b: b
    │
    └── • revscan
          columns: (a, b, c)
          ordering: -a,-b
          estimated row count: 1,000 (missing stats)
          table: abcd@abcd_pkey
          spans: FULL SCAN

# Ensure that filter nodes (and filtered scan nodes) get populated with the correct ordering.
query T
EXPLAIN (VERBOSE) SELECT * FROM abcd WHERE a > b ORDER BY a
----
distribution: local
vectorized: true
·
• filter
│ columns: (a, b, c, d)
│ ordering: +a
│ estimated row count: 333 (missing stats)
│ filter: a > b
│
└── • scan
      columns: (a, b, c, d)
      ordering: +a
      estimated row count: 1,000 (missing stats)
      table: abcd@abcd_pkey
      spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT * FROM abcd WHERE a > b ORDER BY a DESC, b DESC
----
distribution: local
vectorized: true
·
• filter
│ columns: (a, b, c, d)
│ ordering: -a,-b
│ estimated row count: 333 (missing stats)
│ filter: a > b
│
└── • revscan
      columns: (a, b, c, d)
      ordering: -a,-b
      estimated row count: 1,000 (missing stats)
      table: abcd@abcd_pkey
      spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT * FROM (SELECT a, b FROM abcd LIMIT 10) WHERE a > b ORDER BY a
----
distribution: local
vectorized: true
·
• filter
│ columns: (a, b)
│ ordering: +a
│ estimated row count: 3 (missing stats)
│ filter: a > b
│
└── • scan
      columns: (a, b)
      ordering: +a
      estimated row count: 10 (missing stats)
      table: abcd@abcd_pkey
      spans: LIMITED SCAN
      limit: 10

query T
EXPLAIN (VERBOSE) SELECT * FROM (SELECT a, a+b+c AS x FROM (SELECT * FROM abcd LIMIT 10)) WHERE x > 100 ORDER BY a
----
distribution: local
vectorized: true
·
• render
│ columns: (a, x)
│ ordering: +a
│ render x: c + (a + b)
│ render a: a
│
└── • filter
    │ columns: (a, b, c)
    │ ordering: +a
    │ estimated row count: 3 (missing stats)
    │ filter: (c + (a + b)) > 100
    │
    └── • scan
          columns: (a, b, c)
          ordering: +a
          estimated row count: 10 (missing stats)
          table: abcd@abcd_pkey
          spans: LIMITED SCAN
          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 T
EXPLAIN (VERBOSE) SELECT * FROM (SELECT * FROM xyz LIMIT 10) WHERE y = 1 ORDER BY x, y, z
----
distribution: local
vectorized: true
·
• filter
│ columns: (x, y, z)
│ ordering: +x,+z
│ estimated row count: 1 (missing stats)
│ filter: y = 1
│
└── • scan
      columns: (x, y, z)
      ordering: +x,+y,+z
      estimated row count: 10 (missing stats)
      table: xyz@xyz_x_y_z_idx
      spans: LIMITED SCAN
      limit: 10

# ------------------------------------------------------
# Verify that multi-span point lookups are parallelized.
# ------------------------------------------------------
statement ok
CREATE TABLE a (a INT PRIMARY KEY, item STRING, price FLOAT, FAMILY (a, item, price), 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), FAMILY (a, b, c, d))

# No parallel line printed out for single-span selects.
query T
EXPLAIN (VERBOSE) SELECT * FROM a WHERE a = 10
----
distribution: local
vectorized: true
·
• scan
  columns: (a, item, price)
  estimated row count: 1 (missing stats)
  table: a@a_pkey
  spans: /10/0

query T
EXPLAIN (VERBOSE) SELECT * FROM a WHERE a = 10 OR a = 20
----
distribution: local
vectorized: true
·
• scan
  columns: (a, item, price)
  estimated row count: 2 (missing stats)
  table: a@a_pkey
  spans: /10/0 /20/0
  parallel

query T
EXPLAIN (VERBOSE) SELECT * FROM a WHERE a IN (10, 20)
----
distribution: local
vectorized: true
·
• scan
  columns: (a, item, price)
  estimated row count: 2 (missing stats)
  table: a@a_pkey
  spans: /10/0 /20/0
  parallel

# Verify that consolidated point spans are still parallelized.
query T
EXPLAIN (VERBOSE) SELECT * FROM a WHERE a in (10, 11)
----
distribution: local
vectorized: true
·
• scan
  columns: (a, item, price)
  estimated row count: 2 (missing stats)
  table: a@a_pkey
  spans: /10-/12
  parallel

query T
EXPLAIN (VERBOSE) SELECT * FROM a WHERE a > 10 AND a < 20
----
distribution: local
vectorized: true
·
• scan
  columns: (a, item, price)
  estimated row count: 9 (missing stats)
  table: a@a_pkey
  spans: /11-/20
  parallel

# This ticks all the boxes for parallelization apart from the fact that there
# is no end key in the span.
query T
EXPLAIN (VERBOSE) SELECT * FROM a WHERE a > 10
----
distribution: local
vectorized: true
·
• scan
  columns: (a, item, price)
  estimated row count: 333 (missing stats)
  table: a@a_pkey
  spans: /11-

# Test non-int types.

# Point queries on non-int types are parallel.
query T
EXPLAIN (VERBOSE) SELECT price FROM a WHERE item IN ('sock', 'ball')
----
distribution: local
vectorized: true
·
• project
│ columns: (price)
│
└── • index join
    │ columns: (item, price)
    │ estimated row count: 2 (missing stats)
    │ table: a@a_pkey
    │ key columns: a
    │
    └── • scan
          columns: (a, item)
          estimated row count: 2 (missing stats)
          table: a@item
          spans: /"ball"/0 /"sock"/0
          parallel

# Range queries on non-int types are not parallel due to unbounded number of
# results.
query T
EXPLAIN (VERBOSE) SELECT item FROM a WHERE price > 5 AND price < 10 OR price > 20 AND price < 40
----
distribution: local
vectorized: true
·
• project
│ columns: (item)
│
└── • index join
    │ columns: (item, price)
    │ estimated row count: 110 (missing stats)
    │ table: a@a_pkey
    │ key columns: a
    │
    └── • scan
          columns: (a, price)
          estimated row count: 110 (missing stats)
          table: a@p
          spans: /5.000000000000001-/9.999999999999998/PrefixEnd /20.000000000000004-/39.99999999999999/PrefixEnd

query T
EXPLAIN (VERBOSE) SELECT * FROM b WHERE (a = 10 AND b = 10) OR (a = 20 AND b = 20)
----
distribution: local
vectorized: true
·
• scan
  columns: (a, b, c, d)
  estimated row count: 1 (missing stats)
  table: b@b_pkey
  spans: /10/10/0 /20/20/0
  parallel

# This one isn't parallelizable because it's not a point lookup - only part of
# the primary key is specified.
query T
EXPLAIN (VERBOSE) SELECT * FROM b WHERE a = 10 OR a = 20
----
distribution: local
vectorized: true
·
• scan
  columns: (a, b, c, d)
  estimated row count: 20 (missing stats)
  table: b@b_pkey
  spans: /10-/11 /20-/21

# This one isn't parallelizable because it has a LIMIT clause.
query T
EXPLAIN (VERBOSE) SELECT * FROM a WHERE a = 10 OR a = 20 LIMIT 1
----
distribution: local
vectorized: true
·
• scan
  columns: (a, item, price)
  estimated row count: 1 (missing stats)
  table: a@a_pkey
  spans: /10/0 /20/0
  limit: 1

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

# This one isn't parallelizable because its index isn't unique.
query T
EXPLAIN (VERBOSE) SELECT b FROM b WHERE b = 10 OR b = 20
----
distribution: local
vectorized: true
·
• scan
  columns: (b)
  estimated row count: 20 (missing stats)
  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 T
EXPLAIN (VERBOSE) SELECT c FROM b WHERE c = 10 OR c = 20
----
distribution: local
vectorized: true
·
• scan
  columns: (c)
  estimated row count: 2 (missing stats)
  table: b@b_c_key
  spans: /10/0 /20/0
  parallel

query T
EXPLAIN (VERBOSE) SELECT c FROM b WHERE c = 10 OR c < 2
----
distribution: local
vectorized: true
·
• scan
  columns: (c)
  estimated row count: 330 (missing stats)
  table: b@b_c_key
  spans: /!NULL-/2 /10/0

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 T
EXPLAIN (VERBOSE) SELECT d FROM b WHERE d = 10 OR d < 2
----
distribution: local
vectorized: true
·
• scan
  columns: (d)
  estimated row count: 330 (missing stats)
  table: b@b_d_key
  spans: /10/0 /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 T
EXPLAIN (VERBOSE) SELECT d FROM b WHERE c = 10 AND d = 10 OR c IS NULL AND d > 0 AND d < 2
----
distribution: local
vectorized: true
·
• project
│ columns: (d)
│
└── • scan
      columns: (c, d)
      estimated row count: 1 (missing stats)
      table: b@b_c_d_key
      spans: /NULL/1-/NULL/2 /10/10/0

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 T
EXPLAIN (VERBOSE) SELECT b FROM b WHERE b = 10 OR b = 20
----
distribution: local
vectorized: true
·
• scan
  columns: (b)
  estimated row count: 2 (missing stats)
  table: b@b_b_key
  spans: /10/0 /20/0
  parallel

# Now verify that if 'unbounded_parallel_scans' is 'true', then the scans are
# parallelized even when we don't have a small upper bound.

statement ok
SET unbounded_parallel_scans = true

# No end key in the span.
query T
EXPLAIN (VERBOSE) SELECT * FROM a WHERE a > 10
----
distribution: local
vectorized: true
·
• scan
  columns: (a, item, price)
  estimated row count: 333 (missing stats)
  table: a@a_pkey
  spans: /11-
  parallel

# Range queries have unbounded number of results.
query T
EXPLAIN (VERBOSE) SELECT item FROM a WHERE price > 5 AND price < 10 OR price > 20 AND price < 40
----
distribution: local
vectorized: true
·
• project
│ columns: (item)
│
└── • index join
    │ columns: (item, price)
    │ estimated row count: 110 (missing stats)
    │ table: a@a_pkey
    │ key columns: a
    │
    └── • scan
          columns: (a, price)
          estimated row count: 110 (missing stats)
          table: a@p
          spans: /5.000000000000001-/9.999999999999998/PrefixEnd /20.000000000000004-/39.99999999999999/PrefixEnd
          parallel

# Only part of the primary key is specified.
query T
EXPLAIN (VERBOSE) SELECT * FROM b WHERE a = 10 OR a = 20
----
distribution: local
vectorized: true
·
• scan
  columns: (a, b, c, d)
  estimated row count: 20 (missing stats)
  table: b@b_pkey
  spans: /10-/11 /20-/21
  parallel

# Still not parallelizable because it has a LIMIT clause.
query T
EXPLAIN (VERBOSE) SELECT * FROM a WHERE a = 10 OR a = 20 LIMIT 1
----
distribution: local
vectorized: true
·
• scan
  columns: (a, item, price)
  estimated row count: 1 (missing stats)
  table: a@a_pkey
  spans: /10/0 /20/0
  limit: 1

# NULLs at the span boundaries prevent us from putting a bound on the row count.
query T
EXPLAIN (VERBOSE) SELECT c FROM b WHERE c = 10 OR c < 2
----
distribution: local
vectorized: true
·
• scan
  columns: (c)
  estimated row count: 330 (missing stats)
  table: b@b_c_key
  spans: /!NULL-/2 /10/0
  parallel

query T
EXPLAIN (VERBOSE) SELECT d FROM b WHERE d = 10 OR d < 2
----
distribution: local
vectorized: true
·
• scan
  columns: (d)
  estimated row count: 330 (missing stats)
  table: b@b_d_key
  spans: /10/0 /1-/NULL
  parallel

query T
EXPLAIN (VERBOSE) SELECT d FROM b WHERE c = 10 AND d = 10 OR c IS NULL AND d > 0 AND d < 2
----
distribution: local
vectorized: true
·
• project
│ columns: (d)
│
└── • scan
      columns: (c, d)
      estimated row count: 1 (missing stats)
      table: b@b_c_d_key
      spans: /NULL/1-/NULL/2 /10/10/0
      parallel

statement ok
SET unbounded_parallel_scans = false

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

let $t_id3
SELECT id FROM system.namespace WHERE name='a'

# The span "sending partial batch" means that the scan was parallelized. We're
# seeing duplicate "querying next range" entries because we first use the range
# cache to try to partition the spans in order to have parallel TableReaders (we
# end up with a single partition though), and then we have a single TableReader
# performing the scan of two spans in parallel.
# 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 LIKE 'querying next range at /Table/$t_id3/1%' OR
      message = '=== SPAN START: kv.DistSender: sending partial batch ==='
----
querying next range at /Table/127/1/0/0
querying next range at /Table/127/1/10/0
querying next range at /Table/127/1/0/0
=== SPAN START: kv.DistSender: sending partial batch ===
querying next range at /Table/127/1/10/0

# Test for 42202 -- ensure filters can get pushed down through project-set.
statement ok
CREATE TABLE e (x INT PRIMARY KEY, y INT, z STRING);
CREATE TABLE s (x INT PRIMARY KEY, y INT, z INT)

query T
EXPLAIN SELECT e.z, s.z, n FROM e, s, generate_series(0, s.z, 1000) as n WHERE e.y = s.y ORDER BY s.z LIMIT 10
----
distribution: local
vectorized: true
·
• top-k
│ order: +z
│ k: 10
│
└── • project set
    │
    └── • hash join
        │ equality: (y) = (y)
        │
        ├── • scan
        │     missing stats
        │     table: e@e_pkey
        │     spans: FULL SCAN
        │
        └── • scan
              missing stats
              table: s@s_pkey
              spans: FULL SCAN

# Check that we have a sane row count estimate when there are a lot of null
# values.
statement ok
CREATE TABLE nulls (x INT, y INT);

statement ok
ALTER TABLE nulls INJECT STATISTICS '[
    {
        "columns": [
            "x"
        ],
        "created_at": "2021-06-15 02:06:48.036389",
        "distinct_count": 3000,
        "histo_buckets": [
            {
                "distinct_range": 0,
                "num_eq": 5000,
                "num_range": 0,
                "upper_bound": "0"
            },
            {
                "distinct_range": 0,
                "num_eq": 5000,
                "num_range": 0,
                "upper_bound": "1"
            }
        ],
        "histo_col_type": "INT8",
        "name": "__auto__",
        "null_count": 11100000,
        "row_count": 11110000
    }
]'

query T
EXPLAIN (VERBOSE) SELECT * FROM nulls WHERE x IS NULL
----
distribution: local
vectorized: true
·
• filter
│ columns: (x, y)
│ estimated row count: 11,100,000
│ filter: x IS NULL
│
└── • scan
      columns: (x, y)
      estimated row count: 11,110,000 (100% of the table; stats collected <hidden> ago)
      table: nulls@nulls_pkey
      spans: FULL SCAN

# Test resolution of @primary index hint.
statement ok
CREATE TABLE tbl_with_no_primary_constraint (
  id INT PRIMARY KEY,
  b INT
)

statement ok
CREATE TABLE tbl_with_primary_named_index (
  id INT PRIMARY KEY,
  b INT,
  INDEX "primary" (b)
)

query T
EXPLAIN (VERBOSE) SELECT * FROM tbl_with_no_primary_constraint@primary ORDER BY id
----
distribution: local
vectorized: true
·
• scan
  columns: (id, b)
  ordering: +id
  estimated row count: 1,000 (missing stats)
  table: tbl_with_no_primary_constraint@tbl_with_no_primary_constraint_pkey
  spans: FULL SCAN

statement ok
SHOW PARTITIONS FROM INDEX tbl_with_no_primary_constraint@primary

query T
EXPLAIN (VERBOSE) SELECT b FROM tbl_with_primary_named_index@primary ORDER BY b
----
distribution: local
vectorized: true
·
• scan
  columns: (b)
  ordering: +b
  estimated row count: 1,000 (missing stats)
  table: tbl_with_primary_named_index@primary
  spans: FULL SCAN

statement ok
SELECT index_name FROM [SHOW PARTITIONS FROM INDEX tbl_with_primary_named_index@primary]
