diff --git a/pkg/sql/opt/memo/logical_props_builder.go b/pkg/sql/opt/memo/logical_props_builder.go index 192388fb8de6..98f99745e092 100644 --- a/pkg/sql/opt/memo/logical_props_builder.go +++ b/pkg/sql/opt/memo/logical_props_builder.go @@ -1928,9 +1928,14 @@ func (b *logicalPropsBuilder) makeSetCardinality( card = props.Cardinality{Min: 0, Max: left.Max} card = card.Limit(right.Max) - case opt.ExceptOp, opt.ExceptAllOp: + case opt.ExceptOp: // Use left Max cardinality. card = props.Cardinality{Min: 0, Max: left.Max} + + case opt.ExceptAllOp: + // Use left Max cardinality. Cardinality cannot be less than left Min minus + // right Max. + card = props.Cardinality{Min: 0, Max: left.Max} if left.Min > right.Max { card.Min = left.Min - right.Max } diff --git a/pkg/sql/opt/memo/testdata/logprops/set b/pkg/sql/opt/memo/testdata/logprops/set index 948970af0e93..9ae1125d2cb2 100644 --- a/pkg/sql/opt/memo/testdata/logprops/set +++ b/pkg/sql/opt/memo/testdata/logprops/set @@ -585,3 +585,57 @@ except-all └── eq [type=bool, outer=(6,7), constraints=(/6: (/NULL - ]; /7: (/NULL - ]), fd=(6)==(7), (7)==(6)] ├── variable: a:6 [type=int] └── variable: b:7 [type=int] + +# Regression test for #89101. EXCEPT can have cardinality 0 even if left side +# has more rows than the right. +norm +VALUES (1), (1) EXCEPT VALUES (1) +---- +except + ├── columns: column1:1(int!null) + ├── left columns: column1:1(int!null) + ├── right columns: column1:2(int) + ├── cardinality: [0 - 2] + ├── key: (1) + ├── values + │ ├── columns: column1:1(int!null) + │ ├── cardinality: [2 - 2] + │ ├── prune: (1) + │ ├── tuple [type=tuple{int}] + │ │ └── const: 1 [type=int] + │ └── tuple [type=tuple{int}] + │ └── const: 1 [type=int] + └── values + ├── columns: column1:2(int!null) + ├── cardinality: [1 - 1] + ├── key: () + ├── fd: ()-->(2) + ├── prune: (2) + └── tuple [type=tuple{int}] + └── const: 1 [type=int] + +# EXCEPT ALL cannot have cardinality lower than min left - max right. +norm +VALUES (1), (1) EXCEPT ALL VALUES (1) +---- +except-all + ├── columns: column1:1(int!null) + ├── left columns: column1:1(int!null) + ├── right columns: column1:2(int) + ├── cardinality: [1 - 2] + ├── values + │ ├── columns: column1:1(int!null) + │ ├── cardinality: [2 - 2] + │ ├── prune: (1) + │ ├── tuple [type=tuple{int}] + │ │ └── const: 1 [type=int] + │ └── tuple [type=tuple{int}] + │ └── const: 1 [type=int] + └── values + ├── columns: column1:2(int!null) + ├── cardinality: [1 - 1] + ├── key: () + ├── fd: ()-->(2) + ├── prune: (2) + └── tuple [type=tuple{int}] + └── const: 1 [type=int]