diff --git a/pkg/sql/opt/norm/reject_nulls_funcs.go b/pkg/sql/opt/norm/reject_nulls_funcs.go index a368ea46246d..784681ab360a 100644 --- a/pkg/sql/opt/norm/reject_nulls_funcs.go +++ b/pkg/sql/opt/norm/reject_nulls_funcs.go @@ -214,9 +214,10 @@ func DeriveRejectNullCols(in memo.RelExpr, disabledRules intsets.Fast) opt.ColSe relProps.Rule.RejectNullCols.UnionWith(deriveScanRejectNullCols(in)) } - if relProps.Rule.RejectNullCols.Intersects(relProps.NotNullCols) { - panic(errors.AssertionFailedf("null rejection requested on non-null column")) - } + // Don't attempt to request null-rejection for non-null cols. This can happen + // if normalization failed to null-reject, and then exploration "uncovered" + // the possibility for null-rejection of a column. + relProps.Rule.RejectNullCols.DifferenceWith(relProps.NotNullCols) return relProps.Rule.RejectNullCols } diff --git a/pkg/sql/opt/norm/testdata/rules/reject_nulls b/pkg/sql/opt/norm/testdata/rules/reject_nulls index fc90b4046727..42fc00ddbcdf 100644 --- a/pkg/sql/opt/norm/testdata/rules/reject_nulls +++ b/pkg/sql/opt/norm/testdata/rules/reject_nulls @@ -1691,3 +1691,60 @@ project ├── 0 [as="?column?":66] ├── '23:43:20-08:00:00' [as="?column?":67] └── '2026-09-17 11:54:13.000946' [as=col_12038:68] + +# Regression test for #100559 - don't panic when exploration uncovers possible +# null-rejection that normalization failed to find. +exec-ddl +CREATE TABLE t0_100559 (c0 INTERVAL); +---- + +exec-ddl +CREATE TABLE t1_100559 (c0 INTERVAL); +---- + +exec-ddl +CREATE TABLE t2_100559 (c0 FLOAT); +---- + +opt +SELECT t1_100559.c0 AS c0 FROM t0_100559, t2_100559 +FULL OUTER JOIN t1_100559 ON true +WHERE ( + ((t0_100559.c0) IN (t1_100559.c0)) + AND ((t2_100559.c0) IN (SELECT STDDEV(t2_100559.c0) FROM t2_100559)) +); +---- +project + ├── columns: c0:9!null + └── inner-join (hash) + ├── columns: t0_100559.c0:1!null t2_100559.c0:5!null t1_100559.c0:9!null + ├── fd: (1)==(9), (9)==(1) + ├── right-join (cross) + │ ├── columns: t2_100559.c0:5!null t1_100559.c0:9 + │ ├── scan t1_100559 + │ │ └── columns: t1_100559.c0:9 + │ ├── semi-join (hash) + │ │ ├── columns: t2_100559.c0:5!null + │ │ ├── select + │ │ │ ├── columns: t2_100559.c0:5!null + │ │ │ ├── scan t2_100559 + │ │ │ │ └── columns: t2_100559.c0:5 + │ │ │ └── filters + │ │ │ └── t2_100559.c0:5 IS NOT NULL [outer=(5), constraints=(/5: (/NULL - ]; tight)] + │ │ ├── scalar-group-by + │ │ │ ├── columns: stddev:17 + │ │ │ ├── cardinality: [1 - 1] + │ │ │ ├── key: () + │ │ │ ├── fd: ()-->(17) + │ │ │ ├── scan t2_100559 + │ │ │ │ └── columns: t2_100559.c0:13 + │ │ │ └── aggregations + │ │ │ └── std-dev [as=stddev:17, outer=(13)] + │ │ │ └── t2_100559.c0:13 + │ │ └── filters + │ │ └── t2_100559.c0:5 = stddev:17 [outer=(5,17), constraints=(/5: (/NULL - ]; /17: (/NULL - ]), fd=(5)==(17), (17)==(5)] + │ └── filters (true) + ├── scan t0_100559 + │ └── columns: t0_100559.c0:1 + └── filters + └── t0_100559.c0:1 = t1_100559.c0:9 [outer=(1,9), constraints=(/1: (/NULL - ]; /9: (/NULL - ]), fd=(1)==(9), (9)==(1)]