diff --git a/pkg/sql/colexec/colbuilder/execplan.go b/pkg/sql/colexec/colbuilder/execplan.go index 81dc415adb8b..e43d5260872a 100644 --- a/pkg/sql/colexec/colbuilder/execplan.go +++ b/pkg/sql/colexec/colbuilder/execplan.go @@ -2828,11 +2828,16 @@ func planProjectionExpr( resultIdx = len(typs) // The projection result will be outputted to a new column which is // appended to the input batch. - // TODO(#127814): We may need to handle the case when the left is DNull. - op, err = colexecprojconst.GetProjectionLConstOperator( - allocator, typs, left.ResolvedType(), outputType, projOp, input, - rightIdx, lConstArg, resultIdx, evalCtx, binOp, cmpExpr, calledOnNullInput, - ) + if !calledOnNullInput && (left == tree.DNull || right == tree.DNull) { + // If the left or right is NULL and the operator is not called on + // NULL, simply project NULL. + op = colexecbase.NewConstNullOp(allocator, outputType, input, resultIdx) + } else { + op, err = colexecprojconst.GetProjectionLConstOperator( + allocator, typs, left.ResolvedType(), outputType, projOp, input, + rightIdx, lConstArg, resultIdx, evalCtx, binOp, cmpExpr, calledOnNullInput, + ) + } } else { var leftIdx int input, leftIdx, typs, err = planProjectionOperators( diff --git a/pkg/sql/logictest/testdata/logic_test/vectorize b/pkg/sql/logictest/testdata/logic_test/vectorize index d8b92a436c1c..ebd99e09fc4b 100644 --- a/pkg/sql/logictest/testdata/logic_test/vectorize +++ b/pkg/sql/logictest/testdata/logic_test/vectorize @@ -1343,3 +1343,26 @@ statement ok RESET vectorize subtest end + +# Regression test for #152771. Gracefully plan operators that cannot handle NULL +# inputs. +statement ok +CREATE TABLE t152771 (i INT) + +statement ok +INSERT INTO t152771 VALUES (0) + +statement ok +SET plan_cache_mode = force_generic_plan + +statement ok +PREPARE p(INT, INT, INT, INT) AS UPDATE t152771 SET i=($1-$2)+($3-$4) + +statement ok +EXECUTE p(NULL, 3, 33, NULL) + +statement ok +DEALLOCATE p + +statement ok +RESET plan_cache_mode