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 6bcef49165b [fix](function) Handle relative day constants and nulls
(#68001)
6bcef49165b is described below
commit 6bcef49165be8ed5a0828dd85ef4702b07ca17fe
Author: Mryange <[email protected]>
AuthorDate: Fri Sep 18 14:52:24 2026 +0800
[fix](function) Handle relative day constants and nulls (#68001)
`next_day` and `previous_day` reused a mutated date value when the date
argument was constant, producing cumulative cross-row results. Nullable
inputs were also unpacked before execution, causing NULL weekday rows to
be parsed as empty strings and fail the entire query. The functions now
use `ColumnView` to handle constant and nullable columns directly,
compute each row from an independent date value, propagate NULL results,
and continue rejecting invalid non-NULL weekdays.
### Release note
None
### Check List (For Author)
- Test <!-- At least one of them must be included. -->
- [ ] Regression test
- [ ] Unit Test
- [ ] Manual test (add detailed scripts or steps below)
- [ ] No need to test or manual test. Explain why:
- [ ] This is a refactor/code format and no logic has been changed.
- [ ] Previous test can cover this change.
- [ ] No code files have been changed.
- [ ] Other reason <!-- Add your reason? -->
- Behavior changed:
- [ ] No.
- [ ] Yes. <!-- Explain the behavior change -->
- Does this need documentation?
- [ ] No.
- [ ] Yes. <!-- Add document PR link here. eg:
https://github.com/apache/doris-website/pull/1214 -->
### Check List (For Reviewer who merge this PR)
- [ ] Confirm the release note
- [ ] Confirm test cases
- [ ] Confirm document
- [ ] Add branch pick label <!-- Add branch pick label that this PR
should merge into -->
---
.../function_date_or_datetime_computation.h | 90 ++++++++++------------
be/test/exprs/function/function_time_test.cpp | 18 +++++
.../string_functions/test_next_day.out | 8 +-
.../string_functions/test_previous_day.out | 4 +-
4 files changed, 65 insertions(+), 55 deletions(-)
diff --git a/be/src/exprs/function/function_date_or_datetime_computation.h
b/be/src/exprs/function/function_date_or_datetime_computation.h
index 15643880c0a..a056fe482e5 100644
--- a/be/src/exprs/function/function_date_or_datetime_computation.h
+++ b/be/src/exprs/function/function_date_or_datetime_computation.h
@@ -1759,33 +1759,47 @@ public:
String get_name() const override { return name; }
size_t get_number_of_arguments() const override { return 2; }
DataTypePtr get_return_type_impl(const ColumnsWithTypeAndName& arguments)
const override {
- return std::make_shared<DataTypeDateV2>();
+ auto result = std::make_shared<DataTypeDateV2>();
+ if (arguments[0].type->is_nullable() ||
arguments[1].type->is_nullable()) {
+ return make_nullable(std::move(result));
+ }
+ return result;
}
+ bool use_default_implementation_for_nulls() const override { return false;
}
+
Status execute_impl(FunctionContext* context, Block& block, const
ColumnNumbers& arguments,
uint32_t result, size_t input_rows_count) const
override {
CHECK_EQ(arguments.size(), 2);
auto res = ColumnDateV2::create();
res->reserve(input_rows_count);
- const auto& [left_col, left_const] =
- unpack_if_const(block.get_by_position(arguments[0]).column);
- const auto& [right_col, right_const] =
- unpack_if_const(block.get_by_position(arguments[1]).column);
- const auto& week_col = *assert_cast<const
ColumnString*>(right_col.get());
+ const auto& date_column = block.get_by_position(arguments[0]).column;
+ const auto& week_column = block.get_by_position(arguments[1]).column;
+ const auto result_nullable =
block.get_by_position(result).type->is_nullable();
+ ColumnUInt8::MutablePtr null_map;
+ if (result_nullable) {
+ null_map = ColumnUInt8::create(input_rows_count, 0);
+ }
Status status;
+ auto* null_map_data = null_map ? &null_map->get_data() : nullptr;
auto date_type =
block.get_by_position(arguments[0]).type->get_primitive_type();
if (date_type == TYPE_TIMESTAMP_NS) {
- status = execute_typed<ColumnTimeStampNs>(input_rows_count,
left_col, left_const,
- right_const, week_col,
*res);
+ status = execute_vector<TYPE_TIMESTAMP_NS>(input_rows_count,
date_column, week_column,
+ *res, null_map_data);
} else {
DORIS_CHECK_EQ(date_type, TYPE_DATEV2);
- status = execute_typed<ColumnDateV2>(input_rows_count, left_col,
left_const,
- right_const, week_col, *res);
+ status = execute_vector<TYPE_DATEV2>(input_rows_count,
date_column, week_column, *res,
+ null_map_data);
}
if (!status.ok()) {
return status;
}
- block.replace_by_position(result, std::move(res));
+ if (result_nullable) {
+ block.replace_by_position(result,
+ ColumnNullable::create(std::move(res),
std::move(null_map)));
+ } else {
+ block.replace_by_position(result, std::move(res));
+ }
return Status::OK();
}
@@ -1813,48 +1827,26 @@ private:
return Status::OK();
}
- template <typename DateColumn>
- static Status execute_typed(size_t input_rows_count, const ColumnPtr&
left_col, bool left_const,
- bool right_const, const ColumnString& week_col,
- ColumnDateV2& res_col) {
- const auto& date_col = *assert_cast<const DateColumn*>(left_col.get());
- if (left_const) {
- return execute_vector<true, false>(input_rows_count, date_col,
week_col, res_col);
- } else if (right_const) {
- return execute_vector<false, true>(input_rows_count, date_col,
week_col, res_col);
- }
- return execute_vector<false, false>(input_rows_count, date_col,
week_col, res_col);
- }
-
- template <bool left_const, bool right_const, typename DateColumn>
- static Status execute_vector(size_t input_rows_count, const DateColumn&
left_col,
- const ColumnString& right_col, ColumnDateV2&
res_col) {
- DateV2Value<DateV2ValueType> dtv;
- int week_day;
- if constexpr (left_const) {
- dtv = date_v2_from_date_like(left_col.get_element(0));
- }
- if constexpr (right_const) {
- auto week = right_col.get_data_at(0);
- week_day = day_of_week(week);
+ template <PrimitiveType DateType>
+ static Status execute_vector(size_t input_rows_count, const ColumnPtr&
date_column,
+ const ColumnPtr& week_column, ColumnDateV2&
res_col,
+ NullMap* null_map) {
+ const auto date_view = ColumnView<DateType>::create(date_column);
+ const auto week_view = ColumnView<TYPE_STRING>::create(week_column);
+ for (size_t i = 0; i < input_rows_count; ++i) {
+ if (date_view.is_null_at(i) || week_view.is_null_at(i)) {
+ DORIS_CHECK(null_map != nullptr);
+ (*null_map)[i] = 1;
+ res_col.insert_default();
+ continue;
+ }
+ auto dtv = date_v2_from_date_like(date_view.value_at(i));
+ auto week = week_view.value_at(i);
+ auto week_day = day_of_week(week);
if (week_day == 0) {
return Status::InvalidArgument("Function {} failed to parse
weekday: {}", name,
week);
}
- }
-
- for (size_t i = 0; i < input_rows_count; ++i) {
- if constexpr (!left_const) {
- dtv = date_v2_from_date_like(left_col.get_element(i));
- }
- if constexpr (!right_const) {
- auto week = right_col.get_data_at(i);
- week_day = day_of_week(week);
- if (week_day == 0) {
- return Status::InvalidArgument("Function {} failed to
parse weekday: {}", name,
- week);
- }
- }
RETURN_IF_ERROR(compute_relative_day(dtv, week_day));
res_col.insert_value(dtv);
}
diff --git a/be/test/exprs/function/function_time_test.cpp
b/be/test/exprs/function/function_time_test.cpp
index 6104ebd9954..7f44e5b0904 100644
--- a/be/test/exprs/function/function_time_test.cpp
+++ b/be/test/exprs/function/function_time_test.cpp
@@ -1817,6 +1817,24 @@ TEST(VTimestampFunctionsTest, next_day_test) {
}
}
+TEST(VTimestampFunctionsTest, relative_day_nullable_test) {
+ const InputTypeSet nullable_input_types = {Nullable
{PrimitiveType::TYPE_DATEV2},
+ Nullable
{PrimitiveType::TYPE_VARCHAR}};
+ const DataSet nullable_data_set = {
+ {{std::string("2024-01-01"), std::string("MON")},
std::string("2024-01-08")},
+ {{Null(), Null()}, Null()},
+ {{std::string("2024-01-01"), Null()}, Null()},
+ {{Null(), std::string("MON")}, Null()}};
+ static_cast<void>(check_function<DataTypeDateV2, true>("next_day",
nullable_input_types,
+ nullable_data_set));
+ static_cast<void>(check_function<DataTypeDateV2, true>(
+ "previous_day", nullable_input_types,
+ {{{std::string("2024-01-01"), std::string("MON")},
std::string("2023-12-25")},
+ {{Null(), Null()}, Null()},
+ {{std::string("2024-01-01"), Null()}, Null()},
+ {{Null(), std::string("MON")}, Null()}}));
+}
+
TEST(VTimestampFunctionsTest, from_iso8601_date) {
std::string func_name = "from_iso8601_date";
InputTypeSet input_types = {PrimitiveType::TYPE_VARCHAR};
diff --git
a/regression-test/data/query_p0/sql_functions/string_functions/test_next_day.out
b/regression-test/data/query_p0/sql_functions/string_functions/test_next_day.out
index 8bdb8678993..ae54fc34098 100644
---
a/regression-test/data/query_p0/sql_functions/string_functions/test_next_day.out
+++
b/regression-test/data/query_p0/sql_functions/string_functions/test_next_day.out
@@ -116,6 +116,8 @@
-- !const_other_nullable --
2025-01-02
+2025-01-02
+2025-01-02
2025-01-03
2025-01-03
2025-01-05
@@ -126,8 +128,6 @@
2025-01-08
2025-01-08
2025-01-08
-2025-01-09
-2025-01-09
-- !const_other_not_nullable --
0000-01-06
@@ -164,6 +164,8 @@
-- !const_partial_nullable_no_null --
2025-01-02
+2025-01-02
+2025-01-02
2025-01-03
2025-01-03
2025-01-05
@@ -174,8 +176,6 @@
2025-01-08
2025-01-08
2025-01-08
-2025-01-09
-2025-01-09
-- !wrong_date --
\N
diff --git
a/regression-test/data/query_p0/sql_functions/string_functions/test_previous_day.out
b/regression-test/data/query_p0/sql_functions/string_functions/test_previous_day.out
index 61027f2cf47..874ec15d85a 100644
---
a/regression-test/data/query_p0/sql_functions/string_functions/test_previous_day.out
+++
b/regression-test/data/query_p0/sql_functions/string_functions/test_previous_day.out
@@ -127,7 +127,7 @@
2024-12-30
2024-12-25
2024-12-26
-2024-12-24
+2024-12-31
2024-12-25
2024-12-25
2024-12-26
@@ -175,7 +175,7 @@
2024-12-30
2024-12-25
2024-12-26
-2024-12-24
+2024-12-31
2024-12-25
2024-12-25
2024-12-26
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]