From d610375fd6fc0e4185a5cab7503622f4b9a8603d Mon Sep 17 00:00:00 2001 From: Rafi Shamim Date: Thu, 23 May 2019 11:56:29 -0400 Subject: [PATCH] tree: handle null in suboperator expressions Before this change, a null right operand in a suboperator would cause an unhandled error. We were receiving stack trace reports from the wild. Add a test and fix it. Also add a few additional tests to verify correct behavior with a null left operand. Release note (bug fix): a null right operand now causes the suboperator expression to return null --- pkg/sql/sem/tree/eval.go | 4 +- pkg/sql/sem/tree/testdata/eval/any_some_all | 63 +++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) 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]) ----