exec-ddl
CREATE TABLE a (x INT PRIMARY KEY, y INT, arr INT[])
----

exec-ddl
CREATE TABLE b (x STRING PRIMARY KEY, z DECIMAL NOT NULL)
----

build
SELECT y, b.x, y+1 AS c
FROM a, b
WHERE a.y>1 AND a.x::string=b.x
ORDER BY y
LIMIT 10
----
limit
 ├── columns: y:2(int!null) x:6(string!null) c:10(int!null)
 ├── internal-ordering: +2
 ├── cardinality: [0 - 10]
 ├── immutable
 ├── fd: (2)-->(10)
 ├── ordering: +2
 ├── sort
 │    ├── columns: y:2(int!null) b.x:6(string!null) c:10(int!null)
 │    ├── immutable
 │    ├── fd: (2)-->(10)
 │    ├── ordering: +2
 │    ├── limit hint: 10.00
 │    └── project
 │         ├── columns: c:10(int!null) y:2(int!null) b.x:6(string!null)
 │         ├── immutable
 │         ├── fd: (2)-->(10)
 │         ├── select
 │         │    ├── columns: a.x:1(int!null) y:2(int!null) arr:3(int[]) a.crdb_internal_mvcc_timestamp:4(decimal) a.tableoid:5(oid) b.x:6(string!null) z:7(decimal!null) b.crdb_internal_mvcc_timestamp:8(decimal) b.tableoid:9(oid)
 │         │    ├── immutable
 │         │    ├── key: (1,6)
 │         │    ├── fd: (1)-->(2-5), (6)-->(7-9)
 │         │    ├── inner-join (cross)
 │         │    │    ├── columns: a.x:1(int!null) y:2(int) arr:3(int[]) a.crdb_internal_mvcc_timestamp:4(decimal) a.tableoid:5(oid) b.x:6(string!null) z:7(decimal!null) b.crdb_internal_mvcc_timestamp:8(decimal) b.tableoid:9(oid)
 │         │    │    ├── key: (1,6)
 │         │    │    ├── fd: (1)-->(2-5), (6)-->(7-9)
 │         │    │    ├── scan a
 │         │    │    │    ├── columns: a.x:1(int!null) y:2(int) arr:3(int[]) a.crdb_internal_mvcc_timestamp:4(decimal) a.tableoid:5(oid)
 │         │    │    │    ├── key: (1)
 │         │    │    │    └── fd: (1)-->(2-5)
 │         │    │    ├── scan b
 │         │    │    │    ├── columns: b.x:6(string!null) z:7(decimal!null) b.crdb_internal_mvcc_timestamp:8(decimal) b.tableoid:9(oid)
 │         │    │    │    ├── key: (6)
 │         │    │    │    └── fd: (6)-->(7-9)
 │         │    │    └── filters (true)
 │         │    └── filters
 │         │         └── and [type=bool, outer=(1,2,6), immutable, constraints=(/2: [/2 - ])]
 │         │              ├── gt [type=bool]
 │         │              │    ├── variable: y:2 [type=int]
 │         │              │    └── const: 1 [type=int]
 │         │              └── eq [type=bool]
 │         │                   ├── cast: STRING [type=string]
 │         │                   │    └── variable: a.x:1 [type=int]
 │         │                   └── variable: b.x:6 [type=string]
 │         └── projections
 │              └── plus [as=c:10, type=int, outer=(2), immutable]
 │                   ├── variable: y:2 [type=int]
 │                   └── const: 1 [type=int]
 └── const: 10 [type=int]

opt
SELECT y, b.x, y+1 AS c
FROM a, b
WHERE a.y>1 AND a.x::string=b.x
ORDER BY y
LIMIT 10
----
project
 ├── columns: y:2(int!null) x:6(string!null) c:11(int!null)
 ├── cardinality: [0 - 10]
 ├── immutable
 ├── fd: (2)-->(11)
 ├── ordering: +2
 ├── limit
 │    ├── columns: y:2(int!null) b.x:6(string!null) column10:10(string!null)
 │    ├── internal-ordering: +2
 │    ├── cardinality: [0 - 10]
 │    ├── immutable
 │    ├── fd: (6)==(10), (10)==(6)
 │    ├── ordering: +2
 │    ├── inner-join (lookup b)
 │    │    ├── columns: y:2(int!null) b.x:6(string!null) column10:10(string!null)
 │    │    ├── key columns: [10] = [6]
 │    │    ├── lookup columns are key
 │    │    ├── immutable
 │    │    ├── fd: (6)==(10), (10)==(6)
 │    │    ├── ordering: +2
 │    │    ├── limit hint: 10.00
 │    │    ├── sort
 │    │    │    ├── columns: y:2(int!null) column10:10(string!null)
 │    │    │    ├── immutable
 │    │    │    ├── ordering: +2
 │    │    │    ├── limit hint: 100.00
 │    │    │    └── project
 │    │    │         ├── columns: column10:10(string!null) y:2(int!null)
 │    │    │         ├── immutable
 │    │    │         ├── select
 │    │    │         │    ├── columns: a.x:1(int!null) y:2(int!null)
 │    │    │         │    ├── key: (1)
 │    │    │         │    ├── fd: (1)-->(2)
 │    │    │         │    ├── scan a
 │    │    │         │    │    ├── columns: a.x:1(int!null) y:2(int)
 │    │    │         │    │    ├── key: (1)
 │    │    │         │    │    └── fd: (1)-->(2)
 │    │    │         │    └── filters
 │    │    │         │         └── gt [type=bool, outer=(2), constraints=(/2: [/2 - ]; tight)]
 │    │    │         │              ├── variable: y:2 [type=int]
 │    │    │         │              └── const: 1 [type=int]
 │    │    │         └── projections
 │    │    │              └── cast: STRING [as=column10:10, type=string, outer=(1), immutable]
 │    │    │                   └── variable: a.x:1 [type=int]
 │    │    └── filters (true)
 │    └── const: 10 [type=int]
 └── projections
      └── plus [as=c:11, type=int, outer=(2), immutable]
           ├── variable: y:2 [type=int]
           └── const: 1 [type=int]

memo
SELECT y, b.x, y+1 AS c
FROM a, b
WHERE a.y>1 AND a.x::string=b.x
ORDER BY y
LIMIT 10
----
memo (optimized, ~27KB, required=[presentation: y:2,x:6,c:11] [ordering: +2])
 ├── G1: (project G2 G3 y x)
 │    ├── [presentation: y:2,x:6,c:11] [ordering: +2]
 │    │    ├── best: (project G2="[ordering: +2]" G3 y x)
 │    │    └── cost: 1772.82
 │    └── []
 │         ├── best: (project G2 G3 y x)
 │         └── cost: 1772.82
 ├── G2: (limit G4 G5 ordering=+2) (top-k G4 &{10 +2 })
 │    ├── [ordering: +2]
 │    │    ├── best: (limit G4="[ordering: +2] [limit hint: 10.00]" G5 ordering=+2)
 │    │    └── cost: 1772.61
 │    └── []
 │         ├── best: (limit G4="[ordering: +2] [limit hint: 10.00]" G5 ordering=+2)
 │         └── cost: 1772.61
 ├── G3: (projections G6)
 ├── G4: (inner-join G7 G8 G9) (inner-join G8 G7 G9) (lookup-join G7 G10 b,keyCols=[10],outCols=(2,6,10)) (merge-join G8 G7 G10 inner-join,+6,+10)
 │    ├── [ordering: +2] [limit hint: 10.00]
 │    │    ├── best: (lookup-join G7="[ordering: +2] [limit hint: 100.00]" G10 b,keyCols=[10],outCols=(2,6,10))
 │    │    └── cost: 1772.50
 │    └── []
 │         ├── best: (inner-join G8 G7 G9)
 │         └── cost: 2175.26
 ├── G5: (const 10)
 ├── G6: (plus G11 G12)
 ├── G7: (project G13 G14 y)
 │    ├── [ordering: +10]
 │    │    ├── best: (sort G7)
 │    │    └── cost: 1164.48
 │    ├── [ordering: +2] [limit hint: 100.00]
 │    │    ├── best: (sort G7)
 │    │    └── cost: 1164.48
 │    └── []
 │         ├── best: (project G13 G14 y)
 │         └── cost: 1095.24
 ├── G8: (scan b,cols=(6))
 │    ├── [ordering: +6]
 │    │    ├── best: (scan b,cols=(6))
 │    │    └── cost: 1058.32
 │    └── []
 │         ├── best: (scan b,cols=(6))
 │         └── cost: 1058.32
 ├── G9: (filters G15)
 ├── G10: (filters)
 ├── G11: (variable y)
 ├── G12: (const 1)
 ├── G13: (select G16 G17)
 │    ├── [ordering: +2] [limit hint: 100.00]
 │    │    ├── best: (sort G13)
 │    │    └── cost: 1157.79
 │    └── []
 │         ├── best: (select G16 G17)
 │         └── cost: 1088.55
 ├── G14: (projections G18)
 ├── G15: (eq G19 G20)
 ├── G16: (scan a,cols=(1,2))
 │    ├── [ordering: +2] [limit hint: 300.00]
 │    │    ├── best: (sort G16)
 │    │    └── cost: 1318.00
 │    └── []
 │         ├── best: (scan a,cols=(1,2))
 │         └── cost: 1078.52
 ├── G17: (filters G21)
 ├── G18: (cast G22 STRING)
 ├── G19: (variable column10)
 ├── G20: (variable b.x)
 ├── G21: (gt G11 G12)
 └── G22: (variable a.x)

# Test interning of expressions.
memo
SELECT 1 AS a, 1+z AS b, left(x, 10)::TIMESTAMP AS c, left(x, 10)::TIMESTAMPTZ AS d
FROM b
WHERE z=1 AND concat(x, 'foo', x)=concat(x, 'foo', x)
----
memo (optimized, ~8KB, required=[presentation: a:5,b:6,c:7,d:8])
 ├── G1: (project G2 G3)
 │    └── [presentation: a:5,b:6,c:7,d:8]
 │         ├── best: (project G2 G3)
 │         └── cost: 1078.65
 ├── G2: (select G4 G5)
 │    └── []
 │         ├── best: (select G4 G5)
 │         └── cost: 1078.46
 ├── G3: (projections G6 G7 G8 G9)
 ├── G4: (scan b,cols=(1,2))
 │    └── []
 │         ├── best: (scan b,cols=(1,2))
 │         └── cost: 1068.42
 ├── G5: (filters G10 G11)
 ├── G6: (const 1)
 ├── G7: (plus G12 G13)
 ├── G8: (cast G14 TIMESTAMP)
 ├── G9: (cast G14 TIMESTAMPTZ)
 ├── G10: (eq G12 G13)
 ├── G11: (eq G15 G15)
 ├── G12: (variable z)
 ├── G13: (const 1)
 ├── G14: (function G16 left)
 ├── G15: (function G17 concat)
 ├── G16: (scalar-list G18 G19)
 ├── G17: (scalar-list G18 G20 G18)
 ├── G18: (variable x)
 ├── G19: (const 10)
 └── G20: (const 'foo')

# Test topological sorting
memo
SELECT x FROM a WHERE x = 1 AND x+y = 1
----
memo (optimized, ~9KB, required=[presentation: x:1])
 ├── G1: (project G2 G3 x)
 │    └── [presentation: x:1]
 │         ├── best: (project G2 G3 x)
 │         └── cost: 9.11
 ├── G2: (select G4 G5) (select G6 G7)
 │    └── []
 │         ├── best: (select G6 G7)
 │         └── cost: 9.09
 ├── G3: (projections)
 ├── G4: (scan a,cols=(1,2))
 │    └── []
 │         ├── best: (scan a,cols=(1,2))
 │         └── cost: 1078.52
 ├── G5: (filters G8 G9)
 ├── G6: (scan a,cols=(1,2),constrained)
 │    └── []
 │         ├── best: (scan a,cols=(1,2),constrained)
 │         └── cost: 9.06
 ├── G7: (filters G9)
 ├── G8: (eq G10 G11)
 ├── G9: (eq G12 G13)
 ├── G10: (variable x)
 ├── G11: (const 1)
 ├── G12: (variable y)
 └── G13: (const 0)

memo 
SELECT x, y FROM a UNION SELECT x+1, y+1 FROM a
----
memo (optimized, ~10KB, required=[presentation: x:13,y:14])
 ├── G1: (union G2 G3) (union G2 G3 ordering=+13,+14)
 │    └── [presentation: x:13,y:14]
 │         ├── best: (union G2 G3)
 │         └── cost: 2227.69
 ├── G2: (scan a,cols=(1,2))
 │    ├── [ordering: +1]
 │    │    ├── best: (scan a,cols=(1,2))
 │    │    └── cost: 1078.52
 │    └── []
 │         ├── best: (scan a,cols=(1,2))
 │         └── cost: 1078.52
 ├── G3: (project G4 G5)
 │    ├── [ordering: +11,+12]
 │    │    ├── best: (sort G3)
 │    │    └── cost: 1358.99
 │    └── []
 │         ├── best: (project G4 G5)
 │         └── cost: 1108.54
 ├── G4: (scan a,cols=(6,7))
 │    └── []
 │         ├── best: (scan a,cols=(6,7))
 │         └── cost: 1078.52
 ├── G5: (projections G6 G7)
 ├── G6: (plus G8 G9)
 ├── G7: (plus G10 G9)
 ├── G8: (variable a.x)
 ├── G9: (const 1)
 └── G10: (variable a.y)

memo
SELECT array_agg(x) FROM (SELECT * FROM a)
----
memo (optimized, ~6KB, required=[presentation: array_agg:6])
 ├── G1: (scalar-group-by G2 G3 cols=())
 │    └── [presentation: array_agg:6]
 │         ├── best: (scalar-group-by G2 G3 cols=())
 │         └── cost: 1078.45
 ├── G2: (scan a,cols=(1))
 │    └── []
 │         ├── best: (scan a,cols=(1))
 │         └── cost: 1068.42
 ├── G3: (aggregations G4)
 ├── G4: (array-agg G5)
 └── G5: (variable x)

memo
SELECT array_agg(x) FROM (SELECT * FROM a) GROUP BY y
----
memo (optimized, ~7KB, required=[presentation: array_agg:6])
 ├── G1: (project G2 G3 array_agg)
 │    └── [presentation: array_agg:6]
 │         ├── best: (project G2 G3 array_agg)
 │         └── cost: 1110.57
 ├── G2: (group-by G4 G5 cols=(2))
 │    └── []
 │         ├── best: (group-by G4 G5 cols=(2))
 │         └── cost: 1109.55
 ├── G3: (projections)
 ├── G4: (scan a,cols=(1,2))
 │    └── []
 │         ├── best: (scan a,cols=(1,2))
 │         └── cost: 1078.52
 ├── G5: (aggregations G6)
 ├── G6: (array-agg G7)
 └── G7: (variable x)

memo
SELECT array_agg(x) FROM (SELECT * FROM a ORDER BY y)
----
memo (optimized, ~6KB, required=[presentation: array_agg:6])
 ├── G1: (scalar-group-by G2 G3 cols=(),ordering=+2)
 │    └── [presentation: array_agg:6]
 │         ├── best: (scalar-group-by G2="[ordering: +2]" G3 cols=(),ordering=+2)
 │         └── cost: 1328.03
 ├── G2: (scan a,cols=(1,2))
 │    ├── [ordering: +2]
 │    │    ├── best: (sort G2)
 │    │    └── cost: 1318.00
 │    └── []
 │         ├── best: (scan a,cols=(1,2))
 │         └── cost: 1078.52
 ├── G3: (aggregations G4)
 ├── G4: (array-agg G5)
 └── G5: (variable x)

memo
SELECT array_cat_agg(arr) FROM (SELECT * FROM a)
----
memo (optimized, ~6KB, required=[presentation: array_cat_agg:6])
 ├── G1: (scalar-group-by G2 G3 cols=())
 │    └── [presentation: array_cat_agg:6]
 │         ├── best: (scalar-group-by G2 G3 cols=())
 │         └── cost: 1078.45
 ├── G2: (scan a,cols=(3))
 │    └── []
 │         ├── best: (scan a,cols=(3))
 │         └── cost: 1068.42
 ├── G3: (aggregations G4)
 ├── G4: (array-cat-agg G5)
 └── G5: (variable arr)

memo
SELECT array_cat_agg(arr) FROM (SELECT * FROM a) GROUP BY y
----
memo (optimized, ~7KB, required=[presentation: array_cat_agg:6])
 ├── G1: (project G2 G3 array_cat_agg)
 │    └── [presentation: array_cat_agg:6]
 │         ├── best: (project G2 G3 array_cat_agg)
 │         └── cost: 1110.57
 ├── G2: (group-by G4 G5 cols=(2))
 │    └── []
 │         ├── best: (group-by G4 G5 cols=(2))
 │         └── cost: 1109.55
 ├── G3: (projections)
 ├── G4: (scan a,cols=(2,3))
 │    └── []
 │         ├── best: (scan a,cols=(2,3))
 │         └── cost: 1078.52
 ├── G5: (aggregations G6)
 ├── G6: (array-cat-agg G7)
 └── G7: (variable arr)

memo
SELECT array_cat_agg(arr) FROM (SELECT * FROM a ORDER BY y)
----
memo (optimized, ~6KB, required=[presentation: array_cat_agg:6])
 ├── G1: (scalar-group-by G2 G3 cols=(),ordering=+2)
 │    └── [presentation: array_cat_agg:6]
 │         ├── best: (scalar-group-by G2="[ordering: +2]" G3 cols=(),ordering=+2)
 │         └── cost: 1328.03
 ├── G2: (scan a,cols=(2,3))
 │    ├── [ordering: +2]
 │    │    ├── best: (sort G2)
 │    │    └── cost: 1318.00
 │    └── []
 │         ├── best: (scan a,cols=(2,3))
 │         └── cost: 1078.52
 ├── G3: (aggregations G4)
 ├── G4: (array-cat-agg G5)
 └── G5: (variable arr)

memo
SELECT DISTINCT info FROM [EXPLAIN SELECT 123 AS k]
----
memo (optimized, ~10KB, required=[presentation: info:3])
 ├── G1: (distinct-on G2 G3 cols=(3))
 │    └── [presentation: info:3]
 │         ├── best: (distinct-on G2 G3 cols=(3))
 │         └── cost: 0.59
 ├── G2: (project G4 G5)
 │    └── []
 │         ├── best: (project G4 G5)
 │         └── cost: 0.26
 ├── G3: (aggregations)
 ├── G4: (explain G6 [presentation: k:1])
 │    └── []
 │         ├── best: (explain G6="[presentation: k:1]" [presentation: k:1])
 │         └── cost: 0.04
 ├── G5: (projections G7)
 ├── G6: (values G8 id=v1)
 │    └── [presentation: k:1]
 │         ├── best: (values G8 id=v1)
 │         └── cost: 0.02
 ├── G7: (variable info)
 ├── G8: (scalar-list G9)
 ├── G9: (tuple G10)
 ├── G10: (scalar-list G11)
 └── G11: (const 123)

memo
SELECT DISTINCT tag FROM [SHOW TRACE FOR SESSION]
----
memo (optimized, ~8KB, required=[presentation: tag:11])
 ├── G1: (distinct-on G2 G3 cols=(11))
 │    └── [presentation: tag:11]
 │         ├── best: (distinct-on G2 G3 cols=(11))
 │         └── cost: 0.57
 ├── G2: (project G4 G5)
 │    └── []
 │         ├── best: (project G4 G5)
 │         └── cost: 0.24
 ├── G3: (aggregations)
 ├── G4: (show-trace-for-session &{TRACE false [1 2 3 4 5 6 7]})
 │    └── []
 │         ├── best: (show-trace-for-session &{TRACE false [1 2 3 4 5 6 7]})
 │         └── cost: 0.02
 ├── G5: (projections G6)
 └── G6: (variable tag)
