# LogicTest: local

statement ok
CREATE TABLE t (
  a INT,
  b VARCHAR,
  c INT,
  d VARCHAR,
  PRIMARY KEY (a, b),
  INDEX bc (b, c),
  INDEX dc (d, c),
  INDEX a_desc (a DESC),
  FAMILY (a, b),
  FAMILY (c),
  FAMILY (d)
)

statement ok
INSERT INTO t VALUES
  (1, 'one', 11, 'foo'),
  (2, 'two', 22, 'bar'),
  (3, 'three', 33, 'blah')

statement ok
SET tracing = on,kv,results; SELECT * FROM t WHERE a = 2; 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/t_pkey/2/'two' -> <undecoded>
fetched: /t/t_pkey/2/'two'/c -> 22
fetched: /t/t_pkey/2/'two'/d -> 'bar'
output row: [2 'two' 22 'bar']

statement ok
SET tracing = on,kv,results; SELECT * FROM t WHERE a IN (1, 3); 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/t_pkey/1/'one' -> <undecoded>
fetched: /t/t_pkey/1/'one'/c -> 11
fetched: /t/t_pkey/1/'one'/d -> 'foo'
fetched: /t/t_pkey/3/'three' -> <undecoded>
fetched: /t/t_pkey/3/'three'/c -> 33
fetched: /t/t_pkey/3/'three'/d -> 'blah'
output row: [1 'one' 11 'foo']
output row: [3 'three' 33 'blah']

statement ok
SET tracing = on,kv,results; SELECT * FROM t WHERE d = 'foo' OR d = 'bar'; 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/dc/'bar'/22/2/'two' -> <undecoded>
fetched: /t/dc/'foo'/11/1/'one' -> <undecoded>
output row: [2 'two' 22 'bar']
output row: [1 'one' 11 'foo']

statement ok
SET tracing = on,kv,results; SELECT * FROM t WHERE (d, c) IN (('foo', 11), ('bar', 22)); 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/dc/'bar'/22/2/'two' -> <undecoded>
fetched: /t/dc/'foo'/11/1/'one' -> <undecoded>
output row: [2 'two' 22 'bar']
output row: [1 'one' 11 'foo']

statement ok
SET tracing = on,kv,results; SELECT * FROM t WHERE (d, c) = ('foo', 11); 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/dc/'foo'/11/1/'one' -> <undecoded>
output row: [1 'one' 11 'foo']

statement ok
SET tracing = on,kv,results; SELECT * FROM t WHERE a < 2; 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/t_pkey/1/'one' -> <undecoded>
fetched: /t/t_pkey/1/'one'/c -> 11
fetched: /t/t_pkey/1/'one'/d -> 'foo'
output row: [1 'one' 11 'foo']

statement ok
SET tracing = on,kv,results; SELECT * FROM t WHERE a <= (1 + 1); 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/t_pkey/1/'one' -> <undecoded>
fetched: /t/t_pkey/1/'one'/c -> 11
fetched: /t/t_pkey/1/'one'/d -> 'foo'
fetched: /t/t_pkey/2/'two' -> <undecoded>
fetched: /t/t_pkey/2/'two'/c -> 22
fetched: /t/t_pkey/2/'two'/d -> 'bar'
output row: [1 'one' 11 'foo']
output row: [2 'two' 22 'bar']

statement ok
SET tracing = on,kv,results; SELECT a, b FROM t WHERE b > 't'; 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/bc/'three'/?/3 -> <undecoded>
fetched: /t/bc/'two'/?/2 -> <undecoded>
output row: [3 'three']
output row: [2 'two']

statement ok
SET tracing = on,kv,results; SELECT * FROM t WHERE d < ('b' || 'l'); 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/dc/'bar'/22/2/'two' -> <undecoded>
output row: [2 'two' 22 'bar']

statement ok
SET tracing = on,kv,results; SELECT * FROM t WHERE c = 22; 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/t_pkey/1/'one' -> <undecoded>
fetched: /t/t_pkey/1/'one'/c -> 11
fetched: /t/t_pkey/1/'one'/d -> 'foo'
fetched: /t/t_pkey/2/'two' -> <undecoded>
fetched: /t/t_pkey/2/'two'/c -> 22
fetched: /t/t_pkey/2/'two'/d -> 'bar'
fetched: /t/t_pkey/3/'three' -> <undecoded>
fetched: /t/t_pkey/3/'three'/c -> 33
fetched: /t/t_pkey/3/'three'/d -> 'blah'
output row: [2 'two' 22 'bar']

# Use the descending index
statement ok
SET tracing = on,kv,results; SELECT a FROM t ORDER BY a DESC; 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_desc/3/? -> <undecoded>
fetched: /t/a_desc/2/? -> <undecoded>
fetched: /t/a_desc/1/? -> <undecoded>
output row: [3]
output row: [2]
output row: [1]

# Use the descending index with multiple spans.
statement ok
SET tracing = on,kv,results; SELECT a FROM t WHERE a in (2, 3) ORDER BY a DESC; 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_desc/3/? -> <undecoded>
fetched: /t/a_desc/2/? -> <undecoded>
output row: [3]
output row: [2]

# Index selection occurs in direct join operands too.
query T
EXPLAIN (VERBOSE) SELECT * FROM t x JOIN t y USING(b) WHERE x.b = '3'
----
distribution: local
vectorized: true
·
• project
│ columns: (b, a, c, d, a, c, d)
│
└── • merge join (inner)
    │ columns: (a, b, c, d, a, b, c, d)
    │ estimated row count: 100 (missing stats)
    │ equality: (b) = (b)
    │ merge ordering: +"(b=b)"
    │
    ├── • index join
    │   │ columns: (a, b, c, d)
    │   │ estimated row count: 10 (missing stats)
    │   │ table: t@t_pkey
    │   │ key columns: a, b
    │   │
    │   └── • scan
    │         columns: (a, b, c)
    │         estimated row count: 10 (missing stats)
    │         table: t@bc
    │         spans: /"3"-/"3"/PrefixEnd
    │
    └── • index join
        │ columns: (a, b, c, d)
        │ estimated row count: 10 (missing stats)
        │ table: t@t_pkey
        │ key columns: a, b
        │
        └── • scan
              columns: (a, b, c)
              estimated row count: 10 (missing stats)
              table: t@bc
              spans: /"3"-/"3"/PrefixEnd

statement ok
TRUNCATE TABLE t

statement ok
INSERT INTO t VALUES
  (1, 'a', NULL, NULL),
  (1, 'b', NULL, NULL),
  (1, 'c', NULL, NULL)

statement ok
SET tracing = on,kv,results; SELECT * FROM t WHERE a = 1 AND b > 'b'; 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/t_pkey/1/'c' -> <undecoded>
output row: [1 'c' NULL NULL]

statement ok
SET tracing = on,kv,results; SELECT * FROM t WHERE a > 0 AND b > 'b'; 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/t_pkey/1/'c' -> <undecoded>
output row: [1 'c' NULL NULL]

statement ok
SET tracing = on,kv,results; SELECT * FROM t WHERE a > 1 AND b > 'b'; 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
----

query T
EXPLAIN SELECT * FROM t WHERE a > 1 AND a < 2
----
distribution: local
vectorized: true
·
• norows

statement ok
SET tracing = on,kv,results; SELECT * FROM t WHERE a = 1 AND 'a' < b AND 'c' > b; 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/t_pkey/1/'b' -> <undecoded>
output row: [1 'b' NULL NULL]

statement ok
DROP TABLE t

statement ok
CREATE TABLE t (
  a INT PRIMARY KEY,
  b INT,
  INDEX ab (a, b)
)

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

statement ok
SET tracing = on,kv,results; SELECT * FROM t@ab WHERE a >= 3 AND a < 5; 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/ab/3/4 -> <undecoded>
output row: [3 4]

statement ok
SET tracing = on,kv,results; SELECT * FROM t@ab WHERE a BETWEEN 3 AND 4; 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/ab/3/4 -> <undecoded>
output row: [3 4]

statement ok
SET tracing = on,kv,results; SELECT * FROM t@ab WHERE a BETWEEN 3 AND 5; 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/ab/3/4 -> <undecoded>
fetched: /t/ab/5/6 -> <undecoded>
output row: [3 4]
output row: [5 6]

statement ok
SET tracing = on,kv,results; SELECT * FROM t@ab WHERE a < 2 OR a < 4; 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/ab/1/2 -> <undecoded>
fetched: /t/ab/3/4 -> <undecoded>
output row: [1 2]
output row: [3 4]

statement ok
SET tracing = on,kv,results; SELECT * FROM t@ab WHERE a < 3 OR a <= 3; 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/ab/1/2 -> <undecoded>
fetched: /t/ab/3/4 -> <undecoded>
output row: [1 2]
output row: [3 4]

statement ok
SET tracing = on,kv,results; SELECT * FROM t@ab WHERE a <= 3 OR a < 3; 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/ab/1/2 -> <undecoded>
fetched: /t/ab/3/4 -> <undecoded>
output row: [1 2]
output row: [3 4]

statement ok
SET tracing = on,kv,results; SELECT * FROM t@ab WHERE a > 3 OR a >= 3; 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/ab/3/4 -> <undecoded>
fetched: /t/ab/5/6 -> <undecoded>
output row: [3 4]
output row: [5 6]

statement ok
SET tracing = on,kv,results; SELECT * FROM t@ab WHERE a >= 3 OR a > 3; 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/ab/3/4 -> <undecoded>
fetched: /t/ab/5/6 -> <undecoded>
output row: [3 4]
output row: [5 6]

statement ok
SET tracing = on,kv,results; SELECT * FROM t@ab WHERE a = 3 OR a = 5; 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/ab/3/4 -> <undecoded>
fetched: /t/ab/5/6 -> <undecoded>
output row: [3 4]
output row: [5 6]

statement ok
SET tracing = on,kv,results; SELECT * FROM t@ab WHERE a < 3 OR a > 3; 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/ab/1/2 -> <undecoded>
fetched: /t/ab/5/6 -> <undecoded>
output row: [1 2]
output row: [5 6]

statement ok
SET tracing = on,kv,results; SELECT * FROM t@ab WHERE a + 1 = 4; 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/ab/3/4 -> <undecoded>
output row: [3 4]

query T
EXPLAIN SELECT * FROM t WHERE a = 1 AND false
----
distribution: local
vectorized: true
·
• norows

query T
EXPLAIN SELECT * FROM t WHERE a = 1 AND NULL
----
distribution: local
vectorized: true
·
• norows

query T
EXPLAIN SELECT * FROM t WHERE a = NULL AND a != NULL
----
distribution: local
vectorized: true
·
• norows

# Make sure that mixed type comparison operations are not used
# for selecting indexes.

statement ok
DROP TABLE t

statement ok
CREATE TABLE t (
  a INT PRIMARY KEY,
  b INT,
  c INT,
  INDEX b_desc (b DESC),
  INDEX bc (b, c)
)

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

query T
EXPLAIN (VERBOSE) SELECT a FROM t WHERE c < 1 AND b < 5
----
distribution: local
vectorized: true
·
• project
│ columns: (a)
│
└── • filter
    │ columns: (a, b, c)
    │ estimated row count: 311 (missing stats)
    │ filter: c < 1
    │
    └── • scan
          columns: (a, b, c)
          estimated row count: 333 (missing stats)
          table: t@bc
          spans: /!NULL-/4/1

query T
EXPLAIN (VERBOSE) SELECT a FROM t WHERE c > 1.0
----
distribution: local
vectorized: true
·
• project
│ columns: (a)
│
└── • filter
    │ columns: (a, c)
    │ estimated row count: 333 (missing stats)
    │ filter: c > 1
    │
    └── • scan
          columns: (a, c)
          estimated row count: 1,000 (missing stats)
          table: t@t_pkey
          spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT a FROM t WHERE c < 1.0
----
distribution: local
vectorized: true
·
• project
│ columns: (a)
│
└── • filter
    │ columns: (a, c)
    │ estimated row count: 333 (missing stats)
    │ filter: c < 1
    │
    └── • scan
          columns: (a, c)
          estimated row count: 1,000 (missing stats)
          table: t@t_pkey
          spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT a FROM t WHERE c > 1.0 AND b < 5
----
distribution: local
vectorized: true
·
• project
│ columns: (a)
│
└── • filter
    │ columns: (a, b, c)
    │ estimated row count: 311 (missing stats)
    │ filter: c > 1
    │
    └── • scan
          columns: (a, b, c)
          estimated row count: 333 (missing stats)
          table: t@bc
          spans: /!NULL-/5

query T
EXPLAIN (VERBOSE) SELECT a FROM t WHERE b < 5.0 AND c < 1
----
distribution: local
vectorized: true
·
• project
│ columns: (a)
│
└── • filter
    │ columns: (a, b, c)
    │ estimated row count: 311 (missing stats)
    │ filter: c < 1
    │
    └── • scan
          columns: (a, b, c)
          estimated row count: 333 (missing stats)
          table: t@bc
          spans: /!NULL-/4/1

query T
EXPLAIN (VERBOSE) SELECT a FROM t WHERE (b, c) = (5, 1)
----
distribution: local
vectorized: true
·
• project
│ columns: (a)
│
└── • scan
      columns: (a, b, c)
      estimated row count: 1 (missing stats)
      table: t@bc
      spans: /5/1-/5/2

query T
EXPLAIN (VERBOSE) SELECT a FROM t WHERE (b, c) = (5.0, 1)
----
distribution: local
vectorized: true
·
• project
│ columns: (a)
│
└── • scan
      columns: (a, b, c)
      estimated row count: 1 (missing stats)
      table: t@bc
      spans: /5/1-/5/2

query T
EXPLAIN (VERBOSE) SELECT a FROM t WHERE (b, c) = (5.1, 1)
----
distribution: local
vectorized: true
·
• project
│ columns: (a)
│
└── • filter
    │ columns: (a, b, c)
    │ estimated row count: 3 (missing stats)
    │ filter: (b = 5.1) AND (c = 1)
    │
    └── • scan
          columns: (a, b, c)
          estimated row count: 990 (missing stats)
          table: t@bc
          spans: /!NULL-

# Note the span is reversed because of #20203.
query T
EXPLAIN (VERBOSE) SELECT a FROM t WHERE b IN (5.0, 1)
----
distribution: local
vectorized: true
·
• project
│ columns: (a)
│
└── • scan
      columns: (a, b)
      estimated row count: 20 (missing stats)
      table: t@b_desc
      spans: /5-/4 /1-/0

statement ok
CREATE TABLE abcd (
  a INT,
  b INT,
  c INT,
  d INT,
  INDEX adb (a, d, b),
  INDEX abcd (a, b, c, d)
)

# Verify that we prefer the index where more columns are constrained, even if it
# has more keys per row.
query T
EXPLAIN (VERBOSE) SELECT b FROM abcd WHERE (a, b) = (1, 4)
----
distribution: local
vectorized: true
·
• project
│ columns: (b)
│
└── • scan
      columns: (a, b)
      estimated row count: 1 (missing stats)
      table: abcd@abcd
      spans: /1/4-/1/5

query T
EXPLAIN (VERBOSE) SELECT b FROM abcd WHERE (a, b) IN ((1, 4), (2, 9))
----
distribution: local
vectorized: true
·
• project
│ columns: (b)
│
└── • scan
      columns: (a, b)
      estimated row count: 3 (missing stats)
      table: abcd@abcd
      spans: /1/4-/1/5 /2/9-/2/10

statement ok
CREATE TABLE ab (
  s STRING,
  i INT
);

query T
EXPLAIN (VERBOSE) SELECT i, s FROM ab WHERE (i, s) < (1, 'c')
----
distribution: local
vectorized: true
·
• filter
│ columns: (i, s)
│ estimated row count: 333 (missing stats)
│ filter: (i, s) < (1, 'c')
│
└── • scan
      columns: (s, i)
      estimated row count: 1,000 (missing stats)
      table: ab@ab_pkey
      spans: FULL SCAN

statement ok
CREATE INDEX baz ON ab (i, s)

query T
EXPLAIN (VERBOSE) SELECT i, s FROM ab@baz WHERE (i, s) < (1, 'c')
----
distribution: local
vectorized: true
·
• filter
│ columns: (i, s)
│ estimated row count: 333 (missing stats)
│ filter: (i, s) < (1, 'c')
│
└── • scan
      columns: (s, i)
      estimated row count: 333 (missing stats)
      table: ab@baz
      spans: /!NULL-/1/"c"

# Check that primary key definitions can indicate index ordering,
# and this information is subsequently used during index selection
# and span generation. #13882
query TTBITTTBBBF rowsort
CREATE TABLE abz(a INT, b INT, c INT, PRIMARY KEY (a DESC, b ASC), UNIQUE(c DESC, b ASC)); SHOW INDEX FROM abz
----
abz  abz_c_b_key  false  1  c  c  DESC  false  false  true  1
abz  abz_c_b_key  false  2  b  b  ASC   false  false  true  1
abz  abz_c_b_key  false  3  a  a  ASC   true   true   true  1
abz  abz_pkey     false  1  a  a  DESC  false  false  true  1
abz  abz_pkey     false  2  b  b  ASC   false  false  true  1
abz  abz_pkey     false  3  c  c  N/A   true   false  true  1

query T
EXPLAIN (VERBOSE) SELECT a FROM abz ORDER BY a DESC LIMIT 1
----
distribution: local
vectorized: true
·
• scan
  columns: (a)
  estimated row count: 1 (missing stats)
  table: abz@abz_pkey
  spans: LIMITED SCAN
  limit: 1

query T
EXPLAIN (VERBOSE) SELECT c FROM abz ORDER BY c DESC LIMIT 1
----
distribution: local
vectorized: true
·
• scan
  columns: (c)
  estimated row count: 1 (missing stats)
  table: abz@abz_c_b_key
  spans: LIMITED SCAN
  limit: 1

# Issue #14426: verify we don't have an internal filter that contains "a IN ()"
# (which causes an error in DistSQL due to expression serialization).
statement ok
CREATE TABLE tab0(
  k INT PRIMARY KEY,
  a INT,
  b INT
)

query T
EXPLAIN (VERBOSE) SELECT k FROM tab0 WHERE (a IN (6) AND a > 6) OR b >= 4
----
distribution: local
vectorized: true
·
• project
│ columns: (k)
│
└── • filter
    │ columns: (k, a, b)
    │ estimated row count: 333 (missing stats)
    │ filter: ((a = 6) AND (a > 6)) OR (b >= 4)
    │
    └── • scan
          columns: (k, a, b)
          estimated row count: 1,000 (missing stats)
          table: tab0@tab0_pkey
          spans: FULL SCAN

# Check that no extraneous rows are fetched due to excessive batching (#15910)
# The test is composed of three parts: populate a table, check
# that the problematic plan is properly derived from the test query,
# then test the results.

statement ok
CREATE TABLE test2 (id BIGSERIAL PRIMARY KEY, k TEXT UNIQUE, v INT DEFAULT 42);
INSERT INTO test2(k)
     VALUES ('001'),('002'),('003'),('004'),('005'),('006'),('007'),('008'),('009'),('010'),
            ('011'),('012'),('013'),('014'),('015'),('016'),('017'),('018'),('019'),('020'),
            ('021'),('022'),('023'),('024'),('025'),('026'),('027'),('028'),('029'),('030')

# Plan check:
# The query is using an index-join and the limit is propagated to the scan.

query T
EXPLAIN (VERBOSE) SELECT * FROM test2 WHERE k <= '100' ORDER BY k DESC LIMIT 20
----
distribution: local
vectorized: true
·
• index join
│ columns: (id, k, v)
│ ordering: -k
│ estimated row count: 20 (missing stats)
│ table: test2@test2_pkey
│ key columns: id
│
└── • revscan
      columns: (id, k)
      ordering: -k
      estimated row count: 20 (missing stats)
      table: test2@test2_k_key
      spans: /!NULL-/"100"/PrefixEnd
      limit: 20

# The result output of this test requires that vectorized execution
# is not used, so it has been moved to select_index_vectorize_off.


# Regression test for #20035.
statement ok
CREATE TABLE favorites (
  id INT NOT NULL DEFAULT unique_rowid(),
  resource_type STRING(30) NOT NULL,
  resource_key STRING(255) NOT NULL,
  device_group STRING(30) NOT NULL,
  customerid INT NOT NULL,
  jurisdiction STRING(2) NOT NULL,
  brand STRING(255) NOT NULL,
  created_ts TIMESTAMP NULL,
  guid_id STRING(100) NOT NULL,
  locale STRING(10) NOT NULL DEFAULT NULL,
  CONSTRAINT "primary" PRIMARY KEY (id ASC),
  UNIQUE INDEX favorites_idx (resource_type ASC, device_group ASC, resource_key ASC, customerid ASC),
  INDEX favorites_guid_idx (guid_id ASC),
  INDEX favorites_glob_fav_idx (resource_type ASC, device_group ASC, jurisdiction ASC, brand ASC, locale ASC, resource_key ASC),
  FAMILY "primary" (id, resource_type, resource_key, device_group, customerid, jurisdiction, brand, created_ts, guid_id, locale)
)

statement ok
INSERT INTO favorites (customerid, guid_id, resource_type, device_group, jurisdiction, brand, locale, resource_key)
  VALUES (1, '1', 'GAME', 'web', 'MT', 'xxx', 'en_GB', 'tp'),
         (2, '2', 'GAME', 'web', 'MT', 'xxx', 'en_GB', 'ts'),
         (3, '3', 'GAME', 'web', 'MT', 'xxx', 'en_GB', 'ts1'),
         (4, '4', 'GAME', 'web', 'MT', 'xxx', 'en_GB', 'ts2'),
         (5, '5', 'GAME', 'web', 'MT', 'xxx', 'en_GB', 'ts3'),
         (6, '6', 'GAME', 'web', 'MT', 'xxx', 'en_GB', 'ts4')

query T
EXPLAIN SELECT
  resource_key,
  count(resource_key) total
FROM favorites f1
WHERE f1.jurisdiction   = 'MT'
AND   f1.brand          = 'xxx'
AND   f1.resource_type  = 'GAME'
AND   f1.device_group   = 'web'
AND   f1.locale         = 'en_GB'
AND   f1.resource_key IN ('ts', 'ts2', 'ts3')
GROUP BY resource_key
ORDER BY total DESC
----
distribution: local
vectorized: true
·
• sort
│ order: -count_rows
│
└── • group (streaming)
    │ group by: resource_key
    │ ordered: +resource_key
    │
    └── • scan
          missing stats
          table: favorites@favorites_glob_fav_idx
          spans: [/'GAME'/'web'/'MT'/'xxx'/'en_GB'/'ts' - /'GAME'/'web'/'MT'/'xxx'/'en_GB'/'ts'] [/'GAME'/'web'/'MT'/'xxx'/'en_GB'/'ts2' - /'GAME'/'web'/'MT'/'xxx'/'en_GB'/'ts2'] [/'GAME'/'web'/'MT'/'xxx'/'en_GB'/'ts3' - /'GAME'/'web'/'MT'/'xxx'/'en_GB'/'ts3']

query TI rowsort
SELECT
  resource_key,
  count(resource_key) total
FROM favorites f1
WHERE f1.jurisdiction   = 'MT'
AND   f1.brand          = 'xxx'
AND   f1.resource_type  = 'GAME'
AND   f1.device_group   = 'web'
AND   f1.locale         = 'en_GB'
AND   f1.resource_key IN ('ts', 'ts2', 'ts3')
GROUP BY resource_key
ORDER BY total DESC
----
ts  1
ts2 1
ts3 1

# Regression tests for #20362 (IS NULL handling).
query T
EXPLAIN (VERBOSE) SELECT * FROM abcd@abcd WHERE a IS NULL AND b > 5
----
distribution: local
vectorized: true
·
• scan
  columns: (a, b, c, d)
  estimated row count: 9 (missing stats)
  table: abcd@abcd
  spans: /NULL/6-/!NULL

query T
EXPLAIN (VERBOSE) SELECT * FROM abcd@abcd WHERE a IS NULL AND b < 5
----
distribution: local
vectorized: true
·
• scan
  columns: (a, b, c, d)
  estimated row count: 9 (missing stats)
  table: abcd@abcd
  spans: /NULL/!NULL-/NULL/5

query T
EXPLAIN (VERBOSE) SELECT * FROM abcd@abcd WHERE a IS NULL ORDER BY b
----
distribution: local
vectorized: true
·
• scan
  columns: (a, b, c, d)
  ordering: +b
  estimated row count: 10 (missing stats)
  table: abcd@abcd
  spans: /NULL-/!NULL

query T
EXPLAIN (VERBOSE) SELECT * FROM abcd@abcd WHERE a = 1 AND b IS NULL AND c > 0 AND c < 10 ORDER BY c
----
distribution: local
vectorized: true
·
• scan
  columns: (a, b, c, d)
  ordering: +c
  estimated row count: 0 (missing stats)
  table: abcd@abcd
  spans: /1/NULL/1-/1/NULL/10

# Regression test for #3548: verify we create constraints on implicit columns
# when they are part of the key (non-unique index).
statement ok
CREATE TABLE abc (a INT, b INT, c INT, PRIMARY KEY(a,b), INDEX(c))

query T
EXPLAIN (VERBOSE) SELECT c FROM abc WHERE c = 1 and a = 3
----
distribution: local
vectorized: true
·
• project
│ columns: (c)
│
└── • scan
      columns: (a, c)
      estimated row count: 1 (missing stats)
      table: abc@abc_c_idx
      spans: /1/3-/1/4

# Verify we don't create constraints on implicit columns when they may be part
# of the key (unique index on nullable column).
statement ok
CREATE TABLE def (d INT, e INT, f INT, PRIMARY KEY(d,e), UNIQUE INDEX(f))

query T
EXPLAIN (VERBOSE) SELECT f FROM def WHERE f = 1 and d = 3
----
distribution: local
vectorized: true
·
• project
│ columns: (f)
│
└── • filter
    │ columns: (d, f)
    │ estimated row count: 1 (missing stats)
    │ filter: d = 3
    │
    └── • scan
          columns: (d, f)
          estimated row count: 1 (missing stats)
          table: def@def_f_key
          spans: /1/0

statement ok
DROP TABLE def

# Verify we don't create constraints on implicit columns when they are not part
# of the key (unique index on not-null column).
statement ok
CREATE TABLE def (d INT, e INT, f INT NOT NULL, PRIMARY KEY(d,e), UNIQUE INDEX(f))

query T
EXPLAIN (VERBOSE) SELECT f FROM def WHERE f = 1 and d = 3
----
distribution: local
vectorized: true
·
• project
│ columns: (f)
│
└── • filter
    │ columns: (d, f)
    │ estimated row count: 1 (missing stats)
    │ filter: d = 3
    │
    └── • scan
          columns: (d, f)
          estimated row count: 1 (missing stats)
          table: def@def_f_key
          spans: /1/0

# Regression test for #20504.
query T
EXPLAIN (VERBOSE) SELECT a, b FROM abc WHERE (a, b) BETWEEN (1, 2) AND (3, 4)
----
distribution: local
vectorized: true
·
• scan
  columns: (a, b)
  estimated row count: 333 (missing stats)
  table: abc@abc_pkey
  spans: /1/2-/3/5

# Regression test for #21831.
statement ok
CREATE TABLE str (k INT PRIMARY KEY, v STRING, INDEX(v))

query T
EXPLAIN (VERBOSE) SELECT k, v FROM str WHERE v LIKE 'ABC%'
----
distribution: local
vectorized: true
·
• scan
  columns: (k, v)
  estimated row count: 111 (missing stats)
  table: str@str_v_idx
  spans: /"ABC"-/"ABD"

query T
EXPLAIN (VERBOSE) SELECT k, v FROM str WHERE v LIKE 'ABC%Z'
----
distribution: local
vectorized: true
·
• filter
│ columns: (k, v)
│ estimated row count: 37 (missing stats)
│ filter: v LIKE 'ABC%Z'
│
└── • scan
      columns: (k, v)
      estimated row count: 111 (missing stats)
      table: str@str_v_idx
      spans: /"ABC"-/"ABD"

query T
EXPLAIN (VERBOSE) SELECT k, v FROM str WHERE v SIMILAR TO 'ABC_*'
----
distribution: local
vectorized: true
·
• filter
│ columns: (k, v)
│ estimated row count: 37 (missing stats)
│ filter: v SIMILAR TO 'ABC_*'
│
└── • scan
      columns: (k, v)
      estimated row count: 111 (missing stats)
      table: str@str_v_idx
      spans: /"ABC"-/"ABD"

query T
EXPLAIN (VERBOSE) SELECT k, v FROM str WHERE v ~ '^ABC'
----
distribution: local
vectorized: true
·
• scan
  columns: (k, v)
  estimated row count: 330 (missing stats)
  table: str@str_v_idx
  spans: /"ABC"-/"ABD"

# Test that we generate spans for IS (NOT) DISTINCT FROM.
statement ok
CREATE TABLE xy (x INT, y INT, INDEX (y))

query T
EXPLAIN (VERBOSE) SELECT * FROM xy WHERE y IS NOT DISTINCT FROM NULL
----
distribution: local
vectorized: true
·
• index join
│ columns: (x, y)
│ estimated row count: 10 (missing stats)
│ table: xy@xy_pkey
│ key columns: rowid
│
└── • scan
      columns: (y, rowid)
      estimated row count: 10 (missing stats)
      table: xy@xy_y_idx
      spans: /NULL-/!NULL

query T
EXPLAIN (VERBOSE) SELECT * FROM xy WHERE y IS NOT DISTINCT FROM 4
----
distribution: local
vectorized: true
·
• index join
│ columns: (x, y)
│ estimated row count: 10 (missing stats)
│ table: xy@xy_pkey
│ key columns: rowid
│
└── • scan
      columns: (y, rowid)
      estimated row count: 10 (missing stats)
      table: xy@xy_y_idx
      spans: /4-/5

query T
EXPLAIN (VERBOSE) SELECT x FROM xy WHERE y > 0 AND y < 2 ORDER BY y
----
distribution: local
vectorized: true
·
• project
│ columns: (x)
│
└── • index join
    │ columns: (x, y)
    │ estimated row count: 10 (missing stats)
    │ table: xy@xy_pkey
    │ key columns: rowid
    │
    └── • scan
          columns: (y, rowid)
          estimated row count: 10 (missing stats)
          table: xy@xy_y_idx
          spans: /1-/2

query T
EXPLAIN (VERBOSE) SELECT * FROM xy WHERE y IS DISTINCT FROM NULL
----
distribution: local
vectorized: true
·
• filter
│ columns: (x, y)
│ estimated row count: 990 (missing stats)
│ filter: y IS NOT NULL
│
└── • scan
      columns: (x, y)
      estimated row count: 1,000 (missing stats)
      table: xy@xy_pkey
      spans: FULL SCAN

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

# Regression tests for #22670.
statement ok
CREATE INDEX xy_idx ON xy (x, y)

statement ok
INSERT INTO xy VALUES (NULL, NULL), (1, NULL), (NULL, 1), (1, 1)

query T
EXPLAIN (VERBOSE) SELECT * FROM xy WHERE x IN (NULL, 1, 2)
----
distribution: local
vectorized: true
·
• scan
  columns: (x, y)
  estimated row count: 20 (missing stats)
  table: xy@xy_idx
  spans: /1-/3

query T
EXPLAIN (VERBOSE) SELECT * FROM xy WHERE (x, y) IN ((NULL, NULL), (1, NULL), (NULL, 1), (1, 1), (1, 2))
----
distribution: local
vectorized: true
·
• scan
  columns: (x, y)
  estimated row count: 1 (missing stats)
  table: xy@xy_idx
  spans: /1/1-/1/3

# ------------------------------------------------------------------------------
# Non-covering index
# ------------------------------------------------------------------------------
statement ok
CREATE TABLE noncover (
  a INT PRIMARY KEY,
  b INT,
  c INT,
  d INT,
  INDEX b (b),
  UNIQUE INDEX c (c),
  FAMILY (a),
  FAMILY (b),
  FAMILY (c),
  FAMILY (d)
)

statement ok
INSERT INTO noncover VALUES (1, 2, 3, 4), (5, 6, 7, 8)

query T
EXPLAIN SELECT * FROM noncover WHERE b = 2
----
distribution: local
vectorized: true
·
• index join
│ table: noncover@noncover_pkey
│
└── • scan
      missing stats
      table: noncover@b
      spans: [/2 - /2]

statement ok
SET tracing = on,kv,results; SELECT * FROM noncover WHERE b = 2; 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: /noncover/b/2/1 -> <undecoded>
fetched: /noncover/noncover_pkey/1 -> <undecoded>
fetched: /noncover/noncover_pkey/1/b -> 2
fetched: /noncover/noncover_pkey/1/c -> 3
fetched: /noncover/noncover_pkey/1/d -> 4
output row: [1 2 3 4]

# Verify that the index join span created doesn't include any potential child
# interleaved tables.
query T rowsort
SELECT message FROM [SHOW KV TRACE FOR SESSION]
WHERE message LIKE 'Scan /Table/120/1%'
----
Scan /Table/120/1/{1-2}

query T
EXPLAIN SELECT * FROM noncover WHERE c = 6
----
distribution: local
vectorized: true
·
• index join
│ table: noncover@noncover_pkey
│
└── • scan
      missing stats
      table: noncover@c
      spans: [/6 - /6]

statement ok
SET tracing = on,kv,results; SELECT * FROM noncover WHERE c = 7; 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: /noncover/c/7 -> /5
fetched: /noncover/noncover_pkey/5 -> <undecoded>
fetched: /noncover/noncover_pkey/5/b -> 6
fetched: /noncover/noncover_pkey/5/c -> 7
fetched: /noncover/noncover_pkey/5/d -> 8
output row: [5 6 7 8]

query T
EXPLAIN (VERBOSE) SELECT * FROM noncover WHERE c > 0 ORDER BY c DESC
----
distribution: local
vectorized: true
·
• sort
│ columns: (a, b, c, d)
│ estimated row count: 330 (missing stats)
│ order: -c
│
└── • filter
    │ columns: (a, b, c, d)
    │ estimated row count: 330 (missing stats)
    │ filter: c > 0
    │
    └── • scan
          columns: (a, b, c, d)
          estimated row count: 1,000 (missing stats)
          table: noncover@noncover_pkey
          spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT * FROM noncover WHERE c > 0 ORDER BY c
----
distribution: local
vectorized: true
·
• sort
│ columns: (a, b, c, d)
│ estimated row count: 330 (missing stats)
│ order: +c
│
└── • filter
    │ columns: (a, b, c, d)
    │ estimated row count: 330 (missing stats)
    │ filter: c > 0
    │
    └── • scan
          columns: (a, b, c, d)
          estimated row count: 1,000 (missing stats)
          table: noncover@noncover_pkey
          spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT * FROM noncover WHERE c > 0 AND d = 8
----
distribution: local
vectorized: true
·
• filter
│ columns: (a, b, c, d)
│ estimated row count: 9 (missing stats)
│ filter: (c > 0) AND (d = 8)
│
└── • scan
      columns: (a, b, c, d)
      estimated row count: 1,000 (missing stats)
      table: noncover@noncover_pkey
      spans: FULL SCAN

# The following testcases verify that when we have a small limit, we prefer an
# order-matching index.

query T
EXPLAIN SELECT * FROM noncover ORDER BY c
----
distribution: local
vectorized: true
·
• sort
│ order: +c
│
└── • scan
      missing stats
      table: noncover@noncover_pkey
      spans: FULL SCAN

query T
EXPLAIN SELECT * FROM noncover ORDER BY c LIMIT 5
----
distribution: local
vectorized: true
·
• index join
│ table: noncover@noncover_pkey
│
└── • scan
      missing stats
      table: noncover@c
      spans: LIMITED SCAN
      limit: 5

query T
EXPLAIN (VERBOSE) SELECT * FROM noncover ORDER BY c OFFSET 5
----
distribution: local
vectorized: true
·
• limit
│ columns: (a, b, c, d)
│ offset: 5
│
└── • sort
    │ columns: (a, b, c, d)
    │ estimated row count: 1,000 (missing stats)
    │ order: +c
    │
    └── • scan
          columns: (a, b, c, d)
          estimated row count: 1,000 (missing stats)
          table: noncover@noncover_pkey
          spans: FULL SCAN

# TODO(radu): need to prefer the order-matching index when OFFSET is present.
query T
EXPLAIN (VERBOSE) SELECT * FROM noncover ORDER BY c LIMIT 5 OFFSET 5
----
distribution: local
vectorized: true
·
• index join
│ columns: (a, b, c, d)
│ ordering: +c
│ estimated row count: 5 (missing stats)
│ table: noncover@noncover_pkey
│ key columns: a
│
└── • limit
    │ columns: (a, c)
    │ offset: 5
    │
    └── • scan
          columns: (a, c)
          ordering: +c
          estimated row count: 10 (missing stats)
          table: noncover@c
          spans: LIMITED SCAN
          limit: 10

query T
EXPLAIN (VERBOSE) SELECT * FROM noncover ORDER BY c LIMIT 1000000
----
distribution: local
vectorized: true
·
• top-k
│ columns: (a, b, c, d)
│ estimated row count: 1,000 (missing stats)
│ order: +c
│ k: 1000000
│
└── • scan
      columns: (a, b, c, d)
      estimated row count: 1,000 (missing stats)
      table: noncover@noncover_pkey
      spans: FULL SCAN

# ------------------------------------------------------------------------------
# These tests verify that while we are joining an index with the table, we
# evaluate what parts of the filter we can using the columns in the index
# to avoid unnecessary lookups in the table.
# ------------------------------------------------------------------------------
statement ok
CREATE TABLE t2 (
  a INT PRIMARY KEY,
  b INT,
  c INT,
  s STRING,
  INDEX bc (b, c),
  FAMILY (a),
  FAMILY (b),
  FAMILY (c),
  FAMILY (s)
)

statement ok
INSERT INTO t2 VALUES
  (1, 1, 1, '11'),
  (2, 1, 2, '12'),
  (3, 1, 3, '13'),
  (4, 2, 1, '21'),
  (5, 2, 2, '22'),
  (6, 2, 3, '23'),
  (7, 3, 1, '31'),
  (8, 3, 2, '32'),
  (9, 3, 3, '33')

# Pretend we have 10x more rows in the database than we really do.
statement ok
ALTER TABLE t2 INJECT STATISTICS '[
  {
    "columns": ["b"],
    "created_at": "2018-01-01 1:00:00.00000+00:00",
    "row_count": 90,
    "distinct_count": 30
  }
]'

query T
EXPLAIN (VERBOSE) SELECT * FROM t2 WHERE b = 2 AND c % 2 = 0
----
distribution: local
vectorized: true
·
• index join
│ columns: (a, b, c, s)
│ estimated row count: 1
│ table: t2@t2_pkey
│ key columns: a
│
└── • filter
    │ columns: (a, b, c)
    │ estimated row count: 1
    │ filter: (c % 2) = 0
    │
    └── • scan
          columns: (a, b, c)
          estimated row count: 3 (3.3% of the table; stats collected <hidden> ago)
          table: t2@bc
          spans: /2-/3

# We do NOT look up the table row for '21' and '23'.
statement ok
SET tracing = on,kv,results; SELECT * FROM t2 WHERE b = 2 AND c % 2 = 0; 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: /t2/bc/2/1/4 -> <undecoded>
fetched: /t2/bc/2/2/5 -> <undecoded>
fetched: /t2/bc/2/3/6 -> <undecoded>
fetched: /t2/t2_pkey/5 -> <undecoded>
fetched: /t2/t2_pkey/5/b -> 2
fetched: /t2/t2_pkey/5/c -> 2
fetched: /t2/t2_pkey/5/s -> '22'
output row: [5 2 2 '22']

query T
EXPLAIN (VERBOSE) SELECT * FROM t2 WHERE b = 2 AND c != b
----
distribution: local
vectorized: true
·
• index join
│ columns: (a, b, c, s)
│ estimated row count: 1
│ table: t2@t2_pkey
│ key columns: a
│
└── • scan
      columns: (a, b, c)
      estimated row count: 1 (1.2% of the table; stats collected <hidden> ago)
      table: t2@bc
      spans: /2/!NULL-/2/2 /2/3-/3

# We do NOT look up the table row for '22'.
statement ok
SET tracing = on,kv,results; SELECT * FROM t2 WHERE b = 2 AND c != b; 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: /t2/bc/2/1/4 -> <undecoded>
fetched: /t2/bc/2/3/6 -> <undecoded>
fetched: /t2/t2_pkey/4 -> <undecoded>
fetched: /t2/t2_pkey/4/b -> 2
fetched: /t2/t2_pkey/4/c -> 1
fetched: /t2/t2_pkey/4/s -> '21'
fetched: /t2/t2_pkey/6 -> <undecoded>
fetched: /t2/t2_pkey/6/b -> 2
fetched: /t2/t2_pkey/6/c -> 3
fetched: /t2/t2_pkey/6/s -> '23'
output row: [4 2 1 '21']
output row: [6 2 3 '23']

# We do NOT look up the table row for '22'.
statement ok
SET tracing = on,kv,results; SELECT * FROM t2 WHERE b = 2 AND c != b AND s <> '21'; 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: /t2/bc/2/1/4 -> <undecoded>
fetched: /t2/bc/2/3/6 -> <undecoded>
fetched: /t2/t2_pkey/4 -> <undecoded>
fetched: /t2/t2_pkey/4/b -> 2
fetched: /t2/t2_pkey/4/c -> 1
fetched: /t2/t2_pkey/4/s -> '21'
fetched: /t2/t2_pkey/6 -> <undecoded>
fetched: /t2/t2_pkey/6/b -> 2
fetched: /t2/t2_pkey/6/c -> 3
fetched: /t2/t2_pkey/6/s -> '23'
output row: [6 2 3 '23']

# We only look up the table rows where c = b+1 or a > b+4: '23', '32', '33'.
# TODO(justin): we need to push the filter into the index scan.
statement ok
SET tracing = on,kv,results; SELECT * FROM t2 WHERE b > 1 AND ((c = b+1 AND s != '23') OR (a > b+4 AND s != '32')); 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: /t2/t2_pkey/1 -> <undecoded>
fetched: /t2/t2_pkey/1/b -> 1
fetched: /t2/t2_pkey/1/c -> 1
fetched: /t2/t2_pkey/1/s -> '11'
fetched: /t2/t2_pkey/2 -> <undecoded>
fetched: /t2/t2_pkey/2/b -> 1
fetched: /t2/t2_pkey/2/c -> 2
fetched: /t2/t2_pkey/2/s -> '12'
fetched: /t2/t2_pkey/3 -> <undecoded>
fetched: /t2/t2_pkey/3/b -> 1
fetched: /t2/t2_pkey/3/c -> 3
fetched: /t2/t2_pkey/3/s -> '13'
fetched: /t2/t2_pkey/4 -> <undecoded>
fetched: /t2/t2_pkey/4/b -> 2
fetched: /t2/t2_pkey/4/c -> 1
fetched: /t2/t2_pkey/4/s -> '21'
fetched: /t2/t2_pkey/5 -> <undecoded>
fetched: /t2/t2_pkey/5/b -> 2
fetched: /t2/t2_pkey/5/c -> 2
fetched: /t2/t2_pkey/5/s -> '22'
fetched: /t2/t2_pkey/6 -> <undecoded>
fetched: /t2/t2_pkey/6/b -> 2
fetched: /t2/t2_pkey/6/c -> 3
fetched: /t2/t2_pkey/6/s -> '23'
fetched: /t2/t2_pkey/7 -> <undecoded>
fetched: /t2/t2_pkey/7/b -> 3
fetched: /t2/t2_pkey/7/c -> 1
fetched: /t2/t2_pkey/7/s -> '31'
fetched: /t2/t2_pkey/8 -> <undecoded>
fetched: /t2/t2_pkey/8/b -> 3
fetched: /t2/t2_pkey/8/c -> 2
fetched: /t2/t2_pkey/8/s -> '32'
fetched: /t2/t2_pkey/9 -> <undecoded>
fetched: /t2/t2_pkey/9/b -> 3
fetched: /t2/t2_pkey/9/c -> 3
fetched: /t2/t2_pkey/9/s -> '33'
output row: [9 3 3 '33']

# Check that splitting of the expression filter does not mistakenly
# bring non-indexed columns (s) under the index scanNode. (#12582)
# To test this we need an expression containing non-indexed
# columns that disappears during range simplification.
query T
EXPLAIN (VERBOSE) SELECT a FROM t2 WHERE b = 2 OR ((b BETWEEN 2 AND 1) AND ((s != 'a') OR (s = 'a')))
----
distribution: local
vectorized: true
·
• project
│ columns: (a)
│
└── • scan
      columns: (a, b)
      estimated row count: 3 (3.3% of the table; stats collected <hidden> ago)
      table: t2@bc
      spans: /2-/3

statement ok
CREATE TABLE t3 (k INT PRIMARY KEY, v INT, w INT, INDEX v(v))

query T
EXPLAIN (VERBOSE) SELECT w FROM t3 WHERE v > 0 AND v < 10 ORDER BY v
----
distribution: local
vectorized: true
·
• project
│ columns: (w)
│
└── • index join
    │ columns: (v, w)
    │ ordering: +v
    │ estimated row count: 90 (missing stats)
    │ table: t3@t3_pkey
    │ key columns: k
    │
    └── • scan
          columns: (k, v)
          ordering: +v
          estimated row count: 90 (missing stats)
          table: t3@v
          spans: /1-/10

# ------------------------------------------------------------------------------
# These tests are for the point lookup optimization: for single row lookups on
# a table with multiple column families, we only scan the relevant column
# families. Note that this applies to SELECTs and UPDATEs but not DELETEs, since
# we need to ensure that we delete across all column families.
# ------------------------------------------------------------------------------
statement ok
CREATE TABLE t4 (
  a INT,
  b INT,
  c INT,
  d INT,
  e INT,
  PRIMARY KEY (a, b),
  FAMILY (a, b),
  FAMILY (c),
  FAMILY (d),
  FAMILY (e)
)

statement ok
INSERT INTO t4 VALUES (10, 20, 30, 40, 50)

# Point lookup on c does not touch the d or e families.
query T
EXPLAIN SELECT c FROM t4 WHERE a = 10 and b = 20
----
distribution: local
vectorized: true
·
• scan
  missing stats
  table: t4@t4_pkey
  spans: [/10/20 - /10/20]

statement ok
SET tracing = on,kv,results; SELECT c FROM t4 WHERE a = 10 and b = 20; 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: /t4/t4_pkey/10/20 -> <undecoded>
fetched: /t4/t4_pkey/10/20/c -> 30
output row: [30]

# Point lookup on d does not touch the c or e families.
query T
EXPLAIN SELECT d FROM t4 WHERE a = 10 and b = 20
----
distribution: local
vectorized: true
·
• scan
  missing stats
  table: t4@t4_pkey
  spans: [/10/20 - /10/20]

statement ok
SET tracing = on,kv,results; SELECT d FROM t4 WHERE a = 10 and b = 20; 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: /t4/t4_pkey/10/20 -> <undecoded>
fetched: /t4/t4_pkey/10/20/d -> 40
output row: [40]

# Point lookup on both d and e uses a single span for the two adjacent column
# families.
query T
EXPLAIN SELECT d, e FROM t4 WHERE a = 10 and b = 20
----
distribution: local
vectorized: true
·
• scan
  missing stats
  table: t4@t4_pkey
  spans: [/10/20 - /10/20]

# Optimization should also be applied for updates.
query T
EXPLAIN UPDATE t4 SET c = 30 WHERE a = 10 and b = 20
----
distribution: local
vectorized: true
·
• update
│ table: t4
│ set: c
│ auto commit
│
└── • render
    │
    └── • scan
          missing stats
          table: t4@t4_pkey
          spans: [/10/20 - /10/20]
          locking strength: for update

# Optimization should not be applied for deletes.
query T
EXPLAIN DELETE FROM t4 WHERE a = 10 and b = 20
----
distribution: local
vectorized: true
·
• delete range
  from: t4
  auto commit
  spans: [/10/20 - /10/20]

# Optimization should not be applied for non point lookups.
query T
EXPLAIN SELECT c FROM t4 WHERE a = 10 and b >= 20 and b < 22
----
distribution: local
vectorized: true
·
• scan
  missing stats
  table: t4@t4_pkey
  spans: [/10/20 - /10/21]

# Optimization should not be applied for partial primary key filter.
query T
EXPLAIN SELECT c FROM t4 WHERE a = 10
----
distribution: local
vectorized: true
·
• scan
  missing stats
  table: t4@t4_pkey
  spans: [/10 - /10]

# Regression test for #40890: a point lookup on a single column family of a
# table should still work properly in the face of a constraint disjunction.
query T
EXPLAIN SELECT a FROM t4 WHERE a in (1, 5) and b in (1, 5)
----
distribution: local
vectorized: true
·
• scan
  missing stats
  table: t4@t4_pkey
  spans: [/1/1 - /1/1] [/1/5 - /1/5] [/5/1 - /5/1] [/5/5 - /5/5]
