Skip to content

Commit

Permalink
fix: error data input for date(CAST(value AS DATETIME)) causing high … (
Browse files Browse the repository at this point in the history
  • Loading branch information
xzhangxian1008 authored Nov 17, 2022
1 parent 4257621 commit 72f1e57
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 121 deletions.
60 changes: 35 additions & 25 deletions dbms/src/Common/MyTime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,23 @@ int32_t adjustYear(int32_t year)
return year;
}

void scanTimeArgs(const std::vector<String> & seps, std::initializer_list<int *> && list)
bool scanTimeArgs(const std::vector<String> & seps, std::initializer_list<int *> && list)
{
int i = 0;
for (auto * ptr : list)
try
{
*ptr = std::stoi(seps[i]);
i++;
for (auto * ptr : list)
{
*ptr = std::stoi(seps[i]);
i++;
}
}
catch (std::exception & e)
{
return false;
}

return true;
}

// find index of fractional point.
Expand Down Expand Up @@ -631,7 +640,7 @@ std::pair<Field, bool> parseMyDateTimeAndJudgeIsDate(const String & str, int8_t
}
default:
{
throw TiFlashException("Wrong datetime format: " + str, Errors::Types::WrongValue);
return {Field(), is_date};
}
}
if (l == 5 || l == 6 || l == 8)
Expand Down Expand Up @@ -680,40 +689,44 @@ std::pair<Field, bool> parseMyDateTimeAndJudgeIsDate(const String & str, int8_t
}
if (truncated_or_incorrect)
{
throw TiFlashException("Datetime truncated: " + str, Errors::Types::Truncated);
return {Field(), is_date};
}
break;
}
case 3:
{
// YYYY-MM-DD
scanTimeArgs(seps, {&year, &month, &day});
if (!scanTimeArgs(seps, {&year, &month, &day}))
return {Field(), is_date};
is_date = true;
break;
}
case 4:
{
// YYYY-MM-DD HH
scanTimeArgs(seps, {&year, &month, &day, &hour});
if (!scanTimeArgs(seps, {&year, &month, &day, &hour}))
return {Field(), is_date};
break;
}
case 5:
{
// YYYY-MM-DD HH-MM
scanTimeArgs(seps, {&year, &month, &day, &hour, &minute});
if (!scanTimeArgs(seps, {&year, &month, &day, &hour, &minute}))
return {Field(), is_date};
break;
}
case 6:
{
// We don't have fractional seconds part.
// YYYY-MM-DD HH-MM-SS
scanTimeArgs(seps, {&year, &month, &day, &hour, &minute, &second});
if (!scanTimeArgs(seps, {&year, &month, &day, &hour, &minute, &second}))
return {Field(), is_date};
hhmmss = true;
break;
}
default:
{
throw Exception("Wrong datetime format");
return {Field(), is_date};
}
}

Expand Down Expand Up @@ -770,7 +783,7 @@ std::pair<Field, bool> parseMyDateTimeAndJudgeIsDate(const String & str, int8_t

if (needCheckTimeValid && !checkTimeValid(year, month, day, hour, minute, second))
{
throw Exception("Wrong datetime format");
return {Field(), is_date};
}

MyDateTime result(year, month, day, hour, minute, second, micro_second);
Expand All @@ -779,7 +792,7 @@ std::pair<Field, bool> parseMyDateTimeAndJudgeIsDate(const String & str, int8_t
{
if (!hhmmss)
{
throw TiFlashException("Invalid datetime value: " + str, Errors::Types::WrongValue);
return {Field(), is_date};
}
if (!tz_hour.empty())
{
Expand All @@ -793,7 +806,7 @@ std::pair<Field, bool> parseMyDateTimeAndJudgeIsDate(const String & str, int8_t
if (delta_hour > 14 || delta_minute > 59 || (delta_hour == 14 && delta_minute != 0)
|| (tz_sign == "-" && delta_hour == 0 && delta_minute == 0))
{
throw TiFlashException("Invalid datetime value: " + str, Errors::Types::WrongValue);
return {Field(), is_date};
}
// by default, if the temporal string literal does not contain timezone information, it will be in the timezone
// specified by the time_zone system variable. However, if the timezone is specified in the string literal, we
Expand Down Expand Up @@ -1025,21 +1038,19 @@ size_t maxFormattedDateTimeStringLength(const String & format)
return std::max<size_t>(result, 1);
}

void MyTimeBase::check(bool allow_zero_in_date, bool allow_invalid_date) const
bool MyTimeBase::isValid(bool allow_zero_in_date, bool allow_invalid_date) const
{
if (!(year == 0 && month == 0 && day == 0))
{
if (!allow_zero_in_date && (month == 0 || day == 0))
{
throw TiFlashException(
fmt::format("Incorrect datetime value: {0:04d}-{1:02d}-{2:02d}", year, month, day),
Errors::Types::WrongValue);
return false;
}
}

if (year >= 9999 || month > 12)
{
throw TiFlashException("Incorrect time value", Errors::Types::WrongValue);
return false;
}

UInt8 max_day = 31;
Expand All @@ -1057,23 +1068,22 @@ void MyTimeBase::check(bool allow_zero_in_date, bool allow_invalid_date) const
}
if (day > max_day)
{
throw TiFlashException(
fmt::format("Incorrect datetime value: {0:04d}-{1:02d}-{2:02d}", year, month, day),
Errors::Types::WrongValue);
return false;
}

if (hour < 0 || hour >= 24)
{
throw TiFlashException("Incorrect datetime value", Errors::Types::WrongValue);
return false;
}
if (minute >= 60)
{
throw TiFlashException("Incorrect datetime value", Errors::Types::WrongValue);
return false;
}
if (second >= 60)
{
throw TiFlashException("Incorrect datetime value", Errors::Types::WrongValue);
return false;
}
return true;
}

bool toCoreTimeChecked(const UInt64 & year, const UInt64 & month, const UInt64 & day, const UInt64 & hour, const UInt64 & minute, const UInt64 & second, const UInt64 & microsecond, MyDateTime & result)
Expand Down
11 changes: 7 additions & 4 deletions dbms/src/Common/MyTime.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ struct MyTimeBase
std::tuple<int, int> calcWeek(UInt32 mode) const;

// Check validity of time under specified SQL_MODE.
// May throw exception.
void check(bool allow_zero_in_date, bool allow_invalid_date) const;
// return false if time is invalid
bool isValid(bool allow_zero_in_date, bool allow_invalid_date) const;
};

struct MyDateTime : public MyTimeBase
Expand Down Expand Up @@ -159,8 +159,11 @@ struct MyDateTimeParser
std::vector<ParserCallback> parsers;
};

Field parseMyDateTime(const String & str, int8_t fsp = 6, bool needCheckTimeValid = false);
std::pair<Field, bool> parseMyDateTimeAndJudgeIsDate(const String & str, int8_t fsp = 6, bool needCheckTimeValid = false);
static int8_t default_fsp = 6;
static bool default_need_check_time_valid = false;

Field parseMyDateTime(const String & str, int8_t fsp = default_fsp, bool need_check_time_valid = default_need_check_time_valid);
std::pair<Field, bool> parseMyDateTimeAndJudgeIsDate(const String & str, int8_t fsp = default_fsp, bool need_check_time_valid = default_need_check_time_valid);

void convertTimeZone(UInt64 from_time, UInt64 & to_time, const DateLUTImpl & time_zone_from, const DateLUTImpl & time_zone_to, bool throw_exception = false);

Expand Down
2 changes: 1 addition & 1 deletion dbms/src/Common/tests/gtest_mytime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class TestMyTime : public testing::Test
if (expect_error)
{
MyDateTime datetime(0, 0, 0, 0, 0, 0, 0);
EXPECT_THROW({ numberToDateTime(input, datetime, ctx); }, TiFlashException) << "Original time number: " << input;
EXPECT_TRUE(numberToDateTime(input, datetime, ctx));
return;
}

Expand Down
Loading

0 comments on commit 72f1e57

Please sign in to comment.