diff --git a/be/src/vec/data_types/serde/data_type_date_or_datetime_serde.cpp b/be/src/vec/data_types/serde/data_type_date_or_datetime_serde.cpp index 2c0fefdfca9e4d..89c72cbc4680d4 100644 --- a/be/src/vec/data_types/serde/data_type_date_or_datetime_serde.cpp +++ b/be/src/vec/data_types/serde/data_type_date_or_datetime_serde.cpp @@ -408,7 +408,15 @@ Status DataTypeDateSerDe::from_olap_string(const std::string& str, Field& fie // Exception! if (!CastToDateOrDatetime::from_string_non_strict_mode( StringRef(str), res, options.timezone, params)) [[unlikely]] { - return Status::InvalidArgument("parse date or datetime fail, string: '{}'", str); + // Keep the same datelike Field-parser convention as DateV2/DateTimeV2: invalid OLAP + // strings fall back to the type-specific minimum. VecDateTimeValue stores DateV1 and + // DateTimeV1 values, whose minimum valid date is FIRST_DAY. + res = VecDateTimeValue::FIRST_DAY; + if constexpr (IsDatetime) { + res.to_datetime(); + } else { + res.cast_to_date(); + } } field = Field::create_field(std::move(res)); return Status::OK(); diff --git a/be/src/vec/data_types/serde/data_type_datetimev2_serde.cpp b/be/src/vec/data_types/serde/data_type_datetimev2_serde.cpp index 6cc0958e5e1e6a..adaa5804ddc0c5 100644 --- a/be/src/vec/data_types/serde/data_type_datetimev2_serde.cpp +++ b/be/src/vec/data_types/serde/data_type_datetimev2_serde.cpp @@ -130,6 +130,7 @@ Status DataTypeDateTimeV2SerDe::from_olap_string(const std::string& str, Field& std::string date_format = "%Y-%m-%d %H:%i:%s.%f"; if (!res.from_date_format_str(date_format.data(), date_format.size(), str.data(), str.size())) { + // On parse failure, fall back to MIN_DATETIME_V2, the packed lower-bound DateTimeV2 value. res = DateV2Value(MIN_DATETIME_V2); } field = Field::create_field(std::move(res)); diff --git a/be/src/vec/data_types/serde/data_type_datev2_serde.cpp b/be/src/vec/data_types/serde/data_type_datev2_serde.cpp index 1a7a9fed56aae5..4394e397abec72 100644 --- a/be/src/vec/data_types/serde/data_type_datev2_serde.cpp +++ b/be/src/vec/data_types/serde/data_type_datev2_serde.cpp @@ -242,6 +242,7 @@ Status DataTypeDateV2SerDe::from_olap_string(const std::string& str, Field& fiel ((time_tm.tm_year + 1900) << 9) | ((time_tm.tm_mon + 1) << 5) | time_tm.tm_mday; res = DateV2Value(value); } else { + // On parse failure, fall back to MIN_DATE_V2, the packed lower-bound DateV2 value. res = DateV2Value(MIN_DATE_V2); } field = Field::create_field(std::move(res)); diff --git a/be/test/olap/olap_type_test.cpp b/be/test/olap/olap_type_test.cpp index cc406375bd9a1c..a35f41a1469fd2 100644 --- a/be/test/olap/olap_type_test.cpp +++ b/be/test/olap/olap_type_test.cpp @@ -24,7 +24,11 @@ #include "gtest/gtest_pred_impl.h" #include "olap/olap_common.h" #include "olap/types.h" +#include "vec/core/field.h" +#include "vec/data_types/data_type_factory.hpp" +#include "vec/data_types/serde/data_type_serde.h" #include "vec/functions/cast/cast_to_string.h" +#include "vec/runtime/vdatetime_value.h" namespace doris { @@ -39,6 +43,16 @@ class OlapTypeTest : public testing::Test { } }; +static void expect_from_olap_string_default(const vectorized::DataTypePtr& data_type, + const std::string& input, + const vectorized::Field& expected_field) { + vectorized::Field field; + vectorized::DataTypeSerDe::FormatOptions options; + auto status = data_type->get_serde()->from_olap_string(input, field, options); + ASSERT_TRUE(status.ok()) << data_type->get_name() << " failed: " << status.to_string(); + EXPECT_EQ(field, expected_field) << data_type->get_name(); +} + // deserialize float string serialized by old version of Doris TEST_F(OlapTypeTest, deser_float_old) { std::vector normal_input_values = { @@ -576,4 +590,31 @@ TEST_F(OlapTypeTest, ser_deser_double) { << ", diff_ratio: " << fmt::format("{:.17g}", diff_ratio); } } -} // namespace doris \ No newline at end of file + +TEST_F(OlapTypeTest, datelike_from_olap_string_parse_failure_defaults) { + const std::string invalid = "not-a-valid-datelike-value"; + + auto datev1_default = VecDateTimeValue::FIRST_DAY; + datev1_default.cast_to_date(); + expect_from_olap_string_default( + vectorized::DataTypeFactory::instance().create_data_type(TYPE_DATE, false), invalid, + vectorized::Field::create_field(datev1_default)); + + auto datetimev1_default = VecDateTimeValue::FIRST_DAY; + datetimev1_default.to_datetime(); + expect_from_olap_string_default( + vectorized::DataTypeFactory::instance().create_data_type(TYPE_DATETIME, false), invalid, + vectorized::Field::create_field(datetimev1_default)); + + expect_from_olap_string_default( + vectorized::DataTypeFactory::instance().create_data_type(TYPE_DATEV2, false), invalid, + vectorized::Field::create_field( + DateV2Value(MIN_DATE_V2))); + + expect_from_olap_string_default( + vectorized::DataTypeFactory::instance().create_data_type(TYPE_DATETIMEV2, false), + invalid, + vectorized::Field::create_field( + DateV2Value(MIN_DATETIME_V2))); +} +} // namespace doris