# LogicTest: local
# BackupRestoreProbability: 0.0

statement ok
CREATE TABLE t (
  i INT PRIMARY KEY,
  j INT UNIQUE,
  k INT,
  UNIQUE (k) STORING (j)
);
CREATE TABLE t2 (
  i INT PRIMARY KEY,
  j INT UNIQUE,
  k INT,
  UNIQUE (k) STORING (j)
);

statement ok
INSERT INTO t VALUES (2);
INSERT INTO t2 VALUES (2);

statement error pgcode 3D000 pq: database "test" does not exist
SELECT * FROM t AS OF SYSTEM TIME follower_read_timestamp()

statement error pgcode 3D000 pq: database "test" does not exist
SELECT * FROM t AS OF SYSTEM TIME experimental_follower_read_timestamp()

statement error pgcode 3D000 pq: database "test" does not exist
BEGIN; SET TRANSACTION AS OF SYSTEM TIME follower_read_timestamp(); SELECT * FROM t

statement ok
ROLLBACK

statement error pgcode 3D000 pq: database "test" does not exist
BEGIN AS OF SYSTEM TIME follower_read_timestamp(); SELECT * FROM t

statement ok
ROLLBACK

statement error pgcode 0A000 inconsistent AS OF SYSTEM TIME timestamp
SELECT * from t AS OF SYSTEM TIME '-1μs'; SELECT * from t AS OF SYSTEM TIME '-2μs'

statement ok
SET DEFAULT_TRANSACTION_USE_FOLLOWER_READS TO TRUE

statement error pgcode 3D000 pq: database "test" does not exist
SELECT * FROM t

# LSC and DSC would return slightly different error message when attempting to create a
# database as of system time follower_read_timestamp() soon after a node has started.
statement error pq: (cannot execute CREATE DATABASE in a read-only transaction|referenced descriptor ID 1: looking up ID 1: descriptor not found|database \"\[1\]\" does not exist|role/user \"root\" does not exist)
CREATE DATABASE IF NOT EXISTS d2

statement error pgcode 3D000 pq: database "test" does not exist
BEGIN; SELECT * FROM t

statement ok
ROLLBACK

statement error pq: AS OF SYSTEM TIME specified with READ WRITE mode
BEGIN READ WRITE

statement error (pq: cannot execute CREATE DATABASE in a read-only transaction|database \"\[1\]\" does not exist)
BEGIN; CREATE DATABASE IF NOT EXISTS d2

statement ok
ROLLBACK

statement ok
SET DEFAULT_TRANSACTION_USE_FOLLOWER_READS TO FALSE

statement ok
SELECT * FROM t

statement ok
CREATE DATABASE IF NOT EXISTS d2

statement ok
BEGIN; SELECT * FROM t; COMMIT

statement ok
BEGIN READ WRITE; COMMIT

statement ok
BEGIN; CREATE DATABASE IF NOT EXISTS d2; COMMIT

statement ok
SET SESSION CHARACTERISTICS AS TRANSACTION AS OF SYSTEM TIME follower_read_timestamp()

statement error pgcode 3D000 pq: database "test" does not exist
SELECT * FROM t

# LSC and DSC would return slightly different error message when attempting to create a
# database as of system time follower_read_timestamp() soon after a node has started.
statement error pq: (cannot execute CREATE DATABASE in a read-only transaction|referenced descriptor ID 1: looking up ID 1: descriptor not found|database \"\[1\]\" does not exist|role/user \"root\" does not exist)
CREATE DATABASE IF NOT EXISTS d2

statement error pgcode 3D000 pq: database "test" does not exist
BEGIN; SELECT * FROM t

statement ok
ROLLBACK

statement error pq: AS OF SYSTEM TIME specified with READ WRITE mode
BEGIN READ WRITE

statement error (pq: cannot execute CREATE DATABASE in a read-only transaction|database \"\[1\]\" does not exist)
BEGIN; CREATE DATABASE IF NOT EXISTS d2

statement ok
ROLLBACK

statement ok
SET DEFAULT_TRANSACTION_USE_FOLLOWER_READS TO FALSE

query B
SELECT with_min_timestamp(statement_timestamp()) = statement_timestamp()
----
true

query B
SELECT with_min_timestamp(statement_timestamp() - '5s'::interval) = statement_timestamp() - '5s'::interval
----
true

statement error timestamp for with_min_timestamp must be less than or equal to statement_timestamp\(\)
SELECT with_min_timestamp(statement_timestamp() + '5s'::interval) = statement_timestamp()

query B
SELECT with_max_staleness('10s') = statement_timestamp() - '10s'::interval
----
true

statement error interval duration for with_max_staleness must be greater or equal to 0
SELECT with_max_staleness(-'1s')

#
# Tests for optimizer bounded staleness checks.
#

statement error unimplemented: cannot use bounded staleness for queries that may touch more than one range or require an index join
SELECT * FROM t AS OF SYSTEM TIME with_max_staleness('1ms')

statement error unimplemented: cannot use bounded staleness for queries that may touch more than one range or require an index join
SELECT * FROM t AS OF SYSTEM TIME with_min_timestamp(statement_timestamp() - '1ms')

statement error unimplemented: cannot use bounded staleness for MERGE JOIN
SELECT * FROM t AS t1 JOIN t2 AS t2 ON t1.i = t2.i AS OF SYSTEM TIME with_max_staleness('1ms')

statement error unimplemented: cannot use bounded staleness for INNER JOIN
SELECT * FROM t AS t1 INNER HASH JOIN t2 AS t2 ON t1.i = t2.i AS OF SYSTEM TIME with_min_timestamp(statement_timestamp() - '1ms')

statement error unimplemented: cannot use bounded staleness for LOOKUP JOIN
SELECT * FROM t AS t1 LEFT LOOKUP JOIN t2 AS t2 ON t1.i = t2.i AS OF SYSTEM TIME with_max_staleness('1ms')

statement error unimplemented: cannot use bounded staleness for UNION
SELECT * FROM (SELECT * FROM t UNION SELECT * FROM t) AS OF SYSTEM TIME with_max_staleness('1ms')

statement error unimplemented: cannot use bounded staleness for INTERSECT ALL
SELECT * FROM (SELECT * FROM t INTERSECT ALL SELECT * FROM t) AS OF SYSTEM TIME with_min_timestamp(statement_timestamp() - '1ms')

statement ok
SELECT * FROM t AS OF SYSTEM TIME with_max_staleness('1ms') WHERE i = 2

statement ok
SELECT * FROM t AS OF SYSTEM TIME with_min_timestamp(statement_timestamp() - '1ms') WHERE i = 1

# Projections are supported.
statement ok
SELECT i+2 FROM t AS OF SYSTEM TIME with_max_staleness('1ms') WHERE i = 1

# Select is supported.
statement ok
SELECT * FROM t AS OF SYSTEM TIME with_max_staleness('1ms') WHERE i = 2 AND j > 5

# Aggregations are supported.
statement ok
SELECT sum(i) FROM t AS OF SYSTEM TIME with_min_timestamp(statement_timestamp() - '1ms') WHERE i = 2

# Scan from a secondary index is supported.
statement ok
SELECT * FROM t AS OF SYSTEM TIME with_max_staleness('1ms') WHERE k = 2

# Scan from a secondary index is not supported if it requires an index join.
statement error unimplemented: cannot use bounded staleness for queries that may touch more than one range or require an index join
SELECT * FROM t AS OF SYSTEM TIME with_max_staleness('1ms') WHERE j = 2

# No index join or zigzag join is produced.
query T
EXPLAIN (OPT, MEMO) SELECT * FROM t AS OF SYSTEM TIME with_max_staleness('1ms') WHERE j = 2 AND i = 1
----
memo (optimized, ~9KB, required=[presentation: info:8] [distribution: test])
 ├── G1: (explain G2 [presentation: i:1,j:2,k:3] [distribution: test])
 │    └── [presentation: info:8] [distribution: test]
 │         ├── best: (explain G2="[presentation: i:1,j:2,k:3] [distribution: test]" [presentation: i:1,j:2,k:3] [distribution: test])
 │         └── cost: 9.18
 ├── G2: (select G3 G4) (select G5 G6)
 │    ├── [presentation: i:1,j:2,k:3] [distribution: test]
 │    │    ├── best: (select G5="[distribution: test]" G6)
 │    │    └── cost: 9.16
 │    └── []
 │         ├── best: (select G5 G6)
 │         └── cost: 9.16
 ├── G3: (scan t,cols=(1-3)) (scan t@t_k_key,cols=(1-3))
 │    ├── [distribution: test]
 │    │    ├── best: (scan t,cols=(1-3))
 │    │    └── cost: 1149.22
 │    └── []
 │         ├── best: (scan t,cols=(1-3))
 │         └── cost: 1149.22
 ├── G4: (filters G7 G8)
 ├── G5: (scan t,cols=(1-3),constrained)
 │    ├── [distribution: test]
 │    │    ├── best: (scan t,cols=(1-3),constrained)
 │    │    └── cost: 9.13
 │    └── []
 │         ├── best: (scan t,cols=(1-3),constrained)
 │         └── cost: 9.13
 ├── G6: (filters G7)
 ├── G7: (eq G9 G10)
 ├── G8: (eq G11 G12)
 ├── G9: (variable j)
 ├── G10: (const 2)
 ├── G11: (variable i)
 └── G12: (const 1)
select
 ├── scan t
 │    ├── constraint: /1: [/1 - /1]
 │    └── flags: no-index-join no-zigzag-join
 └── filters
      └── j = 2

# Scan may produce multiple rows.
statement error unimplemented: cannot use bounded staleness for queries that may touch more than one range or require an index join
SELECT * FROM t AS OF SYSTEM TIME with_max_staleness('1ms') WHERE k IS NULL

# Scan may produce multiple rows.
statement error unimplemented: cannot use bounded staleness for queries that may touch more than one range or require an index join
SELECT * FROM t AS OF SYSTEM TIME with_max_staleness('1ms') WHERE k IS NULL LIMIT 10

# Even though the scan is limited to 1 row, from KV's perspective, this is a
# multi-row scan with a limit. That means that the scan can span multiple
# ranges, but we expect it to short-circuit once it hits the first row. In
# practice, we expect that to very often be in the first range we hit, but
# there's no guarantee of that - we could have empty ranges.
statement error unimplemented: cannot use bounded staleness for queries that may touch more than one range or require an index join
SELECT * FROM t AS OF SYSTEM TIME with_max_staleness('1ms') WHERE k IS NULL LIMIT 1

# Subquery contains the only scan, so it succeeds.
statement ok
SELECT (SELECT k FROM t WHERE i = 1) FROM generate_series(1, 100) AS OF SYSTEM TIME with_max_staleness('1ms')

# Subquery does not scan data, so it succeeds.
statement ok
SELECT (SELECT random()) FROM t AS OF SYSTEM TIME with_max_staleness('1ms') WHERE k = 1

# Subqueries that perform an additional scan are not supported.
statement error unimplemented: cannot use bounded staleness for queries that may touch more than one range or require an index join
SELECT (SELECT k FROM t WHERE i = 1) FROM t AS OF SYSTEM TIME with_max_staleness('1ms') WHERE k = 1

# Bounded staleness function must match outer query if used in subquery.
statement ok
SELECT (
  SELECT k FROM t AS OF SYSTEM TIME with_max_staleness('1ms') WHERE i = 1
) FROM generate_series(1, 100) AS OF SYSTEM TIME with_max_staleness('1ms')

# Bounded staleness function must match outer query if used in subquery.
statement error unimplemented: cannot specify AS OF SYSTEM TIME with different timestamps
SELECT (
  SELECT k FROM t AS OF SYSTEM TIME with_max_staleness('2ms') WHERE i = 1
) FROM generate_series(1, 100) AS OF SYSTEM TIME with_max_staleness('1ms')

# Bounded staleness function must match outer query if used in subquery.
statement error AS OF SYSTEM TIME must be provided on a top-level statement
SELECT (
  SELECT k FROM t AS OF SYSTEM TIME with_max_staleness('1ms') WHERE i = 1
) FROM generate_series(1, 100)

#
# Tests for nearest_only argument.
#

statement error with_max_staleness: expected bool argument for nearest_only
SELECT * FROM t AS OF SYSTEM TIME with_max_staleness('1ms', 5)

statement error with_min_timestamp: expected bool argument for nearest_only
SELECT * FROM t AS OF SYSTEM TIME with_min_timestamp(statement_timestamp(), 5)

statement ok
SELECT * FROM t AS OF SYSTEM TIME with_max_staleness('1ms', false) WHERE i = 2

statement ok
SELECT * FROM t AS OF SYSTEM TIME with_min_timestamp(statement_timestamp() - '1ms', false) WHERE i = 2

statement error pgcode XCUBS bounded staleness read with minimum timestamp bound.*could not be satisfied by a local resolved timestamp
SELECT * FROM t AS OF SYSTEM TIME with_max_staleness('1ms', true) WHERE i = 2

statement error pgcode XCUBS bounded staleness read with minimum timestamp bound.*could not be satisfied by a local resolved timestamp
SELECT * FROM t AS OF SYSTEM TIME with_min_timestamp(statement_timestamp() - '1ms', true) WHERE i = 2

#
# Tests for running bounded staleness queries in an explicit transaction.
#

statement error AS OF SYSTEM TIME: only constant expressions or follower_read_timestamp are allowed
BEGIN AS OF SYSTEM TIME with_max_staleness('1ms')

statement error cannot use a bounded staleness query in a transaction
BEGIN; SELECT * FROM t AS OF SYSTEM TIME with_max_staleness('1ms')

statement ok
ROLLBACK

#
# Tests for bounded staleness with prepared statements.
#

statement ok
PREPARE with_min_timestamp_prep AS SELECT * FROM t AS OF SYSTEM TIME with_min_timestamp(statement_timestamp() - '10s'::interval) WHERE i = 2

statement ok
EXECUTE with_min_timestamp_prep

statement ok
PREPARE with_max_staleness_prep AS SELECT * FROM t AS OF SYSTEM TIME with_max_staleness('10s') WHERE i = 2

statement ok
EXECUTE with_max_staleness_prep

statement ok
PREPARE bad_max_staleness_stmt AS SELECT * FROM t AS OF SYSTEM TIME with_max_staleness('1ms')

statement error unimplemented: cannot use bounded staleness for queries that may touch more than one range or require an index join
EXECUTE bad_max_staleness_stmt

statement ok
PREPARE bad_min_timestamp_stmt AS SELECT * FROM t AS OF SYSTEM TIME with_min_timestamp(statement_timestamp() - '1ms')

statement error unimplemented: cannot use bounded staleness for queries that may touch more than one range or require an index join
EXECUTE bad_min_timestamp_stmt

statement error expected timestamptz argument for min_timestamp
PREPARE placeholder_min_timestamp_stmt AS SELECT * FROM t AS OF SYSTEM TIME with_min_timestamp($1)

statement error expected interval argument for max_staleness
PREPARE placeholder_bounded_staleness_stmt AS SELECT * FROM t AS OF SYSTEM TIME with_max_staleness($1)

statement error expected float argument for to_timestamp
PREPARE placeholder_with_min_timestamp_to_timestamp_stmt AS SELECT * FROM t AS OF SYSTEM TIME with_min_timestamp(to_timestamp($1))
