exec-ddl
CREATE TABLE kv (k INT PRIMARY KEY, v INT)
----

exec-ddl
CREATE TABLE abcd (
  a INT,
  b INT,
  c INT,
  d INT,
  INDEX (a,b) STORING (c),
  INDEX (c,b,a) STORING (d),
  INDEX (d,c,a),
  INDEX (d,c,b)
)
----

exec-ddl
CREATE TABLE xyz (
  x INT PRIMARY KEY,
  y INT,
  z INT
)
----

placeholder-fast-path
SELECT * FROM kv WHERE k = $1
----
placeholder-scan kv
 ├── columns: k:1!null v:2
 ├── cardinality: [0 - 1]
 ├── has-placeholder
 ├── stats: [rows=1, distinct(1)=1, null(1)=0]
 ├── key: ()
 ├── fd: ()-->(1,2)
 └── span
      └── $1

placeholder-fast-path
SELECT * FROM kv WHERE k = $1 FOR UPDATE
----
placeholder-scan kv
 ├── columns: k:1!null v:2
 ├── locking: for-update
 ├── cardinality: [0 - 1]
 ├── volatile, has-placeholder
 ├── stats: [rows=1, distinct(1)=1, null(1)=0]
 ├── key: ()
 ├── fd: ()-->(1,2)
 └── span
      └── $1

placeholder-fast-path
SELECT k FROM kv WHERE k = $1
----
placeholder-scan kv
 ├── columns: k:1!null
 ├── cardinality: [0 - 1]
 ├── has-placeholder
 ├── stats: [rows=1, distinct(1)=1, null(1)=0]
 ├── key: ()
 ├── fd: ()-->(1)
 └── span
      └── $1

placeholder-fast-path
SELECT k FROM kv WHERE k IN ($1)
----
placeholder-scan kv
 ├── columns: k:1!null
 ├── cardinality: [0 - 1]
 ├── has-placeholder
 ├── stats: [rows=1, distinct(1)=1, null(1)=0]
 ├── key: ()
 ├── fd: ()-->(1)
 └── span
      └── $1

placeholder-fast-path
SELECT v FROM kv WHERE k = $1
----
placeholder-scan kv
 ├── columns: v:2
 ├── cardinality: [0 - 1]
 ├── has-placeholder
 ├── stats: [rows=1]
 ├── key: ()
 ├── fd: ()-->(2)
 └── span
      └── $1

# Fast path not available when we're projecting a new expression.
placeholder-fast-path
SELECT v+1 FROM kv WHERE k = $1
----
no fast path


# Inject statistics so that the estimated row count is high.
exec-ddl
ALTER TABLE abcd INJECT STATISTICS '[
  {
    "columns": ["a"],
    "created_at": "2018-05-01 1:00:00.00000+00:00",
    "row_count": 10000,
    "distinct_count": 5
  },
  {
    "columns": ["b"],
    "created_at": "2018-05-01 1:00:00.00000+00:00",
    "row_count": 10000,
    "distinct_count": 5
  }
]'
----

# The fast path should not kick in because the estimated row count is too high.
placeholder-fast-path
SELECT a, b, c FROM abcd WHERE a=$1 AND b=$2
----
no fast path

# Now inject statistics so that the estimated row count is small.
exec-ddl
ALTER TABLE abcd INJECT STATISTICS '[
  {
    "columns": ["a"],
    "created_at": "2018-05-01 1:00:00.00000+00:00",
    "row_count": 10,
    "distinct_count": 5
  }
]'
----

# The fast path should now kick in.
placeholder-fast-path
SELECT a, b, c FROM abcd WHERE a=$1 AND b=$2
----
placeholder-scan abcd@abcd_a_b_idx
 ├── columns: a:1!null b:2!null c:3
 ├── has-placeholder
 ├── stats: [rows=1.98, distinct(1)=1, null(1)=0, distinct(2)=1, null(2)=0, distinct(1,2)=1, null(1,2)=0]
 ├── fd: ()-->(1,2)
 └── span
      ├── $1
      └── $2

placeholder-fast-path
SELECT a, b, c FROM abcd WHERE b=$1 AND a=$2
----
placeholder-scan abcd@abcd_a_b_idx
 ├── columns: a:1!null b:2!null c:3
 ├── has-placeholder
 ├── stats: [rows=1.98, distinct(1)=1, null(1)=0, distinct(2)=1, null(2)=0, distinct(1,2)=1, null(1,2)=0]
 ├── fd: ()-->(1,2)
 └── span
      ├── $2
      └── $1

# One constant value, one placeholder.
placeholder-fast-path
SELECT a, b, c FROM abcd WHERE a=0 AND b=$1
----
placeholder-scan abcd@abcd_a_b_idx
 ├── columns: a:1!null b:2!null c:3
 ├── has-placeholder
 ├── stats: [rows=1.98, distinct(1)=1, null(1)=0, distinct(2)=1, null(2)=0, distinct(1,2)=1, null(1,2)=0]
 ├── fd: ()-->(1,2)
 └── span
      ├── 0
      └── $1

placeholder-fast-path
SELECT a, b, c FROM abcd WHERE a=$1 AND b=0
----
placeholder-scan abcd@abcd_a_b_idx
 ├── columns: a:1!null b:2!null c:3
 ├── has-placeholder
 ├── stats: [rows=1.98, distinct(1)=1, null(1)=0, distinct(2)=1, null(2)=0, distinct(1,2)=1, null(1,2)=0]
 ├── fd: ()-->(1,2)
 └── span
      ├── $1
      └── 0

# Constant folding is allowed (for immutable operators).
placeholder-fast-path
SELECT a, b, c FROM abcd WHERE a=1+2 AND b=$1
----
placeholder-scan abcd@abcd_a_b_idx
 ├── columns: a:1!null b:2!null c:3
 ├── has-placeholder
 ├── stats: [rows=1.98, distinct(1)=1, null(1)=0, distinct(2)=1, null(2)=0, distinct(1,2)=1, null(1,2)=0]
 ├── fd: ()-->(1,2)
 └── span
      ├── 3
      └── $1

placeholder-fast-path
SELECT a, b, c FROM abcd WHERE a=fnv32a('foo') AND b=$1
----
placeholder-scan abcd@abcd_a_b_idx
 ├── columns: a:1!null b:2!null c:3
 ├── has-placeholder
 ├── stats: [rows=1.98, distinct(1)=1, null(1)=0, distinct(2)=1, null(2)=0, distinct(1,2)=1, null(1,2)=0]
 ├── fd: ()-->(1,2)
 └── span
      ├── 2851307223
      └── $1

# Fast path not available when value is not constant-foldable.
placeholder-fast-path
SELECT a, b, c FROM abcd WHERE a=now()::string::int AND b=$1
----
no fast path

placeholder-fast-path
SELECT a, b, c FROM abcd WHERE a=0 AND b=$1+1
----
no fast path

# Fast path not available when we have an ordering requirement.
placeholder-fast-path
SELECT a, b, c FROM abcd WHERE a=$1 AND b=$2 ORDER BY c
----
no fast path

# Fast path not available when we have a limit.
placeholder-fast-path
SELECT a, b, c FROM abcd WHERE a=$1 AND b=$2 LIMIT 1
----
no fast path

# Fast path not available when index is not covering.
placeholder-fast-path
SELECT a, b, c, d FROM abcd WHERE a=$1 AND b=$2
----
no fast path

# Fast path not available when two indexes are possible.
placeholder-fast-path
SELECT d FROM abcd WHERE d=$1 AND c=$2
----
no fast path

# Now we have only one covering index.
placeholder-fast-path
SELECT a, d FROM abcd WHERE d=$1 AND c=$2
----
placeholder-scan abcd@abcd_d_c_a_idx
 ├── columns: a:1 d:4!null
 ├── has-placeholder
 ├── stats: [rows=9.801]
 ├── fd: ()-->(4)
 └── span
      ├── $1
      └── $2

exec-ddl
CREATE TABLE kj (
  k INT PRIMARY KEY,
  j JSON,
  INVERTED INDEX(j)
)
----

# Verify that we don't incorrectly use an inverted index.
placeholder-fast-path
SELECT j FROM kj WHERE j = '{"foo": "bar"}'::JSON
----
no fast path

exec-ddl
CREATE TABLE partial1 (
  k INT PRIMARY KEY,
  a INT,
  b INT,
  c INT,
  INDEX partial_ab(a, b) WHERE (c = 0),
  INDEX cab(c, a, b),
  INDEX pseudo_ab(a, b) WHERE (1 = 1)
)
----

# The fast path is conditional on having a small estimated row count. Inject
# statistics so that we don't have to worry about this aspect in tests.
exec-ddl
ALTER TABLE partial1 INJECT STATISTICS '[
  {
    "columns": ["k"],
    "created_at": "2018-05-01 1:00:00.00000+00:00",
    "row_count": 10,
    "distinct_count": 10
  }
]'
----

# Make sure the fast path doesn't choose the cab index, getting in the way of
# using partial_ab (which might be the better index when the placeholder is 0).
placeholder-fast-path
SELECT a, b FROM partial1 WHERE c = $1
----
no fast path

# Ok to ignore the partial index when the filters don't involve predicate
# columns; and, ok to use a pseudo-partial index.
placeholder-fast-path
SELECT a, b FROM partial1 WHERE a = $1
----
placeholder-scan partial1@pseudo_ab,partial
 ├── columns: a:2!null b:3
 ├── has-placeholder
 ├── stats: [rows=9.9, distinct(2)=1, null(2)=0]
 ├── fd: ()-->(2)
 └── span
      └── $1

# Regression test for #64765 - we cannot constrain both columns.
placeholder-fast-path
SELECT * FROM xyz WHERE x = $1 AND y = $2
----
no fast path

# Regression test for #81315. Do not use the placeholder fast path
# if the types do not match.
exec-ddl
CREATE TABLE t_dec (a DECIMAL NOT NULL PRIMARY KEY, b INT);
----

# TODO(rytaft): We may be able to use the placeholder fast path for
# this case if we add logic similar to UnifyComparisonTypes.
placeholder-fast-path
SELECT * FROM t_dec WHERE a = $1::INT8;
----
no fast path

placeholder-fast-path
SELECT * FROM t_dec WHERE a = $1;
----
placeholder-scan t_dec
 ├── columns: a:1!null b:2
 ├── cardinality: [0 - 1]
 ├── immutable, has-placeholder
 ├── stats: [rows=1, distinct(1)=1, null(1)=0]
 ├── key: ()
 ├── fd: ()-->(1,2)
 └── span
      └── $1
