# LogicTest: local

statement ok
CREATE TABLE t (
  a INT PRIMARY KEY,
  b INT,
  c BOOLEAN,
  FAMILY "primary" (a, b, c)
)

query T
EXPLAIN SELECT a, b FROM t ORDER BY b
----
distribution: local
vectorized: true
·
• sort
│ order: +b
│
└── • scan
      missing stats
      table: t@t_pkey
      spans: FULL SCAN

query T
EXPLAIN SELECT a, b FROM t ORDER BY b DESC
----
distribution: local
vectorized: true
·
• sort
│ order: -b
│
└── • scan
      missing stats
      table: t@t_pkey
      spans: FULL SCAN

# TODO(radu): Should set "strategy top 2" on sort node
query T
EXPLAIN SELECT a, b FROM t ORDER BY b LIMIT 2
----
distribution: local
vectorized: true
·
• top-k
│ order: +b
│ k: 2
│
└── • scan
      missing stats
      table: t@t_pkey
      spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT DISTINCT c, b FROM t ORDER BY b LIMIT 2
----
distribution: local
vectorized: true
·
• top-k
│ columns: (c, b)
│ estimated row count: 2 (missing stats)
│ order: +b
│ k: 2
│
└── • distinct
    │ columns: (b, c)
    │ estimated row count: 300 (missing stats)
    │ distinct on: b, c
    │
    └── • scan
          columns: (b, c)
          estimated row count: 1,000 (missing stats)
          table: t@t_pkey
          spans: FULL SCAN

query T
EXPLAIN SELECT b FROM t ORDER BY a DESC
----
distribution: local
vectorized: true
·
• revscan
  missing stats
  table: t@t_pkey
  spans: FULL SCAN

# Check that LIMIT propagates past nosort nodes.
query T
EXPLAIN SELECT b FROM t ORDER BY a LIMIT 1
----
distribution: local
vectorized: true
·
• scan
  missing stats
  table: t@t_pkey
  spans: LIMITED SCAN
  limit: 1

query T
EXPLAIN SELECT b FROM t ORDER BY a DESC, b ASC
----
distribution: local
vectorized: true
·
• revscan
  missing stats
  table: t@t_pkey
  spans: FULL SCAN

query T
EXPLAIN SELECT b FROM t ORDER BY a DESC, b DESC
----
distribution: local
vectorized: true
·
• revscan
  missing stats
  table: t@t_pkey
  spans: FULL SCAN

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

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

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

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

# Check that sort is skipped if the ORDER BY clause is constant.
query T
EXPLAIN SELECT * FROM t ORDER BY 1+2
----
distribution: local
vectorized: true
·
• scan
  missing stats
  table: t@t_pkey
  spans: FULL SCAN

query T
EXPLAIN SELECT 1, * FROM t ORDER BY 1
----
distribution: local
vectorized: true
·
• render
│
└── • scan
      missing stats
      table: t@t_pkey
      spans: FULL SCAN

query T
EXPLAIN SELECT * FROM t ORDER BY length('abc')
----
distribution: local
vectorized: true
·
• scan
  missing stats
  table: t@t_pkey
  spans: FULL SCAN

# Check that the sort key reuses the existing render.
query T
EXPLAIN (VERBOSE) SELECT b+2 r FROM t ORDER BY b+2
----
distribution: local
vectorized: true
·
• sort
│ columns: (r)
│ estimated row count: 1,000 (missing stats)
│ order: +r
│
└── • render
    │ columns: (r)
    │ render r: b + 2
    │
    └── • scan
          columns: (b)
          estimated row count: 1,000 (missing stats)
          table: t@t_pkey
          spans: FULL SCAN

# Check that the sort picks up a renamed render properly.
query T
EXPLAIN (VERBOSE) SELECT b+2 AS y FROM t ORDER BY y
----
distribution: local
vectorized: true
·
• sort
│ columns: (y)
│ estimated row count: 1,000 (missing stats)
│ order: +y
│
└── • render
    │ columns: (y)
    │ render y: b + 2
    │
    └── • scan
          columns: (b)
          estimated row count: 1,000 (missing stats)
          table: t@t_pkey
          spans: FULL SCAN

statement ok
CREATE TABLE abc (
  a INT,
  b INT,
  c INT,
  d VARCHAR,
  PRIMARY KEY (a, b, c),
  UNIQUE INDEX bc (b, c),
  INDEX ba (b, a),
  FAMILY (a, b, c),
  FAMILY (d)
)

statement ok
INSERT INTO abc VALUES (1, 2, 3, 'one'), (4, 5, 6, 'Two')

statement ok
SET tracing = on,kv,results; SELECT * FROM abc ORDER BY a; SET tracing = off

query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 ORDER BY message LIKE 'fetched:%' DESC, ordinality ASC
----
fetched: /abc/abc_pkey/1/2/3 -> <undecoded>
fetched: /abc/abc_pkey/1/2/3/d -> 'one'
fetched: /abc/abc_pkey/4/5/6 -> <undecoded>
fetched: /abc/abc_pkey/4/5/6/d -> 'Two'
output row: [1 2 3 'one']
output row: [4 5 6 'Two']

statement ok
SET tracing = on,kv,results; SELECT a, b FROM abc ORDER BY b, a; SET tracing = off

query T
SELECT message FROM [SHOW KV TRACE FOR SESSION] WITH ORDINALITY
 WHERE message LIKE 'fetched:%' OR message LIKE 'output row%'
 ORDER BY message LIKE 'fetched:%' DESC, ordinality ASC
----
fetched: /abc/ba/2/1/? -> <undecoded>
fetched: /abc/ba/5/4/? -> <undecoded>
output row: [1 2]
output row: [4 5]

# The non-unique index ba includes column c (required to make the keys unique)
# so the results will already be sorted.
query T
EXPLAIN SELECT a, b, c FROM abc ORDER BY b, a, c
----
distribution: local
vectorized: true
·
• scan
  missing stats
  table: abc@ba
  spans: FULL SCAN

# We use the WHERE condition to force the use of the index.
query T
EXPLAIN SELECT a, b, c FROM abc WHERE b > 10 AND b < 15 ORDER BY b, a, d
----
distribution: local
vectorized: true
·
• sort
│ order: +b,+a,+d
│ already ordered: +b,+a
│
└── • index join
    │ table: abc@abc_pkey
    │
    └── • scan
          missing stats
          table: abc@ba
          spans: [/11 - /14]

# An inequality should not be enough to force the use of the index.
query T
EXPLAIN SELECT a, b, c FROM abc WHERE b > 10 ORDER BY b, a, d
----
distribution: local
vectorized: true
·
• sort
│ order: +b,+a,+d
│
└── • filter
    │ filter: b > 10
    │
    └── • scan
          missing stats
          table: abc@abc_pkey
          spans: FULL SCAN

query III
SELECT a, b, c FROM abc WHERE b > 4 ORDER BY b, a, d
----
4  5  6

query III
SELECT a, b, c FROM abc WHERE b > 4 ORDER BY b, a, d
----
4  5  6

# We cannot have rows with identical values for a,b,c so we don't need to
# sort for d.
query T
EXPLAIN (VERBOSE) SELECT a, b, c, d FROM abc WHERE b > 10 ORDER BY b, a, c, d
----
distribution: local
vectorized: true
·
• sort
│ columns: (a, b, c, d)
│ estimated row count: 333 (missing stats)
│ order: +b,+a,+c
│
└── • filter
    │ columns: (a, b, c, d)
    │ estimated row count: 333 (missing stats)
    │ filter: b > 10
    │
    └── • scan
          columns: (a, b, c, d)
          estimated row count: 1,000 (missing stats)
          table: abc@abc_pkey
          spans: FULL SCAN

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

query T
EXPLAIN (VERBOSE) SELECT a, b FROM abc ORDER BY b, c
----
distribution: local
vectorized: true
·
• project
│ columns: (a, b)
│
└── • scan
      columns: (a, b, c)
      ordering: +b,+c
      estimated row count: 1,000 (missing stats)
      table: abc@bc
      spans: FULL SCAN

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

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

statement ok
SET tracing = on,kv,results; SELECT b, c FROM abc ORDER BY b, c; 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: /abc/bc/2/3 -> /?
fetched: /abc/bc/5/6 -> /?
output row: [2 3]
output row: [5 6]

statement ok
SET tracing = on,kv,results; SELECT a, b, c FROM abc ORDER BY 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: /abc/bc/2/3 -> /1
fetched: /abc/bc/5/6 -> /4
output row: [1 2 3]
output row: [4 5 6]

statement ok
SET tracing = on,kv,results; SELECT a FROM abc 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: /abc/abc_pkey/4/?/? -> <undecoded>
fetched: /abc/abc_pkey/4/?/? -> <undecoded>
fetched: /abc/abc_pkey/1/?/? -> <undecoded>
fetched: /abc/abc_pkey/1/?/? -> <undecoded>
output row: [4]
output row: [1]

query T
EXPLAIN SELECT a FROM abc ORDER BY a DESC
----
distribution: local
vectorized: true
·
• revscan
  missing stats
  table: abc@abc_pkey
  spans: FULL SCAN

query T
EXPLAIN SELECT c FROM abc WHERE b = 2 ORDER BY c
----
distribution: local
vectorized: true
·
• scan
  missing stats
  table: abc@bc
  spans: [/2 - /2]

query T
EXPLAIN SELECT c FROM abc WHERE b = 2 ORDER BY c DESC
----
distribution: local
vectorized: true
·
• revscan
  missing stats
  table: abc@bc
  spans: [/2 - /2]

# Verify that the ordering of the primary index is still used for the outer sort.
query T
EXPLAIN (VERBOSE) SELECT * FROM (SELECT b, c FROM abc WHERE a=1 ORDER BY a,b) ORDER BY b,c
----
distribution: local
vectorized: true
·
• project
│ columns: (b, c)
│ ordering: +b,+c
│
└── • scan
      columns: (a, b, c)
      ordering: +b,+c
      estimated row count: 10 (missing stats)
      table: abc@abc_pkey
      spans: /1-/2

statement ok
CREATE TABLE bar (id INT PRIMARY KEY, baz STRING, UNIQUE INDEX i_bar (baz))

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

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

# Verify that render expressions after sorts perform correctly. We need the
# rowsort as we're attempting to force a RENDER expression after the first
# ORDER BY, to ensure it renders correctly, but the outer query doesn't
# guarantee that it will preserve the order.

# The following tests verify we recognize that sorting is not necessary
query T
EXPLAIN SELECT a, b, c FROM abcd@abc WHERE (a, b) = (1, 4) ORDER BY c
----
distribution: local
vectorized: true
·
• scan
  missing stats
  table: abcd@abc
  spans: [/1/4 - /1/4]

query T
EXPLAIN SELECT a, b, c FROM abcd@abc WHERE (a, b) = (1, 4) ORDER BY c, b, a
----
distribution: local
vectorized: true
·
• scan
  missing stats
  table: abcd@abc
  spans: [/1/4 - /1/4]

query T
EXPLAIN SELECT a, b, c FROM abcd@abc WHERE (a, b) = (1, 4) ORDER BY b, a, c
----
distribution: local
vectorized: true
·
• scan
  missing stats
  table: abcd@abc
  spans: [/1/4 - /1/4]

query T
EXPLAIN SELECT a, b, c FROM abcd@abc WHERE (a, b) = (1, 4) ORDER BY b, c, a
----
distribution: local
vectorized: true
·
• scan
  missing stats
  table: abcd@abc
  spans: [/1/4 - /1/4]

statement ok
CREATE TABLE nan (id INT PRIMARY KEY, x REAL)

query T
EXPLAIN (VERBOSE) SELECT * FROM (SELECT * FROM (VALUES ('a'), ('b'), ('c')) AS c(x) ORDER BY x)
----
distribution: local
vectorized: true
·
• values
  columns: (x)
  size: 1 column, 3 rows
  row 0, expr 0: 'a'
  row 1, expr 0: 'b'
  row 2, expr 0: 'c'

query T
EXPLAIN SELECT * FROM (VALUES ('a'), ('b'), ('c')) WITH ORDINALITY ORDER BY ordinality ASC
----
distribution: local
vectorized: true
·
• ordinality
│ estimated row count: 3
│
└── • values
      size: 1 column, 3 rows

query T
EXPLAIN SELECT * FROM (VALUES ('a'), ('b'), ('c')) WITH ORDINALITY ORDER BY ordinality DESC
----
distribution: local
vectorized: true
·
• sort
│ estimated row count: 3
│ order: -"ordinality"
│
└── • ordinality
    │ estimated row count: 3
    │
    └── • values
          size: 1 column, 3 rows

query T
EXPLAIN (VERBOSE) SELECT * FROM (SELECT * FROM (VALUES ('a'), ('b'), ('c')) AS c(x)) WITH ORDINALITY
----
distribution: local
vectorized: true
·
• ordinality
│ columns: (x, "ordinality")
│ estimated row count: 3
│
└── • values
      columns: (column1)
      size: 1 column, 3 rows
      row 0, expr 0: 'a'
      row 1, expr 0: 'b'
      row 2, expr 0: 'c'

query T
EXPLAIN (VERBOSE) SELECT * FROM (SELECT * FROM (VALUES ('a'), ('b'), ('c')) AS c(x) ORDER BY x) WITH ORDINALITY
----
distribution: local
vectorized: true
·
• ordinality
│ columns: (x, "ordinality")
│ estimated row count: 3
│
└── • sort
    │ columns: (column1)
    │ estimated row count: 3
    │ order: +column1
    │
    └── • values
          columns: (column1)
          size: 1 column, 3 rows
          row 0, expr 0: 'a'
          row 1, expr 0: 'b'
          row 2, expr 0: 'c'

# Check that the ordering of the source does not propagate blindly to RETURNING.
query T
EXPLAIN (VERBOSE) INSERT INTO t(a, b) SELECT * FROM (SELECT 1 AS x, 2 AS y) ORDER BY x RETURNING b
----
distribution: local
vectorized: true
·
• project
│ columns: (b)
│
└── • insert fast path
      columns: (a, b)
      estimated row count: 1
      into: t(a, b, c)
      auto commit
      size: 3 columns, 1 row
      row 0, expr 0: 1
      row 0, expr 1: 2
      row 0, expr 2: CAST(NULL AS BOOL)

query T
EXPLAIN (VERBOSE) DELETE FROM t WHERE a = 3 RETURNING b
----
distribution: local
vectorized: true
·
• project
│ columns: (b)
│
└── • delete
    │ columns: (a, b)
    │ estimated row count: 1 (missing stats)
    │ from: t
    │ auto commit
    │
    └── • scan
          columns: (a, b)
          estimated row count: 1 (missing stats)
          table: t@t_pkey
          spans: /3/0
          locking strength: for update

query T
EXPLAIN (VERBOSE) UPDATE t SET c = TRUE RETURNING b
----
distribution: local
vectorized: true
·
• project
│ columns: (b)
│
└── • update
    │ columns: (a, b)
    │ estimated row count: 1,000 (missing stats)
    │ table: t
    │ set: c
    │ auto commit
    │
    └── • render
        │ columns: (a, b, c, c_new)
        │ render c_new: true
        │ render a: a
        │ render b: b
        │ render c: c
        │
        └── • scan
              columns: (a, b, c)
              estimated row count: 1,000 (missing stats)
              table: t@t_pkey
              spans: FULL SCAN
              locking strength: for update

statement ok
CREATE TABLE uvwxyz (
  u INT,
  v INT,
  w INT,
  x INT,
  y INT,
  z INT,
  INDEX ywxz (y, w, x, z, u, v),
  INDEX ywz (y, w, z, x)
)

# Verify that the outer ordering is propagated to index selection and we choose
# the index that avoids any sorting.
query T
EXPLAIN (VERBOSE) SELECT * FROM (SELECT y, w, x FROM uvwxyz WHERE y = 1 ORDER BY w) ORDER BY w, x
----
distribution: local
vectorized: true
·
• scan
  columns: (y, w, x)
  ordering: +w,+x
  estimated row count: 10 (missing stats)
  table: uvwxyz@ywxz
  spans: /1-/2


statement ok
CREATE TABLE blocks (
  block_id  INT,
  writer_id STRING,
  block_num INT,
  raw_bytes BYTES,
  PRIMARY KEY (block_id, writer_id, block_num)
)

# Test that ordering goes "through" a renderNode that has a duplicate render of
# an order-by column (#13696).
# Note that if we have a hard limit of 1, the scanNode won't necessarily have an
# ordering; if we ever plan multiple tablereaders in this case, we must make
# sure to set the merge ordering below to the natural order of the index we are
# scanning.
query T
EXPLAIN (VERBOSE) SELECT block_id,writer_id,block_num,block_id FROM blocks ORDER BY block_id, writer_id, block_num LIMIT 1
----
distribution: local
vectorized: true
·
• project
│ columns: (block_id, writer_id, block_num, block_id)
│
└── • scan
      columns: (block_id, writer_id, block_num)
      estimated row count: 1 (missing stats)
      table: blocks@blocks_pkey
      spans: LIMITED SCAN
      limit: 1

statement ok
CREATE TABLE foo(a INT, b CHAR)

statement ok
SET allow_ordinal_column_references=true

# Check that sort by ordinal picks up the existing render.
query T
EXPLAIN (VERBOSE) SELECT b, a FROM foo ORDER BY @1
----
distribution: local
vectorized: true
·
• project
│ columns: (b, a)
│
└── • render
    │ columns: (column8, a, b)
    │ ordering: +a
    │ render column8: a
    │ render a: a
    │ render b: b
    │
    └── • sort
        │ columns: (a, b)
        │ estimated row count: 1,000 (missing stats)
        │ order: +a
        │
        └── • scan
              columns: (a, b)
              estimated row count: 1,000 (missing stats)
              table: foo@foo_pkey
              spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT b, a FROM foo ORDER BY @2
----
distribution: local
vectorized: true
·
• project
│ columns: (b, a)
│
└── • render
    │ columns: (column8, a, b)
    │ ordering: +b
    │ render column8: b
    │ render a: a
    │ render b: b
    │
    └── • sort
        │ columns: (a, b)
        │ estimated row count: 1,000 (missing stats)
        │ order: +b
        │
        └── • scan
              columns: (a, b)
              estimated row count: 1,000 (missing stats)
              table: foo@foo_pkey
              spans: FULL SCAN

statement ok
SET allow_ordinal_column_references=false

# ------------------------------------------------------------------------------
# Check star expansion in ORDER BY.
# ------------------------------------------------------------------------------
statement ok
CREATE TABLE a(x, y) AS VALUES (1, 1), (2, 2)

query T
EXPLAIN (VERBOSE) SELECT * FROM a ORDER BY a.*
----
distribution: local
vectorized: true
·
• sort
│ columns: (x, y)
│ estimated row count: 1,000 (missing stats)
│ order: +x,+y
│
└── • 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 ORDER BY (a.*)
----
distribution: local
vectorized: true
·
• sort
│ columns: (x, y)
│ estimated row count: 1,000 (missing stats)
│ order: +x,+y
│
└── • scan
      columns: (x, y)
      estimated row count: 1,000 (missing stats)
      table: a@a_pkey
      spans: FULL SCAN

# ------------------------------------------------------------------------------
# ORDER BY INDEX test cases.
# ------------------------------------------------------------------------------
# subtest order_by_index

statement ok
CREATE TABLE kv(k INT PRIMARY KEY, v INT); CREATE INDEX foo ON kv(v DESC)

query T
EXPLAIN (VERBOSE) SELECT v FROM kv ORDER BY PRIMARY KEY kv
----
distribution: local
vectorized: true
·
• project
│ columns: (v)
│
└── • scan
      columns: (k, v)
      ordering: +k
      estimated row count: 1,000 (missing stats)
      table: kv@kv_pkey
      spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT v FROM kv ORDER BY PRIMARY KEY kv ASC
----
distribution: local
vectorized: true
·
• project
│ columns: (v)
│
└── • scan
      columns: (k, v)
      ordering: +k
      estimated row count: 1,000 (missing stats)
      table: kv@kv_pkey
      spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT v FROM kv ORDER BY PRIMARY KEY kv DESC
----
distribution: local
vectorized: true
·
• project
│ columns: (v)
│
└── • revscan
      columns: (k, v)
      ordering: -k
      estimated row count: 1,000 (missing stats)
      table: kv@kv_pkey
      spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT k FROM kv ORDER BY v, PRIMARY KEY kv, v-2
----
distribution: local
vectorized: true
·
• project
│ columns: (k)
│
└── • sort
    │ columns: (k, v)
    │ estimated row count: 1,000 (missing stats)
    │ order: +v,+k
    │
    └── • scan
          columns: (k, v)
          estimated row count: 1,000 (missing stats)
          table: kv@kv_pkey
          spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT k FROM kv ORDER BY INDEX kv@foo
----
distribution: local
vectorized: true
·
• project
│ columns: (k)
│
└── • scan
      columns: (k, v)
      ordering: -v,+k
      estimated row count: 1,000 (missing stats)
      table: kv@foo
      spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT k FROM kv ORDER BY INDEX kv@foo ASC
----
distribution: local
vectorized: true
·
• project
│ columns: (k)
│
└── • scan
      columns: (k, v)
      ordering: -v,+k
      estimated row count: 1,000 (missing stats)
      table: kv@foo
      spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT k FROM kv ORDER BY INDEX kv@foo DESC
----
distribution: local
vectorized: true
·
• project
│ columns: (k)
│
└── • revscan
      columns: (k, v)
      ordering: +v,-k
      estimated row count: 1,000 (missing stats)
      table: kv@foo
      spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT k FROM kv ORDER BY INDEX kv@foo, k
----
distribution: local
vectorized: true
·
• project
│ columns: (k)
│
└── • scan
      columns: (k, v)
      ordering: -v,+k
      estimated row count: 1,000 (missing stats)
      table: kv@foo
      spans: FULL SCAN

# Check the syntax can be used with joins.
#
# Note: an ORDER BY INDEX clause on the result of the join
# does not imply use of that index by the underlying scan.
#

query T
EXPLAIN (VERBOSE)
SELECT k FROM kv JOIN (VALUES (1,2), (3,4)) AS z(a,b) ON kv.k = z.a ORDER BY INDEX kv@foo
----
distribution: local
vectorized: true
·
• project
│ columns: (k)
│
└── • sort
    │ columns: (k, v)
    │ estimated row count: 2 (missing stats)
    │ order: -v,+k
    │
    └── • project
        │ columns: (k, v)
        │
        └── • lookup join (inner)
            │ columns: (column1, k, v)
            │ estimated row count: 2 (missing stats)
            │ table: kv@kv_pkey
            │ equality: (column1) = (k)
            │ equality cols are key
            │
            └── • values
                  columns: (column1)
                  size: 1 column, 2 rows
                  row 0, expr 0: 1
                  row 1, expr 0: 3

query T
EXPLAIN (VERBOSE) SELECT k FROM kv a NATURAL JOIN kv ORDER BY INDEX kv@foo
----
distribution: local
vectorized: true
·
• project
│ columns: (k)
│
└── • project
    │ columns: (k, k, v)
    │ ordering: -v,+k
    │
    └── • merge join (inner)
        │ columns: (k, v, k, v)
        │ ordering: -v,+k
        │ estimated row count: 10 (missing stats)
        │ equality: (v, k) = (v, k)
        │ left cols are key
        │ right cols are key
        │ merge ordering: -"(v=v)",+"(k=k)"
        │
        ├── • scan
        │     columns: (k, v)
        │     ordering: -v,+k
        │     estimated row count: 1,000 (missing stats)
        │     table: kv@foo
        │     spans: FULL SCAN
        │
        └── • scan
              columns: (k, v)
              ordering: -v,+k
              estimated row count: 1,000 (missing stats)
              table: kv@foo
              spans: FULL SCAN

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

# Verify that we set up the ordering of the inner scan correctly (see #27347).
query T
EXPLAIN (VERBOSE) SELECT * FROM xyz WHERE z=1 AND x=y ORDER BY x;
----
distribution: local
vectorized: true
·
• filter
│ columns: (x, y, z)
│ ordering: +y
│ estimated row count: 1 (missing stats)
│ filter: x = y
│
└── • index join
    │ columns: (x, y, z)
    │ ordering: +y
    │ estimated row count: 10 (missing stats)
    │ table: xyz@xyz_pkey
    │ key columns: rowid
    │
    └── • scan
          columns: (y, z, rowid)
          ordering: +y
          estimated row count: 10 (missing stats)
          table: xyz@xyz_z_y_idx
          spans: /1/!NULL-/2

# ------------------------------------------------------------------------------
# NULLS FIRST, NULLS LAST test cases.
# ------------------------------------------------------------------------------
# subtest nulls_ordering

query T
EXPLAIN (VERBOSE) SELECT a, b FROM t ORDER BY b NULLS FIRST
----
distribution: local
vectorized: true
·
• sort
│ columns: (a, b)
│ estimated row count: 1,000 (missing stats)
│ order: +b
│
└── • scan
      columns: (a, b)
      estimated row count: 1,000 (missing stats)
      table: t@t_pkey
      spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT a, b FROM t ORDER BY b NULLS LAST
----
distribution: local
vectorized: true
·
• project
│ columns: (a, b)
│
└── • sort
    │ columns: (nulls_ordering_b, a, b)
    │ estimated row count: 1,000 (missing stats)
    │ order: +nulls_ordering_b,+b
    │
    └── • render
        │ columns: (nulls_ordering_b, a, b)
        │ render nulls_ordering_b: b IS NULL
        │ render a: a
        │ render b: b
        │
        └── • scan
              columns: (a, b)
              estimated row count: 1,000 (missing stats)
              table: t@t_pkey
              spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT a, b FROM t ORDER BY b DESC NULLS FIRST
----
distribution: local
vectorized: true
·
• project
│ columns: (a, b)
│
└── • sort
    │ columns: (nulls_ordering_b, a, b)
    │ estimated row count: 1,000 (missing stats)
    │ order: -nulls_ordering_b,-b
    │
    └── • render
        │ columns: (nulls_ordering_b, a, b)
        │ render nulls_ordering_b: b IS NULL
        │ render a: a
        │ render b: b
        │
        └── • scan
              columns: (a, b)
              estimated row count: 1,000 (missing stats)
              table: t@t_pkey
              spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT a, b FROM t ORDER BY b DESC NULLS LAST
----
distribution: local
vectorized: true
·
• sort
│ columns: (a, b)
│ estimated row count: 1,000 (missing stats)
│ order: -b
│
└── • scan
      columns: (a, b)
      estimated row count: 1,000 (missing stats)
      table: t@t_pkey
      spans: FULL SCAN

query T
EXPLAIN (VERBOSE) SELECT a, b FROM t ORDER BY b DESC NULLS FIRST, c NULLS LAST
----
distribution: local
vectorized: true
·
• project
│ columns: (a, b)
│
└── • sort
    │ columns: (nulls_ordering_b, nulls_ordering_c, a, b, c)
    │ estimated row count: 1,000 (missing stats)
    │ order: -nulls_ordering_b,-b,+nulls_ordering_c,+c
    │
    └── • render
        │ columns: (nulls_ordering_b, nulls_ordering_c, a, b, c)
        │ render nulls_ordering_b: b IS NULL
        │ render nulls_ordering_c: c IS NULL
        │ render a: a
        │ render b: b
        │ render c: c
        │
        └── • scan
              columns: (a, b, c)
              estimated row count: 1,000 (missing stats)
              table: t@t_pkey
              spans: FULL SCAN

statement ok
CREATE INDEX b_idx ON t(b);

# TODO(nehageorge): Right now the optimizer does a sort even though there is an
# index on column b. In the future, null-reordering for indexes can be added to
# mitigate this as per #6224. Consider: "CREATE INDEX b_idx ON t(b NULLS LAST)."
query T
EXPLAIN (VERBOSE) SELECT a, b FROM t ORDER BY b NULLS LAST
----
distribution: local
vectorized: true
·
• project
│ columns: (a, b)
│
└── • sort
    │ columns: (nulls_ordering_b, a, b)
    │ estimated row count: 1,000 (missing stats)
    │ order: +nulls_ordering_b,+b
    │
    └── • render
        │ columns: (nulls_ordering_b, a, b)
        │ render nulls_ordering_b: b IS NULL
        │ render a: a
        │ render b: b
        │
        └── • scan
              columns: (a, b)
              estimated row count: 1,000 (missing stats)
              table: t@b_idx
              spans: FULL SCAN
