From 985514a2a7a8feabac267ffbcee2dede1985575d 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 6203890a22dc..cae4a20b7915 100644 --- a/pkg/sql/colexec/colbuilder/execplan.go +++ b/pkg/sql/colexec/colbuilder/execplan.go @@ -2762,11 +2762,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 5b2067ca363e..77d07919866e 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