diff --git a/pkg/sql/sem/tree/eval.go b/pkg/sql/sem/tree/eval.go index a5bcc688c2f8..ece9dda35235 100644 --- a/pkg/sql/sem/tree/eval.go +++ b/pkg/sql/sem/tree/eval.go @@ -3670,7 +3670,9 @@ func (expr *ComparisonExpr) Eval(ctx *EvalContext) (Datum, error) { if op.hasSubOperator() { var datums Datums // Right is either a tuple or an array of Datums. - if tuple, ok := AsDTuple(right); ok { + if !expr.fn.NullableArgs && right == DNull { + return DNull, nil + } else if tuple, ok := AsDTuple(right); ok { datums = tuple.D } else if array, ok := AsDArray(right); ok { datums = array.Array diff --git a/pkg/sql/sem/tree/testdata/eval/any_some_all b/pkg/sql/sem/tree/testdata/eval/any_some_all index b54420534801..6ff7747072c2 100644 --- a/pkg/sql/sem/tree/testdata/eval/any_some_all +++ b/pkg/sql/sem/tree/testdata/eval/any_some_all @@ -70,6 +70,69 @@ eval ---- NULL +# Regression test for #37547 - ensure that null RHS of comparisons with +# suboperators are correctly handled. A null RHS always results in null. +eval +1 = ANY(NULL::int[]) +---- +NULL + +eval +1 = SOME(NULL::int[]) +---- +NULL + +eval +1 = ALL(NULL::int[]) +---- +NULL + +eval +NULL::int = ANY(NULL::int[]) +---- +NULL + +eval +NULL::int = SOME(NULL::int[]) +---- +NULL + +eval +NULL::int = ALL(NULL::int[]) +---- +NULL + +# A null LHS has different behavior if the array is empty or not +eval +NULL::int = ANY(ARRAY[1,2]) +---- +NULL + +eval +NULL::int = SOME(ARRAY[1,2]) +---- +NULL + +eval +NULL::int = ALL(ARRAY[1,2]) +---- +NULL + +eval +NULL::int = ANY(ARRAY[]::int[]) +---- +false + +eval +NULL::int = SOME(ARRAY[]::int[]) +---- +false + +eval +NULL::int = ALL(ARRAY[]::int[]) +---- +true + eval 1 = ALL (ARRAY[1, 2, NULL]) ----