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

exec-ddl
CREATE TABLE kuv (k INT PRIMARY KEY, u FLOAT, v STRING)
----

exec-ddl
CREATE TABLE ab (a INT, b INT)
----

exec-ddl
CREATE TABLE abcde (a INT, b INT, c INT, d DECIMAL, e STRING)
----

build
SELECT * FROM xy WHERE x=1
----
project
 ├── columns: x:1(int!null) y:2(int)
 ├── cardinality: [0 - 1]
 ├── key: ()
 ├── fd: ()-->(1,2)
 ├── prune: (1,2)
 └── select
      ├── columns: x:1(int!null) y:2(int) crdb_internal_mvcc_timestamp:3(decimal) tableoid:4(oid)
      ├── cardinality: [0 - 1]
      ├── key: ()
      ├── fd: ()-->(1-4)
      ├── prune: (2-4)
      ├── scan xy
      │    ├── columns: x:1(int!null) y:2(int) crdb_internal_mvcc_timestamp:3(decimal) tableoid:4(oid)
      │    ├── key: (1)
      │    ├── fd: (1)-->(2-4)
      │    ├── prune: (1-4)
      │    └── interesting orderings: (+1)
      └── filters
           └── eq [type=bool, outer=(1), constraints=(/1: [/1 - /1]; tight), fd=()-->(1)]
                ├── variable: x:1 [type=int]
                └── const: 1 [type=int]

build
SELECT * FROM xy,kuv WHERE xy.x=kuv.k
----
project
 ├── columns: x:1(int!null) y:2(int) k:5(int!null) u:6(float) v:7(string)
 ├── key: (5)
 ├── fd: (1)-->(2), (5)-->(6,7), (1)==(5), (5)==(1)
 ├── prune: (1,2,5-7)
 ├── interesting orderings: (+(1|5))
 └── select
      ├── columns: x:1(int!null) y:2(int) xy.crdb_internal_mvcc_timestamp:3(decimal) xy.tableoid:4(oid) k:5(int!null) u:6(float) v:7(string) kuv.crdb_internal_mvcc_timestamp:8(decimal) kuv.tableoid:9(oid)
      ├── key: (5)
      ├── fd: (1)-->(2-4), (5)-->(6-9), (1)==(5), (5)==(1)
      ├── prune: (2-4,6-9)
      ├── interesting orderings: (+(1|5))
      ├── inner-join (cross)
      │    ├── columns: x:1(int!null) y:2(int) xy.crdb_internal_mvcc_timestamp:3(decimal) xy.tableoid:4(oid) k:5(int!null) u:6(float) v:7(string) kuv.crdb_internal_mvcc_timestamp:8(decimal) kuv.tableoid:9(oid)
      │    ├── key: (1,5)
      │    ├── fd: (1)-->(2-4), (5)-->(6-9)
      │    ├── prune: (1-9)
      │    ├── interesting orderings: (+1) (+5)
      │    ├── scan xy
      │    │    ├── columns: x:1(int!null) y:2(int) xy.crdb_internal_mvcc_timestamp:3(decimal) xy.tableoid:4(oid)
      │    │    ├── key: (1)
      │    │    ├── fd: (1)-->(2-4)
      │    │    ├── prune: (1-4)
      │    │    ├── interesting orderings: (+1)
      │    │    └── unfiltered-cols: (1-4)
      │    ├── scan kuv
      │    │    ├── columns: k:5(int!null) u:6(float) v:7(string) kuv.crdb_internal_mvcc_timestamp:8(decimal) kuv.tableoid:9(oid)
      │    │    ├── key: (5)
      │    │    ├── fd: (5)-->(6-9)
      │    │    ├── prune: (5-9)
      │    │    ├── interesting orderings: (+5)
      │    │    └── unfiltered-cols: (5-9)
      │    └── filters (true)
      └── filters
           └── eq [type=bool, outer=(1,5), constraints=(/1: (/NULL - ]; /5: (/NULL - ]), fd=(1)==(5), (5)==(1)]
                ├── variable: x:1 [type=int]
                └── variable: k:5 [type=int]

# Propagate outer columns.
build
SELECT * FROM xy WHERE EXISTS(SELECT * FROM (SELECT * FROM kuv WHERE k=y) WHERE k=x)
----
project
 ├── columns: x:1(int!null) y:2(int)
 ├── key: (1)
 ├── fd: (1)-->(2)
 ├── prune: (1,2)
 ├── interesting orderings: (+1)
 └── select
      ├── columns: x:1(int!null) y:2(int) xy.crdb_internal_mvcc_timestamp:3(decimal) xy.tableoid:4(oid)
      ├── key: (1)
      ├── fd: (1)-->(2-4)
      ├── prune: (3,4)
      ├── interesting orderings: (+1)
      ├── scan xy
      │    ├── columns: x:1(int!null) y:2(int) xy.crdb_internal_mvcc_timestamp:3(decimal) xy.tableoid:4(oid)
      │    ├── key: (1)
      │    ├── fd: (1)-->(2-4)
      │    ├── prune: (1-4)
      │    └── interesting orderings: (+1)
      └── filters
           └── exists [type=bool, outer=(1,2), correlated-subquery]
                └── select
                     ├── columns: k:5(int!null) u:6(float) v:7(string)
                     ├── outer: (1,2)
                     ├── cardinality: [0 - 1]
                     ├── key: ()
                     ├── fd: ()-->(5-7)
                     ├── prune: (6,7)
                     ├── project
                     │    ├── columns: k:5(int!null) u:6(float) v:7(string)
                     │    ├── outer: (2)
                     │    ├── cardinality: [0 - 1]
                     │    ├── key: ()
                     │    ├── fd: ()-->(5-7)
                     │    ├── prune: (5-7)
                     │    └── select
                     │         ├── columns: k:5(int!null) u:6(float) v:7(string) kuv.crdb_internal_mvcc_timestamp:8(decimal) kuv.tableoid:9(oid)
                     │         ├── outer: (2)
                     │         ├── cardinality: [0 - 1]
                     │         ├── key: ()
                     │         ├── fd: ()-->(5-9)
                     │         ├── prune: (6-9)
                     │         ├── scan kuv
                     │         │    ├── columns: k:5(int!null) u:6(float) v:7(string) kuv.crdb_internal_mvcc_timestamp:8(decimal) kuv.tableoid:9(oid)
                     │         │    ├── key: (5)
                     │         │    ├── fd: (5)-->(6-9)
                     │         │    ├── prune: (5-9)
                     │         │    └── interesting orderings: (+5)
                     │         └── filters
                     │              └── eq [type=bool, outer=(2,5), constraints=(/2: (/NULL - ]; /5: (/NULL - ]), fd=(2)==(5), (5)==(2)]
                     │                   ├── variable: k:5 [type=int]
                     │                   └── variable: y:2 [type=int]
                     └── filters
                          └── eq [type=bool, outer=(1,5), constraints=(/1: (/NULL - ]; /5: (/NULL - ]), fd=(1)==(5), (5)==(1)]
                               ├── variable: k:5 [type=int]
                               └── variable: x:1 [type=int]

# Reduce min cardinality.
build
SELECT count(*) FROM xy HAVING count(*) = 5
----
select
 ├── columns: count:5(int!null)
 ├── cardinality: [0 - 1]
 ├── key: ()
 ├── fd: ()-->(5)
 ├── scalar-group-by
 │    ├── columns: count_rows:5(int!null)
 │    ├── cardinality: [1 - 1]
 │    ├── key: ()
 │    ├── fd: ()-->(5)
 │    ├── prune: (5)
 │    ├── project
 │    │    └── scan xy
 │    │         ├── columns: x:1(int!null) y:2(int) crdb_internal_mvcc_timestamp:3(decimal) tableoid:4(oid)
 │    │         ├── key: (1)
 │    │         ├── fd: (1)-->(2-4)
 │    │         ├── prune: (1-4)
 │    │         └── interesting orderings: (+1)
 │    └── aggregations
 │         └── count-rows [as=count_rows:5, type=int]
 └── filters
      └── eq [type=bool, outer=(5), constraints=(/5: [/5 - /5]; tight), fd=()-->(5)]
           ├── variable: count_rows:5 [type=int]
           └── const: 5 [type=int]

build
SELECT * FROM xy WITH ORDINALITY
----
project
 ├── columns: x:1(int!null) y:2(int) ordinality:5(int!null)
 ├── key: (1)
 ├── fd: (1)-->(2,5), (5)-->(1,2)
 ├── prune: (1,2,5)
 └── ordinality
      ├── columns: x:1(int!null) y:2(int) crdb_internal_mvcc_timestamp:3(decimal) tableoid:4(oid) ordinality:5(int!null)
      ├── key: (1)
      ├── fd: (1)-->(2-5), (5)-->(1-4)
      ├── prune: (1-4)
      └── scan xy
           ├── columns: x:1(int!null) y:2(int) crdb_internal_mvcc_timestamp:3(decimal) tableoid:4(oid)
           ├── key: (1)
           ├── fd: (1)-->(2-4)
           ├── prune: (1-4)
           └── interesting orderings: (+1)

# Verify not-null column deduction from constraints.
exec-ddl
CREATE TABLE abcd (a INT NOT NULL, b INT NOT NULL, c INT, d INT)
----

build
SELECT * FROM abcd WHERE true
----
project
 ├── columns: a:1(int!null) b:2(int!null) c:3(int) d:4(int)
 ├── prune: (1-4)
 └── select
      ├── columns: a:1(int!null) b:2(int!null) c:3(int) d:4(int) rowid:5(int!null) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
      ├── key: (5)
      ├── fd: (5)-->(1-4,6,7)
      ├── prune: (1-7)
      ├── interesting orderings: (+5)
      ├── scan abcd
      │    ├── columns: a:1(int!null) b:2(int!null) c:3(int) d:4(int) rowid:5(int!null) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
      │    ├── key: (5)
      │    ├── fd: (5)-->(1-4,6,7)
      │    ├── prune: (1-7)
      │    └── interesting orderings: (+5)
      └── filters
           └── true [type=bool]

build
SELECT * FROM abcd WHERE c IS NOT NULL
----
project
 ├── columns: a:1(int!null) b:2(int!null) c:3(int!null) d:4(int)
 ├── prune: (1-4)
 └── select
      ├── columns: a:1(int!null) b:2(int!null) c:3(int!null) d:4(int) rowid:5(int!null) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
      ├── key: (5)
      ├── fd: (5)-->(1-4,6,7)
      ├── prune: (1,2,4-7)
      ├── interesting orderings: (+5)
      ├── scan abcd
      │    ├── columns: a:1(int!null) b:2(int!null) c:3(int) d:4(int) rowid:5(int!null) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
      │    ├── key: (5)
      │    ├── fd: (5)-->(1-4,6,7)
      │    ├── prune: (1-7)
      │    └── interesting orderings: (+5)
      └── filters
           └── is-not [type=bool, outer=(3), constraints=(/3: (/NULL - ]; tight)]
                ├── variable: c:3 [type=int]
                └── null [type=unknown]

build
SELECT * FROM abcd WHERE c = d
----
project
 ├── columns: a:1(int!null) b:2(int!null) c:3(int!null) d:4(int!null)
 ├── fd: (3)==(4), (4)==(3)
 ├── prune: (1-4)
 └── select
      ├── columns: a:1(int!null) b:2(int!null) c:3(int!null) d:4(int!null) rowid:5(int!null) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
      ├── key: (5)
      ├── fd: (5)-->(1-4,6,7), (3)==(4), (4)==(3)
      ├── prune: (1,2,5-7)
      ├── interesting orderings: (+5)
      ├── scan abcd
      │    ├── columns: a:1(int!null) b:2(int!null) c:3(int) d:4(int) rowid:5(int!null) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
      │    ├── key: (5)
      │    ├── fd: (5)-->(1-4,6,7)
      │    ├── prune: (1-7)
      │    └── interesting orderings: (+5)
      └── filters
           └── eq [type=bool, outer=(3,4), constraints=(/3: (/NULL - ]; /4: (/NULL - ]), fd=(3)==(4), (4)==(3)]
                ├── variable: c:3 [type=int]
                └── variable: d:4 [type=int]

build
SELECT * FROM abcd WHERE a > c
----
project
 ├── columns: a:1(int!null) b:2(int!null) c:3(int!null) d:4(int)
 ├── prune: (1-4)
 └── select
      ├── columns: a:1(int!null) b:2(int!null) c:3(int!null) d:4(int) rowid:5(int!null) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
      ├── key: (5)
      ├── fd: (5)-->(1-4,6,7)
      ├── prune: (2,4-7)
      ├── interesting orderings: (+5)
      ├── scan abcd
      │    ├── columns: a:1(int!null) b:2(int!null) c:3(int) d:4(int) rowid:5(int!null) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
      │    ├── key: (5)
      │    ├── fd: (5)-->(1-4,6,7)
      │    ├── prune: (1-7)
      │    └── interesting orderings: (+5)
      └── filters
           └── gt [type=bool, outer=(1,3), constraints=(/1: (/NULL - ]; /3: (/NULL - ])]
                ├── variable: a:1 [type=int]
                └── variable: c:3 [type=int]

build
SELECT * FROM (SELECT * FROM abcd WHERE a = c) WHERE b < d
----
select
 ├── columns: a:1(int!null) b:2(int!null) c:3(int!null) d:4(int!null)
 ├── fd: (1)==(3), (3)==(1)
 ├── prune: (1,3)
 ├── project
 │    ├── columns: a:1(int!null) b:2(int!null) c:3(int!null) d:4(int)
 │    ├── fd: (1)==(3), (3)==(1)
 │    ├── prune: (1-4)
 │    └── select
 │         ├── columns: a:1(int!null) b:2(int!null) c:3(int!null) d:4(int) rowid:5(int!null) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
 │         ├── key: (5)
 │         ├── fd: (5)-->(1-4,6,7), (1)==(3), (3)==(1)
 │         ├── prune: (2,4-7)
 │         ├── interesting orderings: (+5)
 │         ├── scan abcd
 │         │    ├── columns: a:1(int!null) b:2(int!null) c:3(int) d:4(int) rowid:5(int!null) crdb_internal_mvcc_timestamp:6(decimal) tableoid:7(oid)
 │         │    ├── key: (5)
 │         │    ├── fd: (5)-->(1-4,6,7)
 │         │    ├── prune: (1-7)
 │         │    └── interesting orderings: (+5)
 │         └── filters
 │              └── eq [type=bool, outer=(1,3), constraints=(/1: (/NULL - ]; /3: (/NULL - ]), fd=(1)==(3), (3)==(1)]
 │                   ├── variable: a:1 [type=int]
 │                   └── variable: c:3 [type=int]
 └── filters
      └── lt [type=bool, outer=(2,4), constraints=(/2: (/NULL - ]; /4: (/NULL - ])]
           ├── variable: b:2 [type=int]
           └── variable: d:4 [type=int]

# Test outer column in select filter that is part of a not-null constraint.
build
SELECT * FROM abcd WHERE (SELECT count(*) FROM xy WHERE y = b) > 0
----
project
 ├── columns: a:1(int!null) b:2(int!null) c:3(int) d:4(int)
 ├── prune: (1-4)
 └── select
      ├── columns: a:1(int!null) b:2(int!null) c:3(int) d:4(int) rowid:5(int!null) abcd.crdb_internal_mvcc_timestamp:6(decimal) abcd.tableoid:7(oid)
      ├── key: (5)
      ├── fd: (5)-->(1-4,6,7)
      ├── prune: (1,3-7)
      ├── interesting orderings: (+5)
      ├── scan abcd
      │    ├── columns: a:1(int!null) b:2(int!null) c:3(int) d:4(int) rowid:5(int!null) abcd.crdb_internal_mvcc_timestamp:6(decimal) abcd.tableoid:7(oid)
      │    ├── key: (5)
      │    ├── fd: (5)-->(1-4,6,7)
      │    ├── prune: (1-7)
      │    └── interesting orderings: (+5)
      └── filters
           └── gt [type=bool, outer=(2), correlated-subquery]
                ├── subquery [type=int]
                │    └── max1-row
                │         ├── columns: count_rows:12(int!null)
                │         ├── error: "more than one row returned by a subquery used as an expression"
                │         ├── outer: (2)
                │         ├── cardinality: [1 - 1]
                │         ├── key: ()
                │         ├── fd: ()-->(12)
                │         └── scalar-group-by
                │              ├── columns: count_rows:12(int!null)
                │              ├── outer: (2)
                │              ├── cardinality: [1 - 1]
                │              ├── key: ()
                │              ├── fd: ()-->(12)
                │              ├── prune: (12)
                │              ├── project
                │              │    ├── outer: (2)
                │              │    └── select
                │              │         ├── columns: x:8(int!null) y:9(int!null) xy.crdb_internal_mvcc_timestamp:10(decimal) xy.tableoid:11(oid)
                │              │         ├── outer: (2)
                │              │         ├── key: (8)
                │              │         ├── fd: ()-->(9), (8)-->(10,11)
                │              │         ├── prune: (8,10,11)
                │              │         ├── interesting orderings: (+8 opt(9))
                │              │         ├── scan xy
                │              │         │    ├── columns: x:8(int!null) y:9(int) xy.crdb_internal_mvcc_timestamp:10(decimal) xy.tableoid:11(oid)
                │              │         │    ├── key: (8)
                │              │         │    ├── fd: (8)-->(9-11)
                │              │         │    ├── prune: (8-11)
                │              │         │    └── interesting orderings: (+8)
                │              │         └── filters
                │              │              └── eq [type=bool, outer=(2,9), constraints=(/2: (/NULL - ]; /9: (/NULL - ]), fd=(2)==(9), (9)==(2)]
                │              │                   ├── variable: y:9 [type=int]
                │              │                   └── variable: b:2 [type=int]
                │              └── aggregations
                │                   └── count-rows [as=count_rows:12, type=int]
                └── const: 0 [type=int]

# Sequences always have a single row when selected from.
exec-ddl
CREATE SEQUENCE x
----

build
SELECT * FROM x
----
sequence-select x
 ├── columns: last_value:1(int!null) log_cnt:2(int!null) is_called:3(bool!null)
 ├── cardinality: [1 - 1]
 ├── key: ()
 └── fd: ()-->(1-3)

# Test that cardinality is set for constrained keys, but not for other columns.
norm
SELECT * FROM xy WHERE x IN (1, 2, 4, 6, 7, 9)
----
select
 ├── columns: x:1(int!null) y:2(int)
 ├── cardinality: [0 - 6]
 ├── key: (1)
 ├── fd: (1)-->(2)
 ├── prune: (2)
 ├── interesting orderings: (+1)
 ├── scan xy
 │    ├── columns: x:1(int!null) y:2(int)
 │    ├── key: (1)
 │    ├── fd: (1)-->(2)
 │    ├── prune: (1,2)
 │    └── interesting orderings: (+1)
 └── filters
      └── in [type=bool, outer=(1), constraints=(/1: [/1 - /1] [/2 - /2] [/4 - /4] [/6 - /6] [/7 - /7] [/9 - /9]; tight)]
           ├── variable: x:1 [type=int]
           └── tuple [type=tuple{int, int, int, int, int, int}]
                ├── const: 1 [type=int]
                ├── const: 2 [type=int]
                ├── const: 4 [type=int]
                ├── const: 6 [type=int]
                ├── const: 7 [type=int]
                └── const: 9 [type=int]

norm
SELECT * FROM xy WHERE x > 0 AND x <= 10
----
select
 ├── columns: x:1(int!null) y:2(int)
 ├── cardinality: [0 - 10]
 ├── key: (1)
 ├── fd: (1)-->(2)
 ├── prune: (2)
 ├── interesting orderings: (+1)
 ├── scan xy
 │    ├── columns: x:1(int!null) y:2(int)
 │    ├── key: (1)
 │    ├── fd: (1)-->(2)
 │    ├── prune: (1,2)
 │    └── interesting orderings: (+1)
 └── filters
      └── range [type=bool, outer=(1), constraints=(/1: [/1 - /10]; tight)]
           └── and [type=bool]
                ├── gt [type=bool]
                │    ├── variable: x:1 [type=int]
                │    └── const: 0 [type=int]
                └── le [type=bool]
                     ├── variable: x:1 [type=int]
                     └── const: 10 [type=int]

norm
SELECT * FROM xy WHERE y > 0 AND y <= 10
----
select
 ├── columns: x:1(int!null) y:2(int!null)
 ├── key: (1)
 ├── fd: (1)-->(2)
 ├── prune: (1)
 ├── interesting orderings: (+1)
 ├── scan xy
 │    ├── columns: x:1(int!null) y:2(int)
 │    ├── key: (1)
 │    ├── fd: (1)-->(2)
 │    ├── prune: (1,2)
 │    └── interesting orderings: (+1)
 └── filters
      └── range [type=bool, outer=(2), constraints=(/2: [/1 - /10]; tight)]
           └── and [type=bool]
                ├── gt [type=bool]
                │    ├── variable: y:2 [type=int]
                │    └── const: 0 [type=int]
                └── le [type=bool]
                     ├── variable: y:2 [type=int]
                     └── const: 10 [type=int]

# Verify that a and b are determined to be not null.
norm
SELECT * FROM ab WHERE a=b
----
select
 ├── columns: a:1(int!null) b:2(int!null)
 ├── fd: (1)==(2), (2)==(1)
 ├── scan ab
 │    ├── columns: a:1(int) b:2(int)
 │    └── prune: (1,2)
 └── filters
      └── eq [type=bool, outer=(1,2), constraints=(/1: (/NULL - ]; /2: (/NULL - ]), fd=(1)==(2), (2)==(1)]
           ├── variable: a:1 [type=int]
           └── variable: b:2 [type=int]

# Here we have the FD (b,c)==>(a).
build
SELECT * FROM abcde WHERE a=b+c
----
project
 ├── columns: a:1(int!null) b:2(int) c:3(int) d:4(decimal) e:5(string)
 ├── immutable
 ├── fd: (2,3)-->(1)
 ├── prune: (1-5)
 └── select
      ├── columns: a:1(int!null) b:2(int) c:3(int) d:4(decimal) e:5(string) rowid:6(int!null) crdb_internal_mvcc_timestamp:7(decimal) tableoid:8(oid)
      ├── immutable
      ├── key: (6)
      ├── fd: (6)-->(1-5,7,8), (2,3)-->(1)
      ├── prune: (4-8)
      ├── interesting orderings: (+6)
      ├── scan abcde
      │    ├── columns: a:1(int) b:2(int) c:3(int) d:4(decimal) e:5(string) rowid:6(int!null) crdb_internal_mvcc_timestamp:7(decimal) tableoid:8(oid)
      │    ├── key: (6)
      │    ├── fd: (6)-->(1-5,7,8)
      │    ├── prune: (1-8)
      │    └── interesting orderings: (+6)
      └── filters
           └── eq [type=bool, outer=(1-3), immutable, constraints=(/1: (/NULL - ]), fd=(2,3)-->(1)]
                ├── variable: a:1 [type=int]
                └── plus [type=int]
                     ├── variable: b:2 [type=int]
                     └── variable: c:3 [type=int]

# No FD from the equality.
build
SELECT * FROM abcde WHERE a=a/2+b
----
project
 ├── columns: a:1(int!null) b:2(int) c:3(int) d:4(decimal) e:5(string)
 ├── immutable
 ├── prune: (1-5)
 └── select
      ├── columns: a:1(int!null) b:2(int) c:3(int) d:4(decimal) e:5(string) rowid:6(int!null) crdb_internal_mvcc_timestamp:7(decimal) tableoid:8(oid)
      ├── immutable
      ├── key: (6)
      ├── fd: (6)-->(1-5,7,8)
      ├── prune: (3-8)
      ├── interesting orderings: (+6)
      ├── scan abcde
      │    ├── columns: a:1(int) b:2(int) c:3(int) d:4(decimal) e:5(string) rowid:6(int!null) crdb_internal_mvcc_timestamp:7(decimal) tableoid:8(oid)
      │    ├── key: (6)
      │    ├── fd: (6)-->(1-5,7,8)
      │    ├── prune: (1-8)
      │    └── interesting orderings: (+6)
      └── filters
           └── eq [type=bool, outer=(1,2), immutable, constraints=(/1: (/NULL - ])]
                ├── variable: a:1 [type=int]
                └── plus [type=decimal]
                     ├── div [type=decimal]
                     │    ├── variable: a:1 [type=int]
                     │    └── const: 2 [type=int]
                     └── variable: b:2 [type=int]

# (b)==>(e).
build
SELECT * FROM abcde WHERE e=b::string
----
project
 ├── columns: a:1(int) b:2(int) c:3(int) d:4(decimal) e:5(string!null)
 ├── immutable
 ├── fd: (2)-->(5)
 ├── prune: (1-5)
 └── select
      ├── columns: a:1(int) b:2(int) c:3(int) d:4(decimal) e:5(string!null) rowid:6(int!null) crdb_internal_mvcc_timestamp:7(decimal) tableoid:8(oid)
      ├── immutable
      ├── key: (6)
      ├── fd: (6)-->(1-5,7,8), (2)-->(5)
      ├── prune: (1,3,4,6-8)
      ├── interesting orderings: (+6)
      ├── scan abcde
      │    ├── columns: a:1(int) b:2(int) c:3(int) d:4(decimal) e:5(string) rowid:6(int!null) crdb_internal_mvcc_timestamp:7(decimal) tableoid:8(oid)
      │    ├── key: (6)
      │    ├── fd: (6)-->(1-5,7,8)
      │    ├── prune: (1-8)
      │    └── interesting orderings: (+6)
      └── filters
           └── eq [type=bool, outer=(2,5), immutable, constraints=(/5: (/NULL - ]), fd=(2)-->(5)]
                ├── variable: e:5 [type=string]
                └── cast: STRING [type=string]
                     └── variable: b:2 [type=int]

# We don't want (d)==>(e), it would not be correct (consider 1.0 and 1.00).
build
SELECT * FROM abcde WHERE e=d::string
----
project
 ├── columns: a:1(int) b:2(int) c:3(int) d:4(decimal) e:5(string!null)
 ├── immutable
 ├── prune: (1-5)
 └── select
      ├── columns: a:1(int) b:2(int) c:3(int) d:4(decimal) e:5(string!null) rowid:6(int!null) crdb_internal_mvcc_timestamp:7(decimal) tableoid:8(oid)
      ├── immutable
      ├── key: (6)
      ├── fd: (6)-->(1-5,7,8)
      ├── prune: (1-3,6-8)
      ├── interesting orderings: (+6)
      ├── scan abcde
      │    ├── columns: a:1(int) b:2(int) c:3(int) d:4(decimal) e:5(string) rowid:6(int!null) crdb_internal_mvcc_timestamp:7(decimal) tableoid:8(oid)
      │    ├── key: (6)
      │    ├── fd: (6)-->(1-5,7,8)
      │    ├── prune: (1-8)
      │    └── interesting orderings: (+6)
      └── filters
           └── eq [type=bool, outer=(4,5), immutable, constraints=(/5: (/NULL - ])]
                ├── variable: e:5 [type=string]
                └── cast: STRING [type=string]
                     └── variable: d:4 [type=decimal]
