# LogicTest: 5node-dist-opt

# This test verifies that we correctly tighten spans during index selection as
# well as after partitioning spans in distsql.

################
# Schema setup #
################

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

statement ok
CREATE TABLE c1 (
  a INT,
  b INT,
  PRIMARY KEY (a,b)
) INTERLEAVE IN PARENT p1 (a, b)

statement ok
CREATE TABLE p2 (
  i INT PRIMARY KEY,
  d INT
)

statement ok
CREATE INDEX p2_id ON p2 (i, d) INTERLEAVE IN PARENT p2 (i)

statement ok
CREATE TABLE bytes_t (a BYTES PRIMARY KEY)

statement ok
CREATE TABLE decimal_t (a DECIMAL PRIMARY KEY)

############################
# Split ranges for distsql #
############################

# Perform some splits to exercise distsql partitioning as well.

# Create split points at X = 2.
# Also split at the beginning of each index (0 for ASC, 100 for DESC) to
# prevent interfering with previous indexes/tables.

# Prevent the merge queue from immediately discarding our splits.
statement ok
SET CLUSTER SETTING kv.range_merge.queue_enabled = false;

# p1 table (interleaved index)
statement ok
ALTER TABLE p1 SPLIT AT VALUES(2)

# Create a split at /2/#
statement ok
ALTER TABLE c1 SPLIT AT VALUES(2,1)

# Split index
statement ok
ALTER INDEX b SPLIT AT VALUES(0)

statement ok
ALTER INDEX b SPLIT AT VALUES(2)

# p2 table (interleaved index)
statement ok
ALTER TABLE p2 SPLIT AT VALUES(0)

statement ok
ALTER TABLE p2 SPLIT AT VALUES(2)

# Create a split at /2/#
statement ok
ALTER INDEX p2_id SPLIT AT VALUES(2)

#####################
# Distribute ranges #
#####################

# Distribute our ranges across the first 3 (for primary index) and last 2
# (for seconary indexes) nodes.

statement ok
ALTER TABLE p1 EXPERIMENTAL_RELOCATE SELECT ARRAY[i], i FROM generate_series(1,3) AS g(i)

statement ok
ALTER INDEX b EXPERIMENTAL_RELOCATE SELECT ARRAY[i+3], i FROM generate_series(1,2) AS g(i)

# Interleaved index table
statement ok
ALTER TABLE p2 EXPERIMENTAL_RELOCATE SELECT ARRAY[i], i FROM generate_series(1,3) as g(i)

#############################
# Verify range distribution #
#############################

# p1 table (interleaved table)

query TTITI colnames
SHOW EXPERIMENTAL_RANGES FROM TABLE p1
----
start_key    end_key      range_id  replicas  lease_holder
NULL         /2           1         {1}       1
/2           /2/1/#/54/1  2         {2}       2
/2/1/#/54/1  NULL         3         {3}       3

# Indexes

query TTITI colnames
SHOW EXPERIMENTAL_RANGES FROM INDEX b
----
start_key  end_key  range_id  replicas  lease_holder
NULL       /0       3         {3}       3
/0         /2       4         {4}       4
/2         NULL     5         {5}       5

# p2 table (interleaved index)

query TTITI colnames
SHOW EXPERIMENTAL_RANGES FROM TABLE p2
----
start_key  end_key    range_id  replicas  lease_holder
NULL       /0         5         {5}       5
/0         /2         6         {1}       1
/2         /2/#/55/2  7         {2}       2
/2/#/55/2  NULL       8         {3}       3

###############
# Query tests #
###############

# p1 table

# Secondary index should not be tightened.
query TTT
EXPLAIN SELECT * FROM p1 WHERE b <= 3
----
scan  ·      ·
·     table  p1@b
·     spans  -/4

# Partial predicate on primary key should not be tightened.
query TTT
EXPLAIN SELECT * FROM p1 WHERE a <= 3
----
scan  ·      ·
·     table  p1@primary
·     spans  -/4

# Tighten end key if span contains full primary key.
query TTT
EXPLAIN SELECT * FROM p1 WHERE a <= 3 AND b <= 3
----
scan  ·       ·
·     table   p1@primary
·     spans   -/3/3/#
·     filter  b <= 3

query TTT
EXPLAIN SELECT * FROM p1 WHERE a <= 3 AND b < 4
----
scan  ·       ·
·     table   p1@primary
·     spans   -/3/3/#
·     filter  b < 4

# Mixed bounds.
query TTT
EXPLAIN SELECT * FROM p1 WHERE a >= 2 AND b <= 3
----
scan  ·       ·
·     table   p1@primary
·     spans   /2-
·     filter  b <= 3

# Edge cases.

query TTT
EXPLAIN SELECT * FROM p1 WHERE a <= 0 AND b <= 0
----
scan  ·       ·
·     table   p1@primary
·     spans   -/0/0/#
·     filter  b <= 0

query TTT
EXPLAIN SELECT * FROM p1 WHERE a <= -1 AND b <= -1
----
scan  ·       ·
·     table   p1@primary
·     spans   -/-1/-1/#
·     filter  b <= -1

query TTT
EXPLAIN SELECT * FROM p1 WHERE a = 1 AND b <= -9223372036854775808
----
scan  ·      ·
·     table  p1@primary
·     spans  /1-/1/-9223372036854775808/#

query TTT
EXPLAIN SELECT * FROM p1 WHERE a = 1 AND b <= 9223372036854775807
----
scan  ·      ·
·     table  p1@primary
·     spans  /1-/1/9223372036854775807/#

# Table c1 (interleaved table)

# Partial primary key does not tighten.

query TTT
EXPLAIN SELECT * FROM c1 WHERE a <= 3
----
scan  ·      ·
·     table  c1@primary
·     spans  -/4

# Tighten span on fully primary key.
query TTT
EXPLAIN SELECT * FROM c1 WHERE a <= 3 AND b <= 3
----
scan  ·       ·
·     table   c1@primary
·     spans   -/3/3/#/54/1/#
·     filter  b <= 3

# Table p2 with interleaved index.

# From the primary index.

# Lower bound (i >= 2)
query TTT
EXPLAIN SELECT * FROM p2 WHERE i >= 2
----
scan  ·      ·
·     table  p2@primary
·     spans  /2-

# Upper bound (i <= 5)

query TTT
EXPLAIN SELECT * FROM p2 WHERE i <= 5
----
scan  ·      ·
·     table  p2@primary
·     spans  -/5/#

# From the interleaved index: no tightening at all.

# Lower bound (i >= 1 AND d >= 2)

# Note 53/2 refers to the 2nd index (after primary index) of table p2.
query TTT
EXPLAIN SELECT * FROM p2@p2_id WHERE i >= 1 AND d >= 2
----
scan  ·       ·
·     table   p2@p2_id
·     spans   /1/#/55/2/2-
·     filter  d >= 2

# Upper bound (i <= 6 AND d <= 5)

query TTT
EXPLAIN SELECT * FROM p2@p2_id WHERE i <= 6 AND d <= 5
----
scan  ·       ·
·     table   p2@p2_id
·     spans   -/6/#/55/2/6
·     filter  d <= 5

# IS NULL

query TTT
EXPLAIN SELECT * FROM p2@p2_id WHERE i >= 1 AND d IS NULL
----
scan  ·       ·
·     table   p2@p2_id
·     spans   /1/#/55/2/NULL-
·     filter  d IS NULL

# IS NOT NULL

query TTT
EXPLAIN SELECT * FROM p2@p2_id WHERE i >= 1 AND d IS NOT NULL
----
scan  ·       ·
·     table   p2@p2_id
·     spans   /1/#/55/2/!NULL-
·     filter  d IS NOT NULL

# String table

query TTT colnames
EXPLAIN SELECT * FROM bytes_t WHERE a = 'a'
----
tree  field  description
scan  ·      ·
·     table  bytes_t@primary
·     spans  /"a"-/"a"/#

# No tightening.

query TTT colnames
EXPLAIN SELECT * FROM bytes_t WHERE a < 'aa'
----
tree  field  description
scan  ·      ·
·     table  bytes_t@primary
·     spans  -/"aa"

query TTT colnames
EXPLAIN SELECT * FROM decimal_t WHERE a = 1.00
----
tree  field  description
scan  ·      ·
·     table  decimal_t@primary
·     spans  /1-/1/#

# No tightening.

query TTT colnames
EXPLAIN SELECT * FROM decimal_t WHERE a < 2
----
tree  field  description
scan  ·      ·
·     table  decimal_t@primary
·     spans  -/2
