[fix](cast) Add validity check for date conversion for non-vectorization (#12608)

actual result
select cast("0.0000031417" as date);
+------------------------------+
| CAST('0.0000031417' AS DATE) |
+------------------------------+
| 2000-00-00 |
+------------------------------+

expect result
select cast("0.0000031417" as date);
+------------------------------+
| CAST('0.0000031417' AS DATE) |
+------------------------------+
| NULL |
+------------------------------+
This commit is contained in:
yinzhijian
2022-09-16 09:08:53 +08:00
committed by GitHub
parent d906e97f1b
commit a97f63141e
7 changed files with 60 additions and 18 deletions

View File

@ -165,7 +165,10 @@ IntVal TimestampFunctions::day_of_month(FunctionContext* context, const DateTime
return IntVal::null();
}
const DateTimeValue& ts_value = DateTimeValue::from_datetime_val(ts_val);
return IntVal(ts_value.day());
if (ts_value.is_valid_date()) {
return IntVal(ts_value.day());
}
return IntVal::null();
}
IntVal TimestampFunctions::day_of_year(FunctionContext* context, const DateTimeVal& ts_val) {

View File

@ -54,15 +54,19 @@ bool DateTimeValue::check_range(uint32_t year, uint32_t month, uint32_t day, uin
uint16_t type) {
bool time = hour > (type == TIME_TIME ? TIME_MAX_HOUR : 23) || minute > 59 || second > 59 ||
microsecond > 999999;
return time || check_date(year, month, day);
if (type == TIME_TIME) {
return time;
} else {
return time || check_date(year, month, day);
}
}
bool DateTimeValue::check_date(uint32_t year, uint32_t month, uint32_t day) {
if (month != 0 && month <= 12 && day > s_days_in_month[month]) {
// Feb 29 in leap year is valid.
if (!(month == 2 && day == 29 && is_leap(year))) return true;
if (month == 2 && day == 29 && doris::is_leap(year)) return false;
if (year > 9999 || month == 0 || month > 12 || day > s_days_in_month[month] || day == 0) {
return true;
}
return year > 9999 || month > 12 || day > 31;
return false;
}
// The interval format is that with no delimiters

View File

@ -175,8 +175,18 @@ public:
_day(0),
_microsecond(0) {}
explicit DateTimeValue(int64_t t) { from_date_int64(t); }
explicit DateTimeValue(int64_t t)
: _neg(0),
_type(TIME_DATETIME),
_hour(0),
_minute(0),
_second(0),
_year(0),
_month(0),
_day(0),
_microsecond(0) {
from_date_int64(t);
}
void set_time(uint32_t year, uint32_t month, uint32_t day, uint32_t hour, uint32_t minute,
uint32_t second, uint32_t microsecond);

View File

@ -123,16 +123,14 @@ TEST_F(TimestampFunctionsTest, day_of_month_test) {
dtv1.set_type(TIME_DATETIME);
doris_udf::DateTimeVal tv1;
dtv1.to_datetime_val(&tv1);
EXPECT_EQ(false, TimestampFunctions::day_of_month(context, tv1).is_null);
EXPECT_EQ(1, TimestampFunctions::day_of_month(context, tv1).val);
EXPECT_EQ(true, TimestampFunctions::day_of_month(context, tv1).is_null);
// 2020-01-00 00:00:00
DateTimeValue dtv2(20200100000000);
dtv2.set_type(TIME_DATETIME);
doris_udf::DateTimeVal tv2;
dtv2.to_datetime_val(&tv2);
EXPECT_EQ(false, TimestampFunctions::day_of_month(context, tv2).is_null);
EXPECT_EQ(0, TimestampFunctions::day_of_month(context, tv2).val);
EXPECT_EQ(true, TimestampFunctions::day_of_month(context, tv2).is_null);
// 2020-02-29 00:00:00
DateTimeValue dtv3(20200229000000);

View File

@ -249,15 +249,15 @@ TEST_F(DateTimeValueTest, check_date) {
EXPECT_TRUE(value.from_date_int64(19880201));
value._month = 0;
EXPECT_FALSE(DateTimeValue::check_range(value.year(), value.month(), value.day(), value.hour(),
value.minute(), value.second(), value.microsecond(),
value.type()));
EXPECT_TRUE(DateTimeValue::check_range(value.year(), value.month(), value.day(), value.hour(),
value.minute(), value.second(), value.microsecond(),
value.type()));
value._month = 2;
value._day = 0;
EXPECT_FALSE(DateTimeValue::check_range(value.year(), value.month(), value.day(), value.hour(),
value.minute(), value.second(), value.microsecond(),
value.type()));
EXPECT_TRUE(DateTimeValue::check_range(value.year(), value.month(), value.day(), value.hour(),
value.minute(), value.second(), value.microsecond(),
value.type()));
value._year = 1987;
value._day = 29;
EXPECT_TRUE(DateTimeValue::check_range(value.year(), value.month(), value.day(), value.hour(),

View File

@ -5,3 +5,21 @@
-- !sql --
11
-- !sql --
2000-01-01T03:14:17
-- !sql --
\N
-- !sql --
1
-- !sql --
11
-- !sql --
2000-01-01T03:14:17
-- !sql --
\N

View File

@ -20,6 +20,15 @@ suite("test_cast_function") {
qt_sql """ select cast (1 as BIGINT) """
qt_sql """ select cast(cast ("11.2" as double) as bigint) """
qt_sql """ select cast ("0.0101031417" as datetime) """
qt_sql """ select cast ("0.0000031417" as datetime) """
sql """ SET enable_vectorized_engine = FALSE; """
qt_sql """ select cast (1 as BIGINT) """
qt_sql """ select cast(cast ("11.2" as double) as bigint) """
qt_sql """ select cast ("0.0101031417" as datetime) """
qt_sql """ select cast ("0.0000031417" as datetime) """
}