exec-ddl
CREATE TABLE xy (x INT PRIMARY KEY, y INT)
----
TABLE xy
 ├── x int not null
 ├── y int
 └── INDEX primary
      └── x int not null

exec-ddl
CREATE TABLE kuv (k INT PRIMARY KEY, u FLOAT, v STRING)
----
TABLE kuv
 ├── k int not null
 ├── u float
 ├── v string
 └── INDEX primary
      └── k int not null

build
SELECT * FROM xy WHERE x=1
----
select
 ├── columns: x:1(int!null) y:2(int)
 ├── cardinality: [0 - 1]
 ├── key: ()
 ├── 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
      └── eq [type=bool, outer=(1), constraints=(/1: [/1 - /1]; tight), fd=()-->(1)]
           ├── variable: x [type=int]
           └── const: 1 [type=int]

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

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

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

build
SELECT * FROM xy WITH ORDINALITY
----
row-number
 ├── columns: x:1(int!null) y:2(int) ordinality:3(int!null)
 ├── key: (1)
 ├── fd: (1)-->(2,3), (3)-->(1,2)
 ├── prune: (1,2)
 └── scan xy
      ├── columns: x:1(int!null) y:2(int)
      ├── key: (1)
      ├── fd: (1)-->(2)
      ├── prune: (1,2)
      └── 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)
----
TABLE abcd
 ├── a int not null
 ├── b int not null
 ├── c int
 ├── d int
 ├── rowid int not null (hidden)
 └── INDEX primary
      └── rowid int not null (hidden)

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)
      ├── key: (5)
      ├── fd: (5)-->(1-4)
      ├── prune: (1-5)
      ├── interesting orderings: (+5)
      ├── scan abcd
      │    ├── columns: a:1(int!null) b:2(int!null) c:3(int) d:4(int) rowid:5(int!null)
      │    ├── key: (5)
      │    ├── fd: (5)-->(1-4)
      │    ├── prune: (1-5)
      │    └── 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)
      ├── key: (5)
      ├── fd: (5)-->(1-4)
      ├── prune: (1,2,4,5)
      ├── interesting orderings: (+5)
      ├── scan abcd
      │    ├── columns: a:1(int!null) b:2(int!null) c:3(int) d:4(int) rowid:5(int!null)
      │    ├── key: (5)
      │    ├── fd: (5)-->(1-4)
      │    ├── prune: (1-5)
      │    └── interesting orderings: (+5)
      └── filters
           └── is-not [type=bool, outer=(3), constraints=(/3: (/NULL - ]; tight)]
                ├── variable: c [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)
      ├── key: (5)
      ├── fd: (5)-->(1-4), (3)==(4), (4)==(3)
      ├── prune: (1,2,5)
      ├── interesting orderings: (+5)
      ├── scan abcd
      │    ├── columns: a:1(int!null) b:2(int!null) c:3(int) d:4(int) rowid:5(int!null)
      │    ├── key: (5)
      │    ├── fd: (5)-->(1-4)
      │    ├── prune: (1-5)
      │    └── interesting orderings: (+5)
      └── filters
           └── eq [type=bool, outer=(3,4), constraints=(/3: (/NULL - ]; /4: (/NULL - ]), fd=(3)==(4), (4)==(3)]
                ├── variable: c [type=int]
                └── variable: d [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)
      ├── key: (5)
      ├── fd: (5)-->(1-4)
      ├── prune: (2,4,5)
      ├── interesting orderings: (+5)
      ├── scan abcd
      │    ├── columns: a:1(int!null) b:2(int!null) c:3(int) d:4(int) rowid:5(int!null)
      │    ├── key: (5)
      │    ├── fd: (5)-->(1-4)
      │    ├── prune: (1-5)
      │    └── interesting orderings: (+5)
      └── filters
           └── gt [type=bool, outer=(1,3), constraints=(/1: (/NULL - ]; /3: (/NULL - ])]
                ├── variable: a [type=int]
                └── variable: c [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)
 │         ├── key: (5)
 │         ├── fd: (5)-->(1-4), (1)==(3), (3)==(1)
 │         ├── prune: (2,4,5)
 │         ├── interesting orderings: (+5)
 │         ├── scan abcd
 │         │    ├── columns: a:1(int!null) b:2(int!null) c:3(int) d:4(int) rowid:5(int!null)
 │         │    ├── key: (5)
 │         │    ├── fd: (5)-->(1-4)
 │         │    ├── prune: (1-5)
 │         │    └── interesting orderings: (+5)
 │         └── filters
 │              └── eq [type=bool, outer=(1,3), constraints=(/1: (/NULL - ]; /3: (/NULL - ]), fd=(1)==(3), (3)==(1)]
 │                   ├── variable: a [type=int]
 │                   └── variable: c [type=int]
 └── filters
      └── lt [type=bool, outer=(2,4), constraints=(/2: (/NULL - ]; /4: (/NULL - ])]
           ├── variable: b [type=int]
           └── variable: d [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)
      ├── key: (5)
      ├── fd: (5)-->(1-4)
      ├── prune: (1,3-5)
      ├── interesting orderings: (+5)
      ├── scan abcd
      │    ├── columns: a:1(int!null) b:2(int!null) c:3(int) d:4(int) rowid:5(int!null)
      │    ├── key: (5)
      │    ├── fd: (5)-->(1-4)
      │    ├── prune: (1-5)
      │    └── interesting orderings: (+5)
      └── filters
           └── gt [type=bool, outer=(2), correlated-subquery]
                ├── subquery [type=int]
                │    └── max1-row
                │         ├── columns: count_rows:8(int)
                │         ├── outer: (2)
                │         ├── cardinality: [1 - 1]
                │         ├── key: ()
                │         ├── fd: ()-->(8)
                │         └── scalar-group-by
                │              ├── columns: count_rows:8(int)
                │              ├── outer: (2)
                │              ├── cardinality: [1 - 1]
                │              ├── key: ()
                │              ├── fd: ()-->(8)
                │              ├── prune: (8)
                │              ├── project
                │              │    ├── outer: (2)
                │              │    └── select
                │              │         ├── columns: x:6(int!null) y:7(int!null)
                │              │         ├── outer: (2)
                │              │         ├── key: (6)
                │              │         ├── fd: ()-->(7)
                │              │         ├── prune: (6)
                │              │         ├── interesting orderings: (+6)
                │              │         ├── scan xy
                │              │         │    ├── columns: x:6(int!null) y:7(int)
                │              │         │    ├── key: (6)
                │              │         │    ├── fd: (6)-->(7)
                │              │         │    ├── prune: (6,7)
                │              │         │    └── interesting orderings: (+6)
                │              │         └── filters
                │              │              └── eq [type=bool, outer=(2,7), constraints=(/2: (/NULL - ]; /7: (/NULL - ]), fd=(2)==(7), (7)==(2)]
                │              │                   ├── variable: y [type=int]
                │              │                   └── variable: b [type=int]
                │              └── aggregations
                │                   └── count-rows [type=int]
                └── const: 0 [type=int]

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

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