This is an automated email from the ASF dual-hosted git repository.
Mryange pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new 4af60fe073c [fix](expr) Enforce nullable column output matching
(#68388)
4af60fe073c is described below
commit 4af60fe073c3fb039de8d2b396efa29e132fcdaf
Author: Mryange <[email protected]>
AuthorDate: Wed Sep 23 14:31:51 2026 +0800
[fix](expr) Enforce nullable column output matching (#68388)
### What problem does this PR solve?
Issue Number: None
Related PR: None
Problem Summary: VExpr::execute_column accepted a non-nullable column
when the expression declared Nullable(T), even though DataTypeNullable
requires a ColumnNullable representation. Remove this expression-only
fallback so data type nullability and column nullability remain aligned.
### Release note
None
### Check List (For Author)
- Test: No need to test (pipeline validation requested)
- Behavior changed: Yes (strictly enforce nullable column output
matching)
- Does this need documentation: No
---
be/src/exprs/vexpr.cpp | 12 +++---------
be/test/exprs/vexpr_test.cpp | 6 +++---
2 files changed, 6 insertions(+), 12 deletions(-)
diff --git a/be/src/exprs/vexpr.cpp b/be/src/exprs/vexpr.cpp
index 557d04a4e1f..e49bb037865 100644
--- a/be/src/exprs/vexpr.cpp
+++ b/be/src/exprs/vexpr.cpp
@@ -1074,16 +1074,10 @@ Status VExpr::execute_column(VExprContext* context,
const Block* block, const Se
if (!check_and_get_column<ColumnNothing>(result_column.get())) {
auto result_type = execute_type(block);
if (result_type != nullptr) {
- Status st = result_type->check_column(*result_column);
- if (!st.ok()) {
- // Nullable(T) may legitimately produce a non-nullable T
column when all rows are
- // non-null (use_default_implementation_for_nulls
optimization). Allow this.
- const auto* nullable_type =
-
check_and_get_data_type<DataTypeNullable>(result_type.get());
- if (nullable_type &&
!check_and_get_column<ColumnNullable>(result_column.get())) {
- st =
nullable_type->get_nested_type()->check_column(*result_column);
- }
+ if (result_type->is_nullable() && !result_column->is_nullable()) {
+ result_column = make_nullable(result_column, false);
}
+ Status st = result_type->check_column(*result_column);
if (!st.ok()) {
return Status::InternalError(
"Expr {} return column type mismatch: declared={},
actual={}", expr_name(),
diff --git a/be/test/exprs/vexpr_test.cpp b/be/test/exprs/vexpr_test.cpp
index 10bdfb815d7..6138fc89ea3 100644
--- a/be/test/exprs/vexpr_test.cpp
+++ b/be/test/exprs/vexpr_test.cpp
@@ -893,11 +893,10 @@ TEST(VExprExecuteColumnTest, TypeMismatchFails) {
EXPECT_FALSE(st.ok());
}
-TEST(VExprExecuteColumnTest, NullableTypeWithNonNullableColumnPasses) {
+TEST(VExprExecuteColumnTest, NullableTypeWithNonNullableColumnIsWrapped) {
using namespace doris;
FakeVExpr expr;
- // Declared type is Nullable(Int32) but result is Int32 (non-nullable).
- // This mirrors the use_default_implementation_for_nulls optimization and
must pass.
+ // Declared type is Nullable(Int32), so the result must carry a nullable
column wrapper.
expr.set_data_type(std::make_shared<DataTypeNullable>(std::make_shared<DataTypeInt32>()));
auto col = ColumnInt32::create();
@@ -907,6 +906,7 @@ TEST(VExprExecuteColumnTest,
NullableTypeWithNonNullableColumnPasses) {
ColumnPtr result;
auto st = expr.execute_column(nullptr, nullptr, nullptr, 1, result);
EXPECT_TRUE(st.ok());
+ EXPECT_TRUE(result->is_nullable());
}
TEST(VExprExecuteColumnTest, ColumnNothingPassesTypeCheck) {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]