From 6c8a11b9d907670a797f5c501b55a714294fb21c Mon Sep 17 00:00:00 2001 From: Marcus Gartner Date: Wed, 5 Nov 2025 15:07:15 -0500 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 30b1b7e78a8b..7bb4279c0db1 100644 --- a/pkg/sql/logictest/testdata/logic_test/vectorize +++ b/pkg/sql/logictest/testdata/logic_test/vectorize @@ -1348,3 +1348,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