exec-ddl
CREATE TABLE a
(
    x INT,
    y FLOAT,
    z DECIMAL,
    s STRING NOT NULL,
    PRIMARY KEY (x, y DESC)
)
----

exec-ddl
CREATE TABLE abc (a INT, b INT, c INT, PRIMARY KEY (a, b, c), INDEX abc_desc(a, b, c DESC))
----

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

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

exec-ddl
CREATE TABLE def (d INT NOT NULL CHECK (d IN (1, 3)), e INT, f INT, INDEX (d, e, f))
----

# --------------------------------------------------
# Scan operator.
# --------------------------------------------------

# Order by entire key, in same order as key.
opt
SELECT * FROM a ORDER BY x, y DESC
----
scan a
 ├── columns: x:1!null y:2!null z:3 s:4!null
 ├── key: (1,2)
 ├── fd: (1,2)-->(3,4)
 └── ordering: +1,-2

# Order by prefix.
opt
SELECT * FROM a ORDER BY x
----
scan a
 ├── columns: x:1!null y:2!null z:3 s:4!null
 ├── key: (1,2)
 ├── fd: (1,2)-->(3,4)
 └── ordering: +1

# Order by additional column (should be dropped by optimizer).
opt
SELECT * FROM a ORDER BY x, y DESC, z
----
scan a
 ├── columns: x:1!null y:2!null z:3 s:4!null
 ├── key: (1,2)
 ├── fd: (1,2)-->(3,4)
 └── ordering: +1,-2

# Order by suffix (scan shouldn't be able to provide).
opt
SELECT * FROM a ORDER BY y DESC
----
sort
 ├── columns: x:1!null y:2!null z:3 s:4!null
 ├── key: (1,2)
 ├── fd: (1,2)-->(3,4)
 ├── ordering: -2
 └── scan a
      ├── columns: x:1!null y:2!null z:3 s:4!null
      ├── key: (1,2)
      └── fd: (1,2)-->(3,4)

# Order by suffix, don't project prefix (scan shouldn't be able to provide).
opt
SELECT y FROM a ORDER BY y DESC
----
sort
 ├── columns: y:2!null
 ├── ordering: -2
 └── scan a
      └── columns: y:2!null

opt
SELECT f FROM def ORDER BY e LIMIT 5
----
limit
 ├── columns: f:3  [hidden: e:2]
 ├── internal-ordering: +2
 ├── cardinality: [0 - 5]
 ├── ordering: +2
 ├── union-all
 │    ├── columns: e:2 f:3
 │    ├── left columns: e:8 f:9
 │    ├── right columns: e:14 f:15
 │    ├── cardinality: [0 - 10]
 │    ├── ordering: +2
 │    ├── limit hint: 5.00
 │    ├── scan def@def_d_e_f_idx
 │    │    ├── columns: e:8 f:9
 │    │    ├── constraint: /7/8/9/10: [/1 - /1]
 │    │    ├── limit: 5
 │    │    ├── ordering: +8
 │    │    └── limit hint: 5.00
 │    └── scan def@def_d_e_f_idx
 │         ├── columns: e:14 f:15
 │         ├── constraint: /13/14/15/16: [/3 - /3]
 │         ├── limit: 5
 │         ├── ordering: +14
 │         └── limit hint: 5.00
 └── 5


# --------------------------------------------------
# Select operator (pass through).
# --------------------------------------------------

# Pass through ordering to scan operator that can support it.
opt
SELECT * FROM a WHERE x>y ORDER BY x, y DESC
----
select
 ├── columns: x:1!null y:2!null z:3 s:4!null
 ├── key: (1,2)
 ├── fd: (1,2)-->(3,4)
 ├── ordering: +1,-2
 ├── scan a
 │    ├── columns: x:1!null y:2!null z:3 s:4!null
 │    ├── key: (1,2)
 │    ├── fd: (1,2)-->(3,4)
 │    └── ordering: +1,-2
 └── filters
      └── x:1 > y:2 [outer=(1,2)]

# Pass through ordering to scan operator that can't support it.
opt
SELECT * FROM a WHERE x>y ORDER BY z DESC
----
sort
 ├── columns: x:1!null y:2!null z:3 s:4!null
 ├── key: (1,2)
 ├── fd: (1,2)-->(3,4)
 ├── ordering: -3
 └── select
      ├── columns: x:1!null y:2!null z:3 s:4!null
      ├── key: (1,2)
      ├── fd: (1,2)-->(3,4)
      ├── scan a
      │    ├── columns: x:1!null y:2!null z:3 s:4!null
      │    ├── key: (1,2)
      │    └── fd: (1,2)-->(3,4)
      └── filters
           └── x:1 > y:2 [outer=(1,2)]

# --------------------------------------------------
# Project operator (pass through).
# --------------------------------------------------

# Pass through ordering to scan operator that can support it.
opt
SELECT x+1 AS r, y FROM a ORDER BY x, y DESC
----
project
 ├── columns: r:7!null y:2!null  [hidden: x:1!null]
 ├── immutable
 ├── key: (1,2)
 ├── fd: (1)-->(7)
 ├── ordering: +1,-2
 ├── scan a
 │    ├── columns: x:1!null y:2!null
 │    ├── key: (1,2)
 │    └── ordering: +1,-2
 └── projections
      └── x:1 + 1 [as=r:7, outer=(1), immutable]

# Pass through ordering to scan operator that can't support it.
opt
SELECT y, x, z+1 AS r FROM a ORDER BY x, y
----
sort (segmented)
 ├── columns: y:2!null x:1!null r:7
 ├── immutable
 ├── key: (1,2)
 ├── fd: (1,2)-->(7)
 ├── ordering: +1,+2
 └── project
      ├── columns: r:7 x:1!null y:2!null
      ├── immutable
      ├── key: (1,2)
      ├── fd: (1,2)-->(7)
      ├── ordering: +1
      ├── scan a
      │    ├── columns: x:1!null y:2!null z:3
      │    ├── key: (1,2)
      │    ├── fd: (1,2)-->(3)
      │    └── ordering: +1
      └── projections
           └── z:3 + 1 [as=r:7, outer=(3), immutable]

# Ordering cannot be passed through because it includes computed column.
opt
SELECT x, y+1 AS computed, y FROM a ORDER BY x, computed
----
sort (segmented)
 ├── columns: x:1!null computed:7!null y:2!null
 ├── immutable
 ├── key: (1,2)
 ├── fd: (2)-->(7)
 ├── ordering: +1,+7
 └── project
      ├── columns: computed:7!null x:1!null y:2!null
      ├── immutable
      ├── key: (1,2)
      ├── fd: (2)-->(7)
      ├── ordering: +1
      ├── scan a
      │    ├── columns: x:1!null y:2!null
      │    ├── key: (1,2)
      │    └── ordering: +1
      └── projections
           └── y:2 + 1.0 [as=computed:7, outer=(2), immutable]

# Ordering on an expression that gets constant-folded to a simple variable.
# Example from #43360: a boolean (possibly a placeholder) indicates the sort
# direction.
opt
SELECT * FROM a ORDER BY CASE WHEN false THEN x END ASC, CASE WHEN NOT false THEN x END DESC
----
project
 ├── columns: x:1!null y:2!null z:3 s:4!null  [hidden: column8:8!null]
 ├── key: (1,2)
 ├── fd: (1,2)-->(3,4), (1)==(8), (8)==(1)
 ├── ordering: -(1|8) [actual: -1]
 ├── scan a,rev
 │    ├── columns: x:1!null y:2!null z:3 s:4!null
 │    ├── key: (1,2)
 │    ├── fd: (1,2)-->(3,4)
 │    └── ordering: -1
 └── projections
      └── x:1 [as=column8:8, outer=(1)]

opt
SELECT * FROM a ORDER BY CASE WHEN true THEN x END ASC, CASE WHEN NOT true THEN x END DESC
----
project
 ├── columns: x:1!null y:2!null z:3 s:4!null  [hidden: column7:7!null]
 ├── key: (1,2)
 ├── fd: (1,2)-->(3,4), (1)==(7), (7)==(1)
 ├── ordering: +(1|7) [actual: +1]
 ├── scan a
 │    ├── columns: x:1!null y:2!null z:3 s:4!null
 │    ├── key: (1,2)
 │    ├── fd: (1,2)-->(3,4)
 │    └── ordering: +1
 └── projections
      └── x:1 [as=column7:7, outer=(1)]

# Similar case, except the equivalent input column is not being projected.
opt
SELECT 1 FROM a ORDER BY CASE WHEN false THEN x END ASC, CASE WHEN NOT false THEN x END DESC
----
project
 ├── columns: "?column?":7!null  [hidden: column9:9!null]
 ├── fd: ()-->(7)
 ├── ordering: -9 opt(7) [actual: -9]
 ├── scan a,rev
 │    ├── columns: x:1!null
 │    └── ordering: -1
 └── projections
      ├── 1 [as="?column?":7]
      └── x:1 [as=column9:9, outer=(1)]

# --------------------------------------------------
# Select + Project operators (pass through both).
# --------------------------------------------------

# Pass through ordering to scan operator that can support it.
opt
SELECT y, x-1 AS z FROM a WHERE x>y ORDER BY x, y DESC
----
project
 ├── columns: y:2!null z:7!null  [hidden: x:1!null]
 ├── immutable
 ├── key: (1,2)
 ├── fd: (1)-->(7)
 ├── ordering: +1,-2
 ├── select
 │    ├── columns: x:1!null y:2!null
 │    ├── key: (1,2)
 │    ├── ordering: +1,-2
 │    ├── scan a
 │    │    ├── columns: x:1!null y:2!null
 │    │    ├── key: (1,2)
 │    │    └── ordering: +1,-2
 │    └── filters
 │         └── x:1 > y:2 [outer=(1,2)]
 └── projections
      └── x:1 - 1 [as=z:7, outer=(1), immutable]

memo
SELECT y, x-1 AS z FROM a WHERE x>y ORDER BY x, y DESC
----
memo (optimized, ~7KB, required=[presentation: y:2,z:7] [ordering: +1,-2])
 ├── G1: (project G2 G3 x y)
 │    ├── [presentation: y:2,z:7] [ordering: +1,-2]
 │    │    ├── best: (project G2="[ordering: +1,-2]" G3 x y)
 │    │    └── cost: 1105.34
 │    └── []
 │         ├── best: (project G2 G3 x y)
 │         └── cost: 1105.34
 ├── G2: (select G4 G5)
 │    ├── [ordering: +1,-2]
 │    │    ├── best: (select G4="[ordering: +1,-2]" G5)
 │    │    └── cost: 1098.65
 │    └── []
 │         ├── best: (select G4 G5)
 │         └── cost: 1098.65
 ├── G3: (projections G6)
 ├── G4: (scan a,cols=(1,2))
 │    ├── [ordering: +1,-2]
 │    │    ├── best: (scan a,cols=(1,2))
 │    │    └── cost: 1088.62
 │    └── []
 │         ├── best: (scan a,cols=(1,2))
 │         └── cost: 1088.62
 ├── G5: (filters G7)
 ├── G6: (minus G8 G9)
 ├── G7: (gt G8 G10)
 ├── G8: (variable x)
 ├── G9: (const 1)
 └── G10: (variable y)

# Pass through ordering to scan operator that can't support it.
opt
SELECT y, z FROM a WHERE x>y ORDER BY y
----
sort
 ├── columns: y:2!null z:3
 ├── ordering: +2
 └── project
      ├── columns: y:2!null z:3
      └── select
           ├── columns: x:1!null y:2!null z:3
           ├── key: (1,2)
           ├── fd: (1,2)-->(3)
           ├── scan a
           │    ├── columns: x:1!null y:2!null z:3
           │    ├── key: (1,2)
           │    └── fd: (1,2)-->(3)
           └── filters
                └── x:1 > y:2 [outer=(1,2)]

memo
SELECT y, z FROM a WHERE x>y ORDER BY y
----
memo (optimized, ~7KB, required=[presentation: y:2,z:3] [ordering: +2])
 ├── G1: (project G2 G3 y z)
 │    ├── [presentation: y:2,z:3] [ordering: +2]
 │    │    ├── best: (sort G1)
 │    │    └── cost: 1181.34
 │    └── []
 │         ├── best: (project G2 G3 y z)
 │         └── cost: 1112.10
 ├── G2: (select G4 G5)
 │    ├── [ordering: +2]
 │    │    ├── best: (sort G2)
 │    │    └── cost: 1181.32
 │    └── []
 │         ├── best: (select G4 G5)
 │         └── cost: 1108.75
 ├── G3: (projections)
 ├── G4: (scan a,cols=(1-3))
 │    ├── [ordering: +2]
 │    │    ├── best: (sort G4)
 │    │    └── cost: 1348.20
 │    └── []
 │         ├── best: (scan a,cols=(1-3))
 │         └── cost: 1098.72
 ├── G5: (filters G6)
 ├── G6: (gt G7 G8)
 ├── G7: (variable x)
 └── G8: (variable y)

# --------------------------------------------------
# GroupBy operator.
# --------------------------------------------------

# Verify that the internal ordering is required of the input.
opt
SELECT array_agg(z) FROM (SELECT * FROM a ORDER BY y)
----
scalar-group-by
 ├── columns: array_agg:7
 ├── internal-ordering: +2
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(7)
 ├── sort
 │    ├── columns: y:2!null z:3
 │    ├── ordering: +2
 │    └── scan a
 │         └── columns: y:2!null z:3
 └── aggregations
      └── array-agg [as=array_agg:7, outer=(3)]
           └── z:3

opt
SELECT array_agg(x) FROM (SELECT * FROM a ORDER BY x, y DESC)
----
scalar-group-by
 ├── columns: array_agg:7
 ├── internal-ordering: +1,-2
 ├── cardinality: [1 - 1]
 ├── key: ()
 ├── fd: ()-->(7)
 ├── scan a
 │    ├── columns: x:1!null y:2!null
 │    ├── key: (1,2)
 │    └── ordering: +1,-2
 └── aggregations
      └── array-agg [as=array_agg:7, outer=(1)]
           └── x:1

# Pass through ordering on grouping columns.
opt
SELECT a, min(b) FROM abc GROUP BY a ORDER BY a
----
group-by (streaming)
 ├── columns: a:1!null min:6!null
 ├── grouping columns: a:1!null
 ├── key: (1)
 ├── fd: (1)-->(6)
 ├── ordering: +1
 ├── scan abc
 │    ├── columns: a:1!null b:2!null
 │    └── ordering: +1
 └── aggregations
      └── min [as=min:6, outer=(2)]
           └── b:2

opt
SELECT a, b, min(c) FROM abc GROUP BY a, b ORDER BY a
----
group-by (streaming)
 ├── columns: a:1!null b:2!null min:6!null
 ├── grouping columns: a:1!null b:2!null
 ├── internal-ordering: +1,+2
 ├── key: (1,2)
 ├── fd: (1,2)-->(6)
 ├── ordering: +1
 ├── scan abc
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1,+2
 └── aggregations
      └── min [as=min:6, outer=(3)]
           └── c:3

opt
SELECT a, b, min(c) FROM abc GROUP BY a, b ORDER BY a, b
----
group-by (streaming)
 ├── columns: a:1!null b:2!null min:6!null
 ├── grouping columns: a:1!null b:2!null
 ├── key: (1,2)
 ├── fd: (1,2)-->(6)
 ├── ordering: +1,+2
 ├── scan abc
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1,+2
 └── aggregations
      └── min [as=min:6, outer=(3)]
           └── c:3

opt
SELECT a, b, min(c) FROM abc GROUP BY b, a ORDER BY a, b
----
group-by (streaming)
 ├── columns: a:1!null b:2!null min:6!null
 ├── grouping columns: a:1!null b:2!null
 ├── key: (1,2)
 ├── fd: (1,2)-->(6)
 ├── ordering: +1,+2
 ├── scan abc
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1,+2
 └── aggregations
      └── min [as=min:6, outer=(3)]
           └── c:3

# We can't pass through the ordering if it refers to aggregation results.
opt
SELECT a, b, min(c) AS m FROM abc GROUP BY a, b ORDER BY a, m
----
sort (segmented)
 ├── columns: a:1!null b:2!null m:6!null
 ├── key: (1,2)
 ├── fd: (1,2)-->(6)
 ├── ordering: +1,+6
 └── group-by (streaming)
      ├── columns: a:1!null b:2!null min:6!null
      ├── grouping columns: a:1!null b:2!null
      ├── internal-ordering: +1,+2
      ├── key: (1,2)
      ├── fd: (1,2)-->(6)
      ├── ordering: +1
      ├── scan abc
      │    ├── columns: a:1!null b:2!null c:3!null
      │    ├── key: (1-3)
      │    └── ordering: +1,+2
      └── aggregations
           └── min [as=min:6, outer=(3)]
                └── c:3

# Satisfy both the required and the internal orderings by requiring a+,b+,c+.
opt
SELECT a, b, array_agg(c) FROM (SELECT * FROM abc ORDER BY c) GROUP BY a, b ORDER BY a, b
----
group-by (streaming)
 ├── columns: a:1!null b:2!null array_agg:6!null
 ├── grouping columns: a:1!null b:2!null
 ├── internal-ordering: +3 opt(1,2)
 ├── key: (1,2)
 ├── fd: (1,2)-->(6)
 ├── ordering: +1,+2
 ├── scan abc
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1,+2,+3
 └── aggregations
      └── array-agg [as=array_agg:6, outer=(3)]
           └── c:3

opt
SELECT a, b, array_agg(c) FROM (SELECT * FROM abc ORDER BY a, b, c) GROUP BY a, b ORDER BY a, b
----
group-by (streaming)
 ├── columns: a:1!null b:2!null array_agg:6!null
 ├── grouping columns: a:1!null b:2!null
 ├── internal-ordering: +3 opt(1,2)
 ├── key: (1,2)
 ├── fd: (1,2)-->(6)
 ├── ordering: +1,+2
 ├── scan abc
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1,+2,+3
 └── aggregations
      └── array-agg [as=array_agg:6, outer=(3)]
           └── c:3

opt
SELECT a, b, array_agg(c) FROM (SELECT * FROM abc ORDER BY b, c, a) GROUP BY b, a ORDER BY a, b
----
group-by (streaming)
 ├── columns: a:1!null b:2!null array_agg:6!null
 ├── grouping columns: a:1!null b:2!null
 ├── internal-ordering: +3 opt(1,2)
 ├── key: (1,2)
 ├── fd: (1,2)-->(6)
 ├── ordering: +1,+2
 ├── scan abc
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1,+2,+3
 └── aggregations
      └── array-agg [as=array_agg:6, outer=(3)]
           └── c:3

# Verify that the GroupBy child ordering is simplified according to the child's
# FD set.
opt
SELECT sum(c) FROM abc WHERE a = 1 GROUP BY b ORDER BY b
----
group-by (streaming)
 ├── columns: sum:6!null  [hidden: b:2!null]
 ├── grouping columns: b:2!null
 ├── key: (2)
 ├── fd: (2)-->(6)
 ├── ordering: +2
 ├── scan abc
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── constraint: /1/2/3: [/1 - /1]
 │    ├── key: (2,3)
 │    ├── fd: ()-->(1)
 │    └── ordering: +2 opt(1) [actual: +2]
 └── aggregations
      └── sum [as=sum:6, outer=(3)]
           └── c:3

# Verify we do a streaming group-by using the a, b ordering.
opt
SELECT sum(d) FROM abcd GROUP BY a, b, c
----
project
 ├── columns: sum:8
 └── group-by (hash)
      ├── columns: a:1 b:2 c:3 sum:8
      ├── grouping columns: a:1 b:2 c:3
      ├── key: (1-3)
      ├── fd: (1-3)-->(8)
      ├── scan abcd
      │    └── columns: a:1 b:2 c:3 d:4
      └── aggregations
           └── sum [as=sum:8, outer=(4)]
                └── d:4

# Verify we do a streaming group-by using the c, d ordering.
opt
SELECT sum(a) FROM abcd GROUP BY b, c, d
----
project
 ├── columns: sum:8
 └── group-by (hash)
      ├── columns: b:2 c:3 d:4 sum:8
      ├── grouping columns: b:2 c:3 d:4
      ├── key: (2-4)
      ├── fd: (2-4)-->(8)
      ├── scan abcd
      │    └── columns: a:1 b:2 c:3 d:4
      └── aggregations
           └── sum [as=sum:8, outer=(1)]
                └── a:1

opt
SELECT array_agg(d) FROM (SELECT * FROM abcd ORDER BY c) GROUP BY a, b
----
project
 ├── columns: array_agg:8
 └── group-by (hash)
      ├── columns: a:1 b:2 array_agg:8
      ├── grouping columns: a:1 b:2
      ├── internal-ordering: +3 opt(1,2)
      ├── key: (1,2)
      ├── fd: (1,2)-->(8)
      ├── scan abcd@cd
      │    ├── columns: a:1 b:2 c:3 d:4
      │    └── ordering: +3 opt(1,2) [actual: +3]
      └── aggregations
           └── array-agg [as=array_agg:8, outer=(4)]
                └── d:4

# --------------------------------------------------
# Explain operator.
# --------------------------------------------------
opt
EXPLAIN (VERBOSE) SELECT * FROM a ORDER BY y
----
explain
 ├── columns: info:7
 ├── mode: verbose
 └── sort
      ├── columns: x:1!null y:2!null z:3 s:4!null
      ├── key: (1,2)
      ├── fd: (1,2)-->(3,4)
      ├── ordering: +2
      └── scan a
           ├── columns: x:1!null y:2!null z:3 s:4!null
           ├── key: (1,2)
           └── fd: (1,2)-->(3,4)

memo
EXPLAIN (VERBOSE) SELECT * FROM a ORDER BY y
----
memo (optimized, ~4KB, required=[presentation: info:7])
 ├── G1: (explain G2 [presentation: x:1,y:2,z:3,s:4] [ordering: +2])
 │    └── [presentation: info:7]
 │         ├── best: (explain G2="[presentation: x:1,y:2,z:3,s:4] [ordering: +2]" [presentation: x:1,y:2,z:3,s:4] [ordering: +2])
 │         └── cost: 1368.32
 └── G2: (scan a,cols=(1-4))
      ├── [presentation: x:1,y:2,z:3,s:4] [ordering: +2]
      │    ├── best: (sort G2)
      │    └── cost: 1368.30
      └── []
           ├── best: (scan a,cols=(1-4))
           └── cost: 1108.82

# --------------------------------------------------
# With Ordinality
# --------------------------------------------------

memo
SELECT y FROM a WITH ORDINALITY ORDER BY ordinality
----
memo (optimized, ~5KB, required=[presentation: y:2] [ordering: +7])
 ├── G1: (ordinality G2)
 │    ├── [presentation: y:2] [ordering: +7]
 │    │    ├── best: (ordinality G2)
 │    │    └── cost: 1088.54
 │    └── []
 │         ├── best: (ordinality G2)
 │         └── cost: 1088.54
 └── G2: (scan a,cols=(2))
      └── []
           ├── best: (scan a,cols=(2))
           └── cost: 1078.52

memo
SELECT y FROM a WITH ORDINALITY ORDER BY -ordinality
----
memo (optimized, ~7KB, required=[presentation: y:2] [ordering: +8])
 ├── G1: (project G2 G3 y)
 │    ├── [presentation: y:2] [ordering: +8]
 │    │    ├── best: (sort G1)
 │    │    └── cost: 1348.04
 │    └── []
 │         ├── best: (project G2 G3 y)
 │         └── cost: 1108.56
 ├── G2: (ordinality G4)
 │    └── []
 │         ├── best: (ordinality G4)
 │         └── cost: 1088.54
 ├── G3: (projections G5)
 ├── G4: (scan a,cols=(2))
 │    └── []
 │         ├── best: (scan a,cols=(2))
 │         └── cost: 1078.52
 ├── G5: (unary-minus G6)
 └── G6: (variable ordinality)

memo
SELECT y FROM a WITH ORDINALITY ORDER BY ordinality, x
----
memo (optimized, ~8KB, required=[presentation: y:2] [ordering: +7])
 ├── G1: (ordinality G2)
 │    ├── [presentation: y:2] [ordering: +7]
 │    │    ├── best: (ordinality G2)
 │    │    └── cost: 1088.54
 │    └── []
 │         ├── best: (ordinality G2)
 │         └── cost: 1088.54
 └── G2: (scan a,cols=(2))
      └── []
           ├── best: (scan a,cols=(2))
           └── cost: 1078.52

memo
SELECT y FROM (SELECT * FROM a ORDER BY y) WITH ORDINALITY ORDER BY y, ordinality
----
memo (optimized, ~7KB, required=[presentation: y:2] [ordering: +2,+7])
 ├── G1: (ordinality G2 ordering=+2)
 │    ├── [presentation: y:2] [ordering: +2,+7]
 │    │    ├── best: (ordinality G2="[ordering: +2]" ordering=+2)
 │    │    └── cost: 1318.02
 │    └── []
 │         ├── best: (ordinality G2="[ordering: +2]" ordering=+2)
 │         └── cost: 1318.02
 └── G2: (scan a,cols=(2))
      ├── [ordering: +2]
      │    ├── best: (sort G2)
      │    └── cost: 1308.00
      └── []
           ├── best: (scan a,cols=(2))
           └── cost: 1078.52

memo
SELECT y FROM (SELECT * FROM a ORDER BY y) WITH ORDINALITY ORDER BY ordinality, y
----
memo (optimized, ~7KB, required=[presentation: y:2] [ordering: +7])
 ├── G1: (ordinality G2 ordering=+2)
 │    ├── [presentation: y:2] [ordering: +7]
 │    │    ├── best: (ordinality G2="[ordering: +2]" ordering=+2)
 │    │    └── cost: 1318.02
 │    └── []
 │         ├── best: (ordinality G2="[ordering: +2]" ordering=+2)
 │         └── cost: 1318.02
 └── G2: (scan a,cols=(2))
      ├── [ordering: +2]
      │    ├── best: (sort G2)
      │    └── cost: 1308.00
      └── []
           ├── best: (scan a,cols=(2))
           └── cost: 1078.52

memo
SELECT y FROM a WITH ORDINALITY ORDER BY ordinality DESC
----
memo (optimized, ~5KB, required=[presentation: y:2] [ordering: -7])
 ├── G1: (ordinality G2)
 │    ├── [presentation: y:2] [ordering: -7]
 │    │    ├── best: (sort G1)
 │    │    └── cost: 1328.02
 │    └── []
 │         ├── best: (ordinality G2)
 │         └── cost: 1088.54
 └── G2: (scan a,cols=(2))
      └── []
           ├── best: (scan a,cols=(2))
           └── cost: 1078.52

# --------------------------------------------------
# Merge Join
# --------------------------------------------------

opt
SELECT * FROM abc JOIN xyz ON a=x ORDER BY a
----
inner-join (merge)
 ├── columns: a:1!null b:2!null c:3!null x:6!null y:7!null z:8!null
 ├── left ordering: +1
 ├── right ordering: +6
 ├── key: (2,3,6-8)
 ├── fd: (1)==(6), (6)==(1)
 ├── ordering: +(1|6) [actual: +1]
 ├── scan abc
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1
 ├── scan xyz
 │    ├── columns: x:6!null y:7!null z:8!null
 │    ├── key: (6-8)
 │    └── ordering: +6
 └── filters (true)

opt
SELECT * FROM abc JOIN xyz ON a=x ORDER BY x
----
inner-join (merge)
 ├── columns: a:1!null b:2!null c:3!null x:6!null y:7!null z:8!null
 ├── left ordering: +1
 ├── right ordering: +6
 ├── key: (2,3,6-8)
 ├── fd: (1)==(6), (6)==(1)
 ├── ordering: +(1|6) [actual: +1]
 ├── scan abc
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1
 ├── scan xyz
 │    ├── columns: x:6!null y:7!null z:8!null
 │    ├── key: (6-8)
 │    └── ordering: +6
 └── filters (true)

# A left join guarantees an ordering on the left side.
opt
SELECT * FROM abc LEFT JOIN xyz ON a=x ORDER BY a
----
left-join (merge)
 ├── columns: a:1!null b:2!null c:3!null x:6 y:7 z:8
 ├── left ordering: +1
 ├── right ordering: +6
 ├── key: (1-3,6-8)
 ├── ordering: +1
 ├── scan abc
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1
 ├── scan xyz
 │    ├── columns: x:6!null y:7!null z:8!null
 │    ├── key: (6-8)
 │    └── ordering: +6
 └── filters (true)

# A left join doesn't guarantee an ordering on x (some rows will have NULLs).
opt
SELECT * FROM abc LEFT JOIN xyz ON a=x ORDER BY x
----
sort
 ├── columns: a:1!null b:2!null c:3!null x:6 y:7 z:8
 ├── key: (1-3,6-8)
 ├── ordering: +6
 └── left-join (merge)
      ├── columns: a:1!null b:2!null c:3!null x:6 y:7 z:8
      ├── left ordering: +1
      ├── right ordering: +6
      ├── key: (1-3,6-8)
      ├── scan abc
      │    ├── columns: a:1!null b:2!null c:3!null
      │    ├── key: (1-3)
      │    └── ordering: +1
      ├── scan xyz
      │    ├── columns: x:6!null y:7!null z:8!null
      │    ├── key: (6-8)
      │    └── ordering: +6
      └── filters (true)

# A right join doesn't guarantee an ordering on a (some rows will have NULLs).
opt
SELECT * FROM abc RIGHT JOIN xyz ON a=x ORDER BY a
----
sort
 ├── columns: a:1 b:2 c:3 x:6!null y:7!null z:8!null
 ├── key: (1-3,6-8)
 ├── ordering: +1
 └── left-join (merge)
      ├── columns: a:1 b:2 c:3 x:6!null y:7!null z:8!null
      ├── left ordering: +6
      ├── right ordering: +1
      ├── key: (1-3,6-8)
      ├── scan xyz
      │    ├── columns: x:6!null y:7!null z:8!null
      │    ├── key: (6-8)
      │    └── ordering: +6
      ├── scan abc
      │    ├── columns: a:1!null b:2!null c:3!null
      │    ├── key: (1-3)
      │    └── ordering: +1
      └── filters (true)

opt
SELECT * FROM abc RIGHT JOIN xyz ON a=x ORDER BY x
----
left-join (merge)
 ├── columns: a:1 b:2 c:3 x:6!null y:7!null z:8!null
 ├── left ordering: +6
 ├── right ordering: +1
 ├── key: (1-3,6-8)
 ├── ordering: +6
 ├── scan xyz
 │    ├── columns: x:6!null y:7!null z:8!null
 │    ├── key: (6-8)
 │    └── ordering: +6
 ├── scan abc
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1
 └── filters (true)

opt
SELECT * FROM abc FULL OUTER JOIN xyz ON a=x ORDER BY a
----
sort
 ├── columns: a:1 b:2 c:3 x:6 y:7 z:8
 ├── key: (1-3,6-8)
 ├── ordering: +1
 └── full-join (merge)
      ├── columns: a:1 b:2 c:3 x:6 y:7 z:8
      ├── left ordering: +1
      ├── right ordering: +6
      ├── key: (1-3,6-8)
      ├── scan abc
      │    ├── columns: a:1!null b:2!null c:3!null
      │    ├── key: (1-3)
      │    └── ordering: +1
      ├── scan xyz
      │    ├── columns: x:6!null y:7!null z:8!null
      │    ├── key: (6-8)
      │    └── ordering: +6
      └── filters (true)

opt
SELECT * FROM abc JOIN xyz ON a=x AND b=y ORDER BY a
----
inner-join (merge)
 ├── columns: a:1!null b:2!null c:3!null x:6!null y:7!null z:8!null
 ├── left ordering: +1,+2
 ├── right ordering: +6,+7
 ├── key: (3,6-8)
 ├── fd: (1)==(6), (6)==(1), (2)==(7), (7)==(2)
 ├── ordering: +(1|6) [actual: +1]
 ├── scan abc
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1,+2
 ├── scan xyz
 │    ├── columns: x:6!null y:7!null z:8!null
 │    ├── key: (6-8)
 │    └── ordering: +6,+7
 └── filters (true)

opt
SELECT * FROM abc JOIN xyz ON a=x AND b=y ORDER BY a, b
----
inner-join (merge)
 ├── columns: a:1!null b:2!null c:3!null x:6!null y:7!null z:8!null
 ├── left ordering: +1,+2
 ├── right ordering: +6,+7
 ├── key: (3,6-8)
 ├── fd: (1)==(6), (6)==(1), (2)==(7), (7)==(2)
 ├── ordering: +(1|6),+(2|7) [actual: +1,+2]
 ├── scan abc
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1,+2
 ├── scan xyz
 │    ├── columns: x:6!null y:7!null z:8!null
 │    ├── key: (6-8)
 │    └── ordering: +6,+7
 └── filters (true)

opt
SELECT * FROM abc JOIN xyz ON a=x AND b=y ORDER BY a, y
----
inner-join (merge)
 ├── columns: a:1!null b:2!null c:3!null x:6!null y:7!null z:8!null
 ├── left ordering: +1,+2
 ├── right ordering: +6,+7
 ├── key: (3,6-8)
 ├── fd: (1)==(6), (6)==(1), (2)==(7), (7)==(2)
 ├── ordering: +(1|6),+(2|7) [actual: +1,+2]
 ├── scan abc
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1,+2
 ├── scan xyz
 │    ├── columns: x:6!null y:7!null z:8!null
 │    ├── key: (6-8)
 │    └── ordering: +6,+7
 └── filters (true)

# --------------------------------------------------
# Limit / Offset
# --------------------------------------------------

# Basic cases.

opt
SELECT * FROM abc ORDER BY a, b LIMIT 10
----
scan abc
 ├── columns: a:1!null b:2!null c:3!null
 ├── limit: 10
 ├── key: (1-3)
 └── ordering: +1,+2

# The filter prevents pushing of the limit into the scan.
opt
SELECT * FROM abc WHERE a+b>c ORDER BY a, b LIMIT 10
----
limit
 ├── columns: a:1!null b:2!null c:3!null
 ├── internal-ordering: +1,+2
 ├── cardinality: [0 - 10]
 ├── immutable
 ├── key: (1-3)
 ├── ordering: +1,+2
 ├── select
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── immutable
 │    ├── key: (1-3)
 │    ├── ordering: +1,+2
 │    ├── limit hint: 10.00
 │    ├── scan abc
 │    │    ├── columns: a:1!null b:2!null c:3!null
 │    │    ├── key: (1-3)
 │    │    ├── ordering: +1,+2
 │    │    └── limit hint: 30.00
 │    └── filters
 │         └── c:3 < (a:1 + b:2) [outer=(1-3), immutable]
 └── 10

opt
SELECT * FROM abc ORDER BY a, b OFFSET 10 
----
offset
 ├── columns: a:1!null b:2!null c:3!null
 ├── internal-ordering: +1,+2
 ├── key: (1-3)
 ├── ordering: +1,+2
 ├── scan abc
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1,+2
 └── 10


# Cases where the requirement on Limit/Offset is incompatible with the
# internal requirement.

opt
SELECT * FROM (SELECT * FROM abc ORDER BY a, b LIMIT 10) ORDER BY b
----
sort
 ├── columns: a:1!null b:2!null c:3!null
 ├── cardinality: [0 - 10]
 ├── key: (1-3)
 ├── ordering: +2
 └── scan abc
      ├── columns: a:1!null b:2!null c:3!null
      ├── limit: 10
      └── key: (1-3)

opt
SELECT * FROM (SELECT * FROM abc WHERE a+b>c ORDER BY a, b LIMIT 10) ORDER BY b
----
sort
 ├── columns: a:1!null b:2!null c:3!null
 ├── cardinality: [0 - 10]
 ├── immutable
 ├── key: (1-3)
 ├── ordering: +2
 └── limit
      ├── columns: a:1!null b:2!null c:3!null
      ├── internal-ordering: +1,+2
      ├── cardinality: [0 - 10]
      ├── immutable
      ├── key: (1-3)
      ├── select
      │    ├── columns: a:1!null b:2!null c:3!null
      │    ├── immutable
      │    ├── key: (1-3)
      │    ├── ordering: +1,+2
      │    ├── limit hint: 10.00
      │    ├── scan abc
      │    │    ├── columns: a:1!null b:2!null c:3!null
      │    │    ├── key: (1-3)
      │    │    ├── ordering: +1,+2
      │    │    └── limit hint: 30.00
      │    └── filters
      │         └── c:3 < (a:1 + b:2) [outer=(1-3), immutable]
      └── 10

opt
SELECT * FROM (SELECT * FROM abc ORDER BY a, b OFFSET 10) ORDER BY b
----
sort
 ├── columns: a:1!null b:2!null c:3!null
 ├── key: (1-3)
 ├── ordering: +2
 └── offset
      ├── columns: a:1!null b:2!null c:3!null
      ├── internal-ordering: +1,+2
      ├── key: (1-3)
      ├── scan abc
      │    ├── columns: a:1!null b:2!null c:3!null
      │    ├── key: (1-3)
      │    └── ordering: +1,+2
      └── 10


# Cases where the requirement on Limit/Offset is weaker than the
# internal requirement.

opt
SELECT * FROM (SELECT * FROM abc ORDER BY a, b LIMIT 10) ORDER BY a
----
scan abc
 ├── columns: a:1!null b:2!null c:3!null
 ├── limit: 10
 ├── key: (1-3)
 └── ordering: +1

opt
SELECT * FROM (SELECT * FROM abc WHERE a+b>c ORDER BY a, b LIMIT 10) ORDER BY a
----
limit
 ├── columns: a:1!null b:2!null c:3!null
 ├── internal-ordering: +1,+2
 ├── cardinality: [0 - 10]
 ├── immutable
 ├── key: (1-3)
 ├── ordering: +1
 ├── select
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── immutable
 │    ├── key: (1-3)
 │    ├── ordering: +1,+2
 │    ├── limit hint: 10.00
 │    ├── scan abc
 │    │    ├── columns: a:1!null b:2!null c:3!null
 │    │    ├── key: (1-3)
 │    │    ├── ordering: +1,+2
 │    │    └── limit hint: 30.00
 │    └── filters
 │         └── c:3 < (a:1 + b:2) [outer=(1-3), immutable]
 └── 10

opt
SELECT * FROM (SELECT * FROM abc ORDER BY a, b OFFSET 10) ORDER BY a
----
offset
 ├── columns: a:1!null b:2!null c:3!null
 ├── internal-ordering: +1,+2
 ├── key: (1-3)
 ├── ordering: +1
 ├── scan abc
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1,+2
 └── 10

# Cases where the requirement on Limit/Offset is stronger than the
# internal requirement.

opt
SELECT * FROM (SELECT * FROM abc ORDER BY a, b LIMIT 10) ORDER BY a, b, c
----
scan abc
 ├── columns: a:1!null b:2!null c:3!null
 ├── limit: 10
 ├── key: (1-3)
 └── ordering: +1,+2,+3

opt
SELECT * FROM (SELECT * FROM abc WHERE a+b>c ORDER BY a, b LIMIT 10) ORDER BY a, b, c
----
limit
 ├── columns: a:1!null b:2!null c:3!null
 ├── internal-ordering: +1,+2
 ├── cardinality: [0 - 10]
 ├── immutable
 ├── key: (1-3)
 ├── ordering: +1,+2,+3
 ├── select
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── immutable
 │    ├── key: (1-3)
 │    ├── ordering: +1,+2,+3
 │    ├── limit hint: 10.00
 │    ├── scan abc
 │    │    ├── columns: a:1!null b:2!null c:3!null
 │    │    ├── key: (1-3)
 │    │    ├── ordering: +1,+2,+3
 │    │    └── limit hint: 30.00
 │    └── filters
 │         └── c:3 < (a:1 + b:2) [outer=(1-3), immutable]
 └── 10

opt
SELECT * FROM (SELECT * FROM abc ORDER BY a, b OFFSET 10) ORDER BY a, b, c
----
offset
 ├── columns: a:1!null b:2!null c:3!null
 ├── internal-ordering: +1,+2
 ├── key: (1-3)
 ├── ordering: +1,+2,+3
 ├── scan abc
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1,+2,+3
 └── 10

# --------------------------------------------------
# DistinctOn
# --------------------------------------------------

# DISTINCT doesn't require any particular ordering of its input. It could pass
# through the requirement, but that doesn't improve the estimated cost in this
# case.
opt
SELECT DISTINCT b, c FROM abc ORDER BY b
----
sort
 ├── columns: b:2!null c:3!null
 ├── key: (2,3)
 ├── ordering: +2
 └── distinct-on
      ├── columns: b:2!null c:3!null
      ├── grouping columns: b:2!null c:3!null
      ├── key: (2,3)
      └── scan abc
           └── columns: b:2!null c:3!null

# In this case the ordering is passed through.
opt
SELECT DISTINCT a, b, c FROM abc ORDER BY a, b
----
scan abc
 ├── columns: a:1!null b:2!null c:3!null
 ├── key: (1-3)
 └── ordering: +1,+2

# DISTINCT ON requires the ordering of its input, as it affects the results
# (values of a in this case).
opt
SELECT DISTINCT ON (b, c) a, b, c FROM abc ORDER BY b
----
sort
 ├── columns: a:1!null b:2!null c:3!null
 ├── key: (2,3)
 ├── fd: (2,3)-->(1)
 ├── ordering: +2
 └── distinct-on
      ├── columns: a:1!null b:2!null c:3!null
      ├── grouping columns: b:2!null c:3!null
      ├── key: (2,3)
      ├── fd: (2,3)-->(1)
      ├── scan abc
      │    ├── columns: a:1!null b:2!null c:3!null
      │    └── key: (1-3)
      └── aggregations
           └── first-agg [as=a:1, outer=(1)]
                └── a:1

opt
SELECT DISTINCT ON (b, c) a, b, c FROM abc ORDER BY b, c, a
----
distinct-on
 ├── columns: a:1!null b:2!null c:3!null
 ├── grouping columns: b:2!null c:3!null
 ├── internal-ordering: +1 opt(2,3)
 ├── key: (2,3)
 ├── fd: (2,3)-->(1)
 ├── ordering: +2,+3
 ├── sort
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (1-3)
 │    ├── ordering: +2,+3,+1
 │    └── scan abc
 │         ├── columns: a:1!null b:2!null c:3!null
 │         └── key: (1-3)
 └── aggregations
      └── first-agg [as=a:1, outer=(1)]
           └── a:1

opt
SELECT DISTINCT ON (a) a, c FROM abc ORDER BY a, c DESC, b
----
distinct-on
 ├── columns: a:1!null c:3!null
 ├── grouping columns: a:1!null
 ├── internal-ordering: -3,+2 opt(1)
 ├── key: (1)
 ├── fd: (1)-->(3)
 ├── ordering: +1
 ├── sort (segmented)
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (1-3)
 │    ├── ordering: +1,-3,+2
 │    └── scan abc
 │         ├── columns: a:1!null b:2!null c:3!null
 │         ├── key: (1-3)
 │         └── ordering: +1
 └── aggregations
      └── first-agg [as=c:3, outer=(3)]
           └── c:3

# Pass through the ordering from above.
opt
SELECT * FROM (SELECT DISTINCT ON (a, b) a, b, c FROM abc) ORDER BY a
----
distinct-on
 ├── columns: a:1!null b:2!null c:3!null
 ├── grouping columns: a:1!null b:2!null
 ├── internal-ordering: +1,+2
 ├── key: (1,2)
 ├── fd: (1,2)-->(3)
 ├── ordering: +1
 ├── scan abc
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1,+2
 └── aggregations
      └── first-agg [as=c:3, outer=(3)]
           └── c:3

# Internal orderings that refer just to ON columns can be ignored.
opt
SELECT * FROM (SELECT DISTINCT ON (a, b) a, b, c FROM abc ORDER BY a) ORDER BY a, b
----
distinct-on
 ├── columns: a:1!null b:2!null c:3!null
 ├── grouping columns: a:1!null b:2!null
 ├── key: (1,2)
 ├── fd: (1,2)-->(3)
 ├── ordering: +1,+2
 ├── scan abc
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1,+2
 └── aggregations
      └── first-agg [as=c:3, outer=(3)]
           └── c:3

opt
SELECT * FROM (SELECT DISTINCT ON (a, b) a, b, c FROM abc ORDER BY a, b) ORDER BY a
----
distinct-on
 ├── columns: a:1!null b:2!null c:3!null
 ├── grouping columns: a:1!null b:2!null
 ├── internal-ordering: +1,+2
 ├── key: (1,2)
 ├── fd: (1,2)-->(3)
 ├── ordering: +1
 ├── scan abc
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1,+2
 └── aggregations
      └── first-agg [as=c:3, outer=(3)]
           └── c:3

# The c,b part of the inner ordering can be ignored.
opt
SELECT * FROM (SELECT DISTINCT ON (b, c) a, b, c FROM abc ORDER BY c, b, a) ORDER BY a
----
distinct-on
 ├── columns: a:1!null b:2!null c:3!null
 ├── grouping columns: b:2!null c:3!null
 ├── internal-ordering: +1 opt(2,3)
 ├── key: (2,3)
 ├── fd: (2,3)-->(1)
 ├── ordering: +1
 ├── scan abc
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1
 └── aggregations
      └── first-agg [as=a:1, outer=(1)]
           └── a:1

# There is no ordering that satisfies both the intra-group ordering of c+ and the
# inter-group ordering of a+; we have to sort twice.
opt
SELECT * FROM (SELECT DISTINCT ON (b) a, b, c FROM abc ORDER BY b, c) ORDER BY a
----
sort
 ├── columns: a:1!null b:2!null c:3!null
 ├── key: (2)
 ├── fd: (2)-->(1,3)
 ├── ordering: +1
 └── distinct-on
      ├── columns: a:1!null b:2!null c:3!null
      ├── grouping columns: b:2!null
      ├── internal-ordering: +3 opt(2)
      ├── key: (2)
      ├── fd: (2)-->(1,3)
      ├── sort
      │    ├── columns: a:1!null b:2!null c:3!null
      │    ├── key: (1-3)
      │    ├── ordering: +3 opt(2) [actual: +3]
      │    └── scan abc
      │         ├── columns: a:1!null b:2!null c:3!null
      │         └── key: (1-3)
      └── aggregations
           ├── first-agg [as=a:1, outer=(1)]
           │    └── a:1
           └── first-agg [as=c:3, outer=(3)]
                └── c:3

# Same as above, except we can use the index ordering for the distinct input.
opt
SELECT * FROM (SELECT DISTINCT ON (a) a, b, c FROM abc ORDER BY a, b) ORDER BY c
----
sort
 ├── columns: a:1!null b:2!null c:3!null
 ├── key: (1)
 ├── fd: (1)-->(2,3)
 ├── ordering: +3
 └── distinct-on
      ├── columns: a:1!null b:2!null c:3!null
      ├── grouping columns: a:1!null
      ├── internal-ordering: +1,+2
      ├── key: (1)
      ├── fd: (1)-->(2,3)
      ├── scan abc
      │    ├── columns: a:1!null b:2!null c:3!null
      │    ├── key: (1-3)
      │    └── ordering: +1,+2
      └── aggregations
           ├── first-agg [as=b:2, outer=(2)]
           │    └── b:2
           └── first-agg [as=c:3, outer=(3)]
                └── c:3

# Verify that we simplify the child ordering of DistinctOn.
opt
SELECT DISTINCT ON(a) a, b FROM abc WHERE a=c ORDER BY a
----
distinct-on
 ├── columns: a:1!null b:2!null
 ├── grouping columns: a:1!null
 ├── key: (1)
 ├── fd: (1)-->(2)
 ├── ordering: +1
 ├── select
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (2,3)
 │    ├── fd: (1)==(3), (3)==(1)
 │    ├── ordering: +(1|3) [actual: +1]
 │    ├── scan abc
 │    │    ├── columns: a:1!null b:2!null c:3!null
 │    │    ├── key: (1-3)
 │    │    └── ordering: +1
 │    └── filters
 │         └── a:1 = c:3 [outer=(1,3), fd=(1)==(3), (3)==(1)]
 └── aggregations
      └── first-agg [as=b:2, outer=(2)]
           └── b:2

# Regression test for #79644
exec-ddl
CREATE TABLE t1 (
  id INT8 PRIMARY KEY,
  col2 INT8 NOT NULL,
  name STRING(1024),
  UNIQUE (col2, name)
)
----

exec-ddl
CREATE TABLE t2 (
  col1 INT8 NOT NULL REFERENCES t1,
  col2 INT4 NOT NULL,
  PRIMARY KEY (col1, col2)
)
----

exec-ddl
CREATE TABLE t3 (
  col1 INT8 NOT NULL,
  col2 INT4 NOT NULL,
  col3 INT8 NOT NULL,
  PRIMARY KEY (col1, col2, col3),
  CONSTRAINT fk_t2 FOREIGN KEY (col1, col2) REFERENCES t2 (col1, col2)
)
----

# DISTINCT ON + GROUP BY + ORDER BY should not use the GROUP BY's empty
# OrderingChoice to try and fulfill the required ordering.
opt format=hide-stats
SELECT
DISTINCT ON (t2.col1)
t1.col2, t2.col1, array_agg(t3.col3) FROM t2
INNER JOIN t1 ON t1.id = t2.col1
INNER JOIN t3 ON t2.col2 = t3.col2
GROUP BY (t2.col1, t1.col2, t2.col2)
ORDER BY (t2.col1, t2.col2)
----
distinct-on
 ├── columns: col2:6!null col1:1!null array_agg:15!null
 ├── grouping columns: t2.col1:1!null
 ├── internal-ordering: +2 opt(1,6)
 ├── key: (1)
 ├── fd: (1)-->(6,15)
 ├── ordering: +1
 ├── sort
 │    ├── columns: t2.col1:1!null t2.col2:2!null t1.col2:6!null array_agg:15!null
 │    ├── key: (1,2)
 │    ├── fd: (1)-->(6), (1,2)-->(6,15)
 │    ├── ordering: +1,+2
 │    └── group-by (hash)
 │         ├── columns: t2.col1:1!null t2.col2:2!null t1.col2:6!null array_agg:15!null
 │         ├── grouping columns: t2.col1:1!null t2.col2:2!null
 │         ├── key: (1,2)
 │         ├── fd: (1)-->(6), (1,2)-->(6,15)
 │         ├── inner-join (hash)
 │         │    ├── columns: t2.col1:1!null t2.col2:2!null id:5!null t1.col2:6!null t3.col2:11!null col3:12!null
 │         │    ├── multiplicity: left-rows(zero-or-more), right-rows(one-or-more)
 │         │    ├── fd: (5)-->(6), (1)==(5), (5)==(1), (2)==(11), (11)==(2)
 │         │    ├── inner-join (merge)
 │         │    │    ├── columns: t2.col1:1!null t2.col2:2!null id:5!null t1.col2:6!null
 │         │    │    ├── left ordering: +1
 │         │    │    ├── right ordering: +5
 │         │    │    ├── key: (2,5)
 │         │    │    ├── fd: (5)-->(6), (1)==(5), (5)==(1)
 │         │    │    ├── scan t2
 │         │    │    │    ├── columns: t2.col1:1!null t2.col2:2!null
 │         │    │    │    ├── key: (1,2)
 │         │    │    │    └── ordering: +1
 │         │    │    ├── scan t1
 │         │    │    │    ├── columns: id:5!null t1.col2:6!null
 │         │    │    │    ├── key: (5)
 │         │    │    │    ├── fd: (5)-->(6)
 │         │    │    │    └── ordering: +5
 │         │    │    └── filters (true)
 │         │    ├── scan t3
 │         │    │    └── columns: t3.col2:11!null col3:12!null
 │         │    └── filters
 │         │         └── t2.col2:2 = t3.col2:11 [outer=(2,11), fd=(2)==(11), (11)==(2)]
 │         └── aggregations
 │              ├── array-agg [as=array_agg:15, outer=(12)]
 │              │    └── col3:12
 │              └── const-agg [as=t1.col2:6, outer=(6)]
 │                   └── t1.col2:6
 └── aggregations
      ├── first-agg [as=t1.col2:6, outer=(6)]
      │    └── t1.col2:6
      └── first-agg [as=array_agg:15, outer=(15)]
           └── array_agg:15

# --------------------------------------------------
# Set Operations.
# --------------------------------------------------

opt
SELECT * FROM (SELECT a, b, c FROM abc UNION SELECT y, x, z FROM xyz) WHERE a = b ORDER BY a
----
union
 ├── columns: a:11!null b:12!null c:13!null
 ├── left columns: abc.a:1 abc.b:2 abc.c:3
 ├── right columns: y:7 x:6 z:8
 ├── internal-ordering: +(11|12),+13
 ├── key: (12,13)
 ├── fd: (12,13)-->(11), (11)==(12), (12)==(11)
 ├── ordering: +(11|12) [actual: +11]
 ├── select
 │    ├── columns: abc.a:1!null abc.b:2!null abc.c:3!null
 │    ├── key: (2,3)
 │    ├── fd: (1)==(2), (2)==(1)
 │    ├── ordering: +(1|2),+3 [actual: +1,+3]
 │    ├── scan abc
 │    │    ├── columns: abc.a:1!null abc.b:2!null abc.c:3!null
 │    │    ├── key: (1-3)
 │    │    └── ordering: +1,+2,+3
 │    └── filters
 │         └── abc.a:1 = abc.b:2 [outer=(1,2), fd=(1)==(2), (2)==(1)]
 └── select
      ├── columns: x:6!null y:7!null z:8!null
      ├── key: (7,8)
      ├── fd: (6)==(7), (7)==(6)
      ├── ordering: +(6|7),+8 [actual: +6,+8]
      ├── scan xyz
      │    ├── columns: x:6!null y:7!null z:8!null
      │    ├── key: (6-8)
      │    └── ordering: +6,+7,+8
      └── filters
           └── y:7 = x:6 [outer=(6,7), fd=(6)==(7), (7)==(6)]

opt
SELECT * FROM (SELECT a, b, c, d FROM abcd UNION ALL SELECT c, d, a, b FROM abcd) ORDER BY a, b
----
union-all
 ├── columns: a:15 b:16 c:17 d:18
 ├── left columns: abcd.a:1 abcd.b:2 abcd.c:3 abcd.d:4
 ├── right columns: abcd.c:10 abcd.d:11 abcd.a:8 abcd.b:9
 ├── ordering: +15,+16
 ├── scan abcd@ab
 │    ├── columns: abcd.a:1 abcd.b:2 abcd.c:3 abcd.d:4
 │    └── ordering: +1,+2
 └── scan abcd@cd
      ├── columns: abcd.a:8 abcd.b:9 abcd.c:10 abcd.d:11
      └── ordering: +10,+11

opt
SELECT * FROM (SELECT a, b, c, d FROM abcd INTERSECT SELECT c, d, a, b FROM abcd) ORDER BY c, d
----
intersect
 ├── columns: a:1 b:2 c:3 d:4
 ├── left columns: a:1 b:2 c:3 d:4
 ├── right columns: c:10 d:11 a:8 b:9
 ├── internal-ordering: +3,+4,+1,+2
 ├── key: (1-4)
 ├── ordering: +3,+4
 ├── sort (segmented)
 │    ├── columns: a:1 b:2 c:3 d:4
 │    ├── ordering: +3,+4,+1,+2
 │    └── scan abcd@cd
 │         ├── columns: a:1 b:2 c:3 d:4
 │         └── ordering: +3,+4
 └── sort (segmented)
      ├── columns: a:8 b:9 c:10 d:11
      ├── ordering: +8,+9,+10,+11
      └── scan abcd@ab
           ├── columns: a:8 b:9 c:10 d:11
           └── ordering: +8,+9

opt
SELECT * FROM (SELECT a, b, c FROM abc INTERSECT ALL SELECT y, x, z FROM xyz) WHERE a = b ORDER BY b
----
intersect-all
 ├── columns: a:1!null b:2!null c:3!null
 ├── left columns: a:1!null b:2!null c:3!null
 ├── right columns: y:7 x:6 z:8
 ├── internal-ordering: +(1|2),+3
 ├── key: (2,3)
 ├── fd: (1)==(2), (2)==(1)
 ├── ordering: +(1|2) [actual: +1]
 ├── select
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (2,3)
 │    ├── fd: (1)==(2), (2)==(1)
 │    ├── ordering: +(1|2),+3 [actual: +1,+3]
 │    ├── scan abc
 │    │    ├── columns: a:1!null b:2!null c:3!null
 │    │    ├── key: (1-3)
 │    │    └── ordering: +1,+2,+3
 │    └── filters
 │         └── a:1 = b:2 [outer=(1,2), fd=(1)==(2), (2)==(1)]
 └── select
      ├── columns: x:6!null y:7!null z:8!null
      ├── key: (7,8)
      ├── fd: (6)==(7), (7)==(6)
      ├── ordering: +(6|7),+8 [actual: +6,+8]
      ├── scan xyz
      │    ├── columns: x:6!null y:7!null z:8!null
      │    ├── key: (6-8)
      │    └── ordering: +6,+7,+8
      └── filters
           └── y:7 = x:6 [outer=(6,7), fd=(6)==(7), (7)==(6)]

opt
SELECT * FROM (SELECT b, c FROM abc EXCEPT SELECT y, x FROM xyz) WHERE b = c ORDER BY c, b
----
except
 ├── columns: b:2!null c:3!null
 ├── left columns: b:2!null c:3!null
 ├── right columns: y:7 x:6
 ├── internal-ordering: +(2|3)
 ├── key: (3)
 ├── fd: (2)==(3), (3)==(2)
 ├── ordering: +(2|3) [actual: +2]
 ├── sort
 │    ├── columns: b:2!null c:3!null
 │    ├── fd: (2)==(3), (3)==(2)
 │    ├── ordering: +(2|3) [actual: +2]
 │    └── select
 │         ├── columns: b:2!null c:3!null
 │         ├── fd: (2)==(3), (3)==(2)
 │         ├── scan abc
 │         │    └── columns: b:2!null c:3!null
 │         └── filters
 │              └── b:2 = c:3 [outer=(2,3), fd=(2)==(3), (3)==(2)]
 └── select
      ├── columns: x:6!null y:7!null
      ├── fd: (6)==(7), (7)==(6)
      ├── ordering: +(6|7) [actual: +6]
      ├── scan xyz
      │    ├── columns: x:6!null y:7!null
      │    └── ordering: +6
      └── filters
           └── y:7 = x:6 [outer=(6,7), fd=(6)==(7), (7)==(6)]

opt
SELECT * FROM (SELECT a, b, c, d FROM abcd EXCEPT ALL SELECT c, d, a, b FROM abcd) ORDER BY a, b
----
except-all
 ├── columns: a:1 b:2 c:3 d:4
 ├── left columns: a:1 b:2 c:3 d:4
 ├── right columns: c:10 d:11 a:8 b:9
 ├── internal-ordering: +1,+2,+3,+4
 ├── ordering: +1,+2
 ├── sort (segmented)
 │    ├── columns: a:1 b:2 c:3 d:4
 │    ├── ordering: +1,+2,+3,+4
 │    └── scan abcd@ab
 │         ├── columns: a:1 b:2 c:3 d:4
 │         └── ordering: +1,+2
 └── sort (segmented)
      ├── columns: a:8 b:9 c:10 d:11
      ├── ordering: +10,+11,+8,+9
      └── scan abcd@cd
           ├── columns: a:8 b:9 c:10 d:11
           └── ordering: +10,+11

opt
VALUES (1) UNION ALL VALUES (NULL) ORDER BY 1
----
union-all
 ├── columns: column1:3
 ├── left columns: column1:1
 ├── right columns: column1:2
 ├── cardinality: [2 - 2]
 ├── ordering: +3
 ├── values
 │    ├── columns: column1:1!null
 │    ├── cardinality: [1 - 1]
 │    ├── key: ()
 │    ├── fd: ()-->(1)
 │    └── (1,)
 └── values
      ├── columns: column1:2
      ├── cardinality: [1 - 1]
      ├── key: ()
      ├── fd: ()-->(2)
      └── (NULL,)

# TODO(rytaft): We could remove the ordering from the INTERSECT operation
# if we updated the FDs to show that column1 is constant (the cardinality
# proves this to be true).
opt
VALUES (1) INTERSECT VALUES (1) ORDER BY 1
----
intersect-all
 ├── columns: column1:1!null
 ├── left columns: column1:1!null
 ├── right columns: column1:2
 ├── cardinality: [0 - 1]
 ├── key: ()
 ├── fd: ()-->(1)
 ├── values
 │    ├── columns: column1:1!null
 │    ├── cardinality: [1 - 1]
 │    ├── key: ()
 │    ├── fd: ()-->(1)
 │    └── (1,)
 └── values
      ├── columns: column1:2!null
      ├── cardinality: [1 - 1]
      ├── key: ()
      ├── fd: ()-->(2)
      └── (1,)

# Regression test for #69497. Ensure streaming set ops specify all columns in
# the ordering.
exec-ddl
CREATE TABLE t69497_abc (a INT, b INT, c INT, INDEX (a, b, c DESC))
----

exec-ddl
CREATE TABLE t69497_def (d INT PRIMARY KEY, e INT, f INT)
----

opt
SELECT d, e, f FROM t69497_def EXCEPT SELECT a, b, c FROM t69497_abc ORDER by d, e
----
except-all
 ├── columns: d:1 e:2 f:3
 ├── left columns: d:1 e:2 f:3
 ├── right columns: a:6 b:7 c:8
 ├── internal-ordering: +1,+2,-3
 ├── key: (1)
 ├── fd: (1)-->(2,3)
 ├── ordering: +1
 ├── scan t69497_def
 │    ├── columns: d:1!null e:2 f:3
 │    ├── key: (1)
 │    ├── fd: (1)-->(2,3)
 │    └── ordering: +1
 └── scan t69497_abc@t69497_abc_a_b_c_idx
      ├── columns: a:6 b:7 c:8
      └── ordering: +6,+7,-8

# Example where the interesting orderings do not include all columns.
exec-ddl
CREATE TABLE t69497_abcd (a INT, b INT, c INT, d INT, INDEX (a, b, c DESC) STORING (d))
----

exec-ddl
CREATE TABLE t69497_efgh (e INT PRIMARY KEY, f INT, g INT, h INT)
----

opt
SELECT e, f, g, h FROM t69497_efgh EXCEPT SELECT a, b, c, d FROM t69497_abcd ORDER by e, f
----
except-all
 ├── columns: e:1 f:2 g:3 h:4
 ├── left columns: e:1 f:2 g:3 h:4
 ├── right columns: a:7 b:8 c:9 d:10
 ├── internal-ordering: +1,+2,-3,+4
 ├── key: (1)
 ├── fd: (1)-->(2-4)
 ├── ordering: +1
 ├── scan t69497_efgh
 │    ├── columns: e:1!null f:2 g:3 h:4
 │    ├── key: (1)
 │    ├── fd: (1)-->(2-4)
 │    └── ordering: +1
 └── sort (segmented)
      ├── columns: a:7 b:8 c:9 d:10
      ├── ordering: +7,+8,-9,+10
      └── scan t69497_abcd@t69497_abcd_a_b_c_idx
           ├── columns: a:7 b:8 c:9 d:10
           └── ordering: +7,+8,-9

# --------------------------------------------------
# Insert operator.
# --------------------------------------------------

# Verify that external ordering is passed through to input.
opt
SELECT * FROM [INSERT INTO abc SELECT * FROM xyz ORDER BY y, z LIMIT 2 RETURNING *] ORDER BY b
----
sort
 ├── columns: a:11!null b:12!null c:13!null
 ├── cardinality: [0 - 2]
 ├── volatile, mutations
 ├── key: (11-13)
 ├── ordering: +12
 └── with &1
      ├── columns: a:11!null b:12!null c:13!null
      ├── cardinality: [0 - 2]
      ├── volatile, mutations
      ├── key: (11-13)
      ├── insert abc
      │    ├── columns: abc.a:1!null abc.b:2!null abc.c:3!null
      │    ├── insert-mapping:
      │    │    ├── x:6 => abc.a:1
      │    │    ├── y:7 => abc.b:2
      │    │    └── z:8 => abc.c:3
      │    ├── return-mapping:
      │    │    ├── x:6 => abc.a:1
      │    │    ├── y:7 => abc.b:2
      │    │    └── z:8 => abc.c:3
      │    ├── cardinality: [0 - 2]
      │    ├── volatile, mutations
      │    ├── key: (1-3)
      │    └── top-k
      │         ├── columns: x:6!null y:7!null z:8!null
      │         ├── internal-ordering: +7,+8
      │         ├── k: 2
      │         ├── cardinality: [0 - 2]
      │         ├── key: (6-8)
      │         └── scan xyz
      │              ├── columns: x:6!null y:7!null z:8!null
      │              └── key: (6-8)
      └── with-scan &1
           ├── columns: a:11!null b:12!null c:13!null
           ├── mapping:
           │    ├──  abc.a:1 => a:11
           │    ├──  abc.b:2 => b:12
           │    └──  abc.c:3 => c:13
           ├── cardinality: [0 - 2]
           └── key: (11-13)

# Verify that provided orderings are derived correctly.
opt
SELECT *
FROM [INSERT INTO xyz SELECT b, c, d FROM abcd ORDER BY c, d LIMIT 2 RETURNING *]
ORDER BY y
----
sort
 ├── columns: x:13!null y:14!null z:15!null
 ├── cardinality: [0 - 2]
 ├── volatile, mutations
 ├── ordering: +14
 └── with &1
      ├── columns: x:13!null y:14!null z:15!null
      ├── cardinality: [0 - 2]
      ├── volatile, mutations
      ├── insert xyz
      │    ├── columns: xyz.x:1!null xyz.y:2!null xyz.z:3!null
      │    ├── insert-mapping:
      │    │    ├── b:7 => xyz.x:1
      │    │    ├── c:8 => xyz.y:2
      │    │    └── d:9 => xyz.z:3
      │    ├── return-mapping:
      │    │    ├── b:7 => xyz.x:1
      │    │    ├── c:8 => xyz.y:2
      │    │    └── d:9 => xyz.z:3
      │    ├── cardinality: [0 - 2]
      │    ├── volatile, mutations
      │    └── scan abcd@cd
      │         ├── columns: b:7 c:8 d:9
      │         └── limit: 2
      └── with-scan &1
           ├── columns: x:13!null y:14!null z:15!null
           ├── mapping:
           │    ├──  xyz.x:1 => x:13
           │    ├──  xyz.y:2 => y:14
           │    └──  xyz.z:3 => z:15
           └── cardinality: [0 - 2]

# Verify that provided orderings are derived correctly with equivalence FD.
# TODO(radu): Use interesting orderings to get rid of top-level sort.
opt
SELECT *
FROM [INSERT INTO xyz SELECT b, c, d FROM abcd ORDER BY c, d LIMIT 2 RETURNING *]
WHERE x=y
ORDER BY y
----
sort
 ├── columns: x:13!null y:14!null z:15!null
 ├── cardinality: [0 - 2]
 ├── volatile, mutations
 ├── fd: (13)==(14), (14)==(13)
 ├── ordering: +(13|14) [actual: +13]
 └── with &1
      ├── columns: x:13!null y:14!null z:15!null
      ├── cardinality: [0 - 2]
      ├── volatile, mutations
      ├── fd: (13)==(14), (14)==(13)
      ├── insert xyz
      │    ├── columns: xyz.x:1!null xyz.y:2!null xyz.z:3!null
      │    ├── insert-mapping:
      │    │    ├── b:7 => xyz.x:1
      │    │    ├── c:8 => xyz.y:2
      │    │    └── d:9 => xyz.z:3
      │    ├── return-mapping:
      │    │    ├── b:7 => xyz.x:1
      │    │    ├── c:8 => xyz.y:2
      │    │    └── d:9 => xyz.z:3
      │    ├── cardinality: [0 - 2]
      │    ├── volatile, mutations
      │    └── scan abcd@cd
      │         ├── columns: b:7 c:8 d:9
      │         └── limit: 2
      └── select
           ├── columns: x:13!null y:14!null z:15!null
           ├── cardinality: [0 - 2]
           ├── fd: (13)==(14), (14)==(13)
           ├── with-scan &1
           │    ├── columns: x:13!null y:14!null z:15!null
           │    ├── mapping:
           │    │    ├──  xyz.x:1 => x:13
           │    │    ├──  xyz.y:2 => y:14
           │    │    └──  xyz.z:3 => z:15
           │    └── cardinality: [0 - 2]
           └── filters
                └── x:13 = y:14 [outer=(13,14), fd=(13)==(14), (14)==(13)]

# Ignore internal ordering.
opt
SELECT * FROM [INSERT INTO abc SELECT * FROM xyz ORDER BY y, z RETURNING *]
----
with &1
 ├── columns: a:11!null b:12!null c:13!null
 ├── volatile, mutations
 ├── key: (11-13)
 ├── insert abc
 │    ├── columns: abc.a:1!null abc.b:2!null abc.c:3!null
 │    ├── insert-mapping:
 │    │    ├── x:6 => abc.a:1
 │    │    ├── y:7 => abc.b:2
 │    │    └── z:8 => abc.c:3
 │    ├── return-mapping:
 │    │    ├── x:6 => abc.a:1
 │    │    ├── y:7 => abc.b:2
 │    │    └── z:8 => abc.c:3
 │    ├── volatile, mutations
 │    ├── key: (1-3)
 │    └── scan xyz
 │         ├── columns: x:6!null y:7!null z:8!null
 │         └── key: (6-8)
 └── with-scan &1
      ├── columns: a:11!null b:12!null c:13!null
      ├── mapping:
      │    ├──  abc.a:1 => a:11
      │    ├──  abc.b:2 => b:12
      │    └──  abc.c:3 => c:13
      └── key: (11-13)

# --------------------------------------------------
# Update operator.
# --------------------------------------------------

# Verify that the external ordering is passed through to input.
opt
SELECT * FROM [UPDATE abcd SET (a, b)=(1, 2) RETURNING *] ORDER BY c
----
sort
 ├── columns: a:17!null b:18!null c:19 d:20
 ├── volatile, mutations
 ├── fd: ()-->(17,18)
 ├── ordering: +19 opt(17,18) [actual: +19]
 └── with &1
      ├── columns: a:17!null b:18!null c:19 d:20
      ├── volatile, mutations
      ├── fd: ()-->(17,18)
      ├── project
      │    ├── columns: abcd.a:1!null abcd.b:2!null abcd.c:3 abcd.d:4
      │    ├── volatile, mutations
      │    ├── fd: ()-->(1,2)
      │    └── update abcd
      │         ├── columns: abcd.a:1!null abcd.b:2!null abcd.c:3 abcd.d:4 rowid:5!null
      │         ├── fetch columns: abcd.a:8 abcd.b:9 abcd.c:10 abcd.d:11 rowid:12
      │         ├── update-mapping:
      │         │    ├── a_new:15 => abcd.a:1
      │         │    └── b_new:16 => abcd.b:2
      │         ├── return-mapping:
      │         │    ├── a_new:15 => abcd.a:1
      │         │    ├── b_new:16 => abcd.b:2
      │         │    ├── abcd.c:10 => abcd.c:3
      │         │    ├── abcd.d:11 => abcd.d:4
      │         │    └── rowid:12 => rowid:5
      │         ├── volatile, mutations
      │         ├── key: (5)
      │         ├── fd: ()-->(1,2), (5)-->(3,4)
      │         └── project
      │              ├── columns: a_new:15!null b_new:16!null abcd.a:8 abcd.b:9 abcd.c:10 abcd.d:11 rowid:12!null
      │              ├── key: (12)
      │              ├── fd: ()-->(15,16), (12)-->(8-11)
      │              ├── scan abcd
      │              │    ├── columns: abcd.a:8 abcd.b:9 abcd.c:10 abcd.d:11 rowid:12!null
      │              │    ├── flags: avoid-full-scan
      │              │    ├── key: (12)
      │              │    └── fd: (12)-->(8-11)
      │              └── projections
      │                   ├── 1 [as=a_new:15]
      │                   └── 2 [as=b_new:16]
      └── with-scan &1
           ├── columns: a:17!null b:18!null c:19 d:20
           ├── mapping:
           │    ├──  abcd.a:1 => a:17
           │    ├──  abcd.b:2 => b:18
           │    ├──  abcd.c:3 => c:19
           │    └──  abcd.d:4 => d:20
           └── fd: ()-->(17,18)

# Verify that provided orderings are derived correctly.
opt
SELECT *
FROM [UPDATE abcd SET b=b+1 ORDER BY c LIMIT 10 RETURNING *]
ORDER BY c, d
----
sort
 ├── columns: a:16 b:17 c:18 d:19
 ├── cardinality: [0 - 10]
 ├── volatile, mutations
 ├── ordering: +18,+19
 └── with &1
      ├── columns: a:16 b:17 c:18 d:19
      ├── cardinality: [0 - 10]
      ├── volatile, mutations
      ├── project
      │    ├── columns: abcd.a:1 abcd.b:2 abcd.c:3 abcd.d:4
      │    ├── cardinality: [0 - 10]
      │    ├── volatile, mutations
      │    └── update abcd
      │         ├── columns: abcd.a:1 abcd.b:2 abcd.c:3 abcd.d:4 rowid:5!null
      │         ├── fetch columns: abcd.a:8 abcd.b:9 abcd.c:10 abcd.d:11 rowid:12
      │         ├── update-mapping:
      │         │    └── b_new:15 => abcd.b:2
      │         ├── return-mapping:
      │         │    ├── abcd.a:8 => abcd.a:1
      │         │    ├── b_new:15 => abcd.b:2
      │         │    ├── abcd.c:10 => abcd.c:3
      │         │    ├── abcd.d:11 => abcd.d:4
      │         │    └── rowid:12 => rowid:5
      │         ├── cardinality: [0 - 10]
      │         ├── volatile, mutations
      │         ├── key: (5)
      │         ├── fd: (5)-->(1-4)
      │         └── project
      │              ├── columns: b_new:15 abcd.a:8 abcd.b:9 abcd.c:10 abcd.d:11 rowid:12!null
      │              ├── cardinality: [0 - 10]
      │              ├── immutable
      │              ├── key: (12)
      │              ├── fd: (12)-->(8-11), (9)-->(15)
      │              ├── scan abcd@cd
      │              │    ├── columns: abcd.a:8 abcd.b:9 abcd.c:10 abcd.d:11 rowid:12!null
      │              │    ├── limit: 10
      │              │    ├── flags: avoid-full-scan
      │              │    ├── key: (12)
      │              │    └── fd: (12)-->(8-11)
      │              └── projections
      │                   └── abcd.b:9 + 1 [as=b_new:15, outer=(9), immutable]
      └── with-scan &1
           ├── columns: a:16 b:17 c:18 d:19
           ├── mapping:
           │    ├──  abcd.a:1 => a:16
           │    ├──  abcd.b:2 => b:17
           │    ├──  abcd.c:3 => c:18
           │    └──  abcd.d:4 => d:19
           └── cardinality: [0 - 10]

# Verify that provided orderings are derived correctly with equivalence FD.
# TODO(radu): Use interesting orderings to get rid of top-level sort.
opt
SELECT *
FROM [UPDATE abcd SET b=b+1 ORDER BY c, d LIMIT 10 RETURNING *]
WHERE b=c
ORDER BY b, d
----
sort
 ├── columns: a:16 b:17!null c:18!null d:19
 ├── cardinality: [0 - 10]
 ├── volatile, mutations
 ├── fd: (17)==(18), (18)==(17)
 ├── ordering: +(17|18),+19 [actual: +17,+19]
 └── with &1
      ├── columns: a:16 b:17!null c:18!null d:19
      ├── cardinality: [0 - 10]
      ├── volatile, mutations
      ├── fd: (17)==(18), (18)==(17)
      ├── project
      │    ├── columns: abcd.a:1 abcd.b:2 abcd.c:3 abcd.d:4
      │    ├── cardinality: [0 - 10]
      │    ├── volatile, mutations
      │    └── update abcd
      │         ├── columns: abcd.a:1 abcd.b:2 abcd.c:3 abcd.d:4 rowid:5!null
      │         ├── fetch columns: abcd.a:8 abcd.b:9 abcd.c:10 abcd.d:11 rowid:12
      │         ├── update-mapping:
      │         │    └── b_new:15 => abcd.b:2
      │         ├── return-mapping:
      │         │    ├── abcd.a:8 => abcd.a:1
      │         │    ├── b_new:15 => abcd.b:2
      │         │    ├── abcd.c:10 => abcd.c:3
      │         │    ├── abcd.d:11 => abcd.d:4
      │         │    └── rowid:12 => rowid:5
      │         ├── cardinality: [0 - 10]
      │         ├── volatile, mutations
      │         ├── key: (5)
      │         ├── fd: (5)-->(1-4)
      │         └── project
      │              ├── columns: b_new:15 abcd.a:8 abcd.b:9 abcd.c:10 abcd.d:11 rowid:12!null
      │              ├── cardinality: [0 - 10]
      │              ├── immutable
      │              ├── key: (12)
      │              ├── fd: (12)-->(8-11), (9)-->(15)
      │              ├── scan abcd@cd
      │              │    ├── columns: abcd.a:8 abcd.b:9 abcd.c:10 abcd.d:11 rowid:12!null
      │              │    ├── limit: 10
      │              │    ├── flags: avoid-full-scan
      │              │    ├── key: (12)
      │              │    └── fd: (12)-->(8-11)
      │              └── projections
      │                   └── abcd.b:9 + 1 [as=b_new:15, outer=(9), immutable]
      └── select
           ├── columns: a:16 b:17!null c:18!null d:19
           ├── cardinality: [0 - 10]
           ├── fd: (17)==(18), (18)==(17)
           ├── with-scan &1
           │    ├── columns: a:16 b:17 c:18 d:19
           │    ├── mapping:
           │    │    ├──  abcd.a:1 => a:16
           │    │    ├──  abcd.b:2 => b:17
           │    │    ├──  abcd.c:3 => c:18
           │    │    └──  abcd.d:4 => d:19
           │    └── cardinality: [0 - 10]
           └── filters
                └── b:17 = c:18 [outer=(17,18), fd=(17)==(18), (18)==(17)]

# --------------------------------------------------
# Upsert operator.
# --------------------------------------------------

# Verify that no ordering is provided once ON CONFLICT clause is added.
opt
SELECT *
FROM
[
	INSERT INTO abc
	SELECT * FROM xyz ORDER BY y, z LIMIT 2
	ON CONFLICT (a, b, c)
	DO UPDATE SET a=10
	RETURNING *
]
ORDER BY b
----
sort
 ├── columns: a:20!null b:21!null c:22!null
 ├── cardinality: [0 - 2]
 ├── volatile, mutations
 ├── ordering: +21
 └── with &1
      ├── columns: a:20!null b:21!null c:22!null
      ├── cardinality: [0 - 2]
      ├── volatile, mutations
      ├── upsert abc
      │    ├── columns: abc.a:1!null abc.b:2!null abc.c:3!null
      │    ├── arbiter indexes: abc_pkey
      │    ├── canary column: abc.a:11
      │    ├── fetch columns: abc.a:11 abc.b:12 abc.c:13
      │    ├── insert-mapping:
      │    │    ├── x:6 => abc.a:1
      │    │    ├── y:7 => abc.b:2
      │    │    └── z:8 => abc.c:3
      │    ├── update-mapping:
      │    │    └── upsert_a:17 => abc.a:1
      │    ├── return-mapping:
      │    │    ├── upsert_a:17 => abc.a:1
      │    │    ├── upsert_b:18 => abc.b:2
      │    │    └── upsert_c:19 => abc.c:3
      │    ├── cardinality: [0 - 2]
      │    ├── volatile, mutations
      │    └── project
      │         ├── columns: upsert_a:17!null upsert_b:18 upsert_c:19 x:6!null y:7!null z:8!null abc.a:11 abc.b:12 abc.c:13
      │         ├── cardinality: [0 - 2]
      │         ├── key: (6-8)
      │         ├── fd: (6-8)-->(11-13), (6,11)-->(17), (7,11,12)-->(18), (8,11,13)-->(19)
      │         ├── left-join (lookup abc)
      │         │    ├── columns: x:6!null y:7!null z:8!null abc.a:11 abc.b:12 abc.c:13
      │         │    ├── key columns: [6 7 8] = [11 12 13]
      │         │    ├── lookup columns are key
      │         │    ├── cardinality: [0 - 2]
      │         │    ├── key: (6-8)
      │         │    ├── fd: (6-8)-->(11-13)
      │         │    ├── top-k
      │         │    │    ├── columns: x:6!null y:7!null z:8!null
      │         │    │    ├── internal-ordering: +7,+8
      │         │    │    ├── k: 2
      │         │    │    ├── cardinality: [0 - 2]
      │         │    │    ├── key: (6-8)
      │         │    │    └── scan xyz
      │         │    │         ├── columns: x:6!null y:7!null z:8!null
      │         │    │         └── key: (6-8)
      │         │    └── filters (true)
      │         └── projections
      │              ├── CASE WHEN abc.a:11 IS NULL THEN x:6 ELSE 10 END [as=upsert_a:17, outer=(6,11)]
      │              ├── CASE WHEN abc.a:11 IS NULL THEN y:7 ELSE abc.b:12 END [as=upsert_b:18, outer=(7,11,12)]
      │              └── CASE WHEN abc.a:11 IS NULL THEN z:8 ELSE abc.c:13 END [as=upsert_c:19, outer=(8,11,13)]
      └── with-scan &1
           ├── columns: a:20!null b:21!null c:22!null
           ├── mapping:
           │    ├──  abc.a:1 => a:20
           │    ├──  abc.b:2 => b:21
           │    └──  abc.c:3 => c:22
           └── cardinality: [0 - 2]

# --------------------------------------------------
# Delete operator.
# --------------------------------------------------

# Verify that the external ordering is passed through to input.
opt
SELECT * FROM [DELETE FROM abcd RETURNING *] ORDER BY c
----
sort
 ├── columns: a:15 b:16 c:17 d:18
 ├── volatile, mutations
 ├── ordering: +17
 └── with &1
      ├── columns: a:15 b:16 c:17 d:18
      ├── volatile, mutations
      ├── project
      │    ├── columns: abcd.a:1 abcd.b:2 abcd.c:3 abcd.d:4
      │    ├── volatile, mutations
      │    └── delete abcd
      │         ├── columns: abcd.a:1 abcd.b:2 abcd.c:3 abcd.d:4 rowid:5!null
      │         ├── fetch columns: abcd.a:8 abcd.b:9 abcd.c:10 abcd.d:11 rowid:12
      │         ├── return-mapping:
      │         │    ├── abcd.a:8 => abcd.a:1
      │         │    ├── abcd.b:9 => abcd.b:2
      │         │    ├── abcd.c:10 => abcd.c:3
      │         │    ├── abcd.d:11 => abcd.d:4
      │         │    └── rowid:12 => rowid:5
      │         ├── volatile, mutations
      │         ├── key: (5)
      │         ├── fd: (5)-->(1-4)
      │         └── scan abcd
      │              ├── columns: abcd.a:8 abcd.b:9 abcd.c:10 abcd.d:11 rowid:12!null
      │              ├── flags: avoid-full-scan
      │              ├── key: (12)
      │              └── fd: (12)-->(8-11)
      └── with-scan &1
           ├── columns: a:15 b:16 c:17 d:18
           └── mapping:
                ├──  abcd.a:1 => a:15
                ├──  abcd.b:2 => b:16
                ├──  abcd.c:3 => c:17
                └──  abcd.d:4 => d:18

# Verify that provided orderings are derived correctly.
opt
SELECT *
FROM [DELETE FROM abcd ORDER BY c LIMIT 10 RETURNING *]
ORDER BY c, d
----
sort
 ├── columns: a:15 b:16 c:17 d:18
 ├── cardinality: [0 - 10]
 ├── volatile, mutations
 ├── ordering: +17,+18
 └── with &1
      ├── columns: a:15 b:16 c:17 d:18
      ├── cardinality: [0 - 10]
      ├── volatile, mutations
      ├── project
      │    ├── columns: abcd.a:1 abcd.b:2 abcd.c:3 abcd.d:4
      │    ├── cardinality: [0 - 10]
      │    ├── volatile, mutations
      │    └── delete abcd
      │         ├── columns: abcd.a:1 abcd.b:2 abcd.c:3 abcd.d:4 rowid:5!null
      │         ├── fetch columns: abcd.a:8 abcd.b:9 abcd.c:10 abcd.d:11 rowid:12
      │         ├── return-mapping:
      │         │    ├── abcd.a:8 => abcd.a:1
      │         │    ├── abcd.b:9 => abcd.b:2
      │         │    ├── abcd.c:10 => abcd.c:3
      │         │    ├── abcd.d:11 => abcd.d:4
      │         │    └── rowid:12 => rowid:5
      │         ├── cardinality: [0 - 10]
      │         ├── volatile, mutations
      │         ├── key: (5)
      │         ├── fd: (5)-->(1-4)
      │         └── scan abcd@cd
      │              ├── columns: abcd.a:8 abcd.b:9 abcd.c:10 abcd.d:11 rowid:12!null
      │              ├── limit: 10
      │              ├── flags: avoid-full-scan
      │              ├── key: (12)
      │              └── fd: (12)-->(8-11)
      └── with-scan &1
           ├── columns: a:15 b:16 c:17 d:18
           ├── mapping:
           │    ├──  abcd.a:1 => a:15
           │    ├──  abcd.b:2 => b:16
           │    ├──  abcd.c:3 => c:17
           │    └──  abcd.d:4 => d:18
           └── cardinality: [0 - 10]

# Verify that provided orderings are derived correctly with equivalence FD.
# TODO(radu): Use interesting orderings to get rid of top-level sort.
opt
SELECT *
FROM [DELETE FROM abcd ORDER BY c, d LIMIT 10 RETURNING *]
WHERE b=c
ORDER BY b, d
----
sort
 ├── columns: a:15 b:16!null c:17!null d:18
 ├── cardinality: [0 - 10]
 ├── volatile, mutations
 ├── fd: (16)==(17), (17)==(16)
 ├── ordering: +(16|17),+18 [actual: +16,+18]
 └── with &1
      ├── columns: a:15 b:16!null c:17!null d:18
      ├── cardinality: [0 - 10]
      ├── volatile, mutations
      ├── fd: (16)==(17), (17)==(16)
      ├── project
      │    ├── columns: abcd.a:1 abcd.b:2 abcd.c:3 abcd.d:4
      │    ├── cardinality: [0 - 10]
      │    ├── volatile, mutations
      │    └── delete abcd
      │         ├── columns: abcd.a:1 abcd.b:2 abcd.c:3 abcd.d:4 rowid:5!null
      │         ├── fetch columns: abcd.a:8 abcd.b:9 abcd.c:10 abcd.d:11 rowid:12
      │         ├── return-mapping:
      │         │    ├── abcd.a:8 => abcd.a:1
      │         │    ├── abcd.b:9 => abcd.b:2
      │         │    ├── abcd.c:10 => abcd.c:3
      │         │    ├── abcd.d:11 => abcd.d:4
      │         │    └── rowid:12 => rowid:5
      │         ├── cardinality: [0 - 10]
      │         ├── volatile, mutations
      │         ├── key: (5)
      │         ├── fd: (5)-->(1-4)
      │         └── scan abcd@cd
      │              ├── columns: abcd.a:8 abcd.b:9 abcd.c:10 abcd.d:11 rowid:12!null
      │              ├── limit: 10
      │              ├── flags: avoid-full-scan
      │              ├── key: (12)
      │              └── fd: (12)-->(8-11)
      └── select
           ├── columns: a:15 b:16!null c:17!null d:18
           ├── cardinality: [0 - 10]
           ├── fd: (16)==(17), (17)==(16)
           ├── with-scan &1
           │    ├── columns: a:15 b:16 c:17 d:18
           │    ├── mapping:
           │    │    ├──  abcd.a:1 => a:15
           │    │    ├──  abcd.b:2 => b:16
           │    │    ├──  abcd.c:3 => c:17
           │    │    └──  abcd.d:4 => d:18
           │    └── cardinality: [0 - 10]
           └── filters
                └── b:16 = c:17 [outer=(16,17), fd=(16)==(17), (17)==(16)]

# --------------------------------------------------
# With operator.
# --------------------------------------------------

# Verify that we can pass through the ordering requirement through the With
# operator.
opt
WITH cte AS MATERIALIZED (SELECT x FROM xyz)
SELECT * FROM abc ORDER BY a,b,c
----
with &1 (cte)
 ├── columns: a:6!null b:7!null c:8!null
 ├── materialized
 ├── key: (6-8)
 ├── ordering: +6,+7,+8
 ├── scan xyz
 │    └── columns: x:1!null
 └── scan abc
      ├── columns: a:6!null b:7!null c:8!null
      ├── key: (6-8)
      └── ordering: +6,+7,+8

opt
WITH cte AS MATERIALIZED (SELECT x FROM xyz)
SELECT * FROM abc INNER MERGE JOIN cte ON a = x ORDER BY a
----
with &1 (cte)
 ├── columns: a:6!null b:7!null c:8!null x:11!null
 ├── materialized
 ├── fd: (6)==(11), (11)==(6)
 ├── ordering: +(6|11) [actual: +6]
 ├── scan xyz
 │    └── columns: xyz.x:1!null
 └── inner-join (merge)
      ├── columns: a:6!null b:7!null c:8!null x:11!null
      ├── flags: force merge join
      ├── left ordering: +6
      ├── right ordering: +11
      ├── fd: (6)==(11), (11)==(6)
      ├── ordering: +(6|11) [actual: +6]
      ├── scan abc
      │    ├── columns: a:6!null b:7!null c:8!null
      │    ├── key: (6-8)
      │    └── ordering: +6
      ├── sort
      │    ├── columns: x:11!null
      │    ├── ordering: +11
      │    └── with-scan &1 (cte)
      │         ├── columns: x:11!null
      │         └── mapping:
      │              └──  xyz.x:1 => x:11
      └── filters (true)


# --------------------------------------------------
# Misc tests.
# --------------------------------------------------

# Regression test for #36219: lookup join with ON condition that imposes an
# equality on two input columns (which isn't pushed down).
opt disable=(PushFilterIntoJoinLeftAndRight,PushFilterIntoJoinLeft,PushFilterIntoJoinRight,MapFilterIntoJoinLeft,MapFilterIntoJoinRight)
SELECT * FROM abc JOIN xyz ON a=x AND x=z ORDER BY z
----
inner-join (merge)
 ├── columns: a:1!null b:2!null c:3!null x:6!null y:7!null z:8!null
 ├── left ordering: +1
 ├── right ordering: +6
 ├── key: (2,3,7,8)
 ├── fd: (1)==(6,8), (6)==(1,8), (8)==(1,6)
 ├── ordering: +(1|6|8) [actual: +1]
 ├── scan abc
 │    ├── columns: a:1!null b:2!null c:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1
 ├── scan xyz
 │    ├── columns: x:6!null y:7!null z:8!null
 │    ├── key: (6-8)
 │    └── ordering: +6
 └── filters
      └── x:6 = z:8 [outer=(6,8), fd=(6)==(8), (8)==(6)]

# TODO(justin): figure out when it is that window functions can preserve their
# input ordering.
opt
SELECT *, row_number() OVER() FROM abc ORDER BY a
----
sort
 ├── columns: a:1!null b:2!null c:3!null row_number:6
 ├── key: (1-3)
 ├── fd: (1-3)-->(6)
 ├── ordering: +1
 └── window partition=()
      ├── columns: a:1!null b:2!null c:3!null row_number:6
      ├── key: (1-3)
      ├── fd: (1-3)-->(6)
      ├── scan abc
      │    ├── columns: a:1!null b:2!null c:3!null
      │    └── key: (1-3)
      └── windows
           └── row-number [as=row_number:6]

# Regression test for #44469 (DistinctOn needs to remap the provided ordering).
exec-ddl
CREATE TABLE t44469_a (a INT, INDEX (a))
----

exec-ddl
CREATE TABLE t44469_b (b INT, INDEX (b))
----

exec-ddl
CREATE TABLE t44469_cd (c INT, d INT, INDEX (c, d));
----

opt
SELECT DISTINCT ON (b) b
FROM t44469_a INNER LOOKUP JOIN t44469_b ON a = b INNER LOOKUP JOIN t44469_cd ON c = 1 AND d = a
ORDER BY b
----
distinct-on
 ├── columns: b:5!null
 ├── grouping columns: b:5!null
 ├── key: (5)
 ├── ordering: +5
 └── inner-join (lookup t44469_cd@t44469_cd_c_d_idx)
      ├── columns: a:1!null b:5!null c:9!null d:10!null
      ├── flags: force lookup join (into right side)
      ├── key columns: [14 1] = [9 10]
      ├── fd: ()-->(9), (1)==(5,10), (5)==(1,10), (10)==(1,5)
      ├── ordering: +(1|5|10) opt(9) [actual: +1]
      ├── project
      │    ├── columns: "lookup_join_const_col_@9":14!null a:1!null b:5!null
      │    ├── fd: ()-->(14), (1)==(5), (5)==(1)
      │    ├── ordering: +(1|5) opt(14) [actual: +1]
      │    ├── inner-join (lookup t44469_b@t44469_b_b_idx)
      │    │    ├── columns: a:1!null b:5!null
      │    │    ├── flags: force lookup join (into right side)
      │    │    ├── key columns: [1] = [5]
      │    │    ├── fd: (1)==(5), (5)==(1)
      │    │    ├── ordering: +(1|5) [actual: +1]
      │    │    ├── scan t44469_a@t44469_a_a_idx
      │    │    │    ├── columns: a:1
      │    │    │    └── ordering: +1
      │    │    └── filters (true)
      │    └── projections
      │         └── 1 [as="lookup_join_const_col_@9":14]
      └── filters (true)

# Regression test for #47041: factor check constraints into the (canonical)
# scan FDs; otherwise operators above won't always be able to remap a provided
# ordering.
exec-ddl
CREATE TABLE t47041 (
  k INT8 PRIMARY KEY,
  a INT8 NOT NULL,
  b INT8 NOT NULL CHECK (b = 0),
  INDEX ba (b, a)
)
----

exec-ddl
ALTER TABLE t47041 INJECT STATISTICS '[
  {
    "columns": ["b"],
    "created_at": "2000-01-01 00:00:00+00:00",
    "distinct_count": 1000,
    "name": "__auto__",
    "null_count": 0,
    "row_count": 1000
  }
]';
----

opt
SELECT 1 FROM t47041 WHERE a > 1 AND k > 0 GROUP BY b, a ORDER BY b
----
project
 ├── columns: "?column?":6!null
 ├── fd: ()-->(6)
 ├── distinct-on
 │    ├── columns: a:2!null
 │    ├── grouping columns: a:2!null
 │    ├── key: (2)
 │    └── select
 │         ├── columns: k:1!null a:2!null
 │         ├── key: (1)
 │         ├── fd: (1)-->(2)
 │         ├── scan t47041@ba
 │         │    ├── columns: k:1!null a:2!null
 │         │    ├── constraint: /3/2/1: [/0/2/1 - /0]
 │         │    ├── key: (1)
 │         │    └── fd: (1)-->(2)
 │         └── filters
 │              └── k:1 > 0 [outer=(1)]
 └── projections
      └── 1 [as="?column?":6]

# Regression test for #73968. Lookup join needs to simplify the ordering
# required of its child.
exec-ddl
CREATE TABLE t73968 (
  k INT PRIMARY KEY,
  name STRING,
  x STRING AS (CAST(k AS STRING)) VIRTUAL,
  y STRING AS (lower(name)) VIRTUAL,
  UNIQUE (y),
  UNIQUE (x)
);
----

exec-ddl
ALTER TABLE t73968 INJECT STATISTICS e'[
  {
    "columns": ["k"],
    "created_at": "2000-01-01 00:00:00+00:00",
    "distinct_count": 1000000,
    "name": "__auto__",
    "null_count": 0,
    "row_count": 1000000000
  }
]';
----

opt
SELECT
  t2.crdb_internal_mvcc_timestamp
FROM
  t73968 AS t1 JOIN t73968 AS t2 ON t1.name = t2.name
      AND t1.y = t2.y
      AND t1.x = t2.y
      AND t1.k = t2.k
      AND t1.x = t2.x
ORDER BY
  t2.x, t2.k
LIMIT
  56
----
project
 ├── columns: crdb_internal_mvcc_timestamp:11  [hidden: k:7!null x:9!null]
 ├── cardinality: [0 - 56]
 ├── immutable
 ├── key: (7)
 ├── fd: (7)-->(9,11)
 ├── ordering: +9,+7
 └── limit
      ├── columns: k:1!null name:2!null x:3!null k:7!null name:8!null x:9!null crdb_internal_mvcc_timestamp:11
      ├── internal-ordering: +(3|9),+(1|7)
      ├── cardinality: [0 - 56]
      ├── immutable
      ├── key: (7)
      ├── fd: (1)-->(2,3), (7)-->(8,9,11), (2)==(8), (8)==(2), (1)==(7), (7)==(1), (3)==(9), (9)==(3)
      ├── ordering: +(3|9),+(1|7) [actual: +3,+7]
      ├── inner-join (lookup t73968)
      │    ├── columns: k:1!null name:2!null x:3!null k:7!null name:8!null x:9!null crdb_internal_mvcc_timestamp:11
      │    ├── key columns: [7] = [7]
      │    ├── lookup columns are key
      │    ├── immutable
      │    ├── key: (7)
      │    ├── fd: (1)-->(2,3), (7)-->(8,9,11), (2)==(8), (8)==(2), (1)==(7), (7)==(1), (3)==(9), (9)==(3)
      │    ├── ordering: +(3|9),+(1|7) [actual: +3,+7]
      │    ├── limit hint: 56.00
      │    ├── inner-join (lookup t73968@t73968_x_key)
      │    │    ├── columns: k:1!null name:2 x:3!null k:7!null x:9!null
      │    │    ├── key columns: [3] = [9]
      │    │    ├── lookup columns are key
      │    │    ├── immutable
      │    │    ├── key: (7)
      │    │    ├── fd: (1)-->(2,3), (7)-->(9), (9)-->(7), (1)==(7), (7)==(1), (3)==(9), (9)==(3)
      │    │    ├── ordering: +(3|9) [actual: +3]
      │    │    ├── limit hint: 200.00
      │    │    ├── sort
      │    │    │    ├── columns: k:1!null name:2 x:3!null
      │    │    │    ├── immutable
      │    │    │    ├── key: (1)
      │    │    │    ├── fd: (1)-->(2,3)
      │    │    │    ├── ordering: +3
      │    │    │    ├── limit hint: 2100.00
      │    │    │    └── project
      │    │    │         ├── columns: x:3!null k:1!null name:2
      │    │    │         ├── immutable
      │    │    │         ├── key: (1)
      │    │    │         ├── fd: (1)-->(2,3)
      │    │    │         ├── select
      │    │    │         │    ├── columns: k:1!null name:2
      │    │    │         │    ├── immutable
      │    │    │         │    ├── key: (1)
      │    │    │         │    ├── fd: (1)-->(2)
      │    │    │         │    ├── scan t73968
      │    │    │         │    │    ├── columns: k:1!null name:2
      │    │    │         │    │    ├── computed column expressions
      │    │    │         │    │    │    ├── x:3
      │    │    │         │    │    │    │    └── k:1::STRING
      │    │    │         │    │    │    └── y:4
      │    │    │         │    │    │         └── lower(name:2)
      │    │    │         │    │    ├── key: (1)
      │    │    │         │    │    └── fd: (1)-->(2)
      │    │    │         │    └── filters
      │    │    │         │         └── k:1::STRING = lower(name:2) [outer=(1,2), immutable]
      │    │    │         └── projections
      │    │    │              └── k:1::STRING [as=x:3, outer=(1), immutable]
      │    │    └── filters
      │    │         └── k:1 = k:7 [outer=(1,7), fd=(1)==(7), (7)==(1)]
      │    └── filters
      │         ├── name:2 = name:8 [outer=(2,8), fd=(2)==(8), (8)==(2)]
      │         └── k:7::STRING = lower(name:8) [outer=(7,8), immutable]
      └── 56

# Preserving lookup ordering (no sort should be added).
opt
SELECT * FROM xyz INNER LOOKUP JOIN abc ON x = a ORDER BY x, y, z, a, b, c
----
inner-join (lookup abc)
 ├── columns: x:1!null y:2!null z:3!null a:6!null b:7!null c:8!null
 ├── flags: force lookup join (into right side)
 ├── key columns: [1] = [6]
 ├── key: (2,3,6-8)
 ├── fd: (1)==(6), (6)==(1)
 ├── ordering: +(1|6),+2,+3,+7,+8 [actual: +1,+2,+3,+7,+8]
 ├── scan xyz
 │    ├── columns: x:1!null y:2!null z:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1,+2,+3
 └── filters (true)

# Preserving lookup ordering (no sort should be added). The 'u' and 'v' columns
# are equivalent to input ordering columns and can be considered optional.
opt
SELECT * FROM xyz INNER LOOKUP JOIN abc ON x = a AND y = b ORDER BY a, x, b, y, z, c
----
inner-join (lookup abc)
 ├── columns: x:1!null y:2!null z:3!null a:6!null b:7!null c:8!null
 ├── flags: force lookup join (into right side)
 ├── key columns: [1 2] = [6 7]
 ├── key: (3,6-8)
 ├── fd: (1)==(6), (6)==(1), (2)==(7), (7)==(2)
 ├── ordering: +(1|6),+(2|7),+3,+8 [actual: +1,+2,+3,+8]
 ├── scan xyz
 │    ├── columns: x:1!null y:2!null z:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1,+2,+3
 └── filters (true)

# Preserving lookup ordering (no sort should be added).
opt
SELECT * FROM xyz INNER LOOKUP JOIN abc ON x = a ORDER BY x, y, z, b
----
inner-join (lookup abc)
 ├── columns: x:1!null y:2!null z:3!null a:6!null b:7!null c:8!null
 ├── flags: force lookup join (into right side)
 ├── key columns: [1] = [6]
 ├── key: (2,3,6-8)
 ├── fd: (1)==(6), (6)==(1)
 ├── ordering: +(1|6),+2,+3,+7 [actual: +1,+2,+3,+7]
 ├── scan xyz
 │    ├── columns: x:1!null y:2!null z:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1,+2,+3
 └── filters (true)

# Preserving lookup ordering (no sort should be added).
opt
SELECT * FROM xyz INNER LOOKUP JOIN abc@abc_desc ON x = a ORDER BY x, y, z, a, b
----
inner-join (lookup abc@abc_desc)
 ├── columns: x:1!null y:2!null z:3!null a:6!null b:7!null c:8!null
 ├── flags: force lookup join (into right side)
 ├── key columns: [1] = [6]
 ├── key: (2,3,6-8)
 ├── fd: (1)==(6), (6)==(1)
 ├── ordering: +(1|6),+2,+3,+7 [actual: +1,+2,+3,+7]
 ├── scan xyz
 │    ├── columns: x:1!null y:2!null z:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1,+2,+3
 └── filters (true)

# Preserving lookup ordering (no sort should be added). Index order includes a
# descending column.
opt
SELECT * FROM xyz INNER LOOKUP JOIN abc@abc_desc ON x = a ORDER BY x, y, z, a, b, c DESC
----
inner-join (lookup abc@abc_desc)
 ├── columns: x:1!null y:2!null z:3!null a:6!null b:7!null c:8!null
 ├── flags: force lookup join (into right side)
 ├── key columns: [1] = [6]
 ├── key: (2,3,6-8)
 ├── fd: (1)==(6), (6)==(1)
 ├── ordering: +(1|6),+2,+3,+7,-8 [actual: +1,+2,+3,+7,-8]
 ├── scan xyz
 │    ├── columns: x:1!null y:2!null z:3!null
 │    ├── key: (1-3)
 │    └── ordering: +1,+2,+3
 └── filters (true)

# Cannot supply requested ordering because input and lookup ordering columns
# are interleaved.
opt
SELECT * FROM xyz INNER LOOKUP JOIN abc ON x = a ORDER BY x, b, y, z, a, c
----
sort
 ├── columns: x:1!null y:2!null z:3!null a:6!null b:7!null c:8!null
 ├── key: (2,3,6-8)
 ├── fd: (1)==(6), (6)==(1)
 ├── ordering: +(1|6),+7,+2,+3,+8 [actual: +1,+7,+2,+3,+8]
 └── inner-join (lookup abc)
      ├── columns: x:1!null y:2!null z:3!null a:6!null b:7!null c:8!null
      ├── flags: force lookup join (into right side)
      ├── key columns: [1] = [6]
      ├── key: (2,3,6-8)
      ├── fd: (1)==(6), (6)==(1)
      ├── scan xyz
      │    ├── columns: x:1!null y:2!null z:3!null
      │    └── key: (1-3)
      └── filters (true)

# Cannot supply requested ordering because input ordering columns do not form
# a key.
opt
SELECT * FROM xyz INNER LOOKUP JOIN abc ON x = a ORDER BY x, y, a, b, c
----
sort (segmented)
 ├── columns: x:1!null y:2!null z:3!null a:6!null b:7!null c:8!null
 ├── key: (2,3,6-8)
 ├── fd: (1)==(6), (6)==(1)
 ├── ordering: +(1|6),+2,+7,+8 [actual: +1,+2,+7,+8]
 └── inner-join (lookup abc)
      ├── columns: x:1!null y:2!null z:3!null a:6!null b:7!null c:8!null
      ├── flags: force lookup join (into right side)
      ├── key columns: [1] = [6]
      ├── key: (2,3,6-8)
      ├── fd: (1)==(6), (6)==(1)
      ├── ordering: +1,+2
      ├── scan xyz
      │    ├── columns: x:1!null y:2!null z:3!null
      │    ├── key: (1-3)
      │    └── ordering: +1,+2
      └── filters (true)

# Cannot supply requested ordering because lookup ordering columns are not in index
# order.
opt
SELECT * FROM xyz INNER LOOKUP JOIN abc ON x = a ORDER BY x, y, z, a, c, b
----
sort (segmented)
 ├── columns: x:1!null y:2!null z:3!null a:6!null b:7!null c:8!null
 ├── key: (2,3,6-8)
 ├── fd: (1)==(6), (6)==(1)
 ├── ordering: +(1|6),+2,+3,+8,+7 [actual: +1,+2,+3,+8,+7]
 └── inner-join (lookup abc)
      ├── columns: x:1!null y:2!null z:3!null a:6!null b:7!null c:8!null
      ├── flags: force lookup join (into right side)
      ├── key columns: [1] = [6]
      ├── key: (2,3,6-8)
      ├── fd: (1)==(6), (6)==(1)
      ├── ordering: +1,+2,+3
      ├── scan xyz
      │    ├── columns: x:1!null y:2!null z:3!null
      │    ├── key: (1-3)
      │    └── ordering: +1,+2,+3
      └── filters (true)

# Cannot supply the requested ordering because the direction of the 'c' column
# is not the same as in the index.
opt
SELECT * FROM xyz INNER LOOKUP JOIN abc@primary ON x = a ORDER BY x, y, z, b, c DESC
----
sort (segmented)
 ├── columns: x:1!null y:2!null z:3!null a:6!null b:7!null c:8!null
 ├── key: (2,3,6-8)
 ├── fd: (1)==(6), (6)==(1)
 ├── ordering: +(1|6),+2,+3,+7,-8 [actual: +1,+2,+3,+7,-8]
 └── inner-join (lookup abc)
      ├── columns: x:1!null y:2!null z:3!null a:6!null b:7!null c:8!null
      ├── flags: force lookup join (into right side)
      ├── key columns: [1] = [6]
      ├── key: (2,3,6-8)
      ├── fd: (1)==(6), (6)==(1)
      ├── ordering: +1,+2,+3
      ├── scan xyz
      │    ├── columns: x:1!null y:2!null z:3!null
      │    ├── key: (1-3)
      │    └── ordering: +1,+2,+3
      └── filters (true)

# Regression test for #85393 - use only columns from the required ordering when
# building the provided ordering for Project operators.
exec-ddl
CREATE TABLE t0_85393 (c0 INT);
----

exec-ddl
CREATE TABLE t1_85393 (c0 INT);
----

opt
SELECT *
FROM t0_85393 CROSS JOIN t1_85393
WHERE (t0_85393.rowid IS NULL) OR (t1_85393.rowid IN (t0_85393.rowid))
ORDER BY t1_85393.rowid;
----
project
 ├── columns: c0:1 c0:5  [hidden: t1_85393.rowid:6!null]
 ├── fd: (6)-->(5)
 ├── ordering: +6
 └── project
      ├── columns: t0_85393.c0:1 t0_85393.rowid:2!null t1_85393.c0:5 t1_85393.rowid:6!null
      ├── key: (2,6)
      ├── fd: (2)-->(1), (6)-->(5)
      ├── ordering: +6
      └── project
           ├── columns: t0_85393.c0:1 t0_85393.rowid:2!null t1_85393.c0:5 t1_85393.rowid:6!null
           ├── key: (6)
           ├── fd: (2)-->(1,5), (2)==(6), (6)==(2)
           ├── ordering: +(2|6) [actual: +2]
           ├── inner-join (merge)
           │    ├── columns: t0_85393.c0:17 t0_85393.rowid:18!null t1_85393.c0:21 t1_85393.rowid:22!null
           │    ├── left ordering: +18
           │    ├── right ordering: +22
           │    ├── key: (22)
           │    ├── fd: (18)-->(17), (22)-->(21), (18)==(22), (22)==(18)
           │    ├── ordering: +(18|22) [actual: +18]
           │    ├── scan t0_85393
           │    │    ├── columns: t0_85393.c0:17 t0_85393.rowid:18!null
           │    │    ├── key: (18)
           │    │    ├── fd: (18)-->(17)
           │    │    └── ordering: +18
           │    ├── scan t1_85393
           │    │    ├── columns: t1_85393.c0:21 t1_85393.rowid:22!null
           │    │    ├── key: (22)
           │    │    ├── fd: (22)-->(21)
           │    │    └── ordering: +22
           │    └── filters (true)
           └── projections
                ├── t0_85393.c0:17 [as=t0_85393.c0:1, outer=(17)]
                ├── t0_85393.rowid:18 [as=t0_85393.rowid:2, outer=(18)]
                ├── t1_85393.c0:21 [as=t1_85393.c0:5, outer=(21)]
                └── t1_85393.rowid:22 [as=t1_85393.rowid:6, outer=(22)]

# Regression test for #83793 - include scan columns that are constrained to be
# constant in the provided ordering when they are in the output of the scan.
exec-ddl
CREATE TABLE t83793 (
  a INT,
  b STRING AS (a::STRING) STORED,
  c STRING AS (a::STRING) VIRTUAL,
  UNIQUE (b, a)
);
----

opt format=hide-all
SELECT NULL FROM t83793
WHERE NOT (c NOT SIMILAR TO '')
GROUP BY b HAVING bool_and(NULL);
----
project
 ├── select
 │    ├── group-by (streaming)
 │    │    ├── project
 │    │    │    ├── scan t83793@t83793_b_a_key
 │    │    │    │    └── constraint: /2/1: [/'' - /'']
 │    │    │    └── projections
 │    │    │         └── NULL
 │    │    └── aggregations
 │    │         └── bool-and
 │    │              └── column7
 │    └── filters
 │         └── bool_and
 └── projections
      └── NULL

# Regression test for #87806 - include optional columns when remapping Project
# provided ordering.
exec-ddl
CREATE TABLE table87806 (
  col1_0 TIMESTAMPTZ, col1_1 BOOL, col1_2 REGPROC, col1_3 REGNAMESPACE,
  PRIMARY KEY (col1_1, col1_2 ASC),
  UNIQUE (col1_1 ASC),
  INDEX (col1_3)
);
----

opt format=hide-all disable=(EliminateJoinUnderProjectLeft,EliminateJoinUnderProjectRight)
SELECT tab_171969.col1_3
FROM table87806 AS tab_171967
JOIN table87806 AS tab_171968
JOIN table87806@table87806_col1_3_idx AS tab_171969
ON tab_171968.col1_1 = tab_171969.col1_1
AND tab_171968.col1_3 = tab_171969.col1_3
AND tab_171968.col1_3 = tab_171969.tableoid
ON tab_171967.col1_2 = tab_171968.tableoid
AND tab_171967.col1_3 = tab_171968.col1_3
WHERE tab_171967.col1_1
ORDER BY tab_171969.col1_1 ASC;
----
project
 └── inner-join (lookup table87806@table87806_col1_3_idx [as=tab_171967])
      ├── lookup columns are key
      ├── project
      │    ├── inner-join (lookup table87806 [as=tab_171968])
      │    │    ├── lookup columns are key
      │    │    ├── select
      │    │    │    ├── index-join table87806
      │    │    │    │    └── scan table87806@table87806_col1_3_idx [as=tab_171969]
      │    │    │    │         ├── constraint: /16/14/15: (/NULL - ]
      │    │    │    │         └── flags: force-index=table87806_col1_3_idx
      │    │    │    └── filters
      │    │    │         └── tab_171969.col1_3 = tab_171969.tableoid
      │    │    └── filters
      │    │         └── tab_171968.col1_3 = tab_171969.col1_3
      │    └── projections
      │         └── true
      └── filters (true)

# Regression test for #88649 - don't panic when zero-cardinality group drops
# trivial equivalences.
exec-ddl
CREATE TABLE table1_88649 (
  col1_0 FLOAT4 NOT NULL,
  col1_1 OID NULL,
  col1_2 STRING NOT NULL,
  col1_3 INET NULL,
  col1_4 INET NOT NULL,
  col1_5 GEOGRAPHY NULL,
  col1_6 DATE NULL,
  col1_7 BOX2D NOT NULL,
  col1_8 STRING NULL AS (lower(CAST(col1_1 AS STRING))) STORED,
  col1_9 STRING NOT NULL AS (lower(CAST(col1_4 AS STRING))) STORED,
  col1_10 FLOAT8 NOT NULL AS (col1_0 + (-2.2259812355041504):::FLOAT8) VIRTUAL,
  col1_11 STRING NOT NULL AS (lower(CAST(col1_4 AS STRING))) VIRTUAL,
  UNIQUE (col1_8),
  UNIQUE (col1_4 ASC)
)
----

exec-ddl
CREATE TABLE table2_88649 (
  col2_0 CHAR NOT NULL,
  col2_1 JSONB NULL,
  col2_2 BOX2D NOT NULL,
  col2_3 OID NOT NULL,
  col2_4 STRING NOT NULL AS (lower(CAST(col2_1 AS STRING))) VIRTUAL,
  PRIMARY KEY (col2_0, col2_4 ASC, col2_2 ASC, col2_3),
  INDEX (col2_0 ASC, col2_4) NOT VISIBLE,
  UNIQUE (col2_3 ASC, col2_4 DESC, col2_0 ASC)
)
----

opt
SELECT
  CASE WHEN true THEN tab_923.col1_4 ELSE tab_923.col1_3 END AS col_2150
FROM
  table2_88649@table2_88649_pkey AS tab_922
FULL JOIN
  table1_88649@table1_88649_col1_8_key AS tab_923 ON NULL
WHERE
  false
ORDER BY
  tab_923.col1_4 ASC, tab_922.crdb_internal_mvcc_timestamp DESC, tab_923.col1_10, tab_923.col1_7
----
sort
 ├── columns: col_2150:23!null  [hidden: tab_922.crdb_internal_mvcc_timestamp:6!null col1_4:12!null]
 ├── cardinality: [0 - 0]
 ├── key: ()
 ├── fd: ()-->(6,12,23)
 ├── ordering: +(12|23),-6 [actual: +12,-6]
 └── values
      ├── columns: tab_922.crdb_internal_mvcc_timestamp:6!null col1_4:12!null col_2150:23!null
      ├── cardinality: [0 - 0]
      ├── key: ()
      └── fd: ()-->(6,12,23)

# Regression test for #96288
exec-ddl
CREATE TABLE v0 (c1 BYTES PRIMARY KEY, c2 TIMESTAMP, INDEX i3(c2))
----

opt
SELECT * FROM v0 WHERE (c1 = c1 AND c2 = '01-31-2023 00:00:00'::TIMESTAMP) OR (c1 = b'00' AND c1 = b'0') OR (c1 IS NULL AND c2 IS NULL)
----
distinct-on
 ├── columns: c1:1!null c2:2
 ├── grouping columns: c1:1!null
 ├── internal-ordering: +1
 ├── key: (1)
 ├── fd: (1)-->(2)
 ├── project
 │    ├── columns: c1:1!null c2:2
 │    ├── key: (1)
 │    ├── fd: (1)-->(2)
 │    ├── ordering: +1
 │    ├── scan v0@i3
 │    │    ├── columns: c1:5!null c2:6
 │    │    ├── constraint: /6/5: [/'2023-01-31 00:00:00' - /'2023-01-31 00:00:00']
 │    │    ├── key: (5)
 │    │    ├── fd: (5)-->(6)
 │    │    └── ordering: +5
 │    └── projections
 │         ├── c1:5 [as=c1:1, outer=(5)]
 │         └── c2:6 [as=c2:2, outer=(6)]
 └── aggregations
      └── const-agg [as=c2:2, outer=(2)]
           └── c2:2

opt
SELECT c1 FROM v0
WHERE (c1 = c1 AND c2 = '01-31-2023 00:00:00'::TIMESTAMP)
  OR (c1 = b'00' AND c1 = b'0')
  OR (c1 IS NULL AND c2 IS NULL)
ORDER BY c1;
----
project
 ├── columns: c1:1!null
 ├── key: (1)
 ├── ordering: +1
 └── distinct-on
      ├── columns: c1:1!null c2:2
      ├── grouping columns: c1:1!null
      ├── key: (1)
      ├── fd: (1)-->(2)
      ├── ordering: +1
      ├── project
      │    ├── columns: c1:1!null c2:2
      │    ├── key: (1)
      │    ├── fd: (1)-->(2)
      │    ├── ordering: +1
      │    ├── scan v0@i3
      │    │    ├── columns: c1:5!null c2:6
      │    │    ├── constraint: /6/5: [/'2023-01-31 00:00:00' - /'2023-01-31 00:00:00']
      │    │    ├── key: (5)
      │    │    ├── fd: (5)-->(6)
      │    │    └── ordering: +5
      │    └── projections
      │         ├── c1:5 [as=c1:1, outer=(5)]
      │         └── c2:6 [as=c2:2, outer=(6)]
      └── aggregations
           └── const-agg [as=c2:2, outer=(2)]
                └── c2:2

# Regression test for #106678 - sort the output of a top-k operator when the
# top-k ordering is a prefix of the required ordering.
exec-ddl
CREATE TABLE t106678 (a INT, b INT);
----

# There should be a segmented sort on top of the top-k operator.
opt
SELECT a, b FROM (SELECT a, b FROM t106678 ORDER BY a LIMIT 3) ORDER BY a, b;
----
sort (segmented)
 ├── columns: a:1 b:2
 ├── cardinality: [0 - 3]
 ├── ordering: +1,+2
 └── top-k
      ├── columns: a:1 b:2
      ├── internal-ordering: +1
      ├── k: 3
      ├── cardinality: [0 - 3]
      ├── ordering: +1
      └── scan t106678
           └── columns: a:1 b:2

# The top limit should become a top-k as well, since the inner top-k does not
# provide an ordering on (a, b).
opt
SELECT a, b FROM (SELECT a, b FROM t106678 ORDER BY a LIMIT 3) ORDER BY a, b LIMIT 1
----
top-k
 ├── columns: a:1 b:2
 ├── internal-ordering: +1,+2
 ├── k: 1
 ├── cardinality: [0 - 1]
 ├── key: ()
 ├── fd: ()-->(1,2)
 └── top-k
      ├── columns: a:1 b:2
      ├── internal-ordering: +1
      ├── k: 3
      ├── cardinality: [0 - 3]
      └── scan t106678
           └── columns: a:1 b:2
