From 1dad09a625ef200591cc143f40a1ed959ef2f750 Mon Sep 17 00:00:00 2001 From: Ti Chi Robot Date: Thu, 14 Apr 2022 17:20:36 +0800 Subject: [PATCH] Add unittests for str_to_date, fix #3556, #3557 (#3581) (#3933) close pingcap/tics#3557 --- dbms/src/Common/MyTime.cpp | 69 +- dbms/src/Common/tests/gtest_mytime.cpp | 89 ++ dbms/src/Functions/FunctionsConversion.h | 1151 +++++++++++++--------- 3 files changed, 816 insertions(+), 493 deletions(-) diff --git a/dbms/src/Common/MyTime.cpp b/dbms/src/Common/MyTime.cpp index 1e4e73e0b5d..4dc768e8dfd 100644 --- a/dbms/src/Common/MyTime.cpp +++ b/dbms/src/Common/MyTime.cpp @@ -73,7 +73,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])) @@ -531,7 +531,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()) @@ -853,9 +853,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) @@ -968,7 +967,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, @@ -989,9 +987,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) @@ -1226,7 +1223,7 @@ struct MyDateTimeParser::Context // The pos we are parsing from size_t pos = 0; - Context(StringRef view_) : view(std::move(view_)) {} + explicit Context(StringRef view_) : view(std::move(view_)) {} }; // Try to parse digits with number of `limit` starting from view[pos] @@ -1269,18 +1266,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 ":" @@ -1289,7 +1286,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" @@ -1310,7 +1307,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; @@ -1322,7 +1319,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; @@ -1361,7 +1358,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; @@ -1373,18 +1370,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 ":" @@ -1393,7 +1390,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" @@ -1410,7 +1407,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; @@ -1422,7 +1419,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; @@ -1436,7 +1433,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; @@ -1481,6 +1478,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) @@ -1522,9 +1522,9 @@ MyDateTimeParser::MyDateTimeParser(String format_) : format(std::move(format_)) time.micro_second = 0; return true; } - // 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; } @@ -1620,19 +1620,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]]; @@ -1879,7 +1866,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])) @@ -1888,7 +1875,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 f8ac39affa9..e79616eb84d 100644 --- a/dbms/src/Functions/FunctionsConversion.h +++ b/dbms/src/Functions/FunctionsConversion.h @@ -47,27 +47,27 @@ namespace DB namespace ErrorCodes { - extern const int ATTEMPT_TO_READ_AFTER_EOF; - extern const int CANNOT_PARSE_NUMBER; - extern const int CANNOT_READ_ARRAY_FROM_TEXT; - extern const int CANNOT_PARSE_INPUT_ASSERTION_FAILED; - extern const int CANNOT_PARSE_QUOTED_STRING; - extern const int CANNOT_PARSE_ESCAPE_SEQUENCE; - extern const int CANNOT_PARSE_DATE; - extern const int CANNOT_PARSE_DATETIME; - extern const int CANNOT_PARSE_TEXT; - extern const int CANNOT_PARSE_UUID; - extern const int TOO_LARGE_STRING_SIZE; - extern const int TOO_LESS_ARGUMENTS_FOR_FUNCTION; - extern const int LOGICAL_ERROR; - extern const int TYPE_MISMATCH; - extern const int CANNOT_CONVERT_TYPE; - extern const int ILLEGAL_COLUMN; - extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; - extern const int ILLEGAL_TYPE_OF_ARGUMENT; - extern const int NOT_IMPLEMENTED; - extern const int CANNOT_INSERT_NULL_IN_ORDINARY_COLUMN; -} +extern const int ATTEMPT_TO_READ_AFTER_EOF; +extern const int CANNOT_PARSE_NUMBER; +extern const int CANNOT_READ_ARRAY_FROM_TEXT; +extern const int CANNOT_PARSE_INPUT_ASSERTION_FAILED; +extern const int CANNOT_PARSE_QUOTED_STRING; +extern const int CANNOT_PARSE_ESCAPE_SEQUENCE; +extern const int CANNOT_PARSE_DATE; +extern const int CANNOT_PARSE_DATETIME; +extern const int CANNOT_PARSE_TEXT; +extern const int CANNOT_PARSE_UUID; +extern const int TOO_LARGE_STRING_SIZE; +extern const int TOO_LESS_ARGUMENTS_FOR_FUNCTION; +extern const int LOGICAL_ERROR; +extern const int TYPE_MISMATCH; +extern const int CANNOT_CONVERT_TYPE; +extern const int ILLEGAL_COLUMN; +extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; +extern const int ILLEGAL_TYPE_OF_ARGUMENT; +extern const int NOT_IMPLEMENTED; +extern const int CANNOT_INSERT_NULL_IN_ORDINARY_COLUMN; +} // namespace ErrorCodes /** Type conversion functions. @@ -102,8 +102,8 @@ struct ConvertImpl block.getByPosition(result).column = std::move(col_to); } else - throw Exception("Illegal column " + block.getByPosition(arguments[0]).column->getName() - + " of first argument of function " + Name::name, + throw Exception( + "Illegal column " + block.getByPosition(arguments[0]).column->getName() + " of first argument of function " + Name::name, ErrorCodes::ILLEGAL_COLUMN); } }; @@ -124,7 +124,8 @@ struct ConvertFromDecimal size_t size = col_from->size(); vec_to.resize(size); - for (size_t i = 0; i < size; ++i) { + for (size_t i = 0; i < size; ++i) + { auto field = (*col_from)[i].template safeGet>(); vec_to[i] = static_cast(field); } @@ -160,8 +161,8 @@ struct ConvertFromDecimal block.getByPosition(result).column = std::move(col_to); } else - throw Exception("Illegal column " + block.getByPosition(arguments[0]).column->getName() - + " of first argument of function " + Name::name, + throw Exception( + "Illegal column " + block.getByPosition(arguments[0]).column->getName() + " of first argument of function " + Name::name, ErrorCodes::ILLEGAL_COLUMN); } }; @@ -171,9 +172,10 @@ struct ConvertToDecimalImpl { using FromFieldType = typename FromDataType::FieldType; - static void execute(Block & block, const ColumnNumbers & arguments, size_t result, PrecType prec[[maybe_unused]], ScaleType scale) + static void execute(Block & block, const ColumnNumbers & arguments, size_t result, PrecType prec [[maybe_unused]], ScaleType scale) { - if constexpr (IsDecimal) { + if constexpr (IsDecimal) + { const auto * col_from = checkAndGetColumn>(block.getByPosition(arguments[0]).column.get()); auto col_to = ColumnDecimal::create(0, scale); @@ -182,13 +184,15 @@ struct ConvertToDecimalImpl size_t size = vec_from.size(); vec_to.resize(size); - for (size_t i = 0; i < size; ++i) { + for (size_t i = 0; i < size; ++i) + { vec_to[i] = ToDecimal(vec_from[i], vec_from.getScale(), scale); } block.getByPosition(result).column = std::move(col_to); } - else { + else + { if (const ColumnVector * col_from = checkAndGetColumn>(block.getByPosition(arguments[0]).column.get())) { @@ -199,15 +203,16 @@ struct ConvertToDecimalImpl size_t size = vec_from.size(); vec_to.resize(size); - for (size_t i = 0; i < size; ++i) { + for (size_t i = 0; i < size; ++i) + { vec_to[i] = ToDecimal(vec_from[i], scale); } block.getByPosition(result).column = std::move(col_to); } else - throw Exception("Illegal column " + block.getByPosition(arguments[0]).column->getName() - + " of first argument of function " + Name::name, + throw Exception("Illegal column " + block.getByPosition(arguments[0]).column->getName() + " of first argument of function " + + Name::name, ErrorCodes::ILLEGAL_COLUMN); } } @@ -218,7 +223,7 @@ struct ConvertToDecimalImpl void throwExceptionForIncompletelyParsedValue(ReadBuffer & read_buffer, Block & block, size_t result); -template +template struct ConvertToDecimalImpl { static void execute(Block & block, const ColumnNumbers & arguments, size_t result, PrecType, ScaleType) @@ -267,20 +272,19 @@ struct ToDateTimeImpl { static constexpr auto name = "toDateTime"; - static inline UInt32 execute(UInt16 d, const DateLUTImpl & time_zone) - { - return time_zone.fromDayNum(DayNum(d)); - } + static inline UInt32 execute(UInt16 d, const DateLUTImpl & time_zone) { return time_zone.fromDayNum(DayNum(d)); } }; -template struct ConvertImpl - : DateTimeTransformImpl {}; +template +struct ConvertImpl : DateTimeTransformImpl +{ +}; struct MyDateTimeToMyDateTransform { static constexpr auto name = "toMyDate"; - static inline UInt64 execute(const UInt64 & datetime, const DateLUTImpl & ) + static inline UInt64 execute(const UInt64 & datetime, const DateLUTImpl &) { // clear all the bit except year-month-day return datetime & MyTimeBase::YMD_MASK; @@ -291,10 +295,7 @@ struct MyDateToMyDateTimeTransform { static constexpr auto name = "toMyDateTime"; - static inline UInt64 execute(const UInt64 & date, const DateLUTImpl & ) - { - return date; - } + static inline UInt64 execute(const UInt64 & date, const DateLUTImpl &) { return date; } }; template @@ -302,7 +303,7 @@ struct ToMyDateTransform32Or64 { static constexpr auto name = "toMyDate"; - static inline ToType execute(const FromType & , const DateLUTImpl & ) + static inline ToType execute(const FromType &, const DateLUTImpl &) { // todo support transformation from numeric type to MyDate throw Exception("toMyDate from source type is not supported yet"); @@ -314,7 +315,7 @@ struct ToMyDateTimeTransform32Or64 { static constexpr auto name = "toMyDateTime"; - static inline ToType execute(const FromType & , const DateLUTImpl & ) + static inline ToType execute(const FromType &, const DateLUTImpl &) { // todo support transformation from numeric type to MyDateTime throw Exception("toMyDateTime from source type is not supported yet"); @@ -335,8 +336,10 @@ struct ToDateTransform32Or64 /** Conversion of DateTime to Date: throw off time component. */ -template struct ConvertImpl - : DateTimeTransformImpl {}; +template +struct ConvertImpl : DateTimeTransformImpl +{ +}; /** Special case of converting (U)Int32 or (U)Int64 (and also, for convenience, Float32, Float64) to Date. * If number is less than 65536, then it is treated as DayNum, and if greater or equals, then as unix timestamp. @@ -345,62 +348,105 @@ template struct ConvertImpl struct ConvertImpl - : DateTimeTransformImpl> {}; -template struct ConvertImpl - : DateTimeTransformImpl> {}; -template struct ConvertImpl - : DateTimeTransformImpl> {}; -template struct ConvertImpl - : DateTimeTransformImpl> {}; -template struct ConvertImpl - : DateTimeTransformImpl> {}; -template struct ConvertImpl - : DateTimeTransformImpl> {}; - - -template struct ConvertImpl - : DateTimeTransformImpl {}; - -template struct ConvertImpl - : DateTimeTransformImpl> {}; -template struct ConvertImpl - : DateTimeTransformImpl> {}; -template struct ConvertImpl - : DateTimeTransformImpl> {}; -template struct ConvertImpl - : DateTimeTransformImpl> {}; -template struct ConvertImpl - : DateTimeTransformImpl> {}; -template struct ConvertImpl - : DateTimeTransformImpl> {}; - - -template struct ConvertImpl - : DateTimeTransformImpl {}; - -template struct ConvertImpl - : DateTimeTransformImpl> {}; -template struct ConvertImpl - : DateTimeTransformImpl> {}; -template struct ConvertImpl - : DateTimeTransformImpl> {}; -template struct ConvertImpl - : DateTimeTransformImpl> {}; -template struct ConvertImpl - : DateTimeTransformImpl> {}; -template struct ConvertImpl - : DateTimeTransformImpl> {}; +template +struct ConvertImpl : DateTimeTransformImpl> +{ +}; +template +struct ConvertImpl : DateTimeTransformImpl> +{ +}; +template +struct ConvertImpl : DateTimeTransformImpl> +{ +}; +template +struct ConvertImpl : DateTimeTransformImpl> +{ +}; +template +struct ConvertImpl : DateTimeTransformImpl> +{ +}; +template +struct ConvertImpl : DateTimeTransformImpl> +{ +}; + + +template +struct ConvertImpl : DateTimeTransformImpl +{ +}; + +template +struct ConvertImpl : DateTimeTransformImpl> +{ +}; +template +struct ConvertImpl : DateTimeTransformImpl> +{ +}; +template +struct ConvertImpl : DateTimeTransformImpl> +{ +}; +template +struct ConvertImpl : DateTimeTransformImpl> +{ +}; +template +struct ConvertImpl : DateTimeTransformImpl> +{ +}; +template +struct ConvertImpl : DateTimeTransformImpl> +{ +}; + + +template +struct ConvertImpl : DateTimeTransformImpl +{ +}; + +template +struct ConvertImpl + : DateTimeTransformImpl> +{ +}; +template +struct ConvertImpl + : DateTimeTransformImpl> +{ +}; +template +struct ConvertImpl + : DateTimeTransformImpl> +{ +}; +template +struct ConvertImpl + : DateTimeTransformImpl> +{ +}; +template +struct ConvertImpl + : DateTimeTransformImpl> +{ +}; +template +struct ConvertImpl + : DateTimeTransformImpl> +{ +}; /** Transformation of numbers, dates, datetimes to strings: through formatting. */ template struct FormatImpl { - static void execute(const typename DataType::FieldType x, WriteBuffer & wb, const DataType *, const DateLUTImpl *) - { - writeText(x, wb); - } + static void execute(const typename DataType::FieldType x, WriteBuffer & wb, const DataType *, const DateLUTImpl *) { writeText(x, wb); } }; template <> @@ -433,7 +479,7 @@ struct FormatImpl template <> struct FormatImpl { - static void execute(const DataTypeMyDateTime::FieldType x, WriteBuffer & wb, const DataTypeMyDateTime *tp, const DateLUTImpl *) + static void execute(const DataTypeMyDateTime::FieldType x, WriteBuffer & wb, const DataTypeMyDateTime * tp, const DateLUTImpl *) { writeMyDateTimeText(x, tp->getFraction(), wb); } @@ -442,7 +488,8 @@ struct FormatImpl template struct FormatImpl> { - static void execute(const typename DataTypeDecimal::FieldType v, WriteBuffer & wb, const DataTypeDecimal * tp, const DateLUTImpl *) + static void execute(const typename DataTypeDecimal::FieldType v, WriteBuffer & wb, const DataTypeDecimal * tp, + const DateLUTImpl *) { writeText(v, tp->getScale(), wb); } @@ -498,7 +545,7 @@ struct ConvertImpl) data_to.resize(size * (strlen("YYYY-MM-DD hh:mm:ss") + 1)); else - data_to.resize(size * 3); /// Arbitary + data_to.resize(size * 3); /// Arbitary offsets_to.resize(size); @@ -516,8 +563,8 @@ struct ConvertImplgetName() - + " of first argument of function " + Name::name, + throw Exception( + "Illegal column " + block.getByPosition(arguments[0]).column->getName() + " of first argument of function " + Name::name, ErrorCodes::ILLEGAL_COLUMN); } }; @@ -559,19 +606,22 @@ struct ConvertImplGenericToString /** Conversion of strings to numbers, dates, datetimes: through parsing. */ -template void parseImpl(typename DataType::FieldType & x, ReadBuffer & rb, const DateLUTImpl *) +template +void parseImpl(typename DataType::FieldType & x, ReadBuffer & rb, const DateLUTImpl *) { readText(x, rb); } -template <> inline void parseImpl(DataTypeDate::FieldType & x, ReadBuffer & rb, const DateLUTImpl *) +template <> +inline void parseImpl(DataTypeDate::FieldType & x, ReadBuffer & rb, const DateLUTImpl *) { DayNum tmp(0); readDateText(tmp, rb); x = tmp; } -template <> inline void parseImpl(DataTypeDateTime::FieldType & x, ReadBuffer & rb, const DateLUTImpl * time_zone) +template <> +inline void parseImpl(DataTypeDateTime::FieldType & x, ReadBuffer & rb, const DateLUTImpl * time_zone) { time_t tmp = 0; readDateTimeText(tmp, rb, *time_zone); @@ -579,21 +629,24 @@ template <> inline void parseImpl(DataTypeDateTime::FieldType } -template <> inline void parseImpl(DataTypeMyDate::FieldType & x, ReadBuffer & rb, const DateLUTImpl *) +template <> +inline void parseImpl(DataTypeMyDate::FieldType & x, ReadBuffer & rb, const DateLUTImpl *) { UInt64 tmp(0); readMyDateText(tmp, rb); x = tmp; } -template <> inline void parseImpl(DataTypeMyDateTime::FieldType & x, ReadBuffer & rb, const DateLUTImpl *) +template <> +inline void parseImpl(DataTypeMyDateTime::FieldType & x, ReadBuffer & rb, const DateLUTImpl *) { UInt64 tmp(0); readMyDateTimeText(tmp, 6, rb); // set max fsp doesn't matter x = tmp; } -template <> inline void parseImpl(DataTypeUUID::FieldType & x, ReadBuffer & rb, const DateLUTImpl *) +template <> +inline void parseImpl(DataTypeUUID::FieldType & x, ReadBuffer & rb, const DateLUTImpl *) { UUID tmp; readText(tmp, rb); @@ -617,19 +670,19 @@ bool tryParseImpl(typename DataType::FieldType & x, ReadBuffer & rb) enum class ConvertFromStringExceptionMode { - Throw, /// Throw exception if value cannot be parsed. - Zero, /// Fill with zero or default if value cannot be parsed. - Null /// Return ColumnNullable with NULLs when value cannot be parsed. + Throw, /// Throw exception if value cannot be parsed. + Zero, /// Fill with zero or default if value cannot be parsed. + Null /// Return ColumnNullable with NULLs when value cannot be parsed. }; enum class ConvertFromStringParsingMode { Normal, - BestEffort /// Only applicable for DateTime. Will use sophisticated method, that is slower. + BestEffort /// Only applicable for DateTime. Will use sophisticated method, that is slower. }; -template +template struct ConvertThroughParsing { static_assert(std::is_same_v || std::is_same_v, @@ -648,7 +701,8 @@ struct ConvertThroughParsing return true; /// Special case, that allows to parse string with DateTime as Date. - if ((std::is_same_v || std::is_same_v) && (in.buffer().size()) == strlen("YYYY-MM-DD hh:mm:ss")) + if ((std::is_same_v || std::is_same_v)&&(in.buffer().size()) + == strlen("YYYY-MM-DD hh:mm:ss")) return true; return false; @@ -673,14 +727,12 @@ struct ConvertThroughParsing const ColumnFixedString * col_from_fixed_string = checkAndGetColumn(col_from); if (std::is_same_v && !col_from_string) - throw Exception("Illegal column " + col_from->getName() - + " of first argument of function " + Name::name, - ErrorCodes::ILLEGAL_COLUMN); + throw Exception( + "Illegal column " + col_from->getName() + " of first argument of function " + Name::name, ErrorCodes::ILLEGAL_COLUMN); if (std::is_same_v && !col_from_fixed_string) - throw Exception("Illegal column " + col_from->getName() - + " of first argument of function " + Name::name, - ErrorCodes::ILLEGAL_COLUMN); + throw Exception( + "Illegal column " + col_from->getName() + " of first argument of function " + Name::name, ErrorCodes::ILLEGAL_COLUMN); size_t size = block.rows(); auto col_to = ColumnVector::create(size); @@ -769,12 +821,17 @@ struct ConvertThroughParsing template struct ConvertImpl, DataTypeString>, ToDataType, Name> - : ConvertThroughParsing {}; + : ConvertThroughParsing +{ +}; template struct ConvertImpl, DataTypeFixedString>, ToDataType, Name> - : ConvertThroughParsing {}; + : ConvertThroughParsing +{ +}; /// Generic conversion of any type from String. Used for complex types: Array and Tuple. @@ -822,11 +879,15 @@ struct ConvertImplGenericFromString /// Function toUnixTimestamp has exactly the same implementation as toDateTime of String type. -struct NameToUnixTimestamp { static constexpr auto name = "toUnixTimestamp"; }; +struct NameToUnixTimestamp +{ + static constexpr auto name = "toUnixTimestamp"; +}; template <> -struct ConvertImpl - : ConvertImpl {}; +struct ConvertImpl : ConvertImpl +{ +}; /** If types are identical, just take reference to column. @@ -881,25 +942,40 @@ struct ConvertImpl block.getByPosition(result).column = std::move(col_to); } else - throw Exception("Illegal column " + block.getByPosition(arguments[0]).column->getName() - + " of first argument of function " + Name::name, + throw Exception( + "Illegal column " + block.getByPosition(arguments[0]).column->getName() + " of first argument of function " + Name::name, ErrorCodes::ILLEGAL_COLUMN); } }; /// Declared early because used below. -struct NameToDate { static constexpr auto name = "toDate"; }; -struct NameToMyDate { static constexpr auto name = "toMyDate"; }; -struct NameToDateTime { static constexpr auto name = "toDateTime"; }; -struct NameToMyDateTime { static constexpr auto name = "toMyDateTime"; }; -struct NameToString { static constexpr auto name = "toString"; }; +struct NameToDate +{ + static constexpr auto name = "toDate"; +}; +struct NameToMyDate +{ + static constexpr auto name = "toMyDate"; +}; +struct NameToDateTime +{ + static constexpr auto name = "toDateTime"; +}; +struct NameToMyDateTime +{ + static constexpr auto name = "toMyDateTime"; +}; +struct NameToString +{ + static constexpr auto name = "toString"; +}; -#define DEFINE_NAME_TO_INTERVAL(INTERVAL_KIND) \ - struct NameToInterval ## INTERVAL_KIND \ - { \ - static constexpr auto name = "toInterval" #INTERVAL_KIND; \ +#define DEFINE_NAME_TO_INTERVAL(INTERVAL_KIND) \ + struct NameToInterval##INTERVAL_KIND \ + { \ + static constexpr auto name = "toInterval" #INTERVAL_KIND; \ static constexpr int kind = DataTypeInterval::INTERVAL_KIND; \ }; @@ -923,10 +999,7 @@ class FunctionConvert : public IFunction static constexpr auto name = Name::name; static FunctionPtr create(const Context &) { return std::make_shared(); } - String getName() const override - { - return name; - } + String getName() const override { return name; } bool isVariadic() const override { return true; } size_t getNumberOfArguments() const override { return 0; } @@ -935,8 +1008,8 @@ class FunctionConvert : public IFunction DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override { if (arguments.size() != 1 && arguments.size() != 2) - throw Exception("Number of arguments for function " + getName() + " doesn't match: passed " - + toString(arguments.size()) + ", should be 1 or 2. Second argument (time zone) is optional only make sense for DateTime.", + throw Exception("Number of arguments for function " + getName() + " doesn't match: passed " + toString(arguments.size()) + + ", should be 1 or 2. Second argument (time zone) is optional only make sense for DateTime.", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); if constexpr (std::is_same_v) @@ -962,8 +1035,8 @@ class FunctionConvert : public IFunction || (std::is_same_v && checkDataType(arguments[0].type.get())))) { - throw Exception("Number of arguments for function " + getName() + " doesn't match: passed " - + toString(arguments.size()) + ", should be 1.", + throw Exception("Number of arguments for function " + getName() + " doesn't match: passed " + toString(arguments.size()) + + ", should be 1.", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); } } @@ -989,22 +1062,15 @@ class FunctionConvert : public IFunction /// More convenient error message. if (e.code() == ErrorCodes::ATTEMPT_TO_READ_AFTER_EOF) { - e.addMessage("Cannot parse " - + block.getByPosition(result).type->getName() + " from " - + block.getByPosition(arguments[0]).type->getName() - + ", because value is too short"); + e.addMessage("Cannot parse " + block.getByPosition(result).type->getName() + " from " + + block.getByPosition(arguments[0]).type->getName() + ", because value is too short"); } - else if (e.code() == ErrorCodes::CANNOT_PARSE_NUMBER - || e.code() == ErrorCodes::CANNOT_READ_ARRAY_FROM_TEXT - || e.code() == ErrorCodes::CANNOT_PARSE_INPUT_ASSERTION_FAILED - || e.code() == ErrorCodes::CANNOT_PARSE_QUOTED_STRING - || e.code() == ErrorCodes::CANNOT_PARSE_ESCAPE_SEQUENCE - || e.code() == ErrorCodes::CANNOT_PARSE_DATE - || e.code() == ErrorCodes::CANNOT_PARSE_DATETIME - || e.code() == ErrorCodes::CANNOT_PARSE_UUID) + else if (e.code() == ErrorCodes::CANNOT_PARSE_NUMBER || e.code() == ErrorCodes::CANNOT_READ_ARRAY_FROM_TEXT + || e.code() == ErrorCodes::CANNOT_PARSE_INPUT_ASSERTION_FAILED || e.code() == ErrorCodes::CANNOT_PARSE_QUOTED_STRING + || e.code() == ErrorCodes::CANNOT_PARSE_ESCAPE_SEQUENCE || e.code() == ErrorCodes::CANNOT_PARSE_DATE + || e.code() == ErrorCodes::CANNOT_PARSE_DATETIME || e.code() == ErrorCodes::CANNOT_PARSE_UUID) { - e.addMessage("Cannot parse " - + block.getByPosition(result).type->getName() + " from " + e.addMessage("Cannot parse " + block.getByPosition(result).type->getName() + " from " + block.getByPosition(arguments[0]).type->getName()); } @@ -1012,10 +1078,7 @@ class FunctionConvert : public IFunction } } - bool hasInformationAboutMonotonicity() const override - { - return Monotonic::has(); - } + bool hasInformationAboutMonotonicity() const override { return Monotonic::has(); } Monotonicity getMonotonicityForRange(const IDataType & type, const Field & left, const Field & right) const override { @@ -1026,34 +1089,56 @@ class FunctionConvert : public IFunction void executeInternal(Block & block, const ColumnNumbers & arguments, size_t result) { if (!arguments.size()) - throw Exception{"Function " + getName() + " expects at least 1 arguments", - ErrorCodes::TOO_LESS_ARGUMENTS_FOR_FUNCTION}; + throw Exception{"Function " + getName() + " expects at least 1 arguments", ErrorCodes::TOO_LESS_ARGUMENTS_FOR_FUNCTION}; const IDataType * from_type = block.getByPosition(arguments[0]).type.get(); - if (checkDataType(from_type)) ConvertImpl::execute(block, arguments, result); - else if (checkDataType(from_type)) ConvertImpl::execute(block, arguments, result); - else if (checkDataType(from_type)) ConvertImpl::execute(block, arguments, result); - else if (checkDataType(from_type)) ConvertImpl::execute(block, arguments, result); - else if (checkDataType(from_type)) ConvertImpl::execute(block, arguments, result); - else if (checkDataType(from_type)) ConvertImpl::execute(block, arguments, result); - else if (checkDataType(from_type)) ConvertImpl::execute(block, arguments, result); - else if (checkDataType(from_type)) ConvertImpl::execute(block, arguments, result); - else if (checkDataType(from_type)) ConvertImpl::execute(block, arguments, result); - else if (checkDataType(from_type)) ConvertImpl::execute(block, arguments, result); - else if (checkDataType(from_type)) ConvertImpl::execute(block, arguments, result); - else if (checkDataType(from_type)) ConvertImpl::execute(block, arguments, result); - else if (checkDataType(from_type)) ConvertImpl::execute(block, arguments, result); - else if (checkDataType(from_type)) ConvertImpl::execute(block, arguments, result); - else if (checkDataType(from_type)) ConvertImpl::execute(block, arguments, result); - else if (checkDataType(from_type)) ConvertImpl::execute(block, arguments, result); - else if (checkDataType(from_type)) ConvertImpl::execute(block, arguments, result); - else if (checkDataType(from_type)) ConvertImpl::execute(block, arguments, result); - else if (checkDataType(from_type)) ConvertImpl::execute(block, arguments, result); - else if (checkDataType(from_type)) ConvertFromDecimal::execute(block, arguments, result); - else if (checkDataType(from_type)) ConvertFromDecimal::execute(block, arguments, result); - else if (checkDataType(from_type)) ConvertFromDecimal::execute(block, arguments, result); - else if (checkDataType(from_type)) ConvertFromDecimal::execute(block, arguments, result); + if (checkDataType(from_type)) + ConvertImpl::execute(block, arguments, result); + else if (checkDataType(from_type)) + ConvertImpl::execute(block, arguments, result); + else if (checkDataType(from_type)) + ConvertImpl::execute(block, arguments, result); + else if (checkDataType(from_type)) + ConvertImpl::execute(block, arguments, result); + else if (checkDataType(from_type)) + ConvertImpl::execute(block, arguments, result); + else if (checkDataType(from_type)) + ConvertImpl::execute(block, arguments, result); + else if (checkDataType(from_type)) + ConvertImpl::execute(block, arguments, result); + else if (checkDataType(from_type)) + ConvertImpl::execute(block, arguments, result); + else if (checkDataType(from_type)) + ConvertImpl::execute(block, arguments, result); + else if (checkDataType(from_type)) + ConvertImpl::execute(block, arguments, result); + else if (checkDataType(from_type)) + ConvertImpl::execute(block, arguments, result); + else if (checkDataType(from_type)) + ConvertImpl::execute(block, arguments, result); + else if (checkDataType(from_type)) + ConvertImpl::execute(block, arguments, result); + else if (checkDataType(from_type)) + ConvertImpl::execute(block, arguments, result); + else if (checkDataType(from_type)) + ConvertImpl::execute(block, arguments, result); + else if (checkDataType(from_type)) + ConvertImpl::execute(block, arguments, result); + else if (checkDataType(from_type)) + ConvertImpl::execute(block, arguments, result); + else if (checkDataType(from_type)) + ConvertImpl::execute(block, arguments, result); + else if (checkDataType(from_type)) + ConvertImpl::execute(block, arguments, result); + else if (checkDataType(from_type)) + ConvertFromDecimal::execute(block, arguments, result); + else if (checkDataType(from_type)) + ConvertFromDecimal::execute(block, arguments, result); + else if (checkDataType(from_type)) + ConvertFromDecimal::execute(block, arguments, result); + else if (checkDataType(from_type)) + ConvertFromDecimal::execute(block, arguments, result); else { /// Generic conversion of any type to String. @@ -1062,7 +1147,8 @@ class FunctionConvert : public IFunction ConvertImplGenericToString::execute(block, arguments, result); } else - throw Exception("Illegal type " + block.getByPosition(arguments[0]).type->getName() + " of argument of function " + getName(), + throw Exception( + "Illegal type " + block.getByPosition(arguments[0]).type->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); } } @@ -1075,8 +1161,7 @@ class FunctionConvert : public IFunction * Function toTOrNull will return Nullable type with NULL when cannot parse. * NOTE Also need to implement tryToUnixTimestamp with timezone. */ -template class FunctionConvertFromString : public IFunction { @@ -1084,10 +1169,7 @@ class FunctionConvertFromString : public IFunction static constexpr auto name = Name::name; static FunctionPtr create(const Context &) { return std::make_shared(); } - String getName() const override - { - return name; - } + String getName() const override { return name; } bool isVariadic() const override { return true; } size_t getNumberOfArguments() const override { return 0; } @@ -1098,8 +1180,8 @@ class FunctionConvertFromString : public IFunction DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override { if (arguments.size() != 1 && arguments.size() != 2) - throw Exception("Number of arguments for function " + getName() + " doesn't match: passed " - + toString(arguments.size()) + ", should be 1 or 2. Second argument (time zone) is optional only make sense for DateTime.", + throw Exception("Number of arguments for function " + getName() + " doesn't match: passed " + toString(arguments.size()) + + ", should be 1 or 2. Second argument (time zone) is optional only make sense for DateTime.", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); if (!arguments[0].type->isStringOrFixedString()) @@ -1111,8 +1193,8 @@ class FunctionConvertFromString : public IFunction if (arguments.size() == 2) { if constexpr (!std::is_same_v) - throw Exception("Number of arguments for function " + getName() + " doesn't match: passed " - + toString(arguments.size()) + ", should be 1. Second argument makes sense only when converting to DateTime.", + throw Exception("Number of arguments for function " + getName() + " doesn't match: passed " + toString(arguments.size()) + + ", should be 1. Second argument makes sense only when converting to DateTime.", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); if (!arguments[1].type->isString()) @@ -1143,23 +1225,24 @@ class FunctionConvertFromString : public IFunction ConvertThroughParsing::execute(block, arguments, result); else throw Exception("Illegal type " + block.getByPosition(arguments[0]).type->getName() + " of argument of function " + getName() - + ". Only String or FixedString argument is accepted for try-conversion function. For other arguments, use function without 'orZero' or 'orNull'.", + + ". Only String or FixedString argument is accepted for try-conversion function. For other arguments, use function " + "without 'orZero' or 'orNull'.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); } }; -template +template class FunctionToDecimal : public IFunction { public: - struct NameToDecimal { static constexpr auto name = "toDecimal"; }; + struct NameToDecimal + { + static constexpr auto name = "toDecimal"; + }; static constexpr auto name = "toDecimal"; static FunctionPtr create(const Context &) { return std::make_shared>(); }; - String getName() const override - { - return name; - } + String getName() const override { return name; } size_t getNumberOfArguments() const override { return 3; } DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override { @@ -1180,22 +1263,37 @@ class FunctionToDecimal : public IFunction { const IDataType * from_type = block.getByPosition(arguments[0]).type.get(); - if (checkDataType(from_type)) ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); - else if (checkDataType(from_type)) ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); - else if (checkDataType(from_type)) ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); - else if (checkDataType(from_type)) ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); - else if (checkDataType(from_type)) ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); - else if (checkDataType(from_type)) ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); - else if (checkDataType(from_type)) ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); - else if (checkDataType(from_type)) ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); - else if (checkDataType(from_type)) ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); - else if (checkDataType(from_type)) ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); - else if (checkDataType(from_type)) ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); + if (checkDataType(from_type)) + ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); + else if (checkDataType(from_type)) + ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); + else if (checkDataType(from_type)) + ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); + else if (checkDataType(from_type)) + ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); + else if (checkDataType(from_type)) + ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); + else if (checkDataType(from_type)) + ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); + else if (checkDataType(from_type)) + ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); + else if (checkDataType(from_type)) + ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); + else if (checkDataType(from_type)) + ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); + else if (checkDataType(from_type)) + ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); + else if (checkDataType(from_type)) + ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); //else if (checkDataType(from_type)) ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); - else if (checkDataType(from_type)) ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); - else if (checkDataType(from_type)) ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); - else if (checkDataType(from_type)) ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); - else if (checkDataType(from_type)) ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); + else if (checkDataType(from_type)) + ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); + else if (checkDataType(from_type)) + ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); + else if (checkDataType(from_type)) + ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); + else if (checkDataType(from_type)) + ConvertToDecimalImpl::execute(block, arguments, result, prec, scale); else throw Exception("Illegal type " + block.getByPosition(arguments[0]).type->getName() + " of argument of function " + name, ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); @@ -1210,10 +1308,7 @@ class FunctionToFixedString : public IFunction static constexpr auto name = "toFixedString"; static FunctionPtr create(const Context &) { return std::make_shared(); }; - String getName() const override - { - return name; - } + String getName() const override { return name; } size_t getNumberOfArguments() const override { return 2; } bool isInjective(const Block &) override { return true; } @@ -1259,8 +1354,7 @@ class FunctionToFixedString : public IFunction const size_t off = i ? in_offsets[i - 1] : 0; const size_t len = in_offsets[i] - off - 1; if (len > n) - throw Exception("String too long for type FixedString(" + toString(n) + ")", - ErrorCodes::TOO_LARGE_STRING_SIZE); + throw Exception("String too long for type FixedString(" + toString(n) + ")", ErrorCodes::TOO_LARGE_STRING_SIZE); memcpy(&out_chars[i * n], &in_chars[off], len); } @@ -1270,9 +1364,7 @@ class FunctionToFixedString : public IFunction { const auto src_n = column_fixed_string->getN(); if (src_n > n) - throw Exception{ - "String too long for type FixedString(" + toString(n) + ")", - ErrorCodes::TOO_LARGE_STRING_SIZE}; + throw Exception{"String too long for type FixedString(" + toString(n) + ")", ErrorCodes::TOO_LARGE_STRING_SIZE}; auto column_fixed = ColumnFixedString::create(n); @@ -1296,12 +1388,9 @@ class FunctionFromUnixTime : public IFunction public: static constexpr auto name = "fromUnixTime"; static FunctionPtr create(const Context & context_) { return std::make_shared(context_); }; - FunctionFromUnixTime(const Context & context_) : context(context_) {}; + FunctionFromUnixTime(const Context & context_) : context(context_){}; - String getName() const override - { - return name; - } + String getName() const override { return name; } bool isVariadic() const override { return true; } size_t getNumberOfArguments() const override { return 0; } @@ -1327,7 +1416,7 @@ class FunctionFromUnixTime : public IFunction /// scale_multiplier is used to compensate the fsp part if the scale is less than 6 /// for example, for decimal xxxx.23, the decimal part is 23, and it should be /// converted to 230000 - static constexpr int scale_multiplier[] = {1000000,100000,10000,1000,100,10,1}; + static constexpr int scale_multiplier[] = {1000000, 100000, 10000, 1000, 100, 10, 1}; template void decimalToMyDatetime(const ColumnPtr & input_col, ColumnUInt64::Container & datetime_res, ColumnUInt8::Container & null_res, @@ -1500,22 +1589,11 @@ class FunctionFromUnixTime : public IFunction else { // need append date format - Block temporary_block - { - { - ColumnNullable::create(std::move(datetime_column), std::move(null_column)), - makeNullable(std::make_shared(std::min(scale, 6))), - "" - }, - block.getByPosition(arguments[1]), - { - nullptr, - makeNullable(std::make_shared()), - "" - } - }; + Block temporary_block{{ColumnNullable::create(std::move(datetime_column), std::move(null_column)), + makeNullable(std::make_shared(std::min(scale, 6))), ""}, + block.getByPosition(arguments[1]), {nullptr, makeNullable(std::make_shared()), ""}}; FunctionBuilderPtr func_builder_date_format = FunctionFactory::instance().get("dateFormat", context); - ColumnsWithTypeAndName args{ temporary_block.getByPosition(0), temporary_block.getByPosition(1) }; + ColumnsWithTypeAndName args{temporary_block.getByPosition(0), temporary_block.getByPosition(1)}; auto func_date_format = func_builder_date_format->build(args); func_date_format->execute(temporary_block, {0, 1}, 2); @@ -1525,7 +1603,6 @@ class FunctionFromUnixTime : public IFunction private: const Context & context; - }; class FunctionDateFormat : public IFunction @@ -1534,10 +1611,7 @@ class FunctionDateFormat : public IFunction static constexpr auto name = "dateFormat"; static FunctionPtr create(const Context &) { return std::make_shared(); }; - String getName() const override - { - return name; - } + String getName() const override { return name; } size_t getNumberOfArguments() const override { return 2; } bool isInjective(const Block &) override { return false; } @@ -1621,8 +1695,7 @@ class FunctionStrToDate : public IFunction throw Exception("First argument for function " + getName() + " must be String, but get " + arguments[0].type->getName(), ErrorCodes::ILLEGAL_COLUMN); if (!removeNullable(arguments[1].type)->isString()) - throw Exception( - "Second argument for function " + getName() + " must be String, but get " + arguments[1].type->getName(), + 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) @@ -1652,7 +1725,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 +1775,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 +1783,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 +1815,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; @@ -1756,10 +1840,7 @@ class FunctionStrToDate : public IFunction struct PositiveMonotonicity { static bool has() { return true; } - static IFunction::Monotonicity get(const IDataType &, const Field &, const Field &) - { - return { true }; - } + static IFunction::Monotonicity get(const IDataType &, const Field &, const Field &) { return {true}; } }; template @@ -1781,27 +1862,25 @@ struct ToIntMonotonicity /// If type is expanding, then function is monotonic. if (sizeof(T) > size_of_type) - return { true, true, true }; + return {true, true, true}; /// If type is same, too. (Enum has separate case, because it is different data type) - if (checkDataType>(&type) || - checkDataType>(&type)) - return { true, true, true }; + if (checkDataType>(&type) || checkDataType>(&type)) + return {true, true, true}; /// In other cases, if range is unbounded, we don't know, whether function is monotonic or not. if (left.isNull() || right.isNull()) return {}; /// If converting from float, for monotonicity, arguments must fit in range of result type. - if (checkDataType(&type) - || checkDataType(&type)) + if (checkDataType(&type) || checkDataType(&type)) { Float64 left_float = left.get(); Float64 right_float = right.get(); if (left_float >= std::numeric_limits::min() && left_float <= std::numeric_limits::max() && right_float >= std::numeric_limits::min() && right_float <= std::numeric_limits::max()) - return { true }; + return {true}; return {}; } @@ -1809,15 +1888,14 @@ struct ToIntMonotonicity /// If signedness of type is changing, or converting from Date, DateTime, then arguments must be from same half, /// and after conversion, resulting values must be from same half. /// Just in case, it is required in rest of cases too. - if ((left.get() >= 0) != (right.get() >= 0) - || (T(left.get()) >= 0) != (T(right.get()) >= 0)) + if ((left.get() >= 0) != (right.get() >= 0) || (T(left.get()) >= 0) != (T(right.get()) >= 0)) return {}; /// If type is shrinked, then for monotonicity, all bits other than that fits, must be same. if (divideByRangeOfType(left.get()) != divideByRangeOfType(right.get())) return {}; - return { true }; + return {true}; } }; @@ -1835,27 +1913,27 @@ struct ToStringMonotonicity /// `toString` function is monotonous if the argument is Date or DateTime, or non-negative numbers with the same number of symbols. - if (checkAndGetDataType(&type) - || typeid_cast(&type)) + if (checkAndGetDataType(&type) || typeid_cast(&type)) return positive; if (left.isNull() || right.isNull()) return {}; - if (left.getType() == Field::Types::UInt64 - && right.getType() == Field::Types::UInt64) + if (left.getType() == Field::Types::UInt64 && right.getType() == Field::Types::UInt64) { return (left.get() == 0 && right.get() == 0) - || (floor(log10(left.get())) == floor(log10(right.get()))) - ? positive : not_monotonic; + || (floor(log10(left.get())) == floor(log10(right.get()))) + ? positive + : not_monotonic; } - if (left.getType() == Field::Types::Int64 - && right.getType() == Field::Types::Int64) + if (left.getType() == Field::Types::Int64 && right.getType() == Field::Types::Int64) { return (left.get() == 0 && right.get() == 0) - || (left.get() > 0 && right.get() > 0 && floor(log10(left.get())) == floor(log10(right.get()))) - ? positive : not_monotonic; + || (left.get() > 0 && right.get() > 0 + && floor(log10(left.get())) == floor(log10(right.get()))) + ? positive + : not_monotonic; } return not_monotonic; @@ -1863,17 +1941,50 @@ struct ToStringMonotonicity }; -struct NameToUInt8 { static constexpr auto name = "toUInt8"; }; -struct NameToUInt16 { static constexpr auto name = "toUInt16"; }; -struct NameToUInt32 { static constexpr auto name = "toUInt32"; }; -struct NameToUInt64 { static constexpr auto name = "toUInt64"; }; -struct NameToInt8 { static constexpr auto name = "toInt8"; }; -struct NameToInt16 { static constexpr auto name = "toInt16"; }; -struct NameToInt32 { static constexpr auto name = "toInt32"; }; -struct NameToInt64 { static constexpr auto name = "toInt64"; }; -struct NameToFloat32 { static constexpr auto name = "toFloat32"; }; -struct NameToFloat64 { static constexpr auto name = "toFloat64"; }; -struct NameToUUID { static constexpr auto name = "toUUID"; }; +struct NameToUInt8 +{ + static constexpr auto name = "toUInt8"; +}; +struct NameToUInt16 +{ + static constexpr auto name = "toUInt16"; +}; +struct NameToUInt32 +{ + static constexpr auto name = "toUInt32"; +}; +struct NameToUInt64 +{ + static constexpr auto name = "toUInt64"; +}; +struct NameToInt8 +{ + static constexpr auto name = "toInt8"; +}; +struct NameToInt16 +{ + static constexpr auto name = "toInt16"; +}; +struct NameToInt32 +{ + static constexpr auto name = "toInt32"; +}; +struct NameToInt64 +{ + static constexpr auto name = "toInt64"; +}; +struct NameToFloat32 +{ + static constexpr auto name = "toFloat32"; +}; +struct NameToFloat64 +{ + static constexpr auto name = "toFloat64"; +}; +struct NameToUUID +{ + static constexpr auto name = "toUUID"; +}; using FunctionToUInt8 = FunctionConvert>; using FunctionToUInt16 = FunctionConvert>; @@ -1894,43 +2005,144 @@ using FunctionToString = FunctionConvert>; -template struct FunctionTo; +template +struct FunctionTo; -template <> struct FunctionTo { using Type = FunctionToUInt8; }; -template <> struct FunctionTo { using Type = FunctionToUInt16; }; -template <> struct FunctionTo { using Type = FunctionToUInt32; }; -template <> struct FunctionTo { using Type = FunctionToUInt64; }; -template <> struct FunctionTo { using Type = FunctionToInt8; }; -template <> struct FunctionTo { using Type = FunctionToInt16; }; -template <> struct FunctionTo { using Type = FunctionToInt32; }; -template <> struct FunctionTo { using Type = FunctionToInt64; }; -template <> struct FunctionTo { using Type = FunctionToFloat32; }; -template <> struct FunctionTo { using Type = FunctionToFloat64; }; +template <> +struct FunctionTo +{ + using Type = FunctionToUInt8; +}; +template <> +struct FunctionTo +{ + using Type = FunctionToUInt16; +}; +template <> +struct FunctionTo +{ + using Type = FunctionToUInt32; +}; +template <> +struct FunctionTo +{ + using Type = FunctionToUInt64; +}; +template <> +struct FunctionTo +{ + using Type = FunctionToInt8; +}; +template <> +struct FunctionTo +{ + using Type = FunctionToInt16; +}; +template <> +struct FunctionTo +{ + using Type = FunctionToInt32; +}; +template <> +struct FunctionTo +{ + using Type = FunctionToInt64; +}; +template <> +struct FunctionTo +{ + using Type = FunctionToFloat32; +}; +template <> +struct FunctionTo +{ + using Type = FunctionToFloat64; +}; //template <> struct FunctionTo { using Type = FunctionToDate; }; -template <> struct FunctionTo { using Type = FunctionToDateTime; }; -template <> struct FunctionTo { using Type = FunctionToMyDate; }; -template <> struct FunctionTo { using Type = FunctionToMyDateTime; }; -template <> struct FunctionTo { using Type = FunctionToUUID; }; -template <> struct FunctionTo { using Type = FunctionToString; }; -template <> struct FunctionTo { using Type = FunctionToFixedString; }; - -template struct FunctionTo> - : FunctionTo> -{ -}; - -struct NameToUInt8OrZero { static constexpr auto name = "toUInt8OrZero"; }; -struct NameToUInt16OrZero { static constexpr auto name = "toUInt16OrZero"; }; -struct NameToUInt32OrZero { static constexpr auto name = "toUInt32OrZero"; }; -struct NameToUInt64OrZero { static constexpr auto name = "toUInt64OrZero"; }; -struct NameToInt8OrZero { static constexpr auto name = "toInt8OrZero"; }; -struct NameToInt16OrZero { static constexpr auto name = "toInt16OrZero"; }; -struct NameToInt32OrZero { static constexpr auto name = "toInt32OrZero"; }; -struct NameToInt64OrZero { static constexpr auto name = "toInt64OrZero"; }; -struct NameToFloat32OrZero { static constexpr auto name = "toFloat32OrZero"; }; -struct NameToFloat64OrZero { static constexpr auto name = "toFloat64OrZero"; }; -struct NameToDateOrZero { static constexpr auto name = "toDateOrZero"; }; -struct NameToDateTimeOrZero { static constexpr auto name = "toDateTimeOrZero"; }; +template <> +struct FunctionTo +{ + using Type = FunctionToDateTime; +}; +template <> +struct FunctionTo +{ + using Type = FunctionToMyDate; +}; +template <> +struct FunctionTo +{ + using Type = FunctionToMyDateTime; +}; +template <> +struct FunctionTo +{ + using Type = FunctionToUUID; +}; +template <> +struct FunctionTo +{ + using Type = FunctionToString; +}; +template <> +struct FunctionTo +{ + using Type = FunctionToFixedString; +}; + +template +struct FunctionTo> : FunctionTo> +{ +}; + +struct NameToUInt8OrZero +{ + static constexpr auto name = "toUInt8OrZero"; +}; +struct NameToUInt16OrZero +{ + static constexpr auto name = "toUInt16OrZero"; +}; +struct NameToUInt32OrZero +{ + static constexpr auto name = "toUInt32OrZero"; +}; +struct NameToUInt64OrZero +{ + static constexpr auto name = "toUInt64OrZero"; +}; +struct NameToInt8OrZero +{ + static constexpr auto name = "toInt8OrZero"; +}; +struct NameToInt16OrZero +{ + static constexpr auto name = "toInt16OrZero"; +}; +struct NameToInt32OrZero +{ + static constexpr auto name = "toInt32OrZero"; +}; +struct NameToInt64OrZero +{ + static constexpr auto name = "toInt64OrZero"; +}; +struct NameToFloat32OrZero +{ + static constexpr auto name = "toFloat32OrZero"; +}; +struct NameToFloat64OrZero +{ + static constexpr auto name = "toFloat64OrZero"; +}; +struct NameToDateOrZero +{ + static constexpr auto name = "toDateOrZero"; +}; +struct NameToDateTimeOrZero +{ + static constexpr auto name = "toDateTimeOrZero"; +}; using FunctionToUInt8OrZero = FunctionConvertFromString; using FunctionToUInt16OrZero = FunctionConvertFromString; @@ -1945,20 +2157,62 @@ using FunctionToFloat64OrZero = FunctionConvertFromString; using FunctionToDateTimeOrZero = FunctionConvertFromString; -struct NameToUInt8OrNull { static constexpr auto name = "toUInt8OrNull"; }; -struct NameToUInt16OrNull { static constexpr auto name = "toUInt16OrNull"; }; -struct NameToUInt32OrNull { static constexpr auto name = "toUInt32OrNull"; }; -struct NameToUInt64OrNull { static constexpr auto name = "toUInt64OrNull"; }; -struct NameToInt8OrNull { static constexpr auto name = "toInt8OrNull"; }; -struct NameToInt16OrNull { static constexpr auto name = "toInt16OrNull"; }; -struct NameToInt32OrNull { static constexpr auto name = "toInt32OrNull"; }; -struct NameToInt64OrNull { static constexpr auto name = "toInt64OrNull"; }; -struct NameToFloat32OrNull { static constexpr auto name = "toFloat32OrNull"; }; -struct NameToFloat64OrNull { static constexpr auto name = "toFloat64OrNull"; }; -struct NameToDateOrNull { static constexpr auto name = "toDateOrNull"; }; -struct NameToDateTimeOrNull { static constexpr auto name = "toDateTimeOrNull"; }; -struct NameToMyDateOrNull { static constexpr auto name = "toMyDateOrNull"; }; -struct NameToMyDateTimeOrNull { static constexpr auto name = "toMyDateTimeOrNull"; }; +struct NameToUInt8OrNull +{ + static constexpr auto name = "toUInt8OrNull"; +}; +struct NameToUInt16OrNull +{ + static constexpr auto name = "toUInt16OrNull"; +}; +struct NameToUInt32OrNull +{ + static constexpr auto name = "toUInt32OrNull"; +}; +struct NameToUInt64OrNull +{ + static constexpr auto name = "toUInt64OrNull"; +}; +struct NameToInt8OrNull +{ + static constexpr auto name = "toInt8OrNull"; +}; +struct NameToInt16OrNull +{ + static constexpr auto name = "toInt16OrNull"; +}; +struct NameToInt32OrNull +{ + static constexpr auto name = "toInt32OrNull"; +}; +struct NameToInt64OrNull +{ + static constexpr auto name = "toInt64OrNull"; +}; +struct NameToFloat32OrNull +{ + static constexpr auto name = "toFloat32OrNull"; +}; +struct NameToFloat64OrNull +{ + static constexpr auto name = "toFloat64OrNull"; +}; +struct NameToDateOrNull +{ + static constexpr auto name = "toDateOrNull"; +}; +struct NameToDateTimeOrNull +{ + static constexpr auto name = "toDateTimeOrNull"; +}; +struct NameToMyDateOrNull +{ + static constexpr auto name = "toMyDateOrNull"; +}; +struct NameToMyDateTimeOrNull +{ + static constexpr auto name = "toMyDateTimeOrNull"; +}; using FunctionToUInt8OrNull = FunctionConvertFromString; using FunctionToUInt16OrNull = FunctionConvertFromString; @@ -1973,18 +2227,28 @@ using FunctionToFloat64OrNull = FunctionConvertFromString; using FunctionToDateTimeOrNull = FunctionConvertFromString; using FunctionToMyDateOrNull = FunctionConvertFromString; -using FunctionToMyDateTimeOrNull = FunctionConvertFromString; +using FunctionToMyDateTimeOrNull + = FunctionConvertFromString; -struct NameParseDateTimeBestEffort { static constexpr auto name = "parseDateTimeBestEffort"; }; -struct NameParseDateTimeBestEffortOrZero { static constexpr auto name = "parseDateTimeBestEffortOrZero"; }; -struct NameParseDateTimeBestEffortOrNull { static constexpr auto name = "parseDateTimeBestEffortOrNull"; }; +struct NameParseDateTimeBestEffort +{ + static constexpr auto name = "parseDateTimeBestEffort"; +}; +struct NameParseDateTimeBestEffortOrZero +{ + static constexpr auto name = "parseDateTimeBestEffortOrZero"; +}; +struct NameParseDateTimeBestEffortOrNull +{ + static constexpr auto name = "parseDateTimeBestEffortOrNull"; +}; -using FunctionParseDateTimeBestEffort = FunctionConvertFromString< - DataTypeDateTime, NameParseDateTimeBestEffort, ConvertFromStringExceptionMode::Throw, ConvertFromStringParsingMode::BestEffort>; -using FunctionParseDateTimeBestEffortOrZero = FunctionConvertFromString< - DataTypeDateTime, NameParseDateTimeBestEffortOrZero, ConvertFromStringExceptionMode::Zero, ConvertFromStringParsingMode::BestEffort>; -using FunctionParseDateTimeBestEffortOrNull = FunctionConvertFromString< - DataTypeDateTime, NameParseDateTimeBestEffortOrNull, ConvertFromStringExceptionMode::Null, ConvertFromStringParsingMode::BestEffort>; +using FunctionParseDateTimeBestEffort = FunctionConvertFromString; +using FunctionParseDateTimeBestEffortOrZero = FunctionConvertFromString; +using FunctionParseDateTimeBestEffortOrNull = FunctionConvertFromString; class PreparedFunctionCast : public PreparedFunctionImpl @@ -1993,7 +2257,8 @@ class PreparedFunctionCast : public PreparedFunctionImpl using WrapperType = std::function; explicit PreparedFunctionCast(WrapperType && wrapper_function, const char * name) - : wrapper_function(std::move(wrapper_function)), name(name) {} + : wrapper_function(std::move(wrapper_function)), name(name) + {} String getName() const override { return name; } @@ -2023,12 +2288,14 @@ class FunctionCast final : public IFunctionBase using WrapperType = std::function; using MonotonicityForRange = std::function; - FunctionCast(const Context & context, const char * name, MonotonicityForRange && monotonicity_for_range - , const DataTypes & argument_types, const DataTypePtr & return_type) - : context(context), name(name), monotonicity_for_range(monotonicity_for_range) - , argument_types(argument_types), return_type(return_type) - { - } + FunctionCast(const Context & context, const char * name, MonotonicityForRange && monotonicity_for_range, + const DataTypes & argument_types, const DataTypePtr & return_type) + : context(context), + name(name), + monotonicity_for_range(monotonicity_for_range), + argument_types(argument_types), + return_type(return_type) + {} const DataTypes & getArgumentTypes() const override { return argument_types; } const DataTypePtr & getReturnType() const override { return return_type; } @@ -2040,10 +2307,7 @@ class FunctionCast final : public IFunctionBase String getName() const override { return name; } - bool hasInformationAboutMonotonicity() const override - { - return static_cast(monotonicity_for_range); - } + bool hasInformationAboutMonotonicity() const override { return static_cast(monotonicity_for_range); } Monotonicity getMonotonicityForRange(const IDataType & type, const Field & left, const Field & right) const override { @@ -2051,7 +2315,6 @@ class FunctionCast final : public IFunctionBase } private: - const Context & context; const char * name; MonotonicityForRange monotonicity_for_range; @@ -2068,20 +2331,17 @@ class FunctionCast final : public IFunctionBase /// Check conversion using underlying function { - function->getReturnType(ColumnsWithTypeAndName(1, { nullptr, from_type, "" })); + function->getReturnType(ColumnsWithTypeAndName(1, {nullptr, from_type, ""})); } - return [function] (Block & block, const ColumnNumbers & arguments, const size_t result) - { - function->execute(block, arguments, result); - }; + return [function]( + Block & block, const ColumnNumbers & arguments, const size_t result) { function->execute(block, arguments, result); }; } template static WrapperType createDecimalWrapper(PrecType prec, ScaleType scale) { - return [prec, scale] (Block & block, const ColumnNumbers & arguments, const size_t result) - { + return [prec, scale](Block & block, const ColumnNumbers & arguments, const size_t result) { FunctionToDecimal::execute(block, arguments, result, prec, scale); }; } @@ -2091,8 +2351,7 @@ class FunctionCast final : public IFunctionBase if (!from_type->isStringOrFixedString()) throw Exception{"CAST AS FixedString is only implemented for types String and FixedString", ErrorCodes::NOT_IMPLEMENTED}; - return [N] (Block & block, const ColumnNumbers & arguments, const size_t result) - { + return [N](Block & block, const ColumnNumbers & arguments, const size_t result) { FunctionToFixedString::execute(block, arguments, result, N); }; } @@ -2102,8 +2361,7 @@ class FunctionCast final : public IFunctionBase /// Conversion from String through parsing. if (checkAndGetDataType(from_type_untyped.get())) { - return [] (Block & block, const ColumnNumbers & arguments, const size_t result) - { + return [](Block & block, const ColumnNumbers & arguments, const size_t result) { ConvertImplGenericFromString::execute(block, arguments, result); }; } @@ -2124,24 +2382,19 @@ class FunctionCast final : public IFunctionBase /// both from_type and to_type should be nullptr now is array types had same dimensions if ((from_type == nullptr) != (to_type == nullptr)) - throw Exception{"CAST AS Array can only be performed between same-dimensional array types or from String", ErrorCodes::TYPE_MISMATCH}; + throw Exception{ + "CAST AS Array can only be performed between same-dimensional array types or from String", ErrorCodes::TYPE_MISMATCH}; /// Prepare nested type conversion const auto nested_function = prepare(from_nested_type, to_nested_type); - return [nested_function, from_nested_type, to_nested_type]( - Block & block, const ColumnNumbers & arguments, const size_t result) - { + return [nested_function, from_nested_type, to_nested_type](Block & block, const ColumnNumbers & arguments, const size_t result) { const auto & array_arg = block.getByPosition(arguments.front()); if (const ColumnArray * col_array = checkAndGetColumn(array_arg.column.get())) { /// create block for converting nested column containing original and result columns - Block nested_block - { - { col_array->getDataPtr(), from_nested_type, "" }, - { nullptr, to_nested_type, "" } - }; + Block nested_block{{col_array->getDataPtr(), from_nested_type, ""}, {nullptr, to_nested_type, ""}}; /// convert nested column nested_function(nested_block, {0}, 1); @@ -2159,20 +2412,22 @@ class FunctionCast final : public IFunctionBase /// Conversion from String through parsing. if (checkAndGetDataType(from_type_untyped.get())) { - return [] (Block & block, const ColumnNumbers & arguments, const size_t result) - { + return [](Block & block, const ColumnNumbers & arguments, const size_t result) { ConvertImplGenericFromString::execute(block, arguments, result); }; } const auto from_type = checkAndGetDataType(from_type_untyped.get()); if (!from_type) - throw Exception{"CAST AS Tuple can only be performed between tuple types or from String.\nLeft type: " + from_type_untyped->getName() + - ", right type: " + to_type->getName(), ErrorCodes::TYPE_MISMATCH}; + throw Exception{"CAST AS Tuple can only be performed between tuple types or from String.\nLeft type: " + + from_type_untyped->getName() + ", right type: " + to_type->getName(), + ErrorCodes::TYPE_MISMATCH}; if (from_type->getElements().size() != to_type->getElements().size()) throw Exception{"CAST AS Tuple can only be performed between tuple types with the same number of elements or from String.\n" - "Left type: " + from_type->getName() + ", right type: " + to_type->getName(), ErrorCodes::TYPE_MISMATCH}; + "Left type: " + + from_type->getName() + ", right type: " + to_type->getName(), + ErrorCodes::TYPE_MISMATCH}; const auto & from_element_types = from_type->getElements(); const auto & to_element_types = to_type->getElements(); @@ -2183,39 +2438,37 @@ class FunctionCast final : public IFunctionBase for (const auto idx_type : ext::enumerate(from_type->getElements())) element_wrappers.push_back(prepare(idx_type.second, to_element_types[idx_type.first])); - return [element_wrappers, from_element_types, to_element_types] - (Block & block, const ColumnNumbers & arguments, const size_t result) - { - const auto col = block.getByPosition(arguments.front()).column.get(); + return + [element_wrappers, from_element_types, to_element_types](Block & block, const ColumnNumbers & arguments, const size_t result) { + const auto col = block.getByPosition(arguments.front()).column.get(); - /// copy tuple elements to a separate block - Block element_block; + /// copy tuple elements to a separate block + Block element_block; - size_t tuple_size = from_element_types.size(); - const ColumnTuple & column_tuple = typeid_cast(*col); + size_t tuple_size = from_element_types.size(); + const ColumnTuple & column_tuple = typeid_cast(*col); - /// create columns for source elements - for (size_t i = 0; i < tuple_size; ++i) - element_block.insert({ column_tuple.getColumns()[i], from_element_types[i], "" }); + /// create columns for source elements + for (size_t i = 0; i < tuple_size; ++i) + element_block.insert({column_tuple.getColumns()[i], from_element_types[i], ""}); - /// create columns for converted elements - for (const auto & to_element_type : to_element_types) - element_block.insert({ nullptr, to_element_type, "" }); + /// create columns for converted elements + for (const auto & to_element_type : to_element_types) + element_block.insert({nullptr, to_element_type, ""}); - /// insert column for converted tuple - element_block.insert({ nullptr, std::make_shared(to_element_types), "" }); + /// insert column for converted tuple + element_block.insert({nullptr, std::make_shared(to_element_types), ""}); - /// invoke conversion for each element - for (const auto idx_element_wrapper : ext::enumerate(element_wrappers)) - idx_element_wrapper.second(element_block, { idx_element_wrapper.first }, - tuple_size + idx_element_wrapper.first); + /// invoke conversion for each element + for (const auto idx_element_wrapper : ext::enumerate(element_wrappers)) + idx_element_wrapper.second(element_block, {idx_element_wrapper.first}, tuple_size + idx_element_wrapper.first); - Columns converted_columns(tuple_size); - for (size_t i = 0; i < tuple_size; ++i) - converted_columns[i] = element_block.getByPosition(tuple_size + i).column; + Columns converted_columns(tuple_size); + for (size_t i = 0; i < tuple_size; ++i) + converted_columns[i] = element_block.getByPosition(tuple_size + i).column; - block.getByPosition(result).column = ColumnTuple::create(converted_columns); - }; + block.getByPosition(result).column = ColumnTuple::create(converted_columns); + }; } template @@ -2239,17 +2492,16 @@ class FunctionCast final : public IFunctionBase /// Check conversion using underlying function { - function->getReturnType(ColumnsWithTypeAndName(1, { nullptr, from_type, "" })); + function->getReturnType(ColumnsWithTypeAndName(1, {nullptr, from_type, ""})); } - return [function] (Block & block, const ColumnNumbers & arguments, const size_t result) - { + return [function](Block & block, const ColumnNumbers & arguments, const size_t result) { function->execute(block, arguments, result); }; } else - throw Exception{"Conversion from " + from_type->getName() + " to " + to_type->getName() + - " is not supported", ErrorCodes::CANNOT_CONVERT_TYPE}; + throw Exception{"Conversion from " + from_type->getName() + " to " + to_type->getName() + " is not supported", + ErrorCodes::CANNOT_CONVERT_TYPE}; } template @@ -2263,17 +2515,17 @@ class FunctionCast final : public IFunctionBase using EnumValues = std::vector; EnumValues name_intersection; - std::set_intersection(std::begin(from_values), std::end(from_values), - std::begin(to_values), std::end(to_values), std::back_inserter(name_intersection), - [] (auto && from, auto && to) { return from.first < to.first; }); + std::set_intersection(std::begin(from_values), std::end(from_values), std::begin(to_values), std::end(to_values), + std::back_inserter(name_intersection), [](auto && from, auto && to) { return from.first < to.first; }); for (const auto & name_value : name_intersection) { const auto & old_value = name_value.second; const auto & new_value = to_type->getValue(name_value.first); if (old_value != new_value) - throw Exception{"Enum conversion changes value for element '" + name_value.first + - "' from " + toString(old_value) + " to " + toString(new_value), ErrorCodes::CANNOT_CONVERT_TYPE}; + throw Exception{"Enum conversion changes value for element '" + name_value.first + "' from " + toString(old_value) + " to " + + toString(new_value), + ErrorCodes::CANNOT_CONVERT_TYPE}; } }; @@ -2281,8 +2533,7 @@ class FunctionCast final : public IFunctionBase WrapperType createStringToEnumWrapper() const { const char * function_name = name; - return [function_name] (Block & block, const ColumnNumbers & arguments, const size_t result) - { + return [function_name](Block & block, const ColumnNumbers & arguments, const size_t result) { const auto first_col = block.getByPosition(arguments.front()).column.get(); auto & col_with_type_and_name = block.getByPosition(result); @@ -2309,8 +2560,7 @@ class FunctionCast final : public IFunctionBase WrapperType createIdentityWrapper(const DataTypePtr &) const { - return [] (Block & block, const ColumnNumbers & arguments, const size_t result) - { + return [](Block & block, const ColumnNumbers & arguments, const size_t result) { block.getByPosition(result).column = block.getByPosition(arguments.front()).column; }; } @@ -2318,8 +2568,7 @@ class FunctionCast final : public IFunctionBase WrapperType createNothingWrapper(const IDataType * to_type) const { ColumnPtr res = to_type->createColumnConstWithDefaultValue(1); - return [res] (Block & block, const ColumnNumbers &, const size_t result) - { + return [res](Block & block, const ColumnNumbers &, const size_t result) { /// Column of Nothing type is trivially convertible to any other column block.getByPosition(result).column = res->cloneResized(block.rows())->convertToFullColumnIfConst(); }; @@ -2345,8 +2594,7 @@ class FunctionCast final : public IFunctionBase if (!nullable_conversion.result_is_nullable) throw Exception{"Cannot convert NULL to a non-nullable type", ErrorCodes::CANNOT_CONVERT_TYPE}; - return [](Block & block, const ColumnNumbers &, const size_t result) - { + return [](Block & block, const ColumnNumbers &, const size_t result) { auto & res = block.getByPosition(result); res.column = res.type->createColumnConstWithDefaultValue(block.rows())->convertToFullColumnIfConst(); }; @@ -2359,8 +2607,7 @@ class FunctionCast final : public IFunctionBase if (nullable_conversion.result_is_nullable) { - return [wrapper, nullable_conversion] (Block & block, const ColumnNumbers & arguments, const size_t result) - { + return [wrapper, nullable_conversion](Block & block, const ColumnNumbers & arguments, const size_t result) { /// Create a temporary block on which to perform the operation. auto & res = block.getByPosition(result); const auto & ret_type = res.type; @@ -2405,8 +2652,7 @@ class FunctionCast final : public IFunctionBase { /// Conversion from Nullable to non-Nullable. - return [wrapper] (Block & block, const ColumnNumbers & arguments, const size_t result) - { + return [wrapper](Block & block, const ColumnNumbers & arguments, const size_t result) { Block tmp_block = createBlockWithNestedColumns(block, arguments, result); /// Check that all values are not-NULL. @@ -2416,8 +2662,7 @@ class FunctionCast final : public IFunctionBase const auto & null_map = nullable_col.getNullMapData(); if (!memoryIsZero(null_map.data(), null_map.size())) - throw Exception{"Cannot convert NULL value to non-Nullable type", - ErrorCodes::CANNOT_INSERT_NULL_IN_ORDINARY_COLUMN}; + throw Exception{"Cannot convert NULL value to non-Nullable type", ErrorCodes::CANNOT_INSERT_NULL_IN_ORDINARY_COLUMN}; wrapper(tmp_block, arguments, result); block.getByPosition(result).column = tmp_block.getByPosition(result).column; @@ -2461,8 +2706,8 @@ class FunctionCast final : public IFunctionBase return createDecimalWrapper(decimal_type->getPrec(), decimal_type->getScale()); else if (const auto decimal_type = checkAndGetDataType(to_type.get())) return createDecimalWrapper(decimal_type->getPrec(), decimal_type->getScale()); -// else if (const auto to_actual_type = checkAndGetDataType(to_type.get())) -// return createWrapper(from_type, to_actual_type); + // else if (const auto to_actual_type = checkAndGetDataType(to_type.get())) + // return createWrapper(from_type, to_actual_type); else if (const auto to_actual_type = checkAndGetDataType(to_type.get())) return createWrapper(from_type, to_actual_type); else if (const auto to_actual_type = checkAndGetDataType(to_type.get())) @@ -2485,7 +2730,8 @@ class FunctionCast final : public IFunctionBase /// It's possible to use ConvertImplGenericFromString to convert from String to AggregateFunction, /// but it is disabled because deserializing aggregate functions state might be unsafe. - throw Exception{"Conversion from " + from_type->getName() + " to " + to_type->getName() + " is not supported", ErrorCodes::CANNOT_CONVERT_TYPE}; + throw Exception{ + "Conversion from " + from_type->getName() + " to " + to_type->getName() + " is not supported", ErrorCodes::CANNOT_CONVERT_TYPE}; } }; @@ -2505,8 +2751,8 @@ class FunctionBuilderCast : public FunctionBuilderImpl protected: - - FunctionBasePtr buildImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & return_type, std::shared_ptr) const override + FunctionBasePtr buildImpl( + const ColumnsWithTypeAndName & arguments, const DataTypePtr & return_type, std::shared_ptr) const override { DataTypes data_types(arguments.size()); @@ -2521,7 +2767,8 @@ class FunctionBuilderCast : public FunctionBuilderImpl { const auto type_col = checkAndGetColumnConst(arguments.back().column.get()); if (!type_col) - throw Exception("Second argument to " + getName() + " must be a constant string describing type", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + throw Exception( + "Second argument to " + getName() + " must be a constant string describing type", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); return DataTypeFactory::instance().get(type_col->getValue()); } @@ -2557,8 +2804,8 @@ class FunctionBuilderCast : public FunctionBuilderImpl return monotonicityForType(type); else if (const auto type = checkAndGetDataType(to_type)) return monotonicityForType(type); -// else if (const auto type = checkAndGetDataType(to_type)) -// return monotonicityForType(type); + // else if (const auto type = checkAndGetDataType(to_type)) + // return monotonicityForType(type); else if (const auto type = checkAndGetDataType(to_type)) return monotonicityForType(type); else if (const auto type = checkAndGetDataType(to_type)) @@ -2577,4 +2824,4 @@ class FunctionBuilderCast : public FunctionBuilderImpl const Context & context; }; -} +} // namespace DB