From 6dd2e305324f1c572173bffa3038752882cf2c4b 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 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