From 6cbb6c843ea2a12b85709b40c570613885b304af Mon Sep 17 00:00:00 2001 From: Marcus Gartner Date: Wed, 5 Nov 2025 20:07:15 +0000 Subject: [PATCH] colexec: fix projections with constant NULL values This commit fixes a bug in the vectorized engine that caused internal errors when projections operated on constant NULL values. The proj_const_right_ops operators do not correctly handle NULL inputs. So, we avoid these code paths when operator does not operate on NULL values and the LHS or RHS of an operator is NULL by simply projecting NULLs. This is similar to the change made in #128123 and addresses a TODO added in that PR. This code path is unlikely to hit (maybe impossible) without generic query plans. In an optimized cusotm plan, the optimizer will fold expressions with `NULL` values at optimization time, and the execution engine will never see expressions of this form. Fixes #152771 Release note (bug fix): A bug has been fixed that could cause internal errors for queries using generic query plans with `NULL` placeholder values. --- pkg/sql/colexec/colbuilder/execplan.go | 15 ++++++++---- .../logictest/testdata/logic_test/vectorize | 23 +++++++++++++++++++ 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/pkg/sql/colexec/colbuilder/execplan.go b/pkg/sql/colexec/colbuilder/execplan.go index 8ef2ee6cf097..b22001cca247 100644 --- a/pkg/sql/colexec/colbuilder/execplan.go +++ b/pkg/sql/colexec/colbuilder/execplan.go @@ -2818,11 +2818,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