exec-ddl
CREATE TABLE t (x INT PRIMARY KEY, y INT, z INT, INDEX y_idx (y))
----

# t has 200 rows where z=0, 200 where z=1, and 600 where z=2.
exec-ddl
ALTER TABLE t INJECT STATISTICS ' [
   {
      "columns":[
         "z"
      ],
      "created_at":"2019-11-11 22:16:04.314619+00:00",
      "distinct_count":3,
      "histo_buckets":[
         {
            "distinct_range":0,
            "num_eq":200,
            "num_range":0,
            "upper_bound":"0"
         },
         {
            "distinct_range":0,
            "num_eq":200,
            "num_range":0,
            "upper_bound":"1"
         },
         {
            "distinct_range":0,
            "num_eq":600,
            "num_range":0,
            "upper_bound":"2"
         }
      ],
      "histo_col_type":"INT8",
      "name":"statistics",
      "null_count":0,
      "row_count":1000
   }
]'
----

# In order to test how limit hints are propagated through a particular operator,
# a limit operator must exist higher in the tree, and all operators between the
# limit and the operator targeted by the test must pass a limit hint to their
# children. An easy way to construct a plan like this is to set the limit's
# child to be an ordinality operator (which passes through limit hints
# unchanged), and order the limit by the ordinality column (to prevent
# normalization rules from pushing the limit down the tree).

# --------------------------------------------------
# Offset operator.
# --------------------------------------------------

opt
SELECT * FROM (SELECT * FROM t OFFSET 5) WITH ORDINALITY ORDER BY ordinality LIMIT 10
----
limit
 ├── columns: x:1!null y:2 z:3 ordinality:6!null
 ├── internal-ordering: +6
 ├── cardinality: [0 - 10]
 ├── key: (1)
 ├── fd: (1)-->(2,3,6), (6)-->(1-3)
 ├── ordering: +6
 ├── ordinality
 │    ├── columns: x:1!null y:2 z:3 ordinality:6!null
 │    ├── key: (1)
 │    ├── fd: (1)-->(2,3,6), (6)-->(1-3)
 │    ├── ordering: +6
 │    ├── limit hint: 10.00
 │    └── offset
 │         ├── columns: x:1!null y:2 z:3
 │         ├── key: (1)
 │         ├── fd: (1)-->(2,3)
 │         ├── limit hint: 10.00
 │         ├── scan t
 │         │    ├── columns: x:1!null y:2 z:3
 │         │    ├── key: (1)
 │         │    ├── fd: (1)-->(2,3)
 │         │    └── limit hint: 15.00
 │         └── 5
 └── 10


# --------------------------------------------------
# Set operators.
# --------------------------------------------------

opt
SELECT * FROM (SELECT x, y, z FROM t UNION SELECT x, z, y from t) LIMIT 10
----
limit
 ├── columns: x:11!null y:12 z:13
 ├── cardinality: [0 - 10]
 ├── key: (11-13)
 ├── union
 │    ├── columns: x:11!null y:12 z:13
 │    ├── left columns: t.x:1 t.y:2 t.z:3
 │    ├── right columns: t.x:6 t.z:8 t.y:7
 │    ├── internal-ordering: +11,+12,+13
 │    ├── key: (11-13)
 │    ├── limit hint: 10.00
 │    ├── scan t
 │    │    ├── columns: t.x:1!null t.y:2 t.z:3
 │    │    ├── key: (1)
 │    │    ├── fd: (1)-->(2,3)
 │    │    ├── ordering: +1
 │    │    └── limit hint: 10.00
 │    └── scan t
 │         ├── columns: t.x:6!null t.y:7 t.z:8
 │         ├── key: (6)
 │         ├── fd: (6)-->(7,8)
 │         ├── ordering: +6
 │         └── limit hint: 10.00
 └── 10

opt
SELECT * FROM (SELECT * FROM t UNION ALL SELECT * from t) LIMIT 10
----
limit
 ├── columns: x:11!null y:12 z:13
 ├── cardinality: [0 - 10]
 ├── union-all
 │    ├── columns: x:11!null y:12 z:13
 │    ├── left columns: t.x:1 t.y:2 t.z:3
 │    ├── right columns: t.x:6 t.y:7 t.z:8
 │    ├── limit hint: 10.00
 │    ├── scan t
 │    │    ├── columns: t.x:1!null t.y:2 t.z:3
 │    │    ├── key: (1)
 │    │    ├── fd: (1)-->(2,3)
 │    │    └── limit hint: 10.00
 │    └── scan t
 │         ├── columns: t.x:6!null t.y:7 t.z:8
 │         ├── key: (6)
 │         ├── fd: (6)-->(7,8)
 │         └── limit hint: 10.00
 └── 10

opt
SELECT * FROM (SELECT z FROM t INTERSECT SELECT y from t) LIMIT 10
----
limit
 ├── columns: z:3
 ├── cardinality: [0 - 10]
 ├── key: (3)
 ├── intersect
 │    ├── columns: z:3
 │    ├── left columns: z:3
 │    ├── right columns: y:7
 │    ├── key: (3)
 │    ├── limit hint: 10.00
 │    ├── scan t
 │    │    ├── columns: z:3
 │    │    └── limit hint: 10.00
 │    └── scan t@y_idx
 │         ├── columns: y:7
 │         └── limit hint: 10.00
 └── 10

opt
SELECT * FROM (SELECT z FROM t INTERSECT ALL SELECT y from t) LIMIT 10
----
limit
 ├── columns: z:3
 ├── cardinality: [0 - 10]
 ├── intersect-all
 │    ├── columns: z:3
 │    ├── left columns: z:3
 │    ├── right columns: y:7
 │    ├── limit hint: 10.00
 │    ├── scan t
 │    │    ├── columns: z:3
 │    │    └── limit hint: 10.00
 │    └── scan t@y_idx
 │         ├── columns: y:7
 │         └── limit hint: 10.00
 └── 10

opt
SELECT * FROM (SELECT z FROM t EXCEPT SELECT y from t) LIMIT 10
----
limit
 ├── columns: z:3
 ├── cardinality: [0 - 10]
 ├── key: (3)
 ├── except
 │    ├── columns: z:3
 │    ├── left columns: z:3
 │    ├── right columns: y:7
 │    ├── key: (3)
 │    ├── limit hint: 10.00
 │    ├── scan t
 │    │    ├── columns: z:3
 │    │    └── limit hint: 10.00
 │    └── scan t@y_idx
 │         ├── columns: y:7
 │         └── limit hint: 10.00
 └── 10

opt
SELECT * FROM (SELECT z FROM t EXCEPT ALL SELECT y from t) LIMIT 10
----
limit
 ├── columns: z:3
 ├── cardinality: [0 - 10]
 ├── except-all
 │    ├── columns: z:3
 │    ├── left columns: z:3
 │    ├── right columns: y:7
 │    ├── limit hint: 10.00
 │    ├── scan t
 │    │    ├── columns: z:3
 │    │    └── limit hint: 10.00
 │    └── scan t@y_idx
 │         ├── columns: y:7
 │         └── limit hint: 10.00
 └── 10

# --------------------------------------------------
# Limit hint depends on statistics.
# --------------------------------------------------

# Select operator.
opt
SELECT * FROM t WHERE z=1 LIMIT 10
----
limit
 ├── columns: x:1!null y:2 z:3!null
 ├── cardinality: [0 - 10]
 ├── key: (1)
 ├── fd: ()-->(3), (1)-->(2)
 ├── select
 │    ├── columns: x:1!null y:2 z:3!null
 │    ├── key: (1)
 │    ├── fd: ()-->(3), (1)-->(2)
 │    ├── limit hint: 10.00
 │    ├── scan t
 │    │    ├── columns: x:1!null y:2 z:3
 │    │    ├── key: (1)
 │    │    ├── fd: (1)-->(2,3)
 │    │    └── limit hint: 50.00
 │    └── filters
 │         └── z:3 = 1 [outer=(3), fd=()-->(3)]
 └── 10

# DistinctOn operator.
opt
SELECT DISTINCT z FROM t LIMIT 1
----
limit
 ├── columns: z:3
 ├── cardinality: [0 - 1]
 ├── key: ()
 ├── fd: ()-->(3)
 ├── distinct-on
 │    ├── columns: z:3
 │    ├── grouping columns: z:3
 │    ├── key: (3)
 │    ├── limit hint: 1.00
 │    └── scan t
 │         ├── columns: z:3
 │         └── limit hint: 1.23
 └── 1

# No limit hint propagation if number of distinct rows < required number of rows.
opt
SELECT DISTINCT z FROM t LIMIT 10
----
limit
 ├── columns: z:3
 ├── cardinality: [0 - 10]
 ├── key: (3)
 ├── distinct-on
 │    ├── columns: z:3
 │    ├── grouping columns: z:3
 │    ├── key: (3)
 │    ├── limit hint: 10.00
 │    └── scan t
 │         └── columns: z:3
 └── 10

# GroupBy operator.
opt
SELECT y, count(*) FROM t GROUP BY y LIMIT 1
----
limit
 ├── columns: y:2 count:6!null
 ├── cardinality: [0 - 1]
 ├── key: ()
 ├── fd: ()-->(2,6)
 ├── group-by (streaming)
 │    ├── columns: y:2 count_rows:6!null
 │    ├── grouping columns: y:2
 │    ├── internal-ordering: +2
 │    ├── key: (2)
 │    ├── fd: (2)-->(6)
 │    ├── limit hint: 1.00
 │    ├── scan t@y_idx
 │    │    ├── columns: y:2
 │    │    ├── ordering: +2
 │    │    └── limit hint: 10.00
 │    └── aggregations
 │         └── count-rows [as=count_rows:6]
 └── 1

exec-ddl
CREATE INDEX zy_idx ON t (z, y)
----

# Do not propagate a limit hint when the output rows are less than the limit
# hint.
opt format=show-stats
SELECT y, count(*) FROM t WHERE z = 3 GROUP BY y LIMIT 10
----
limit
 ├── columns: y:2 count:6!null
 ├── cardinality: [0 - 10]
 ├── stats: [rows=2e-07]
 ├── key: (2)
 ├── fd: (2)-->(6)
 ├── group-by (streaming)
 │    ├── columns: y:2 count_rows:6!null
 │    ├── grouping columns: y:2
 │    ├── internal-ordering: +2 opt(3)
 │    ├── stats: [rows=2e-07, distinct(2)=2e-07, null(2)=2e-09]
 │    ├── key: (2)
 │    ├── fd: (2)-->(6)
 │    ├── limit hint: 10.00
 │    ├── scan t@zy_idx
 │    │    ├── columns: y:2 z:3!null
 │    │    ├── constraint: /3/2/1: [/3 - /3]
 │    │    ├── stats: [rows=2e-07, distinct(2)=2e-07, null(2)=2e-09, distinct(3)=2e-07, null(3)=0]
 │    │    │   histogram(3)=
 │    │    ├── fd: ()-->(3)
 │    │    └── ordering: +2 opt(3) [actual: +2]
 │    └── aggregations
 │         └── count-rows [as=count_rows:6]
 └── 10

exec-ddl
DROP INDEX zy_idx
----

# Do not propagate limit hints for a non-streaming GroupBy.
opt
SELECT z, count(*) FROM t GROUP BY z LIMIT 1
----
limit
 ├── columns: z:3 count:6!null
 ├── cardinality: [0 - 1]
 ├── key: ()
 ├── fd: ()-->(3,6)
 ├── group-by (hash)
 │    ├── columns: z:3 count_rows:6!null
 │    ├── grouping columns: z:3
 │    ├── key: (3)
 │    ├── fd: (3)-->(6)
 │    ├── limit hint: 1.00
 │    ├── scan t
 │    │    └── columns: z:3
 │    └── aggregations
 │         └── count-rows [as=count_rows:6]
 └── 1

opt
SELECT * FROM t WHERE z=4 LIMIT 10
----
limit
 ├── columns: x:1!null y:2 z:3!null
 ├── cardinality: [0 - 10]
 ├── key: (1)
 ├── fd: ()-->(3), (1)-->(2)
 ├── select
 │    ├── columns: x:1!null y:2 z:3!null
 │    ├── key: (1)
 │    ├── fd: ()-->(3), (1)-->(2)
 │    ├── limit hint: 10.00
 │    ├── scan t
 │    │    ├── columns: x:1!null y:2 z:3
 │    │    ├── key: (1)
 │    │    └── fd: (1)-->(2,3)
 │    └── filters
 │         └── z:3 = 4 [outer=(3), fd=()-->(3)]
 └── 10


# --------------------------------------------------
# Passing limit hint through unchanged.
# --------------------------------------------------

# IndexJoin operator.
opt
SELECT z FROM t@y_idx WITH ORDINALITY ORDER BY ordinality LIMIT 10
----
limit
 ├── columns: z:3  [hidden: ordinality:6!null]
 ├── internal-ordering: +6
 ├── cardinality: [0 - 10]
 ├── key: (6)
 ├── fd: (6)-->(3)
 ├── ordering: +6
 ├── ordinality
 │    ├── columns: z:3 ordinality:6!null
 │    ├── key: (6)
 │    ├── fd: (6)-->(3)
 │    ├── ordering: +6
 │    ├── limit hint: 10.00
 │    └── index-join t
 │         ├── columns: z:3
 │         ├── limit hint: 10.00
 │         └── scan t@y_idx
 │              ├── columns: x:1!null
 │              ├── flags: force-index=y_idx
 │              ├── key: (1)
 │              └── limit hint: 10.00
 └── 10

# Ordinality operator.
opt
SELECT * FROM t WITH ORDINALITY ORDER BY ordinality LIMIT 10
----
limit
 ├── columns: x:1!null y:2 z:3 ordinality:6!null
 ├── internal-ordering: +6
 ├── cardinality: [0 - 10]
 ├── key: (1)
 ├── fd: (1)-->(2,3,6), (6)-->(1-3)
 ├── ordering: +6
 ├── ordinality
 │    ├── columns: x:1!null y:2 z:3 ordinality:6!null
 │    ├── key: (1)
 │    ├── fd: (1)-->(2,3,6), (6)-->(1-3)
 │    ├── ordering: +6
 │    ├── limit hint: 10.00
 │    └── scan t
 │         ├── columns: x:1!null y:2 z:3
 │         ├── key: (1)
 │         ├── fd: (1)-->(2,3)
 │         └── limit hint: 10.00
 └── 10

# Project operator.
opt
SELECT * FROM (SELECT 1 FROM t) WITH ORDINALITY ORDER BY ordinality LIMIT 10
----
limit
 ├── columns: "?column?":6!null ordinality:7!null
 ├── internal-ordering: +7 opt(6)
 ├── cardinality: [0 - 10]
 ├── key: (7)
 ├── fd: ()-->(6)
 ├── ordering: +7 opt(6) [actual: +7]
 ├── ordinality
 │    ├── columns: "?column?":6!null ordinality:7!null
 │    ├── key: (7)
 │    ├── fd: ()-->(6)
 │    ├── ordering: +7 opt(6) [actual: +7]
 │    ├── limit hint: 10.00
 │    └── project
 │         ├── columns: "?column?":6!null
 │         ├── fd: ()-->(6)
 │         ├── limit hint: 10.00
 │         ├── scan t@y_idx
 │         │    └── limit hint: 10.00
 │         └── projections
 │              └── 1 [as="?column?":6]
 └── 10

# ProjectSet operator.
opt
SELECT *, generate_series(1, t.x) FROM t LIMIT 10
----
limit
 ├── columns: x:1!null y:2 z:3 generate_series:6
 ├── cardinality: [0 - 10]
 ├── immutable
 ├── fd: (1)-->(2,3)
 ├── project-set
 │    ├── columns: x:1!null y:2 z:3 generate_series:6
 │    ├── immutable
 │    ├── fd: (1)-->(2,3)
 │    ├── limit hint: 10.00
 │    ├── scan t
 │    │    ├── columns: x:1!null y:2 z:3
 │    │    ├── key: (1)
 │    │    ├── fd: (1)-->(2,3)
 │    │    └── limit hint: 10.00
 │    └── zip
 │         └── generate_series(1, x:1) [outer=(1), immutable]
 └── 10

# --------------------------------------------------
# Lookup join.
# --------------------------------------------------

exec-ddl
CREATE TABLE a (k INT PRIMARY KEY, i INT, s STRING, d DECIMAL NOT NULL)
----

exec-ddl
CREATE TABLE b (x INT, z INT NOT NULL)
----

exec-ddl
ALTER TABLE a INJECT STATISTICS '[
  {
    "columns": ["k"],
    "created_at": "2019-02-08 04:10:40.001179+00:00",
    "row_count": 100000,
    "distinct_count": 100000
  }
]'
----

exec-ddl
ALTER TABLE b INJECT STATISTICS '[
  {
    "columns": ["x"],
    "created_at": "2019-02-08 04:10:40.001179+00:00",
    "row_count": 10000,
    "distinct_count": 1000
  }
]'
----

# Ensure the limit hint is propagated to the lookup join input as a multiple
# of the batch size.
opt
SELECT * FROM a JOIN b ON k=z WHERE x > 0 AND x <= 5000 LIMIT 6003
----
limit
 ├── columns: k:1!null i:2 s:3 d:4!null x:7!null z:8!null
 ├── cardinality: [0 - 6003]
 ├── fd: (1)-->(2-4), (1)==(8), (8)==(1)
 ├── inner-join (lookup a)
 │    ├── columns: k:1!null i:2 s:3 d:4!null x:7!null z:8!null
 │    ├── key columns: [8] = [1]
 │    ├── lookup columns are key
 │    ├── fd: (1)-->(2-4), (1)==(8), (8)==(1)
 │    ├── limit hint: 6003.00
 │    ├── select
 │    │    ├── columns: x:7!null z:8!null
 │    │    ├── limit hint: 6100.00
 │    │    ├── scan b
 │    │    │    ├── columns: x:7 z:8!null
 │    │    │    └── limit hint: 6100.00
 │    │    └── filters
 │    │         └── (x:7 > 0) AND (x:7 <= 5000) [outer=(7)]
 │    └── filters (true)
 └── 6003

# The limit hint for the lookup join input must be at least the batch size.
opt
SELECT * FROM a JOIN b ON k=z WHERE x > 0 AND x <= 5000 LIMIT 3
----
limit
 ├── columns: k:1!null i:2 s:3 d:4!null x:7!null z:8!null
 ├── cardinality: [0 - 3]
 ├── fd: (1)-->(2-4), (1)==(8), (8)==(1)
 ├── inner-join (lookup a)
 │    ├── columns: k:1!null i:2 s:3 d:4!null x:7!null z:8!null
 │    ├── key columns: [8] = [1]
 │    ├── lookup columns are key
 │    ├── fd: (1)-->(2-4), (1)==(8), (8)==(1)
 │    ├── limit hint: 3.00
 │    ├── select
 │    │    ├── columns: x:7!null z:8!null
 │    │    ├── limit hint: 100.00
 │    │    ├── scan b
 │    │    │    ├── columns: x:7 z:8!null
 │    │    │    └── limit hint: 100.00
 │    │    └── filters
 │    │         └── (x:7 > 0) AND (x:7 <= 5000) [outer=(7)]
 │    └── filters (true)
 └── 3

# --------------------------------------------------
# Negative limits.
# --------------------------------------------------

# Regression test for #44683.
exec-ddl
CREATE TABLE t44683(c0 INT)
----

exec-ddl
CREATE VIEW v44683(c0) AS SELECT 1 FROM t44683 LIMIT -1
----

opt
SELECT DISTINCT t44683.c0 FROM t44683, v44683 LIMIT -1;
----
limit
 ├── columns: c0:1
 ├── cardinality: [0 - 0]
 ├── immutable
 ├── key: ()
 ├── fd: ()-->(1)
 ├── distinct-on
 │    ├── columns: c0:1
 │    ├── grouping columns: c0:1
 │    ├── cardinality: [0 - 0]
 │    ├── immutable
 │    ├── key: (1)
 │    ├── limit hint: 1.00
 │    └── inner-join (cross)
 │         ├── columns: c0:1
 │         ├── cardinality: [0 - 0]
 │         ├── multiplicity: left-rows(zero-or-one), right-rows(zero-or-more)
 │         ├── immutable
 │         ├── scan t44683
 │         │    └── columns: c0:1
 │         ├── limit
 │         │    ├── cardinality: [0 - 0]
 │         │    ├── immutable
 │         │    ├── key: ()
 │         │    ├── scan t44683
 │         │    │    └── limit hint: 1.00
 │         │    └── -1
 │         └── filters (true)
 └── -1

exec-ddl
CREATE TABLE t0(c0 INT UNIQUE)
----

exec-ddl
CREATE TABLE t1(c0 INT)
----

exec-ddl
CREATE VIEW v0(c0) AS SELECT 0 FROM t1 LIMIT -1
----

# Regression test for #46187. Ensure that the estimated cost of a lookup join
# with a limit hint is finite when the number of output rows is 0.
opt
SELECT * FROM v0, t0 NATURAL JOIN t1 LIMIT -1
----
project
 ├── columns: c0:5!null c0:6!null
 ├── cardinality: [0 - 0]
 ├── immutable
 ├── key: ()
 ├── fd: ()-->(5,6)
 └── limit
      ├── columns: "?column?":5!null t0.c0:6!null t1.c0:10!null
      ├── cardinality: [0 - 0]
      ├── immutable
      ├── key: ()
      ├── fd: ()-->(5,6,10), (6)==(10), (10)==(6)
      ├── inner-join (cross)
      │    ├── columns: "?column?":5!null t0.c0:6!null t1.c0:10!null
      │    ├── cardinality: [0 - 0]
      │    ├── multiplicity: left-rows(zero-or-one), right-rows(zero-or-more)
      │    ├── immutable
      │    ├── fd: ()-->(5), (6)==(10), (10)==(6)
      │    ├── limit hint: 1.00
      │    ├── inner-join (hash)
      │    │    ├── columns: t0.c0:6!null t1.c0:10!null
      │    │    ├── multiplicity: left-rows(zero-or-more), right-rows(zero-or-one)
      │    │    ├── fd: (6)==(10), (10)==(6)
      │    │    ├── scan t0
      │    │    │    ├── columns: t0.c0:6
      │    │    │    └── lax-key: (6)
      │    │    ├── scan t1
      │    │    │    └── columns: t1.c0:10
      │    │    └── filters
      │    │         └── t0.c0:6 = t1.c0:10 [outer=(6,10), fd=(6)==(10), (10)==(6)]
      │    ├── project
      │    │    ├── columns: "?column?":5!null
      │    │    ├── cardinality: [0 - 0]
      │    │    ├── immutable
      │    │    ├── key: ()
      │    │    ├── fd: ()-->(5)
      │    │    ├── limit
      │    │    │    ├── cardinality: [0 - 0]
      │    │    │    ├── immutable
      │    │    │    ├── key: ()
      │    │    │    ├── scan t1
      │    │    │    │    └── limit hint: 1.00
      │    │    │    └── -1
      │    │    └── projections
      │    │         └── 0 [as="?column?":5]
      │    └── filters (true)
      └── -1
