Skip to content

Commit

Permalink
This is an automated cherry-pick of pingcap#3581
Browse files Browse the repository at this point in the history
Signed-off-by: ti-chi-bot <[email protected]>
  • Loading branch information
wshwsh12 authored and ti-chi-bot committed Jan 24, 2022
1 parent 2e0d16c commit 0394219
Show file tree
Hide file tree
Showing 4 changed files with 1,262 additions and 33 deletions.
227 changes: 202 additions & 25 deletions dbms/src/Common/MyTime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ std::vector<String> parseDateFormat(String format)
{
format = Poco::trimInPlace(format);

if (format.size() == 0)
if (format.empty())
return {};

if (!std::isdigit(format[0]) || !std::isdigit(format[format.size() - 1]))
Expand Down Expand Up @@ -530,7 +530,7 @@ Field parseMyDateTime(const String & str, int8_t fsp)
{
// if tz_sign is empty, it's sure that the string literal contains timezone (e.g., 2010-10-10T10:10:10Z),
// therefore we could safely skip this branch.
if (!noAbsorb(seps) && !(tz_minute != "" && tz_sep == ""))
if (!noAbsorb(seps) && !(!tz_minute.empty() && tz_sep.empty()))
{
// we can't absorb timezone if there is no separate between tz_hour and tz_minute
if (!tz_hour.empty())
Expand Down Expand Up @@ -852,9 +852,8 @@ size_t maxFormattedDateTimeStringLength(const String & format)
{
size_t result = 0;
bool in_pattern_match = false;
for (size_t i = 0; i < format.size(); i++)
for (char x : format)
{
char x = format[i];
if (in_pattern_match)
{
switch (x)
Expand Down Expand Up @@ -969,7 +968,6 @@ void MyTimeBase::check(bool allow_zero_in_date, bool allow_invalid_date) const
{
throw TiFlashException("Incorrect datetime value", Errors::Types::WrongValue);
}
return;
}

bool toCoreTimeChecked(const UInt64 & year, const UInt64 & month, const UInt64 & day, const UInt64 & hour, const UInt64 & minute,
Expand All @@ -990,9 +988,8 @@ bool toCoreTimeChecked(const UInt64 & year, const UInt64 & month, const UInt64 &
MyDateTimeFormatter::MyDateTimeFormatter(const String & layout)
{
bool in_pattern_match = false;
for (size_t i = 0; i < layout.size(); i++)
for (char x : layout)
{
char x = layout[i];
if (in_pattern_match)
{
switch (x)
Expand Down Expand Up @@ -1227,7 +1224,13 @@ struct MyDateTimeParser::Context
// The pos we are parsing from
size_t pos = 0;

<<<<<<< HEAD
Context(StringRef view_) : view(std::move(view_)) {}
=======
explicit Context(StringRef view_)
: view(std::move(view_))
{}
>>>>>>> 4b4b8b4240 (Add unittests for str_to_date, fix #3556, #3557 (#3581))
};

// Try to parse digits with number of `limit` starting from view[pos]
Expand Down Expand Up @@ -1270,18 +1273,18 @@ static bool parseTime12Hour(MyDateTimeParser::Context & ctx, MyTimeBase & time)
{
// Use temp_pos instead of changing `ctx.pos` directly in case of parsing failure
size_t temp_pos = ctx.pos;
auto checkIfEnd = [&temp_pos, &ctx]() -> ParseState {
auto check_if_end = [&temp_pos, &ctx]() -> ParseState {
// To the end
if (temp_pos == ctx.view.size)
return ParseState::END_OF_FILE;
return ParseState::NORMAL;
};
auto skipWhitespaces = [&temp_pos, &ctx, &checkIfEnd]() -> ParseState {
auto skipWhitespaces = [&temp_pos, &ctx, &check_if_end]() -> ParseState {
while (temp_pos < ctx.view.size && isWhitespaceASCII(ctx.view.data[temp_pos]))
++temp_pos;
return checkIfEnd();
return check_if_end();
};
auto parseSep = [&temp_pos, &ctx, &skipWhitespaces]() -> ParseState {
auto parse_sep = [&temp_pos, &ctx, &skipWhitespaces]() -> ParseState {
if (skipWhitespaces() == ParseState::END_OF_FILE)
return ParseState::END_OF_FILE;
// parse ":"
Expand All @@ -1290,7 +1293,7 @@ static bool parseTime12Hour(MyDateTimeParser::Context & ctx, MyTimeBase & time)
temp_pos += 1; // move forward
return ParseState::NORMAL;
};
auto tryParse = [&]() -> ParseState {
auto try_parse = [&]() -> ParseState {
ParseState state = ParseState::NORMAL;
/// Note that we should update `time` as soon as possible, or we
/// can not get correct result for incomplete input like "12:13"
Expand All @@ -1311,7 +1314,7 @@ static bool parseTime12Hour(MyDateTimeParser::Context & ctx, MyTimeBase & time)
time.hour = hour;
temp_pos += step; // move forward

if (state = parseSep(); state != ParseState::NORMAL)
if (state = parse_sep(); state != ParseState::NORMAL)
return state;

int32_t minute = 0;
Expand All @@ -1323,7 +1326,7 @@ static bool parseTime12Hour(MyDateTimeParser::Context & ctx, MyTimeBase & time)
time.minute = minute;
temp_pos += step; // move forward

if (state = parseSep(); state != ParseState::NORMAL)
if (state = parse_sep(); state != ParseState::NORMAL)
return state;

int32_t second = 0;
Expand Down Expand Up @@ -1362,7 +1365,7 @@ static bool parseTime12Hour(MyDateTimeParser::Context & ctx, MyTimeBase & time)
temp_pos += 2; // move forward
return ParseState::NORMAL;
};
if (auto state = tryParse(); state == ParseState::FAIL)
if (auto state = try_parse(); state == ParseState::FAIL)
return false;
// Other state, forward the `ctx.pos` and return true
ctx.pos = temp_pos;
Expand All @@ -1374,18 +1377,18 @@ static bool parseTime24Hour(MyDateTimeParser::Context & ctx, MyTimeBase & time)
{
// Use temp_pos instead of changing `ctx.pos` directly in case of parsing failure
size_t temp_pos = ctx.pos;
auto checkIfEnd = [&temp_pos, &ctx]() -> ParseState {
auto check_if_end = [&temp_pos, &ctx]() -> ParseState {
// To the end
if (temp_pos == ctx.view.size)
return ParseState::END_OF_FILE;
return ParseState::NORMAL;
};
auto skipWhitespaces = [&temp_pos, &ctx, &checkIfEnd]() -> ParseState {
auto skipWhitespaces = [&temp_pos, &ctx, &check_if_end]() -> ParseState {
while (temp_pos < ctx.view.size && isWhitespaceASCII(ctx.view.data[temp_pos]))
++temp_pos;
return checkIfEnd();
return check_if_end();
};
auto parseSep = [&temp_pos, &ctx, &skipWhitespaces]() -> ParseState {
auto parse_sep = [&temp_pos, &ctx, &skipWhitespaces]() -> ParseState {
if (skipWhitespaces() == ParseState::END_OF_FILE)
return ParseState::END_OF_FILE;
// parse ":"
Expand All @@ -1394,7 +1397,7 @@ static bool parseTime24Hour(MyDateTimeParser::Context & ctx, MyTimeBase & time)
temp_pos += 1; // move forward
return ParseState::NORMAL;
};
auto tryParse = [&]() -> ParseState {
auto try_parse = [&]() -> ParseState {
ParseState state = ParseState::NORMAL;
/// Note that we should update `time` as soon as possible, or we
/// can not get correct result for incomplete input like "12:13"
Expand All @@ -1411,7 +1414,7 @@ static bool parseTime24Hour(MyDateTimeParser::Context & ctx, MyTimeBase & time)
time.hour = hour;
temp_pos += step; // move forward

if (state = parseSep(); state != ParseState::NORMAL)
if (state = parse_sep(); state != ParseState::NORMAL)
return state;

int32_t minute = 0;
Expand All @@ -1423,7 +1426,7 @@ static bool parseTime24Hour(MyDateTimeParser::Context & ctx, MyTimeBase & time)
time.minute = minute;
temp_pos += step; // move forward

if (state = parseSep(); state != ParseState::NORMAL)
if (state = parse_sep(); state != ParseState::NORMAL)
return state;

int32_t second = 0;
Expand All @@ -1437,7 +1440,7 @@ static bool parseTime24Hour(MyDateTimeParser::Context & ctx, MyTimeBase & time)

return ParseState::NORMAL;
};
if (auto state = tryParse(); state == ParseState::FAIL)
if (auto state = try_parse(); state == ParseState::FAIL)
return false;
// Other state, forward the `ctx.pos` and return true
ctx.pos = temp_pos;
Expand Down Expand Up @@ -1475,6 +1478,7 @@ MyDateTimeParser::MyDateTimeParser(String format_) : format(std::move(format_))
break;
}
}
<<<<<<< HEAD
if (step == 0)
return false;
ctx.pos += step;
Expand Down Expand Up @@ -1519,10 +1523,150 @@ MyDateTimeParser::MyDateTimeParser(String format_) : format(std::move(format_))
auto [step, ms] = parseNDigits(ctx.view, ctx.pos, 6);
// Empty string is a valid input
if (step == 0)
=======
}
if (step == 0)
return false;
ctx.pos += step;
return true;
});
break;
}
case 'm':
//"%m": Month, numeric (00..12)
[[fallthrough]];
case 'c':
{
//"%c": Month, numeric (0..12)
parsers.emplace_back([](MyDateTimeParser::Context & ctx, MyTimeBase & time) -> bool {
// To be compatible with TiDB & MySQL, first try to take two digit and parse it as `num`
auto [step, month] = parseNDigits(ctx.view, ctx.pos, 2);
// Then check whether num is valid month
// Note that 0 is valid when sql_mode does not contain NO_ZERO_IN_DATE,NO_ZERO_DATE
if (step == 0 || month > 12)
return false;
time.month = month;
ctx.pos += step;
return true;
});
break;
}
case 'd': //"%d": Day of the month, numeric (00..31)
[[fallthrough]];
case 'e': //"%e": Day of the month, numeric (0..31)
{
parsers.emplace_back([](MyDateTimeParser::Context & ctx, MyTimeBase & time) -> bool {
auto [step, day] = parseNDigits(ctx.view, ctx.pos, 2);
if (step == 0 || day > 31)
return false;
time.day = day;
ctx.pos += step;
return true;
});
break;
}
case 'f':
{
//"%f": Microseconds (000000..999999)
parsers.emplace_back([](MyDateTimeParser::Context & ctx, MyTimeBase & time) -> bool {
auto [step, ms] = parseNDigits(ctx.view, ctx.pos, 6);
// Empty string is a valid input
if (step == 0)
{
time.micro_second = 0;
return true;
}
// The suffix '0' can be ignored.
// "9" means 900000
for (size_t i = step; i < 6; i++)
{
ms *= 10;
}
time.micro_second = ms;
ctx.pos += step;
return true;
});
break;
}
case 'k':
//"%k": Hour (0..23)
[[fallthrough]];
case 'H':
{
//"%H": Hour (00..23)
parsers.emplace_back([](MyDateTimeParser::Context & ctx, MyTimeBase & time) -> bool {
auto [step, hour] = parseNDigits(ctx.view, ctx.pos, 2);
if (step == 0 || hour > 23)
return false;
ctx.state |= MyDateTimeParser::Context::ST_HOUR_0_23;
time.hour = hour;
ctx.pos += step;
return true;
});
break;
}
case 'l':
//"%l": Hour (1..12)
[[fallthrough]];
case 'I':
//"%I": Hour (01..12)
[[fallthrough]];
case 'h':
{
//"%h": Hour (01..12)
parsers.emplace_back([](MyDateTimeParser::Context & ctx, MyTimeBase & time) -> bool {
auto [step, hour] = parseNDigits(ctx.view, ctx.pos, 2);
if (step == 0 || hour <= 0 || hour > 12)
return false;
ctx.state |= MyDateTimeParser::Context::ST_HOUR_1_12;
time.hour = hour;
ctx.pos += step;
return true;
});
break;
}
case 'i':
{
//"%i": Minutes, numeric (00..59)
parsers.emplace_back([](MyDateTimeParser::Context & ctx, MyTimeBase & time) -> bool {
auto [step, num] = parseNDigits(ctx.view, ctx.pos, 2);
if (step == 0 || num > 59)
return false;
time.minute = num;
ctx.pos += step;
return true;
});
break;
}
case 'j':
{
//"%j": Day of year (001..366)
parsers.emplace_back([](MyDateTimeParser::Context & ctx, MyTimeBase &) -> bool {
auto [step, num] = parseNDigits(ctx.view, ctx.pos, 3);
if (step == 0 || num == 0 || num > 366)
return false;
ctx.state |= MyDateTimeParser::Context::ST_DAY_OF_YEAR;
ctx.day_of_year = num;
ctx.pos += step;
return true;
});
break;
}
case 'M':
{
//"%M": Month name (January..December)
parsers.emplace_back([](MyDateTimeParser::Context & ctx, MyTimeBase & time) -> bool {
auto v = removePrefix(ctx.view, ctx.pos);
size_t step = 0;
for (size_t p = 0; p < 12; p++)
{
if (startsWithCI(v, month_names[p]))
>>>>>>> 4b4b8b4240 (Add unittests for str_to_date, fix #3556, #3557 (#3581))
{
time.micro_second = 0;
return true;
}
<<<<<<< HEAD
// The siffix '0' can be ignored.
// "9" means 900000
while (ms > 0 && ms * 10 < 1000000)
Expand Down Expand Up @@ -1657,6 +1801,39 @@ MyDateTimeParser::MyDateTimeParser(String format_) : format(std::move(format_))
// Check the offset that will visit
if (ctx.view.size - ctx.pos < 2)
return false;
=======
}
if (step == 0)
return false;
ctx.pos += step;
return true;
});
break;
}
case 'S':
//"%S": Seconds (00..59)
[[fallthrough]];
case 's':
{
//"%s": Seconds (00..59)
parsers.emplace_back([](MyDateTimeParser::Context & ctx, MyTimeBase & time) -> bool {
auto [step, second] = parseNDigits(ctx.view, ctx.pos, 2);
if (step == 0 || second > 59)
return false;
time.second = second;
ctx.pos += step;
return true;
});
break;
}
case 'p':
{
//"%p": AM or PM
parsers.emplace_back([](MyDateTimeParser::Context & ctx, MyTimeBase &) -> bool {
// Check the offset that will visit
if (ctx.view.size - ctx.pos < 2)
return false;
>>>>>>> 4b4b8b4240 (Add unittests for str_to_date, fix #3556, #3557 (#3581))

int meridiem = 0; // 0 - invalid, 1 - am, 2 - pm
if (toLowerIfAlphaASCII(ctx.view.data[ctx.pos]) == 'a')
Expand Down Expand Up @@ -1880,7 +2057,7 @@ std::optional<UInt64> MyDateTimeParser::parseAsPackedUInt(const StringRef & str_
MyDateTimeParser::Context ctx(str_view);

// TODO: can we return warnings to TiDB?
for (auto & f : parsers)
for (const auto & f : parsers)
{
// Ignore all prefix white spaces before each pattern match (TODO: handle unicode space?)
while (ctx.pos < str_view.size && isWhitespaceASCII(str_view.data[ctx.pos]))
Expand All @@ -1889,7 +2066,7 @@ std::optional<UInt64> MyDateTimeParser::parseAsPackedUInt(const StringRef & str_
if (ctx.pos == ctx.view.size)
break;

if (f(ctx, my_time) != true)
if (!f(ctx, my_time))
{
#ifndef NDEBUG
LOG_TRACE(&Logger::get("MyDateTimeParser"),
Expand Down
Loading

0 comments on commit 0394219

Please sign in to comment.