From f5c93960599c5e9e63503de88009c2cc67861f3a Mon Sep 17 00:00:00 2001 From: Shenghui Wu <793703860@qq.com> Date: Tue, 14 Dec 2021 17:56:35 +0800 Subject: [PATCH 1/2] This is an automated cherry-pick of #3581 Signed-off-by: ti-chi-bot --- dbms/src/Common/MyTime.cpp | 227 ++++- dbms/src/Common/tests/gtest_mytime.cpp | 89 ++ dbms/src/Functions/FunctionsConversion.h | 31 +- .../Functions/tests/gtest_tidb_conversion.cpp | 948 ++++++++++++++++++ 4 files changed, 1262 insertions(+), 33 deletions(-) create mode 100644 dbms/src/Functions/tests/gtest_tidb_conversion.cpp diff --git a/dbms/src/Common/MyTime.cpp b/dbms/src/Common/MyTime.cpp index 1436ad08342..e8670981b18 100644 --- a/dbms/src/Common/MyTime.cpp +++ b/dbms/src/Common/MyTime.cpp @@ -72,7 +72,7 @@ std::vector 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])) @@ -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()) @@ -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) @@ -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, @@ -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) @@ -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] @@ -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 ":" @@ -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" @@ -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; @@ -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; @@ -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; @@ -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 ":" @@ -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" @@ -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; @@ -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; @@ -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; @@ -1475,6 +1478,7 @@ MyDateTimeParser::MyDateTimeParser(String format_) : format(std::move(format_)) break; } } +<<<<<<< HEAD if (step == 0) return false; ctx.pos += step; @@ -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) @@ -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') @@ -1880,7 +2057,7 @@ std::optional 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])) @@ -1889,7 +2066,7 @@ std::optional 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"), diff --git a/dbms/src/Common/tests/gtest_mytime.cpp b/dbms/src/Common/tests/gtest_mytime.cpp index 31647d0787c..376ec0bf534 100644 --- a/dbms/src/Common/tests/gtest_mytime.cpp +++ b/dbms/src/Common/tests/gtest_mytime.cpp @@ -393,7 +393,96 @@ try // {"Tuesday 52 2001", "%W %V %Y", std::nullopt}, // // {"Tuesday 52 2001", "%W %V %x", std::nullopt}, // // {"Tuesday 52 2001", "%W %u %x", std::nullopt}, // + + // Test cases for %b + {"10/JAN/2010", "%d/%b/%Y", MyDateTime{2010, 1, 10, 0, 0, 0, 0}}, // Right spill, case-insensitive + {"10/FeB/2010", "%d/%b/%Y", MyDateTime{2010, 2, 10, 0, 0, 0, 0}}, + {"10/MAr/2010", "%d/%b/%Y", MyDateTime{2010, 3, 10, 0, 0, 0, 0}}, + {"10/ApR/2010", "%d/%b/%Y", MyDateTime{2010, 4, 10, 0, 0, 0, 0}}, + {"10/mAY/2010", "%d/%b/%Y", MyDateTime{2010, 5, 10, 0, 0, 0, 0}}, + {"10/JuN/2010", "%d/%b/%Y", MyDateTime{2010, 6, 10, 0, 0, 0, 0}}, + {"10/JUL/2010", "%d/%b/%Y", MyDateTime{2010, 7, 10, 0, 0, 0, 0}}, + {"10/Aug/2010", "%d/%b/%Y", MyDateTime{2010, 8, 10, 0, 0, 0, 0}}, + {"10/seP/2010", "%d/%b/%Y", MyDateTime{2010, 9, 10, 0, 0, 0, 0}}, + {"10/Oct/2010", "%d/%b/%Y", MyDateTime{2010, 10, 10, 0, 0, 0, 0}}, + {"10/NOV/2010", "%d/%b/%Y", MyDateTime{2010, 11, 10, 0, 0, 0, 0}}, + {"10/DEC/2010", "%d/%b/%Y", MyDateTime{2010, 12, 10, 0, 0, 0, 0}}, + {"10/January/2010", "%d/%b/%Y", std::nullopt}, // Test full spilling + + // Test cases for %M + {"10/January/2010", "%d/%M/%Y", MyDateTime{2010, 1, 10, 0, 0, 0, 0}}, // Test full spilling + {"10/February/2010", "%d/%M/%Y", MyDateTime{2010, 2, 10, 0, 0, 0, 0}}, + {"10/March/2010", "%d/%M/%Y", MyDateTime{2010, 3, 10, 0, 0, 0, 0}}, + {"10/April/2010", "%d/%M/%Y", MyDateTime{2010, 4, 10, 0, 0, 0, 0}}, + {"10/May/2010", "%d/%M/%Y", MyDateTime{2010, 5, 10, 0, 0, 0, 0}}, + {"10/June/2010", "%d/%M/%Y", MyDateTime{2010, 6, 10, 0, 0, 0, 0}}, + {"10/July/2010", "%d/%M/%Y", MyDateTime{2010, 7, 10, 0, 0, 0, 0}}, + {"10/August/2010", "%d/%M/%Y", MyDateTime{2010, 8, 10, 0, 0, 0, 0}}, + {"10/September/2010", "%d/%M/%Y", MyDateTime{2010, 9, 10, 0, 0, 0, 0}}, + {"10/October/2010", "%d/%M/%Y", MyDateTime{2010, 10, 10, 0, 0, 0, 0}}, + {"10/November/2010", "%d/%M/%Y", MyDateTime{2010, 11, 10, 0, 0, 0, 0}}, + {"10/December/2010", "%d/%M/%Y", MyDateTime{2010, 12, 10, 0, 0, 0, 0}}, + + // Test cases for %c + // {"10/0/2010", "%d/%c/%Y", MyDateTime{2010, 0, 10, 0, 0, 0, 0}}, // TODO: Need Check NO_ZERO_DATE + {"10/1/2010", "%d/%c/%Y", MyDateTime{2010, 1, 10, 0, 0, 0, 0}}, + {"10/01/2010", "%d/%c/%Y", MyDateTime{2010, 1, 10, 0, 0, 0, 0}}, + {"10/001/2010", "%d/%c/%Y", std::nullopt}, + {"10/13/2010", "%d/%c/%Y", std::nullopt}, + {"10/12/2010", "%d/%c/%Y", MyDateTime{2010, 12, 10, 0, 0, 0, 0}}, + + // Test cases for %d, %e + // {"0/12/2010", "%d/%c/%Y", MyDateTime{2010, 12, 0, 0, 0, 0, 0}}, // TODO: Need Check NO_ZERO_DATE + {"1/12/2010", "%d/%c/%Y", MyDateTime{2010, 12, 1, 0, 0, 0, 0}}, + {"05/12/2010", "%d/%c/%Y", MyDateTime{2010, 12, 5, 0, 0, 0, 0}}, + {"05/12/2010", "%e/%c/%Y", MyDateTime{2010, 12, 5, 0, 0, 0, 0}}, + {"31/12/2010", "%d/%c/%Y", MyDateTime{2010, 12, 31, 0, 0, 0, 0}}, + {"32/12/2010", "%d/%c/%Y", std::nullopt}, + {"30/11/2010", "%d/%c/%Y", MyDateTime{2010, 11, 30, 0, 0, 0, 0}}, + {"31/11/2010", "%e/%c/%Y", MyDateTime{2010, 11, 31, 0, 0, 0, 0}}, + {"28/2/2010", "%e/%c/%Y", MyDateTime{2010, 2, 28, 0, 0, 0, 0}}, + {"29/2/2010", "%e/%c/%Y", MyDateTime{2010, 2, 29, 0, 0, 0, 0}}, + {"29/2/2020", "%e/%c/%Y", MyDateTime{2020, 2, 29, 0, 0, 0, 0}}, + + // Test cases for %Y + // {"1/12/0000", "%d/%c/%Y", MyDateTime{0000, 12, 1, 0, 0, 0, 0}}, // TODO: Need Check NO_ZERO_DATE + {"1/12/01", "%d/%c/%Y", MyDateTime{2001, 12, 1, 0, 0, 0, 0}}, + {"1/12/0001", "%d/%c/%Y", MyDateTime{0001, 12, 1, 0, 0, 0, 0}}, + {"1/12/2020", "%d/%c/%Y", MyDateTime{2020, 12, 1, 0, 0, 0, 0}}, + {"1/12/9999", "%d/%c/%Y", MyDateTime{9999, 12, 1, 0, 0, 0, 0}}, + + // Test cases for %f + {"01,5,2013 999999", "%d,%c,%Y %f", MyDateTime{2013, 5, 1, 0, 0, 0, 999999}}, + {"01,5,2013 0", "%d,%c,%Y %f", MyDateTime{2013, 5, 1, 0, 0, 0, 0}}, + {"01,5,2013 9999990000000", "%d,%c,%Y %f", MyDateTime{2013, 5, 1, 0, 0, 0, 999999}}, + {"01,5,2013 1", "%d,%c,%Y %f", MyDateTime{2013, 5, 1, 0, 0, 0, 100000}}, + {"01,5,2013 1230", "%d,%c,%Y %f", MyDateTime{2013, 5, 1, 0, 0, 0, 123000}}, + {"01,5,2013 01", "%d,%c,%Y %f", MyDateTime{2013, 5, 1, 0, 0, 0, 10000}}, // issue 3556 + + // Test cases for %h, %I, %l + {"00:11:12 ", "%h:%i:%S ", std::nullopt}, // 0 is not a valid number of %h + {"01:11:12 ", "%I:%i:%S ", MyDateTime{0, 0, 0, 01, 11, 12, 0}}, + {"12:11:12 ", "%l:%i:%S ", MyDateTime{0, 0, 0, 0, 11, 12, 0}}, + + // Test cases for %k, %H + {"00:11:12 ", "%H:%i:%S ", MyDateTime{0, 0, 0, 00, 11, 12, 0}}, + {"01:11:12 ", "%k:%i:%S ", MyDateTime{0, 0, 0, 01, 11, 12, 0}}, + {"12:11:12 ", "%H:%i:%S ", MyDateTime{0, 0, 0, 12, 11, 12, 0}}, + {"24:11:12 ", "%k:%i:%S ", std::nullopt}, + + // Test cases for %i + {"00:00:12 ", "%H:%i:%S ", MyDateTime{0, 0, 0, 00, 00, 12, 0}}, + {"00:01:12 ", "%H:%i:%S ", MyDateTime{0, 0, 0, 00, 01, 12, 0}}, + {"00:59:12 ", "%H:%i:%S ", MyDateTime{0, 0, 0, 00, 59, 12, 0}}, + {"00:60:12 ", "%H:%i:%S ", std::nullopt}, + + // Test cases for %s, %S + {"00:00:00 ", "%H:%i:%s ", MyDateTime{0, 0, 0, 00, 00, 00, 0}}, + {"00:01:01 ", "%H:%i:%s ", MyDateTime{0, 0, 0, 00, 01, 01, 0}}, + {"00:59:59 ", "%H:%i:%S ", MyDateTime{0, 0, 0, 00, 59, 59, 0}}, + {"00:59:60 ", "%H:%i:%S ", std::nullopt}, }; + auto result_formatter = MyDateTimeFormatter("%Y/%m/%d %T.%f"); size_t idx = 0; for (const auto & [input, fmt, expected] : cases) diff --git a/dbms/src/Functions/FunctionsConversion.h b/dbms/src/Functions/FunctionsConversion.h index 3e7abeb2e55..609f48f75ba 100644 --- a/dbms/src/Functions/FunctionsConversion.h +++ b/dbms/src/Functions/FunctionsConversion.h @@ -1614,16 +1614,20 @@ class FunctionStrToDate : public IFunction DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override { if (arguments.size() != 2) - throw Exception("Function " + getName() + " only accept 2 arguments", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); + throw Exception(fmt::format("Function {} only accept 2 arguments", getName()), ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); // TODO: Maybe FixedString? if (!removeNullable(arguments[0].type)->isString()) +<<<<<<< HEAD throw Exception("First argument for function " + getName() + " must be String, but get " + arguments[0].type->getName(), ErrorCodes::ILLEGAL_COLUMN); +======= + throw Exception(fmt::format("First argument for function {} must be String, but get {}", getName(), arguments[0].type->getName()), + ErrorCodes::ILLEGAL_COLUMN); +>>>>>>> 4b4b8b4240 (Add unittests for str_to_date, fix #3556, #3557 (#3581)) if (!removeNullable(arguments[1].type)->isString()) - throw Exception( - "Second argument for function " + getName() + " must be String, but get " + arguments[1].type->getName(), - ErrorCodes::ILLEGAL_COLUMN); + throw Exception(fmt::format("Second argument for function {} must be String, but get {}", getName(), arguments[1].type->getName()), + ErrorCodes::ILLEGAL_COLUMN); if constexpr (std::is_same_v) { @@ -1638,7 +1642,7 @@ class FunctionStrToDate : public IFunction } else { - throw Exception("Unknown name for FunctionStrToDate:" + getName(), ErrorCodes::LOGICAL_ERROR); + throw Exception(fmt::format("Unknown name for FunctionStrToDate: {}", getName()), ErrorCodes::LOGICAL_ERROR); } } @@ -1652,7 +1656,7 @@ class FunctionStrToDate : public IFunction const ColumnString * input_raw_col = nullptr; if (input_column->isColumnNullable()) { - auto null_input_column = checkAndGetColumn(input_column.get()); + const auto * null_input_column = checkAndGetColumn(input_column.get()); input_raw_col = checkAndGetColumn(null_input_column->getNestedColumnPtr().get()); } else @@ -1702,7 +1706,7 @@ class FunctionStrToDate : public IFunction const ColumnString * format_raw_col = nullptr; if (format_column->isColumnNullable()) { - auto null_format_column = checkAndGetColumn(format_column.get()); + const auto * null_format_column = checkAndGetColumn(format_column.get()); format_raw_col = checkAndGetColumn(null_format_column->getNestedColumnPtr().get()); } else @@ -1710,6 +1714,14 @@ class FunctionStrToDate : public IFunction format_raw_col = checkAndGetColumn(format_column.get()); } + String str_input_const; + StringRef str_ref; + if (input_column->isColumnConst()) + { + const auto & input_const = checkAndGetColumnConst(input_column.get()); + str_input_const = input_const->getValue(); + str_ref = StringRef(str_input_const); + } for (size_t i = 0; i < num_rows; ++i) { // Set null for either null input or null format @@ -1734,7 +1746,10 @@ class FunctionStrToDate : public IFunction const auto format_ref = format_raw_col->getDataAt(i); auto parser = MyDateTimeParser(format_ref.toString()); - const auto str_ref = input_raw_col->getDataAt(i); + if (!input_column->isColumnConst()) + { + str_ref = input_raw_col->getDataAt(i); + } if (auto parse_res = parser.parseAsPackedUInt(str_ref); parse_res) { datetime_res[i] = *parse_res; diff --git a/dbms/src/Functions/tests/gtest_tidb_conversion.cpp b/dbms/src/Functions/tests/gtest_tidb_conversion.cpp new file mode 100644 index 00000000000..c1932f710e5 --- /dev/null +++ b/dbms/src/Functions/tests/gtest_tidb_conversion.cpp @@ -0,0 +1,948 @@ +#include + +#include "Columns/ColumnsNumber.h" +#include "Core/ColumnWithTypeAndName.h" +#include "DataTypes/DataTypeMyDateTime.h" +#include "DataTypes/DataTypeMyDuration.h" +#include "DataTypes/DataTypeNullable.h" +#include "DataTypes/DataTypesNumber.h" +#include "Functions/FunctionFactory.h" +#include "Functions/FunctionHelpers.h" +#include "TestUtils/FunctionTestUtils.h" +#include "common/types.h" +#include "gtest/gtest.h" + +namespace DB +{ +namespace tests +{ +namespace +{ +auto getDatetimeColumn(bool single_field = false) +{ + MyDateTime datetime(2021, 10, 26, 16, 8, 59, 0); + MyDateTime datetime_frac(2021, 10, 26, 16, 8, 59, 123456); + + auto col_datetime = ColumnUInt64::create(); + col_datetime->insert(Field(datetime.toPackedUInt())); + if (!single_field) + col_datetime->insert(Field(datetime_frac.toPackedUInt())); + return col_datetime; +} + +auto createCastTypeConstColumn(String str) +{ + return createConstColumn(1, str); +} + +const std::string func_name = "tidb_cast"; + +const Int8 MAX_INT8 = std::numeric_limits::max(); +const Int8 MIN_INT8 = std::numeric_limits::min(); +const Int16 MAX_INT16 = std::numeric_limits::max(); +const Int16 MIN_INT16 = std::numeric_limits::min(); +const Int32 MAX_INT32 = std::numeric_limits::max(); +const Int32 MIN_INT32 = std::numeric_limits::min(); +const Int64 MAX_INT64 = std::numeric_limits::max(); +const Int64 MIN_INT64 = std::numeric_limits::min(); +const UInt8 MAX_UINT8 = std::numeric_limits::max(); +const UInt16 MAX_UINT16 = std::numeric_limits::max(); +const UInt32 MAX_UINT32 = std::numeric_limits::max(); +const UInt64 MAX_UINT64 = std::numeric_limits::max(); + +class TestTidbConversion : public DB::tests::FunctionTest +{ +}; + +using DecimalField32 = DecimalField; +using DecimalField64 = DecimalField; +using DecimalField128 = DecimalField; +using DecimalField256 = DecimalField; + +TEST_F(TestTidbConversion, castIntAsInt) +try +{ + /// null only cases + ASSERT_COLUMN_EQ( + createColumn>({{}}), + executeFunction(func_name, + {createOnlyNullColumn(1), + createCastTypeConstColumn("Nullable(UInt64)")})); + ASSERT_COLUMN_EQ( + createColumn>({{}}), + executeFunction(func_name, + {createOnlyNullColumn(1), + createCastTypeConstColumn("Nullable(Int64)")})); + + /// const cases + // uint8/16/32/64 -> uint64, no overflow + ASSERT_COLUMN_EQ( + createConstColumn(1, MAX_UINT8), + executeFunction(func_name, + {createConstColumn(1, MAX_UINT8), + createCastTypeConstColumn("UInt64")})); + ASSERT_COLUMN_EQ( + createConstColumn(1, MAX_UINT16), + executeFunction(func_name, + {createConstColumn(1, MAX_UINT16), + createCastTypeConstColumn("UInt64")})); + ASSERT_COLUMN_EQ( + createConstColumn(1, MAX_UINT32), + executeFunction(func_name, + {createConstColumn(1, MAX_UINT32), + createCastTypeConstColumn("UInt64")})); + ASSERT_COLUMN_EQ( + createConstColumn(1, MAX_UINT64), + executeFunction(func_name, + {createConstColumn(1, MAX_UINT64), + createCastTypeConstColumn("UInt64")})); + // int8/16/32/64 -> uint64, no overflow + ASSERT_COLUMN_EQ( + createConstColumn(1, MAX_INT8), + executeFunction(func_name, + {createConstColumn(1, MAX_INT8), + createCastTypeConstColumn("UInt64")})); + ASSERT_COLUMN_EQ( + createConstColumn(1, MAX_INT16), + executeFunction(func_name, + {createConstColumn(1, MAX_INT16), + createCastTypeConstColumn("UInt64")})); + ASSERT_COLUMN_EQ( + createConstColumn(1, MAX_INT32), + executeFunction(func_name, + {createConstColumn(1, MAX_INT32), + createCastTypeConstColumn("UInt64")})); + ASSERT_COLUMN_EQ( + createConstColumn(1, MAX_INT64), + executeFunction(func_name, + {createConstColumn(1, MAX_INT64), + createCastTypeConstColumn("UInt64")})); + // uint8/16/32 -> int64, no overflow + ASSERT_COLUMN_EQ( + createConstColumn(1, MAX_UINT8), + executeFunction(func_name, + {createConstColumn(1, MAX_UINT8), + createCastTypeConstColumn("Int64")})); + ASSERT_COLUMN_EQ( + createConstColumn(1, MAX_UINT16), + executeFunction(func_name, + {createConstColumn(1, MAX_UINT16), + createCastTypeConstColumn("Int64")})); + ASSERT_COLUMN_EQ( + createConstColumn(1, MAX_UINT32), + executeFunction(func_name, + {createConstColumn(1, MAX_UINT32), + createCastTypeConstColumn("Int64")})); + // uint64 -> int64, will overflow + ASSERT_COLUMN_EQ( + createConstColumn(1, -1), + executeFunction(func_name, + {createConstColumn(1, MAX_UINT64), + createCastTypeConstColumn("Int64")})); + // int8/16/32/64 -> int64, no overflow + ASSERT_COLUMN_EQ( + createConstColumn(1, MAX_INT8), + executeFunction(func_name, + {createConstColumn(1, MAX_INT8), + createCastTypeConstColumn("Int64")})); + ASSERT_COLUMN_EQ( + createConstColumn(1, MAX_INT16), + executeFunction(func_name, + {createConstColumn(1, MAX_INT16), + createCastTypeConstColumn("Int64")})); + ASSERT_COLUMN_EQ( + createConstColumn(1, MAX_INT32), + executeFunction(func_name, + {createConstColumn(1, MAX_INT32), + createCastTypeConstColumn("Int64")})); + ASSERT_COLUMN_EQ( + createConstColumn(1, MAX_INT64), + executeFunction(func_name, + {createConstColumn(1, MAX_INT64), + createCastTypeConstColumn("Int64")})); + + /// normal cases + // uint8/16/32/64 -> uint64, no overflow + ASSERT_COLUMN_EQ( + createColumn>({0, 1, MAX_UINT8, {}}), + executeFunction(func_name, + {createColumn>({0, 1, MAX_UINT8, {}}), + createCastTypeConstColumn("Nullable(UInt64)")})); + ASSERT_COLUMN_EQ( + createColumn>({0, 1, MAX_UINT16, {}}), + executeFunction(func_name, + {createColumn>({0, 1, MAX_UINT16, {}}), + createCastTypeConstColumn("Nullable(UInt64)")})); + ASSERT_COLUMN_EQ( + createColumn>({0, 1, MAX_UINT32, {}}), + executeFunction(func_name, + {createColumn>({0, 1, MAX_UINT32, {}}), + createCastTypeConstColumn("Nullable(UInt64)")})); + ASSERT_COLUMN_EQ( + createColumn>({0, 1, MAX_UINT64, {}}), + executeFunction(func_name, + {createColumn>({0, 1, MAX_UINT64, {}}), + createCastTypeConstColumn("Nullable(UInt64)")})); + // int8/16/32/64 -> uint64, no overflow + ASSERT_COLUMN_EQ( + createColumn>({0, MAX_INT8, MAX_UINT64, MAX_UINT64 - MAX_INT8, {}}), + executeFunction(func_name, + {createColumn>({0, MAX_INT8, -1, MIN_INT8, {}}), + createCastTypeConstColumn("Nullable(UInt64)")})); + ASSERT_COLUMN_EQ( + createColumn>({0, MAX_INT16, MAX_UINT64, MAX_UINT64 - MAX_INT16, {}}), + executeFunction(func_name, + {createColumn>({0, MAX_INT16, -1, MIN_INT16, {}}), + createCastTypeConstColumn("Nullable(UInt64)")})); + ASSERT_COLUMN_EQ( + createColumn>({0, MAX_INT32, MAX_UINT64, MAX_UINT64 - MAX_INT32, {}}), + executeFunction(func_name, + {createColumn>({0, MAX_INT32, -1, MIN_INT32, {}}), + createCastTypeConstColumn("Nullable(UInt64)")})); + ASSERT_COLUMN_EQ( + createColumn>({0, MAX_INT64, MAX_UINT64, MAX_UINT64 - MAX_INT64, {}}), + executeFunction(func_name, + {createColumn>({0, MAX_INT64, -1, MIN_INT64, {}}), + createCastTypeConstColumn("Nullable(UInt64)")})); + // uint8/16/32 -> int64, no overflow + ASSERT_COLUMN_EQ( + createColumn>({0, MAX_INT8, MAX_UINT8, {}}), + executeFunction(func_name, + {createColumn>({0, MAX_INT8, MAX_UINT8, {}}), + createCastTypeConstColumn("Nullable(Int64)")})); + ASSERT_COLUMN_EQ( + createColumn>({0, MAX_INT16, MAX_UINT16, {}}), + executeFunction(func_name, + {createColumn>({0, MAX_INT16, MAX_UINT16, {}}), + createCastTypeConstColumn("Nullable(Int64)")})); + ASSERT_COLUMN_EQ( + createColumn>({0, MAX_INT32, MAX_UINT32, {}}), + executeFunction(func_name, + {createColumn>({0, MAX_INT32, MAX_UINT32, {}}), + createCastTypeConstColumn("Nullable(Int64)")})); + // uint64 -> int64, overflow may happen + ASSERT_COLUMN_EQ( + createColumn>({0, MAX_INT64, -1, {}}), + executeFunction(func_name, + {createColumn>({0, MAX_INT64, MAX_UINT64, {}}), + createCastTypeConstColumn("Nullable(Int64)")})); + // int8/16/32/64 -> int64, no overflow + ASSERT_COLUMN_EQ( + createColumn>({0, MAX_INT8, -1, MIN_INT8, {}}), + executeFunction(func_name, + {createColumn>({0, MAX_INT8, -1, MIN_INT8, {}}), + createCastTypeConstColumn("Nullable(Int64)")})); + ASSERT_COLUMN_EQ( + createColumn>({0, MAX_INT16, -1, MIN_INT16, {}}), + executeFunction(func_name, + {createColumn>({0, MAX_INT16, -1, MIN_INT16, {}}), + createCastTypeConstColumn("Nullable(Int64)")})); + ASSERT_COLUMN_EQ( + createColumn>({0, MAX_INT32, -1, MIN_INT32, {}}), + executeFunction(func_name, + {createColumn>({0, MAX_INT32, -1, MIN_INT32, {}}), + createCastTypeConstColumn("Nullable(Int64)")})); + ASSERT_COLUMN_EQ( + createColumn>({0, MAX_INT64, -1, MIN_INT64, {}}), + executeFunction(func_name, + {createColumn>({0, MAX_INT64, -1, MIN_INT64, {}}), + createCastTypeConstColumn("Nullable(Int64)")})); +} +CATCH + +TEST_F(TestTidbConversion, castIntAsReal) +try +{ + // uint64/int64 -> float64, may be not precise + ASSERT_COLUMN_EQ( + createColumn>( + {1234567890.0, + 123456789012345680.0, + 0.0, + {}}), + executeFunction(func_name, + {createColumn>( + {1234567890, // this is fine + 123456789012345678, // but this cannot be represented precisely in the IEEE 754 64-bit float format + 0, + {}}), + createCastTypeConstColumn("Nullable(Float64)")})); + ASSERT_COLUMN_EQ( + createColumn>( + {1234567890.0, + 123456789012345680.0, + 0.0, + {}}), + executeFunction(func_name, + {createColumn>( + {1234567890, // this is fine + 123456789012345678, // but this cannot be represented precisely in the IEEE 754 64-bit float format + 0, + {}}), + createCastTypeConstColumn("Nullable(Float64)")})); + // uint32/16/8 and int32/16/8 -> float64, precise + ASSERT_COLUMN_EQ( + createColumn>({MAX_UINT32, 0, {}}), + executeFunction(func_name, + {createColumn>({MAX_UINT32, 0, {}}), + createCastTypeConstColumn("Nullable(Float64)")})); + ASSERT_COLUMN_EQ( + createColumn>({MAX_UINT16, 0, {}}), + executeFunction(func_name, + {createColumn>({MAX_UINT16, 0, {}}), + createCastTypeConstColumn("Nullable(Float64)")})); + ASSERT_COLUMN_EQ( + createColumn>({MAX_UINT8, 0, {}}), + executeFunction(func_name, + {createColumn>({MAX_UINT8, 0, {}}), + createCastTypeConstColumn("Nullable(Float64)")})); + ASSERT_COLUMN_EQ( + createColumn>({MAX_INT32, MIN_INT32, 0, {}}), + executeFunction(func_name, + {createColumn>({MAX_INT32, MIN_INT32, 0, {}}), + createCastTypeConstColumn("Nullable(Float64)")})); + ASSERT_COLUMN_EQ( + createColumn>({MAX_INT16, MIN_INT16, 0, {}}), + executeFunction(func_name, + {createColumn>({MAX_INT16, MIN_INT16, 0, {}}), + createCastTypeConstColumn("Nullable(Float64)")})); + ASSERT_COLUMN_EQ( + createColumn>({MAX_INT8, MIN_INT8, 0, {}}), + executeFunction(func_name, + {createColumn>({MAX_INT8, MIN_INT8, 0, {}}), + createCastTypeConstColumn("Nullable(Float64)")})); +} +CATCH + +TEST_F(TestTidbConversion, castIntAsString) +try +{ + /// null only cases + ASSERT_COLUMN_EQ( + createColumn>({{}}), + executeFunction(func_name, + {createOnlyNullColumn(1), + createCastTypeConstColumn("Nullable(String)")})); + + /// const cases + // uint64/32/16/8 -> string + ASSERT_COLUMN_EQ( + createConstColumn(1, "18446744073709551615"), + executeFunction(func_name, + {createConstColumn(1, MAX_UINT64), + createCastTypeConstColumn("String")})); + ASSERT_COLUMN_EQ( + createConstColumn(1, "4294967295"), + executeFunction(func_name, + {createConstColumn(1, MAX_UINT32), + createCastTypeConstColumn("String")})); + ASSERT_COLUMN_EQ( + createConstColumn(1, "65535"), + executeFunction(func_name, + {createConstColumn(1, MAX_UINT16), + createCastTypeConstColumn("String")})); + ASSERT_COLUMN_EQ( + createConstColumn(1, "255"), + executeFunction(func_name, + {createConstColumn(1, MAX_UINT8), + createCastTypeConstColumn("String")})); + // int64/32/16/8 -> string + ASSERT_COLUMN_EQ( + createConstColumn(1, "9223372036854775807"), + executeFunction(func_name, + {createConstColumn(1, MAX_INT64), + createCastTypeConstColumn("String")})); + ASSERT_COLUMN_EQ( + createConstColumn(1, "2147483647"), + executeFunction(func_name, + {createConstColumn(1, MAX_INT32), + createCastTypeConstColumn("String")})); + ASSERT_COLUMN_EQ( + createConstColumn(1, "32767"), + executeFunction(func_name, + {createConstColumn(1, MAX_INT16), + createCastTypeConstColumn("String")})); + ASSERT_COLUMN_EQ( + createConstColumn(1, "127"), + executeFunction(func_name, + {createConstColumn(1, MAX_INT8), + createCastTypeConstColumn("String")})); + + /// normal cases + // uint64/32/16/8 -> string + ASSERT_COLUMN_EQ( + createColumn>({"18446744073709551615", "0", {}}), + executeFunction(func_name, + {createColumn>({MAX_UINT64, 0, {}}), + createCastTypeConstColumn("Nullable(String)")})); + ASSERT_COLUMN_EQ( + createColumn>({"4294967295", "0", {}}), + executeFunction(func_name, + {createColumn>({MAX_UINT32, 0, {}}), + createCastTypeConstColumn("Nullable(String)")})); + ASSERT_COLUMN_EQ( + createColumn>({"65535", "0", {}}), + executeFunction(func_name, + {createColumn>({MAX_UINT16, 0, {}}), + createCastTypeConstColumn("Nullable(String)")})); + ASSERT_COLUMN_EQ( + createColumn>({"255", "0", {}}), + executeFunction(func_name, + {createColumn>({MAX_UINT8, 0, {}}), + createCastTypeConstColumn("Nullable(String)")})); + // int64/32/16/8 -> string + ASSERT_COLUMN_EQ( + createColumn>({"9223372036854775807", "-9223372036854775808", "0", {}}), + executeFunction(func_name, + {createColumn>({MAX_INT64, MIN_INT64, 0, {}}), + createCastTypeConstColumn("Nullable(String)")})); + ASSERT_COLUMN_EQ( + createColumn>({"2147483647", "-2147483648", "0", {}}), + executeFunction(func_name, + {createColumn>({MAX_INT32, MIN_INT32, 0, {}}), + createCastTypeConstColumn("Nullable(String)")})); + ASSERT_COLUMN_EQ( + createColumn>({"32767", "-32768", "0", {}}), + executeFunction(func_name, + {createColumn>({MAX_INT16, MIN_INT16, 0, {}}), + createCastTypeConstColumn("Nullable(String)")})); + ASSERT_COLUMN_EQ( + createColumn>({"127", "-128", "0", {}}), + executeFunction(func_name, + {createColumn>({MAX_INT8, MIN_INT8, 0, {}}), + createCastTypeConstColumn("Nullable(String)")})); +} +CATCH + +TEST_F(TestTidbConversion, castIntAsDecimal) +try +{ + // int8 -> decimal32/64/128/256 + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(9, 0), + {DecimalField32(MAX_INT8, 0), DecimalField32(MIN_INT8, 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_INT8, MIN_INT8, {}}), + createCastTypeConstColumn("Nullable(Decimal(9,0))")})); + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(18, 0), + {DecimalField64(MAX_INT8, 0), DecimalField64(MIN_INT8, 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_INT8, MIN_INT8, {}}), + createCastTypeConstColumn("Nullable(Decimal(18,0))")})); + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(38, 0), + {DecimalField128(MAX_INT8, 0), DecimalField128(MIN_INT8, 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_INT8, MIN_INT8, {}}), + createCastTypeConstColumn("Nullable(Decimal(38,0))")})); + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(65, 0), + {DecimalField256(static_cast(MAX_INT8), 0), DecimalField256(static_cast(MIN_INT8), 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_INT8, MIN_INT8, {}}), + createCastTypeConstColumn("Nullable(Decimal(65,0))")})); + // int16 -> decimal32/64/128/256 + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(9, 0), + {DecimalField32(MAX_INT16, 0), DecimalField32(MIN_INT16, 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_INT16, MIN_INT16, {}}), + createCastTypeConstColumn("Nullable(Decimal(9,0))")})); + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(18, 0), + {DecimalField64(MAX_INT16, 0), DecimalField64(MIN_INT16, 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_INT16, MIN_INT16, {}}), + createCastTypeConstColumn("Nullable(Decimal(18,0))")})); + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(38, 0), + {DecimalField128(MAX_INT16, 0), DecimalField128(MIN_INT16, 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_INT16, MIN_INT16, {}}), + createCastTypeConstColumn("Nullable(Decimal(38,0))")})); + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(65, 0), + {DecimalField256(static_cast(MAX_INT16), 0), DecimalField256(static_cast(MIN_INT16), 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_INT16, MIN_INT16, {}}), + createCastTypeConstColumn("Nullable(Decimal(65,0))")})); + // int32 -> decimal32/64/128/256 + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(9, 0), + {DecimalField32(999999999, 0), DecimalField32(-999999999, 0), {}}), + executeFunction(func_name, + {createColumn>({999999999, -999999999, {}}), + createCastTypeConstColumn("Nullable(Decimal(9,0))")})); + ASSERT_THROW(executeFunction(func_name, + {createColumn>({1000000000, -1000000000, {}}), + createCastTypeConstColumn("Nullable(Decimal(9,0))")}), + TiFlashException); + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(18, 0), + {DecimalField64(MAX_INT32, 0), DecimalField64(MIN_INT32, 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_INT32, MIN_INT32, {}}), + createCastTypeConstColumn("Nullable(Decimal(18,0))")})); + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(38, 0), + {DecimalField128(MAX_INT32, 0), DecimalField128(MIN_INT32, 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_INT32, MIN_INT32, {}}), + createCastTypeConstColumn("Nullable(Decimal(38,0))")})); + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(65, 0), + {DecimalField256(static_cast(MAX_INT32), 0), DecimalField256(static_cast(MIN_INT32), 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_INT32, MIN_INT32, {}}), + createCastTypeConstColumn("Nullable(Decimal(65,0))")})); + // int64 -> decimal32/64/128/256 + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(9, 0), + {DecimalField32(999999999, 0), DecimalField32(-999999999, 0), {}}), + executeFunction(func_name, + {createColumn>({999999999, -999999999, {}}), + createCastTypeConstColumn("Nullable(Decimal(9,0))")})); + ASSERT_THROW(executeFunction(func_name, + {createColumn>({1000000000, -1000000000, {}}), + createCastTypeConstColumn("Nullable(Decimal(9,0))")}), + TiFlashException); + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(18, 0), + {DecimalField64(999999999999999999, 0), DecimalField64(-999999999999999999, 0), {}}), + executeFunction(func_name, + {createColumn>({999999999999999999, -999999999999999999, {}}), + createCastTypeConstColumn("Nullable(Decimal(18,0))")})); + ASSERT_THROW(executeFunction(func_name, + {createColumn>({1000000000000000000, -1000000000000000000, {}}), + createCastTypeConstColumn("Nullable(Decimal(18,0))")}), + TiFlashException); + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(38, 0), + {DecimalField128(MAX_INT64, 0), DecimalField128(MIN_INT64, 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_INT64, MIN_INT64, {}}), + createCastTypeConstColumn("Nullable(Decimal(38,0))")})); + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(65, 0), + {DecimalField256(static_cast(MAX_INT64), 0), DecimalField256(static_cast(MIN_INT64), 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_INT64, MIN_INT64, {}}), + createCastTypeConstColumn("Nullable(Decimal(65,0))")})); + // uint8 -> decimal32/64/128/256 + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(9, 0), + {DecimalField32(MAX_UINT8, 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_UINT8, {}}), + createCastTypeConstColumn("Nullable(Decimal(9,0))")})); + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(18, 0), + {DecimalField64(MAX_UINT8, 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_UINT8, {}}), + createCastTypeConstColumn("Nullable(Decimal(18,0))")})); + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(38, 0), + {DecimalField128(MAX_UINT8, 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_UINT8, {}}), + createCastTypeConstColumn("Nullable(Decimal(38,0))")})); + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(65, 0), + {DecimalField256(static_cast(MAX_UINT8), 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_UINT8, {}}), + createCastTypeConstColumn("Nullable(Decimal(65,0))")})); + // uint16 -> decimal32/64/128/256 + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(9, 0), + {DecimalField32(MAX_UINT16, 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_UINT16, {}}), + createCastTypeConstColumn("Nullable(Decimal(9,0))")})); + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(18, 0), + {DecimalField64(MAX_UINT16, 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_UINT16, {}}), + createCastTypeConstColumn("Nullable(Decimal(18,0))")})); + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(38, 0), + {DecimalField128(MAX_UINT16, 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_UINT16, {}}), + createCastTypeConstColumn("Nullable(Decimal(38,0))")})); + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(65, 0), + {DecimalField256(static_cast(MAX_UINT16), 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_UINT16, {}}), + createCastTypeConstColumn("Nullable(Decimal(65,0))")})); + // uint32 -> decimal32/64/128/256 + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(9, 0), + {DecimalField32(999999999, 0), {}}), + executeFunction(func_name, + {createColumn>({999999999, {}}), + createCastTypeConstColumn("Nullable(Decimal(9,0))")})); + ASSERT_THROW(executeFunction(func_name, + {createColumn>({1000000000, {}}), + createCastTypeConstColumn("Nullable(Decimal(9,0))")}), + TiFlashException); + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(18, 0), + {DecimalField64(MAX_UINT32, 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_UINT32, {}}), + createCastTypeConstColumn("Nullable(Decimal(18,0))")})); + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(38, 0), + {DecimalField128(MAX_UINT32, 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_UINT32, {}}), + createCastTypeConstColumn("Nullable(Decimal(38,0))")})); + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(65, 0), + {DecimalField256(static_cast(MAX_UINT32), 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_UINT32, {}}), + createCastTypeConstColumn("Nullable(Decimal(65,0))")})); + // uint64 -> decimal32/64/128/256 + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(9, 0), + {DecimalField32(999999999, 0), {}}), + executeFunction(func_name, + {createColumn>({999999999, {}}), + createCastTypeConstColumn("Nullable(Decimal(9,0))")})); + ASSERT_THROW(executeFunction(func_name, + {createColumn>({1000000000, {}}), + createCastTypeConstColumn("Nullable(Decimal(9,0))")}), + TiFlashException); + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(18, 0), + {DecimalField64(999999999999999999, 0), {}}), + executeFunction(func_name, + {createColumn>({999999999999999999, {}}), + createCastTypeConstColumn("Nullable(Decimal(18,0))")})); + ASSERT_THROW(executeFunction(func_name, + {createColumn>({1000000000000000000, {}}), + createCastTypeConstColumn("Nullable(Decimal(18,0))")}), + TiFlashException); + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(38, 0), + {DecimalField128(MAX_INT64, 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_INT64, {}}), + createCastTypeConstColumn("Nullable(Decimal(38,0))")})); + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(65, 0), + {DecimalField256(static_cast(MAX_INT64), 0), {}}), + executeFunction(func_name, + {createColumn>({MAX_INT64, {}}), + createCastTypeConstColumn("Nullable(Decimal(65,0))")})); +} +CATCH + +TEST_F(TestTidbConversion, castIntAsTime) +try +{ + ASSERT_COLUMN_EQ( + createNullableDateTimeColumn({{}, {{2021, 10, 26, 16, 8, 59, 0}}}, 6), + executeFunction(func_name, + {createColumn>({{}, 20211026160859}), + createCastTypeConstColumn("Nullable(MyDateTime(6))")})); + ASSERT_COLUMN_EQ( + createNullableDateTimeColumn({{}, {{2021, 10, 26, 16, 8, 59, 0}}}, 6), + executeFunction(func_name, + {createColumn>({{}, 20211026160859}), + createCastTypeConstColumn("Nullable(MyDateTime(6))")})); + ASSERT_THROW( + executeFunction(func_name, + {createColumn>({MAX_UINT8}), + createCastTypeConstColumn("Nullable(MyDateTime(6))")}), + TiFlashException); + ASSERT_THROW( + executeFunction(func_name, + {createColumn>({MAX_UINT16}), + createCastTypeConstColumn("Nullable(MyDateTime(6))")}), + TiFlashException); + ASSERT_THROW( + executeFunction(func_name, + {createColumn>({MAX_UINT32}), + createCastTypeConstColumn("Nullable(MyDateTime(6))")}), + TiFlashException); + ASSERT_COLUMN_EQ( + createNullableDateTimeColumn({{}}, 6), + executeFunction(func_name, + {createColumn>({0}), + createCastTypeConstColumn("Nullable(MyDateTime(6))")})); + ASSERT_THROW( + executeFunction(func_name, + {createColumn>({{}, -20211026160859}), + createCastTypeConstColumn("Nullable(MyDateTime(6))")}), + TiFlashException); +} +CATCH + +TEST_F(TestTidbConversion, castTimeAsReal) +try +{ + const auto data_type_ptr = std::make_shared(6); + const Float64 datetime_float = 20211026160859; + const Float64 datetime_frac_float = 20211026160859.125; + + // cast datetime to float + auto col_datetime1 = getDatetimeColumn(); + auto ctn_datetime1 = ColumnWithTypeAndName(std::move(col_datetime1), data_type_ptr, "datetime"); + ASSERT_COLUMN_EQ( + createColumn({datetime_float, datetime_frac_float}), + executeFunction(func_name, + {ctn_datetime1, + createCastTypeConstColumn("Float64")})); + + // cast datetime to nullable float + auto col_datetime2 = getDatetimeColumn(); + auto ctn_datetime2 = ColumnWithTypeAndName(std::move(col_datetime2), data_type_ptr, "datetime"); + ASSERT_COLUMN_EQ( + createColumn>({datetime_float, datetime_frac_float}), + executeFunction(func_name, + {ctn_datetime2, + createCastTypeConstColumn("Nullable(Float64)")})); + + // cast nullable datetime to nullable float + auto col_datetime3 = getDatetimeColumn(); + auto datetime3_null_map = ColumnUInt8::create(2, 0); + datetime3_null_map->getData()[1] = 1; + auto col_datetime3_nullable = ColumnNullable::create(std::move(col_datetime3), std::move(datetime3_null_map)); + auto ctn_datetime3_nullable = ColumnWithTypeAndName(std::move(col_datetime3_nullable), makeNullable(data_type_ptr), "datetime"); + ASSERT_COLUMN_EQ( + createColumn>({datetime_float, {}}), + executeFunction(func_name, + {ctn_datetime3_nullable, + createCastTypeConstColumn("Nullable(Float64)")})); + + // cast const datetime to float + auto col_datetime4_const = ColumnConst::create(getDatetimeColumn(true), 1); + auto ctn_datetime4_const = ColumnWithTypeAndName(std::move(col_datetime4_const), data_type_ptr, "datetime"); + ASSERT_COLUMN_EQ( + createConstColumn(1, datetime_float), + executeFunction(func_name, + {ctn_datetime4_const, + createCastTypeConstColumn("Float64")})); + + // cast nullable const datetime to float + auto col_datetime5 = getDatetimeColumn(true); + auto datetime5_null_map = ColumnUInt8::create(1, 0); + auto col_datetime5_nullable = ColumnNullable::create(std::move(col_datetime5), std::move(datetime5_null_map)); + auto col_datetime5_nullable_const = ColumnConst::create(std::move(col_datetime5_nullable), 1); + auto ctn_datetime5_nullable_const = ColumnWithTypeAndName(std::move(col_datetime5_nullable_const), makeNullable(data_type_ptr), "datetime"); + ASSERT_COLUMN_EQ( + createConstColumn>(1, datetime_float), + executeFunction(func_name, + {ctn_datetime5_nullable_const, + createCastTypeConstColumn("Nullable(Float64)")})); +} +CATCH + +TEST_F(TestTidbConversion, castDurationAsDuration) +try +{ + const auto from_type = std::make_shared(3); + const auto to_type_1 = std::make_shared(5); // from_fsp < to_fsp + const auto to_type_2 = std::make_shared(3); // from_fsp == to_fsp + const auto to_type_3 = std::make_shared(2); // from_fsp < to_fsp + + ColumnWithTypeAndName input( + createColumn({(20 * 3600 + 20 * 60 + 20) * 1000000000L + 555000000L, + -(20 * 3600 + 20 * 60 + 20) * 1000000000L - 555000000L, + (20 * 3600 + 20 * 60 + 20) * 1000000000L + 554000000L, + -(20 * 3600 + 20 * 60 + 20) * 1000000000L - 554000000L, + (20 * 3600 + 20 * 60 + 20) * 1000000000L + 999000000L, + -(20 * 3600 + 20 * 60 + 20) * 1000000000L - 999000000L}) + .column, + from_type, + "input"); + + ColumnWithTypeAndName output1(input.column, to_type_1, "output1"); + ColumnWithTypeAndName output2(input.column, to_type_2, "output2"); + ColumnWithTypeAndName output3( + createColumn({(20 * 3600 + 20 * 60 + 20) * 1000000000L + 560000000L, + -(20 * 3600 + 20 * 60 + 20) * 1000000000L - 560000000L, + (20 * 3600 + 20 * 60 + 20) * 1000000000L + 550000000L, + -(20 * 3600 + 20 * 60 + 20) * 1000000000L - 550000000L, + (20 * 3600 + 20 * 60 + 21) * 1000000000L + 000000000L, + -(20 * 3600 + 20 * 60 + 21) * 1000000000L - 000000000L}) + .column, + to_type_3, + "output3"); + + ASSERT_COLUMN_EQ(output1, executeFunction(func_name, {input, createCastTypeConstColumn(to_type_1->getName())})); + ASSERT_COLUMN_EQ(output2, executeFunction(func_name, {input, createCastTypeConstColumn(to_type_2->getName())})); + ASSERT_COLUMN_EQ(output3, executeFunction(func_name, {input, createCastTypeConstColumn(to_type_3->getName())})); + + // Test Nullable + ColumnWithTypeAndName input_nullable( + createColumn>({(20 * 3600 + 20 * 60 + 20) * 1000000000L + 555000000L, + -(20 * 3600 + 20 * 60 + 20) * 1000000000L - 555000000L, + {}, + (20 * 3600 + 20 * 60 + 20) * 1000000000L + 554000000L, + -(20 * 3600 + 20 * 60 + 20) * 1000000000L - 554000000L, + {}, + (20 * 3600 + 20 * 60 + 20) * 1000000000L + 999000000L, + -(20 * 3600 + 20 * 60 + 20) * 1000000000L - 999000000L}) + .column, + makeNullable(input.type), + "input_nullable"); + ColumnWithTypeAndName output1_nullable(input_nullable.column, makeNullable(to_type_1), "output1_nullable"); + ColumnWithTypeAndName output2_nullable(input_nullable.column, makeNullable(to_type_2), "output2_nullable"); + ColumnWithTypeAndName output3_nullable( + createColumn>({(20 * 3600 + 20 * 60 + 20) * 1000000000L + 560000000L, + -(20 * 3600 + 20 * 60 + 20) * 1000000000L - 560000000L, + {}, + (20 * 3600 + 20 * 60 + 20) * 1000000000L + 550000000L, + -(20 * 3600 + 20 * 60 + 20) * 1000000000L - 550000000L, + {}, + (20 * 3600 + 20 * 60 + 21) * 1000000000L + 000000000L, + -(20 * 3600 + 20 * 60 + 21) * 1000000000L - 000000000L}) + .column, + makeNullable(to_type_3), + "output3_output"); + + ASSERT_COLUMN_EQ(output1_nullable, executeFunction(func_name, {input_nullable, createCastTypeConstColumn(makeNullable(to_type_1)->getName())})); + ASSERT_COLUMN_EQ(output2_nullable, executeFunction(func_name, {input_nullable, createCastTypeConstColumn(makeNullable(to_type_2)->getName())})); + ASSERT_COLUMN_EQ(output3_nullable, executeFunction(func_name, {input_nullable, createCastTypeConstColumn(makeNullable(to_type_3)->getName())})); + + // Test Const + ColumnWithTypeAndName input_const(createConstColumn(1, (20 * 3600 + 20 * 60 + 20) * 1000000000L + 999000000L).column, from_type, "input_const"); + ColumnWithTypeAndName output1_const(input_const.column, to_type_1, "output1_const"); + ColumnWithTypeAndName output2_const(input_const.column, to_type_2, "output2_const"); + ColumnWithTypeAndName output3_const(createConstColumn(1, (20 * 3600 + 20 * 60 + 21) * 1000000000L + 000000000L).column, to_type_3, "output3_const"); + + ASSERT_COLUMN_EQ(output1_const, executeFunction(func_name, {input_const, createCastTypeConstColumn(to_type_1->getName())})); + ASSERT_COLUMN_EQ(output2_const, executeFunction(func_name, {input_const, createCastTypeConstColumn(to_type_2->getName())})); + ASSERT_COLUMN_EQ(output3_const, executeFunction(func_name, {input_const, createCastTypeConstColumn(to_type_3->getName())})); +} +CATCH + +TEST_F(TestTidbConversion, StrToDateTypeTest) +try +{ + // Arg1 is ColumnVector, Arg2 is ColumnVector + auto arg1_column = createColumn>({{}, "1/12/2020", "00:59:60 ", "1/12/2020"}); + auto arg2_column = createColumn>({"%d/%c/%Y", {}, "%H:%i:%S ", "%d/%c/%Y"}); + ColumnWithTypeAndName result_column( + createColumn>({{}, {}, {}, MyDateTime{2020, 12, 1, 0, 0, 0, 0}.toPackedUInt()}).column, + makeNullable(std::make_shared(0)), + "result"); + ASSERT_COLUMN_EQ(result_column, executeFunction("strToDateDatetime", arg1_column, arg2_column)); + + // Arg1 is ColumnConst(ColumnNullable(non-null value)), Arg2 is ColumnVector + arg1_column = createConstColumn>(2, {"1/12/2020"}); + arg2_column = createColumn>({"%d/%c/%Y", "%d/%c/%Y"}); + result_column = ColumnWithTypeAndName( + createColumn>({MyDateTime{2020, 12, 1, 0, 0, 0, 0}.toPackedUInt(), MyDateTime{2020, 12, 1, 0, 0, 0, 0}.toPackedUInt()}).column, + makeNullable(std::make_shared(0)), + "result"); + ASSERT_COLUMN_EQ(result_column, executeFunction("strToDateDatetime", arg1_column, arg2_column)); + + // Arg1 is ColumnConst(ColumnNullable(null value)), Arg2 is ColumnVector + arg1_column = createConstColumn>(2, {}); + arg2_column = createColumn>({"%d/%c/%Y", "%d/%c/%Y"}); + result_column = ColumnWithTypeAndName( + createConstColumn>(2, {}).column, + makeNullable(std::make_shared(0)), + "result"); + ASSERT_COLUMN_EQ(result_column, executeFunction("strToDateDatetime", arg1_column, arg2_column)); + + // Arg1 is ColumnVector, Arg2 is ColumnConst(ColumnNullable(non-null value)) + arg1_column = createColumn>({"1/12/2020", "1/12/2020"}); + arg2_column = createConstColumn>(2, "%d/%c/%Y"); + result_column = ColumnWithTypeAndName( + createColumn>({MyDateTime{2020, 12, 1, 0, 0, 0, 0}.toPackedUInt(), MyDateTime{2020, 12, 1, 0, 0, 0, 0}.toPackedUInt()}).column, + makeNullable(std::make_shared(0)), + "result"); + ASSERT_COLUMN_EQ(result_column, executeFunction("strToDateDatetime", arg1_column, arg2_column)); + + // Arg1 is ColumnConst(ColumnNullable(non-null value)), Arg2 is ColumnConst(ColumnNullable(non-null value)) + arg1_column = createConstColumn>(2, "1/12/2020"); + arg2_column = createConstColumn>(2, "%d/%c/%Y"); + result_column = ColumnWithTypeAndName( + createConstColumn>(2, {MyDateTime{2020, 12, 1, 0, 0, 0, 0}.toPackedUInt()}).column, + makeNullable(std::make_shared(0)), + "result"); + ASSERT_COLUMN_EQ(result_column, executeFunction("strToDateDatetime", arg1_column, arg2_column)); + + // Arg1 is ColumnConst(ColumnNullable(null value)), Arg2 is ColumnConst(ColumnNullable(non-null value)) + arg1_column = createConstColumn>(2, {}); + arg2_column = createConstColumn>(2, "%d/%c/%Y"); + result_column = ColumnWithTypeAndName( + createConstColumn>(2, {}).column, + makeNullable(std::make_shared(0)), + "result"); + ASSERT_COLUMN_EQ(result_column, executeFunction("strToDateDatetime", arg1_column, arg2_column)); + + // Arg1 is ColumnVector, Arg2 is ColumnConst(ColumnNullable(null value)) + arg1_column = createColumn>({"1/12/2020", "1/12/2020"}); + arg2_column = createConstColumn>(2, {}); + result_column = ColumnWithTypeAndName( + createConstColumn>(2, {}).column, + makeNullable(std::make_shared(0)), + "result"); + ASSERT_COLUMN_EQ(result_column, executeFunction("strToDateDatetime", arg1_column, arg2_column)); + + // Arg1 is ColumnConst(ColumnNullable(non-null value)), Arg2 is ColumnConst(ColumnNullable(null value)) + arg1_column = createConstColumn>(2, {"1/12/2020"}); + arg2_column = createConstColumn>(2, {}); + result_column = ColumnWithTypeAndName( + createConstColumn>(2, {}).column, + makeNullable(std::make_shared(0)), + "result"); + ASSERT_COLUMN_EQ(result_column, executeFunction("strToDateDatetime", arg1_column, arg2_column)); + + // Arg1 is ColumnConst(ColumnNullable(null value)), Arg2 is ColumnConst(ColumnNullable(null value)) + arg1_column = createConstColumn>(2, {}); + arg2_column = createConstColumn>(2, {}); + result_column = ColumnWithTypeAndName( + createConstColumn>(2, {}).column, + makeNullable(std::make_shared(0)), + "result"); + ASSERT_COLUMN_EQ(result_column, executeFunction("strToDateDatetime", arg1_column, arg2_column)); +} +CATCH + +} // namespace +} // namespace tests +} // namespace DB From 1204c7613ae9f42b4beb04ba59ef553b25442129 Mon Sep 17 00:00:00 2001 From: wshwsh12 <793703860@qq.com> Date: Tue, 25 Jan 2022 17:36:16 +0800 Subject: [PATCH 2/2] resolve conflict --- dbms/src/Common/MyTime.cpp | 198 +--- dbms/src/Functions/FunctionsConversion.h | 14 +- .../Functions/tests/gtest_tidb_conversion.cpp | 948 ------------------ 3 files changed, 10 insertions(+), 1150 deletions(-) delete mode 100644 dbms/src/Functions/tests/gtest_tidb_conversion.cpp diff --git a/dbms/src/Common/MyTime.cpp b/dbms/src/Common/MyTime.cpp index e8670981b18..4e9aacf5dbb 100644 --- a/dbms/src/Common/MyTime.cpp +++ b/dbms/src/Common/MyTime.cpp @@ -1224,13 +1224,9 @@ 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] @@ -1478,7 +1474,6 @@ MyDateTimeParser::MyDateTimeParser(String format_) : format(std::move(format_)) break; } } -<<<<<<< HEAD if (step == 0) return false; ctx.pos += step; @@ -1486,6 +1481,9 @@ MyDateTimeParser::MyDateTimeParser(String format_) : format(std::move(format_)) }); break; } + case 'm': + //"%m": Month, numeric (00..12) + [[fallthrough]]; case 'c': { //"%c": Month, numeric (0..12) @@ -1523,153 +1521,13 @@ 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. + // The suffix '0' can be ignored. // "9" means 900000 - while (ms > 0 && ms * 10 < 1000000) + for (size_t i = step; i < 6; i++) { ms *= 10; } @@ -1765,19 +1623,6 @@ MyDateTimeParser::MyDateTimeParser(String format_) : format(std::move(format_)) }); break; } - case 'm': - { - //"%m": Month, numeric (00..12) - parsers.emplace_back([](MyDateTimeParser::Context & ctx, MyTimeBase & time) -> bool { - auto [step, month] = parseNDigits(ctx.view, ctx.pos, 2); - if (step == 0 || month > 12) - return false; - time.month = month; - ctx.pos += step; - return true; - }); - break; - } case 'S': //"%S": Seconds (00..59) [[fallthrough]]; @@ -1801,39 +1646,6 @@ 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') diff --git a/dbms/src/Functions/FunctionsConversion.h b/dbms/src/Functions/FunctionsConversion.h index 609f48f75ba..3c1840b86d2 100644 --- a/dbms/src/Functions/FunctionsConversion.h +++ b/dbms/src/Functions/FunctionsConversion.h @@ -1614,20 +1614,16 @@ class FunctionStrToDate : public IFunction DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override { if (arguments.size() != 2) - throw Exception(fmt::format("Function {} only accept 2 arguments", getName()), ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); + throw Exception("Function " + getName() + " only accept 2 arguments", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); // TODO: Maybe FixedString? if (!removeNullable(arguments[0].type)->isString()) -<<<<<<< HEAD throw Exception("First argument for function " + getName() + " must be String, but get " + arguments[0].type->getName(), ErrorCodes::ILLEGAL_COLUMN); -======= - throw Exception(fmt::format("First argument for function {} must be String, but get {}", getName(), arguments[0].type->getName()), - ErrorCodes::ILLEGAL_COLUMN); ->>>>>>> 4b4b8b4240 (Add unittests for str_to_date, fix #3556, #3557 (#3581)) if (!removeNullable(arguments[1].type)->isString()) - throw Exception(fmt::format("Second argument for function {} must be String, but get {}", getName(), arguments[1].type->getName()), - ErrorCodes::ILLEGAL_COLUMN); + throw Exception( + "Second argument for function " + getName() + " must be String, but get " + arguments[1].type->getName(), + ErrorCodes::ILLEGAL_COLUMN); if constexpr (std::is_same_v) { @@ -1642,7 +1638,7 @@ class FunctionStrToDate : public IFunction } else { - throw Exception(fmt::format("Unknown name for FunctionStrToDate: {}", getName()), ErrorCodes::LOGICAL_ERROR); + throw Exception("Unknown name for FunctionStrToDate:" + getName(), ErrorCodes::LOGICAL_ERROR); } } diff --git a/dbms/src/Functions/tests/gtest_tidb_conversion.cpp b/dbms/src/Functions/tests/gtest_tidb_conversion.cpp deleted file mode 100644 index c1932f710e5..00000000000 --- a/dbms/src/Functions/tests/gtest_tidb_conversion.cpp +++ /dev/null @@ -1,948 +0,0 @@ -#include - -#include "Columns/ColumnsNumber.h" -#include "Core/ColumnWithTypeAndName.h" -#include "DataTypes/DataTypeMyDateTime.h" -#include "DataTypes/DataTypeMyDuration.h" -#include "DataTypes/DataTypeNullable.h" -#include "DataTypes/DataTypesNumber.h" -#include "Functions/FunctionFactory.h" -#include "Functions/FunctionHelpers.h" -#include "TestUtils/FunctionTestUtils.h" -#include "common/types.h" -#include "gtest/gtest.h" - -namespace DB -{ -namespace tests -{ -namespace -{ -auto getDatetimeColumn(bool single_field = false) -{ - MyDateTime datetime(2021, 10, 26, 16, 8, 59, 0); - MyDateTime datetime_frac(2021, 10, 26, 16, 8, 59, 123456); - - auto col_datetime = ColumnUInt64::create(); - col_datetime->insert(Field(datetime.toPackedUInt())); - if (!single_field) - col_datetime->insert(Field(datetime_frac.toPackedUInt())); - return col_datetime; -} - -auto createCastTypeConstColumn(String str) -{ - return createConstColumn(1, str); -} - -const std::string func_name = "tidb_cast"; - -const Int8 MAX_INT8 = std::numeric_limits::max(); -const Int8 MIN_INT8 = std::numeric_limits::min(); -const Int16 MAX_INT16 = std::numeric_limits::max(); -const Int16 MIN_INT16 = std::numeric_limits::min(); -const Int32 MAX_INT32 = std::numeric_limits::max(); -const Int32 MIN_INT32 = std::numeric_limits::min(); -const Int64 MAX_INT64 = std::numeric_limits::max(); -const Int64 MIN_INT64 = std::numeric_limits::min(); -const UInt8 MAX_UINT8 = std::numeric_limits::max(); -const UInt16 MAX_UINT16 = std::numeric_limits::max(); -const UInt32 MAX_UINT32 = std::numeric_limits::max(); -const UInt64 MAX_UINT64 = std::numeric_limits::max(); - -class TestTidbConversion : public DB::tests::FunctionTest -{ -}; - -using DecimalField32 = DecimalField; -using DecimalField64 = DecimalField; -using DecimalField128 = DecimalField; -using DecimalField256 = DecimalField; - -TEST_F(TestTidbConversion, castIntAsInt) -try -{ - /// null only cases - ASSERT_COLUMN_EQ( - createColumn>({{}}), - executeFunction(func_name, - {createOnlyNullColumn(1), - createCastTypeConstColumn("Nullable(UInt64)")})); - ASSERT_COLUMN_EQ( - createColumn>({{}}), - executeFunction(func_name, - {createOnlyNullColumn(1), - createCastTypeConstColumn("Nullable(Int64)")})); - - /// const cases - // uint8/16/32/64 -> uint64, no overflow - ASSERT_COLUMN_EQ( - createConstColumn(1, MAX_UINT8), - executeFunction(func_name, - {createConstColumn(1, MAX_UINT8), - createCastTypeConstColumn("UInt64")})); - ASSERT_COLUMN_EQ( - createConstColumn(1, MAX_UINT16), - executeFunction(func_name, - {createConstColumn(1, MAX_UINT16), - createCastTypeConstColumn("UInt64")})); - ASSERT_COLUMN_EQ( - createConstColumn(1, MAX_UINT32), - executeFunction(func_name, - {createConstColumn(1, MAX_UINT32), - createCastTypeConstColumn("UInt64")})); - ASSERT_COLUMN_EQ( - createConstColumn(1, MAX_UINT64), - executeFunction(func_name, - {createConstColumn(1, MAX_UINT64), - createCastTypeConstColumn("UInt64")})); - // int8/16/32/64 -> uint64, no overflow - ASSERT_COLUMN_EQ( - createConstColumn(1, MAX_INT8), - executeFunction(func_name, - {createConstColumn(1, MAX_INT8), - createCastTypeConstColumn("UInt64")})); - ASSERT_COLUMN_EQ( - createConstColumn(1, MAX_INT16), - executeFunction(func_name, - {createConstColumn(1, MAX_INT16), - createCastTypeConstColumn("UInt64")})); - ASSERT_COLUMN_EQ( - createConstColumn(1, MAX_INT32), - executeFunction(func_name, - {createConstColumn(1, MAX_INT32), - createCastTypeConstColumn("UInt64")})); - ASSERT_COLUMN_EQ( - createConstColumn(1, MAX_INT64), - executeFunction(func_name, - {createConstColumn(1, MAX_INT64), - createCastTypeConstColumn("UInt64")})); - // uint8/16/32 -> int64, no overflow - ASSERT_COLUMN_EQ( - createConstColumn(1, MAX_UINT8), - executeFunction(func_name, - {createConstColumn(1, MAX_UINT8), - createCastTypeConstColumn("Int64")})); - ASSERT_COLUMN_EQ( - createConstColumn(1, MAX_UINT16), - executeFunction(func_name, - {createConstColumn(1, MAX_UINT16), - createCastTypeConstColumn("Int64")})); - ASSERT_COLUMN_EQ( - createConstColumn(1, MAX_UINT32), - executeFunction(func_name, - {createConstColumn(1, MAX_UINT32), - createCastTypeConstColumn("Int64")})); - // uint64 -> int64, will overflow - ASSERT_COLUMN_EQ( - createConstColumn(1, -1), - executeFunction(func_name, - {createConstColumn(1, MAX_UINT64), - createCastTypeConstColumn("Int64")})); - // int8/16/32/64 -> int64, no overflow - ASSERT_COLUMN_EQ( - createConstColumn(1, MAX_INT8), - executeFunction(func_name, - {createConstColumn(1, MAX_INT8), - createCastTypeConstColumn("Int64")})); - ASSERT_COLUMN_EQ( - createConstColumn(1, MAX_INT16), - executeFunction(func_name, - {createConstColumn(1, MAX_INT16), - createCastTypeConstColumn("Int64")})); - ASSERT_COLUMN_EQ( - createConstColumn(1, MAX_INT32), - executeFunction(func_name, - {createConstColumn(1, MAX_INT32), - createCastTypeConstColumn("Int64")})); - ASSERT_COLUMN_EQ( - createConstColumn(1, MAX_INT64), - executeFunction(func_name, - {createConstColumn(1, MAX_INT64), - createCastTypeConstColumn("Int64")})); - - /// normal cases - // uint8/16/32/64 -> uint64, no overflow - ASSERT_COLUMN_EQ( - createColumn>({0, 1, MAX_UINT8, {}}), - executeFunction(func_name, - {createColumn>({0, 1, MAX_UINT8, {}}), - createCastTypeConstColumn("Nullable(UInt64)")})); - ASSERT_COLUMN_EQ( - createColumn>({0, 1, MAX_UINT16, {}}), - executeFunction(func_name, - {createColumn>({0, 1, MAX_UINT16, {}}), - createCastTypeConstColumn("Nullable(UInt64)")})); - ASSERT_COLUMN_EQ( - createColumn>({0, 1, MAX_UINT32, {}}), - executeFunction(func_name, - {createColumn>({0, 1, MAX_UINT32, {}}), - createCastTypeConstColumn("Nullable(UInt64)")})); - ASSERT_COLUMN_EQ( - createColumn>({0, 1, MAX_UINT64, {}}), - executeFunction(func_name, - {createColumn>({0, 1, MAX_UINT64, {}}), - createCastTypeConstColumn("Nullable(UInt64)")})); - // int8/16/32/64 -> uint64, no overflow - ASSERT_COLUMN_EQ( - createColumn>({0, MAX_INT8, MAX_UINT64, MAX_UINT64 - MAX_INT8, {}}), - executeFunction(func_name, - {createColumn>({0, MAX_INT8, -1, MIN_INT8, {}}), - createCastTypeConstColumn("Nullable(UInt64)")})); - ASSERT_COLUMN_EQ( - createColumn>({0, MAX_INT16, MAX_UINT64, MAX_UINT64 - MAX_INT16, {}}), - executeFunction(func_name, - {createColumn>({0, MAX_INT16, -1, MIN_INT16, {}}), - createCastTypeConstColumn("Nullable(UInt64)")})); - ASSERT_COLUMN_EQ( - createColumn>({0, MAX_INT32, MAX_UINT64, MAX_UINT64 - MAX_INT32, {}}), - executeFunction(func_name, - {createColumn>({0, MAX_INT32, -1, MIN_INT32, {}}), - createCastTypeConstColumn("Nullable(UInt64)")})); - ASSERT_COLUMN_EQ( - createColumn>({0, MAX_INT64, MAX_UINT64, MAX_UINT64 - MAX_INT64, {}}), - executeFunction(func_name, - {createColumn>({0, MAX_INT64, -1, MIN_INT64, {}}), - createCastTypeConstColumn("Nullable(UInt64)")})); - // uint8/16/32 -> int64, no overflow - ASSERT_COLUMN_EQ( - createColumn>({0, MAX_INT8, MAX_UINT8, {}}), - executeFunction(func_name, - {createColumn>({0, MAX_INT8, MAX_UINT8, {}}), - createCastTypeConstColumn("Nullable(Int64)")})); - ASSERT_COLUMN_EQ( - createColumn>({0, MAX_INT16, MAX_UINT16, {}}), - executeFunction(func_name, - {createColumn>({0, MAX_INT16, MAX_UINT16, {}}), - createCastTypeConstColumn("Nullable(Int64)")})); - ASSERT_COLUMN_EQ( - createColumn>({0, MAX_INT32, MAX_UINT32, {}}), - executeFunction(func_name, - {createColumn>({0, MAX_INT32, MAX_UINT32, {}}), - createCastTypeConstColumn("Nullable(Int64)")})); - // uint64 -> int64, overflow may happen - ASSERT_COLUMN_EQ( - createColumn>({0, MAX_INT64, -1, {}}), - executeFunction(func_name, - {createColumn>({0, MAX_INT64, MAX_UINT64, {}}), - createCastTypeConstColumn("Nullable(Int64)")})); - // int8/16/32/64 -> int64, no overflow - ASSERT_COLUMN_EQ( - createColumn>({0, MAX_INT8, -1, MIN_INT8, {}}), - executeFunction(func_name, - {createColumn>({0, MAX_INT8, -1, MIN_INT8, {}}), - createCastTypeConstColumn("Nullable(Int64)")})); - ASSERT_COLUMN_EQ( - createColumn>({0, MAX_INT16, -1, MIN_INT16, {}}), - executeFunction(func_name, - {createColumn>({0, MAX_INT16, -1, MIN_INT16, {}}), - createCastTypeConstColumn("Nullable(Int64)")})); - ASSERT_COLUMN_EQ( - createColumn>({0, MAX_INT32, -1, MIN_INT32, {}}), - executeFunction(func_name, - {createColumn>({0, MAX_INT32, -1, MIN_INT32, {}}), - createCastTypeConstColumn("Nullable(Int64)")})); - ASSERT_COLUMN_EQ( - createColumn>({0, MAX_INT64, -1, MIN_INT64, {}}), - executeFunction(func_name, - {createColumn>({0, MAX_INT64, -1, MIN_INT64, {}}), - createCastTypeConstColumn("Nullable(Int64)")})); -} -CATCH - -TEST_F(TestTidbConversion, castIntAsReal) -try -{ - // uint64/int64 -> float64, may be not precise - ASSERT_COLUMN_EQ( - createColumn>( - {1234567890.0, - 123456789012345680.0, - 0.0, - {}}), - executeFunction(func_name, - {createColumn>( - {1234567890, // this is fine - 123456789012345678, // but this cannot be represented precisely in the IEEE 754 64-bit float format - 0, - {}}), - createCastTypeConstColumn("Nullable(Float64)")})); - ASSERT_COLUMN_EQ( - createColumn>( - {1234567890.0, - 123456789012345680.0, - 0.0, - {}}), - executeFunction(func_name, - {createColumn>( - {1234567890, // this is fine - 123456789012345678, // but this cannot be represented precisely in the IEEE 754 64-bit float format - 0, - {}}), - createCastTypeConstColumn("Nullable(Float64)")})); - // uint32/16/8 and int32/16/8 -> float64, precise - ASSERT_COLUMN_EQ( - createColumn>({MAX_UINT32, 0, {}}), - executeFunction(func_name, - {createColumn>({MAX_UINT32, 0, {}}), - createCastTypeConstColumn("Nullable(Float64)")})); - ASSERT_COLUMN_EQ( - createColumn>({MAX_UINT16, 0, {}}), - executeFunction(func_name, - {createColumn>({MAX_UINT16, 0, {}}), - createCastTypeConstColumn("Nullable(Float64)")})); - ASSERT_COLUMN_EQ( - createColumn>({MAX_UINT8, 0, {}}), - executeFunction(func_name, - {createColumn>({MAX_UINT8, 0, {}}), - createCastTypeConstColumn("Nullable(Float64)")})); - ASSERT_COLUMN_EQ( - createColumn>({MAX_INT32, MIN_INT32, 0, {}}), - executeFunction(func_name, - {createColumn>({MAX_INT32, MIN_INT32, 0, {}}), - createCastTypeConstColumn("Nullable(Float64)")})); - ASSERT_COLUMN_EQ( - createColumn>({MAX_INT16, MIN_INT16, 0, {}}), - executeFunction(func_name, - {createColumn>({MAX_INT16, MIN_INT16, 0, {}}), - createCastTypeConstColumn("Nullable(Float64)")})); - ASSERT_COLUMN_EQ( - createColumn>({MAX_INT8, MIN_INT8, 0, {}}), - executeFunction(func_name, - {createColumn>({MAX_INT8, MIN_INT8, 0, {}}), - createCastTypeConstColumn("Nullable(Float64)")})); -} -CATCH - -TEST_F(TestTidbConversion, castIntAsString) -try -{ - /// null only cases - ASSERT_COLUMN_EQ( - createColumn>({{}}), - executeFunction(func_name, - {createOnlyNullColumn(1), - createCastTypeConstColumn("Nullable(String)")})); - - /// const cases - // uint64/32/16/8 -> string - ASSERT_COLUMN_EQ( - createConstColumn(1, "18446744073709551615"), - executeFunction(func_name, - {createConstColumn(1, MAX_UINT64), - createCastTypeConstColumn("String")})); - ASSERT_COLUMN_EQ( - createConstColumn(1, "4294967295"), - executeFunction(func_name, - {createConstColumn(1, MAX_UINT32), - createCastTypeConstColumn("String")})); - ASSERT_COLUMN_EQ( - createConstColumn(1, "65535"), - executeFunction(func_name, - {createConstColumn(1, MAX_UINT16), - createCastTypeConstColumn("String")})); - ASSERT_COLUMN_EQ( - createConstColumn(1, "255"), - executeFunction(func_name, - {createConstColumn(1, MAX_UINT8), - createCastTypeConstColumn("String")})); - // int64/32/16/8 -> string - ASSERT_COLUMN_EQ( - createConstColumn(1, "9223372036854775807"), - executeFunction(func_name, - {createConstColumn(1, MAX_INT64), - createCastTypeConstColumn("String")})); - ASSERT_COLUMN_EQ( - createConstColumn(1, "2147483647"), - executeFunction(func_name, - {createConstColumn(1, MAX_INT32), - createCastTypeConstColumn("String")})); - ASSERT_COLUMN_EQ( - createConstColumn(1, "32767"), - executeFunction(func_name, - {createConstColumn(1, MAX_INT16), - createCastTypeConstColumn("String")})); - ASSERT_COLUMN_EQ( - createConstColumn(1, "127"), - executeFunction(func_name, - {createConstColumn(1, MAX_INT8), - createCastTypeConstColumn("String")})); - - /// normal cases - // uint64/32/16/8 -> string - ASSERT_COLUMN_EQ( - createColumn>({"18446744073709551615", "0", {}}), - executeFunction(func_name, - {createColumn>({MAX_UINT64, 0, {}}), - createCastTypeConstColumn("Nullable(String)")})); - ASSERT_COLUMN_EQ( - createColumn>({"4294967295", "0", {}}), - executeFunction(func_name, - {createColumn>({MAX_UINT32, 0, {}}), - createCastTypeConstColumn("Nullable(String)")})); - ASSERT_COLUMN_EQ( - createColumn>({"65535", "0", {}}), - executeFunction(func_name, - {createColumn>({MAX_UINT16, 0, {}}), - createCastTypeConstColumn("Nullable(String)")})); - ASSERT_COLUMN_EQ( - createColumn>({"255", "0", {}}), - executeFunction(func_name, - {createColumn>({MAX_UINT8, 0, {}}), - createCastTypeConstColumn("Nullable(String)")})); - // int64/32/16/8 -> string - ASSERT_COLUMN_EQ( - createColumn>({"9223372036854775807", "-9223372036854775808", "0", {}}), - executeFunction(func_name, - {createColumn>({MAX_INT64, MIN_INT64, 0, {}}), - createCastTypeConstColumn("Nullable(String)")})); - ASSERT_COLUMN_EQ( - createColumn>({"2147483647", "-2147483648", "0", {}}), - executeFunction(func_name, - {createColumn>({MAX_INT32, MIN_INT32, 0, {}}), - createCastTypeConstColumn("Nullable(String)")})); - ASSERT_COLUMN_EQ( - createColumn>({"32767", "-32768", "0", {}}), - executeFunction(func_name, - {createColumn>({MAX_INT16, MIN_INT16, 0, {}}), - createCastTypeConstColumn("Nullable(String)")})); - ASSERT_COLUMN_EQ( - createColumn>({"127", "-128", "0", {}}), - executeFunction(func_name, - {createColumn>({MAX_INT8, MIN_INT8, 0, {}}), - createCastTypeConstColumn("Nullable(String)")})); -} -CATCH - -TEST_F(TestTidbConversion, castIntAsDecimal) -try -{ - // int8 -> decimal32/64/128/256 - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(9, 0), - {DecimalField32(MAX_INT8, 0), DecimalField32(MIN_INT8, 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_INT8, MIN_INT8, {}}), - createCastTypeConstColumn("Nullable(Decimal(9,0))")})); - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(18, 0), - {DecimalField64(MAX_INT8, 0), DecimalField64(MIN_INT8, 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_INT8, MIN_INT8, {}}), - createCastTypeConstColumn("Nullable(Decimal(18,0))")})); - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(38, 0), - {DecimalField128(MAX_INT8, 0), DecimalField128(MIN_INT8, 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_INT8, MIN_INT8, {}}), - createCastTypeConstColumn("Nullable(Decimal(38,0))")})); - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(65, 0), - {DecimalField256(static_cast(MAX_INT8), 0), DecimalField256(static_cast(MIN_INT8), 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_INT8, MIN_INT8, {}}), - createCastTypeConstColumn("Nullable(Decimal(65,0))")})); - // int16 -> decimal32/64/128/256 - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(9, 0), - {DecimalField32(MAX_INT16, 0), DecimalField32(MIN_INT16, 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_INT16, MIN_INT16, {}}), - createCastTypeConstColumn("Nullable(Decimal(9,0))")})); - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(18, 0), - {DecimalField64(MAX_INT16, 0), DecimalField64(MIN_INT16, 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_INT16, MIN_INT16, {}}), - createCastTypeConstColumn("Nullable(Decimal(18,0))")})); - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(38, 0), - {DecimalField128(MAX_INT16, 0), DecimalField128(MIN_INT16, 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_INT16, MIN_INT16, {}}), - createCastTypeConstColumn("Nullable(Decimal(38,0))")})); - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(65, 0), - {DecimalField256(static_cast(MAX_INT16), 0), DecimalField256(static_cast(MIN_INT16), 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_INT16, MIN_INT16, {}}), - createCastTypeConstColumn("Nullable(Decimal(65,0))")})); - // int32 -> decimal32/64/128/256 - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(9, 0), - {DecimalField32(999999999, 0), DecimalField32(-999999999, 0), {}}), - executeFunction(func_name, - {createColumn>({999999999, -999999999, {}}), - createCastTypeConstColumn("Nullable(Decimal(9,0))")})); - ASSERT_THROW(executeFunction(func_name, - {createColumn>({1000000000, -1000000000, {}}), - createCastTypeConstColumn("Nullable(Decimal(9,0))")}), - TiFlashException); - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(18, 0), - {DecimalField64(MAX_INT32, 0), DecimalField64(MIN_INT32, 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_INT32, MIN_INT32, {}}), - createCastTypeConstColumn("Nullable(Decimal(18,0))")})); - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(38, 0), - {DecimalField128(MAX_INT32, 0), DecimalField128(MIN_INT32, 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_INT32, MIN_INT32, {}}), - createCastTypeConstColumn("Nullable(Decimal(38,0))")})); - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(65, 0), - {DecimalField256(static_cast(MAX_INT32), 0), DecimalField256(static_cast(MIN_INT32), 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_INT32, MIN_INT32, {}}), - createCastTypeConstColumn("Nullable(Decimal(65,0))")})); - // int64 -> decimal32/64/128/256 - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(9, 0), - {DecimalField32(999999999, 0), DecimalField32(-999999999, 0), {}}), - executeFunction(func_name, - {createColumn>({999999999, -999999999, {}}), - createCastTypeConstColumn("Nullable(Decimal(9,0))")})); - ASSERT_THROW(executeFunction(func_name, - {createColumn>({1000000000, -1000000000, {}}), - createCastTypeConstColumn("Nullable(Decimal(9,0))")}), - TiFlashException); - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(18, 0), - {DecimalField64(999999999999999999, 0), DecimalField64(-999999999999999999, 0), {}}), - executeFunction(func_name, - {createColumn>({999999999999999999, -999999999999999999, {}}), - createCastTypeConstColumn("Nullable(Decimal(18,0))")})); - ASSERT_THROW(executeFunction(func_name, - {createColumn>({1000000000000000000, -1000000000000000000, {}}), - createCastTypeConstColumn("Nullable(Decimal(18,0))")}), - TiFlashException); - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(38, 0), - {DecimalField128(MAX_INT64, 0), DecimalField128(MIN_INT64, 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_INT64, MIN_INT64, {}}), - createCastTypeConstColumn("Nullable(Decimal(38,0))")})); - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(65, 0), - {DecimalField256(static_cast(MAX_INT64), 0), DecimalField256(static_cast(MIN_INT64), 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_INT64, MIN_INT64, {}}), - createCastTypeConstColumn("Nullable(Decimal(65,0))")})); - // uint8 -> decimal32/64/128/256 - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(9, 0), - {DecimalField32(MAX_UINT8, 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_UINT8, {}}), - createCastTypeConstColumn("Nullable(Decimal(9,0))")})); - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(18, 0), - {DecimalField64(MAX_UINT8, 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_UINT8, {}}), - createCastTypeConstColumn("Nullable(Decimal(18,0))")})); - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(38, 0), - {DecimalField128(MAX_UINT8, 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_UINT8, {}}), - createCastTypeConstColumn("Nullable(Decimal(38,0))")})); - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(65, 0), - {DecimalField256(static_cast(MAX_UINT8), 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_UINT8, {}}), - createCastTypeConstColumn("Nullable(Decimal(65,0))")})); - // uint16 -> decimal32/64/128/256 - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(9, 0), - {DecimalField32(MAX_UINT16, 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_UINT16, {}}), - createCastTypeConstColumn("Nullable(Decimal(9,0))")})); - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(18, 0), - {DecimalField64(MAX_UINT16, 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_UINT16, {}}), - createCastTypeConstColumn("Nullable(Decimal(18,0))")})); - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(38, 0), - {DecimalField128(MAX_UINT16, 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_UINT16, {}}), - createCastTypeConstColumn("Nullable(Decimal(38,0))")})); - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(65, 0), - {DecimalField256(static_cast(MAX_UINT16), 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_UINT16, {}}), - createCastTypeConstColumn("Nullable(Decimal(65,0))")})); - // uint32 -> decimal32/64/128/256 - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(9, 0), - {DecimalField32(999999999, 0), {}}), - executeFunction(func_name, - {createColumn>({999999999, {}}), - createCastTypeConstColumn("Nullable(Decimal(9,0))")})); - ASSERT_THROW(executeFunction(func_name, - {createColumn>({1000000000, {}}), - createCastTypeConstColumn("Nullable(Decimal(9,0))")}), - TiFlashException); - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(18, 0), - {DecimalField64(MAX_UINT32, 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_UINT32, {}}), - createCastTypeConstColumn("Nullable(Decimal(18,0))")})); - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(38, 0), - {DecimalField128(MAX_UINT32, 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_UINT32, {}}), - createCastTypeConstColumn("Nullable(Decimal(38,0))")})); - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(65, 0), - {DecimalField256(static_cast(MAX_UINT32), 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_UINT32, {}}), - createCastTypeConstColumn("Nullable(Decimal(65,0))")})); - // uint64 -> decimal32/64/128/256 - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(9, 0), - {DecimalField32(999999999, 0), {}}), - executeFunction(func_name, - {createColumn>({999999999, {}}), - createCastTypeConstColumn("Nullable(Decimal(9,0))")})); - ASSERT_THROW(executeFunction(func_name, - {createColumn>({1000000000, {}}), - createCastTypeConstColumn("Nullable(Decimal(9,0))")}), - TiFlashException); - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(18, 0), - {DecimalField64(999999999999999999, 0), {}}), - executeFunction(func_name, - {createColumn>({999999999999999999, {}}), - createCastTypeConstColumn("Nullable(Decimal(18,0))")})); - ASSERT_THROW(executeFunction(func_name, - {createColumn>({1000000000000000000, {}}), - createCastTypeConstColumn("Nullable(Decimal(18,0))")}), - TiFlashException); - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(38, 0), - {DecimalField128(MAX_INT64, 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_INT64, {}}), - createCastTypeConstColumn("Nullable(Decimal(38,0))")})); - ASSERT_COLUMN_EQ( - createColumn>( - std::make_tuple(65, 0), - {DecimalField256(static_cast(MAX_INT64), 0), {}}), - executeFunction(func_name, - {createColumn>({MAX_INT64, {}}), - createCastTypeConstColumn("Nullable(Decimal(65,0))")})); -} -CATCH - -TEST_F(TestTidbConversion, castIntAsTime) -try -{ - ASSERT_COLUMN_EQ( - createNullableDateTimeColumn({{}, {{2021, 10, 26, 16, 8, 59, 0}}}, 6), - executeFunction(func_name, - {createColumn>({{}, 20211026160859}), - createCastTypeConstColumn("Nullable(MyDateTime(6))")})); - ASSERT_COLUMN_EQ( - createNullableDateTimeColumn({{}, {{2021, 10, 26, 16, 8, 59, 0}}}, 6), - executeFunction(func_name, - {createColumn>({{}, 20211026160859}), - createCastTypeConstColumn("Nullable(MyDateTime(6))")})); - ASSERT_THROW( - executeFunction(func_name, - {createColumn>({MAX_UINT8}), - createCastTypeConstColumn("Nullable(MyDateTime(6))")}), - TiFlashException); - ASSERT_THROW( - executeFunction(func_name, - {createColumn>({MAX_UINT16}), - createCastTypeConstColumn("Nullable(MyDateTime(6))")}), - TiFlashException); - ASSERT_THROW( - executeFunction(func_name, - {createColumn>({MAX_UINT32}), - createCastTypeConstColumn("Nullable(MyDateTime(6))")}), - TiFlashException); - ASSERT_COLUMN_EQ( - createNullableDateTimeColumn({{}}, 6), - executeFunction(func_name, - {createColumn>({0}), - createCastTypeConstColumn("Nullable(MyDateTime(6))")})); - ASSERT_THROW( - executeFunction(func_name, - {createColumn>({{}, -20211026160859}), - createCastTypeConstColumn("Nullable(MyDateTime(6))")}), - TiFlashException); -} -CATCH - -TEST_F(TestTidbConversion, castTimeAsReal) -try -{ - const auto data_type_ptr = std::make_shared(6); - const Float64 datetime_float = 20211026160859; - const Float64 datetime_frac_float = 20211026160859.125; - - // cast datetime to float - auto col_datetime1 = getDatetimeColumn(); - auto ctn_datetime1 = ColumnWithTypeAndName(std::move(col_datetime1), data_type_ptr, "datetime"); - ASSERT_COLUMN_EQ( - createColumn({datetime_float, datetime_frac_float}), - executeFunction(func_name, - {ctn_datetime1, - createCastTypeConstColumn("Float64")})); - - // cast datetime to nullable float - auto col_datetime2 = getDatetimeColumn(); - auto ctn_datetime2 = ColumnWithTypeAndName(std::move(col_datetime2), data_type_ptr, "datetime"); - ASSERT_COLUMN_EQ( - createColumn>({datetime_float, datetime_frac_float}), - executeFunction(func_name, - {ctn_datetime2, - createCastTypeConstColumn("Nullable(Float64)")})); - - // cast nullable datetime to nullable float - auto col_datetime3 = getDatetimeColumn(); - auto datetime3_null_map = ColumnUInt8::create(2, 0); - datetime3_null_map->getData()[1] = 1; - auto col_datetime3_nullable = ColumnNullable::create(std::move(col_datetime3), std::move(datetime3_null_map)); - auto ctn_datetime3_nullable = ColumnWithTypeAndName(std::move(col_datetime3_nullable), makeNullable(data_type_ptr), "datetime"); - ASSERT_COLUMN_EQ( - createColumn>({datetime_float, {}}), - executeFunction(func_name, - {ctn_datetime3_nullable, - createCastTypeConstColumn("Nullable(Float64)")})); - - // cast const datetime to float - auto col_datetime4_const = ColumnConst::create(getDatetimeColumn(true), 1); - auto ctn_datetime4_const = ColumnWithTypeAndName(std::move(col_datetime4_const), data_type_ptr, "datetime"); - ASSERT_COLUMN_EQ( - createConstColumn(1, datetime_float), - executeFunction(func_name, - {ctn_datetime4_const, - createCastTypeConstColumn("Float64")})); - - // cast nullable const datetime to float - auto col_datetime5 = getDatetimeColumn(true); - auto datetime5_null_map = ColumnUInt8::create(1, 0); - auto col_datetime5_nullable = ColumnNullable::create(std::move(col_datetime5), std::move(datetime5_null_map)); - auto col_datetime5_nullable_const = ColumnConst::create(std::move(col_datetime5_nullable), 1); - auto ctn_datetime5_nullable_const = ColumnWithTypeAndName(std::move(col_datetime5_nullable_const), makeNullable(data_type_ptr), "datetime"); - ASSERT_COLUMN_EQ( - createConstColumn>(1, datetime_float), - executeFunction(func_name, - {ctn_datetime5_nullable_const, - createCastTypeConstColumn("Nullable(Float64)")})); -} -CATCH - -TEST_F(TestTidbConversion, castDurationAsDuration) -try -{ - const auto from_type = std::make_shared(3); - const auto to_type_1 = std::make_shared(5); // from_fsp < to_fsp - const auto to_type_2 = std::make_shared(3); // from_fsp == to_fsp - const auto to_type_3 = std::make_shared(2); // from_fsp < to_fsp - - ColumnWithTypeAndName input( - createColumn({(20 * 3600 + 20 * 60 + 20) * 1000000000L + 555000000L, - -(20 * 3600 + 20 * 60 + 20) * 1000000000L - 555000000L, - (20 * 3600 + 20 * 60 + 20) * 1000000000L + 554000000L, - -(20 * 3600 + 20 * 60 + 20) * 1000000000L - 554000000L, - (20 * 3600 + 20 * 60 + 20) * 1000000000L + 999000000L, - -(20 * 3600 + 20 * 60 + 20) * 1000000000L - 999000000L}) - .column, - from_type, - "input"); - - ColumnWithTypeAndName output1(input.column, to_type_1, "output1"); - ColumnWithTypeAndName output2(input.column, to_type_2, "output2"); - ColumnWithTypeAndName output3( - createColumn({(20 * 3600 + 20 * 60 + 20) * 1000000000L + 560000000L, - -(20 * 3600 + 20 * 60 + 20) * 1000000000L - 560000000L, - (20 * 3600 + 20 * 60 + 20) * 1000000000L + 550000000L, - -(20 * 3600 + 20 * 60 + 20) * 1000000000L - 550000000L, - (20 * 3600 + 20 * 60 + 21) * 1000000000L + 000000000L, - -(20 * 3600 + 20 * 60 + 21) * 1000000000L - 000000000L}) - .column, - to_type_3, - "output3"); - - ASSERT_COLUMN_EQ(output1, executeFunction(func_name, {input, createCastTypeConstColumn(to_type_1->getName())})); - ASSERT_COLUMN_EQ(output2, executeFunction(func_name, {input, createCastTypeConstColumn(to_type_2->getName())})); - ASSERT_COLUMN_EQ(output3, executeFunction(func_name, {input, createCastTypeConstColumn(to_type_3->getName())})); - - // Test Nullable - ColumnWithTypeAndName input_nullable( - createColumn>({(20 * 3600 + 20 * 60 + 20) * 1000000000L + 555000000L, - -(20 * 3600 + 20 * 60 + 20) * 1000000000L - 555000000L, - {}, - (20 * 3600 + 20 * 60 + 20) * 1000000000L + 554000000L, - -(20 * 3600 + 20 * 60 + 20) * 1000000000L - 554000000L, - {}, - (20 * 3600 + 20 * 60 + 20) * 1000000000L + 999000000L, - -(20 * 3600 + 20 * 60 + 20) * 1000000000L - 999000000L}) - .column, - makeNullable(input.type), - "input_nullable"); - ColumnWithTypeAndName output1_nullable(input_nullable.column, makeNullable(to_type_1), "output1_nullable"); - ColumnWithTypeAndName output2_nullable(input_nullable.column, makeNullable(to_type_2), "output2_nullable"); - ColumnWithTypeAndName output3_nullable( - createColumn>({(20 * 3600 + 20 * 60 + 20) * 1000000000L + 560000000L, - -(20 * 3600 + 20 * 60 + 20) * 1000000000L - 560000000L, - {}, - (20 * 3600 + 20 * 60 + 20) * 1000000000L + 550000000L, - -(20 * 3600 + 20 * 60 + 20) * 1000000000L - 550000000L, - {}, - (20 * 3600 + 20 * 60 + 21) * 1000000000L + 000000000L, - -(20 * 3600 + 20 * 60 + 21) * 1000000000L - 000000000L}) - .column, - makeNullable(to_type_3), - "output3_output"); - - ASSERT_COLUMN_EQ(output1_nullable, executeFunction(func_name, {input_nullable, createCastTypeConstColumn(makeNullable(to_type_1)->getName())})); - ASSERT_COLUMN_EQ(output2_nullable, executeFunction(func_name, {input_nullable, createCastTypeConstColumn(makeNullable(to_type_2)->getName())})); - ASSERT_COLUMN_EQ(output3_nullable, executeFunction(func_name, {input_nullable, createCastTypeConstColumn(makeNullable(to_type_3)->getName())})); - - // Test Const - ColumnWithTypeAndName input_const(createConstColumn(1, (20 * 3600 + 20 * 60 + 20) * 1000000000L + 999000000L).column, from_type, "input_const"); - ColumnWithTypeAndName output1_const(input_const.column, to_type_1, "output1_const"); - ColumnWithTypeAndName output2_const(input_const.column, to_type_2, "output2_const"); - ColumnWithTypeAndName output3_const(createConstColumn(1, (20 * 3600 + 20 * 60 + 21) * 1000000000L + 000000000L).column, to_type_3, "output3_const"); - - ASSERT_COLUMN_EQ(output1_const, executeFunction(func_name, {input_const, createCastTypeConstColumn(to_type_1->getName())})); - ASSERT_COLUMN_EQ(output2_const, executeFunction(func_name, {input_const, createCastTypeConstColumn(to_type_2->getName())})); - ASSERT_COLUMN_EQ(output3_const, executeFunction(func_name, {input_const, createCastTypeConstColumn(to_type_3->getName())})); -} -CATCH - -TEST_F(TestTidbConversion, StrToDateTypeTest) -try -{ - // Arg1 is ColumnVector, Arg2 is ColumnVector - auto arg1_column = createColumn>({{}, "1/12/2020", "00:59:60 ", "1/12/2020"}); - auto arg2_column = createColumn>({"%d/%c/%Y", {}, "%H:%i:%S ", "%d/%c/%Y"}); - ColumnWithTypeAndName result_column( - createColumn>({{}, {}, {}, MyDateTime{2020, 12, 1, 0, 0, 0, 0}.toPackedUInt()}).column, - makeNullable(std::make_shared(0)), - "result"); - ASSERT_COLUMN_EQ(result_column, executeFunction("strToDateDatetime", arg1_column, arg2_column)); - - // Arg1 is ColumnConst(ColumnNullable(non-null value)), Arg2 is ColumnVector - arg1_column = createConstColumn>(2, {"1/12/2020"}); - arg2_column = createColumn>({"%d/%c/%Y", "%d/%c/%Y"}); - result_column = ColumnWithTypeAndName( - createColumn>({MyDateTime{2020, 12, 1, 0, 0, 0, 0}.toPackedUInt(), MyDateTime{2020, 12, 1, 0, 0, 0, 0}.toPackedUInt()}).column, - makeNullable(std::make_shared(0)), - "result"); - ASSERT_COLUMN_EQ(result_column, executeFunction("strToDateDatetime", arg1_column, arg2_column)); - - // Arg1 is ColumnConst(ColumnNullable(null value)), Arg2 is ColumnVector - arg1_column = createConstColumn>(2, {}); - arg2_column = createColumn>({"%d/%c/%Y", "%d/%c/%Y"}); - result_column = ColumnWithTypeAndName( - createConstColumn>(2, {}).column, - makeNullable(std::make_shared(0)), - "result"); - ASSERT_COLUMN_EQ(result_column, executeFunction("strToDateDatetime", arg1_column, arg2_column)); - - // Arg1 is ColumnVector, Arg2 is ColumnConst(ColumnNullable(non-null value)) - arg1_column = createColumn>({"1/12/2020", "1/12/2020"}); - arg2_column = createConstColumn>(2, "%d/%c/%Y"); - result_column = ColumnWithTypeAndName( - createColumn>({MyDateTime{2020, 12, 1, 0, 0, 0, 0}.toPackedUInt(), MyDateTime{2020, 12, 1, 0, 0, 0, 0}.toPackedUInt()}).column, - makeNullable(std::make_shared(0)), - "result"); - ASSERT_COLUMN_EQ(result_column, executeFunction("strToDateDatetime", arg1_column, arg2_column)); - - // Arg1 is ColumnConst(ColumnNullable(non-null value)), Arg2 is ColumnConst(ColumnNullable(non-null value)) - arg1_column = createConstColumn>(2, "1/12/2020"); - arg2_column = createConstColumn>(2, "%d/%c/%Y"); - result_column = ColumnWithTypeAndName( - createConstColumn>(2, {MyDateTime{2020, 12, 1, 0, 0, 0, 0}.toPackedUInt()}).column, - makeNullable(std::make_shared(0)), - "result"); - ASSERT_COLUMN_EQ(result_column, executeFunction("strToDateDatetime", arg1_column, arg2_column)); - - // Arg1 is ColumnConst(ColumnNullable(null value)), Arg2 is ColumnConst(ColumnNullable(non-null value)) - arg1_column = createConstColumn>(2, {}); - arg2_column = createConstColumn>(2, "%d/%c/%Y"); - result_column = ColumnWithTypeAndName( - createConstColumn>(2, {}).column, - makeNullable(std::make_shared(0)), - "result"); - ASSERT_COLUMN_EQ(result_column, executeFunction("strToDateDatetime", arg1_column, arg2_column)); - - // Arg1 is ColumnVector, Arg2 is ColumnConst(ColumnNullable(null value)) - arg1_column = createColumn>({"1/12/2020", "1/12/2020"}); - arg2_column = createConstColumn>(2, {}); - result_column = ColumnWithTypeAndName( - createConstColumn>(2, {}).column, - makeNullable(std::make_shared(0)), - "result"); - ASSERT_COLUMN_EQ(result_column, executeFunction("strToDateDatetime", arg1_column, arg2_column)); - - // Arg1 is ColumnConst(ColumnNullable(non-null value)), Arg2 is ColumnConst(ColumnNullable(null value)) - arg1_column = createConstColumn>(2, {"1/12/2020"}); - arg2_column = createConstColumn>(2, {}); - result_column = ColumnWithTypeAndName( - createConstColumn>(2, {}).column, - makeNullable(std::make_shared(0)), - "result"); - ASSERT_COLUMN_EQ(result_column, executeFunction("strToDateDatetime", arg1_column, arg2_column)); - - // Arg1 is ColumnConst(ColumnNullable(null value)), Arg2 is ColumnConst(ColumnNullable(null value)) - arg1_column = createConstColumn>(2, {}); - arg2_column = createConstColumn>(2, {}); - result_column = ColumnWithTypeAndName( - createConstColumn>(2, {}).column, - makeNullable(std::make_shared(0)), - "result"); - ASSERT_COLUMN_EQ(result_column, executeFunction("strToDateDatetime", arg1_column, arg2_column)); -} -CATCH - -} // namespace -} // namespace tests -} // namespace DB