From f55cd5e9b03ffabf052d02e027753ee7a5ca4afa Mon Sep 17 00:00:00 2001 From: guo-shaoge Date: Wed, 26 Jan 2022 11:58:44 +0800 Subject: [PATCH] This is an automated cherry-pick of #3922 Signed-off-by: ti-chi-bot --- dbms/src/Flash/Coprocessor/DAGContext.cpp | 77 +- dbms/src/Flash/Coprocessor/DAGContext.h | 84 ++ .../Coprocessor/tests/gtest_dag_context.cpp | 27 + dbms/src/Functions/FunctionsTiDBConversion.h | 25 +- .../Functions/tests/gtest_tidb_conversion.cpp | 721 ++++++++++++++++++ 5 files changed, 863 insertions(+), 71 deletions(-) create mode 100644 dbms/src/Flash/Coprocessor/tests/gtest_dag_context.cpp diff --git a/dbms/src/Flash/Coprocessor/DAGContext.cpp b/dbms/src/Flash/Coprocessor/DAGContext.cpp index ddeb8d9d5c4..302964b2606 100644 --- a/dbms/src/Flash/Coprocessor/DAGContext.cpp +++ b/dbms/src/Flash/Coprocessor/DAGContext.cpp @@ -11,76 +11,19 @@ extern const int DIVIDED_BY_ZERO; extern const int INVALID_TIME; } // namespace ErrorCodes -namespace -{ -enum Flag -{ - IGNORE_TRUNCATE = 1, - TRUNCATE_AS_WARNING = 1u << 1u, - PAD_CHAR_TO_FULL_LENGTH = 1u << 2u, - IN_INSERT_STMT = 1u << 3u, - IN_UPDATE_OR_DELETE_STMT = 1u << 4u, - IN_SELECT_STMT = 1u << 5u, - OVERFLOW_AS_WARNING = 1u << 6u, - IGNORE_ZERO_IN_DATE = 1u << 7u, - DIVIDED_BY_ZERO_AS_WARNING = 1u << 8u, - IN_LOAD_DATA_STMT = 1u << 10u, -}; - -enum SqlMode -{ - REAL_AS_FLOAT = 1ul, - PIPES_AS_CONCAT = 1ul << 1ul, - ANSI_QUOTES = 1ul << 2ul, - IGNORE_SPACE = 1ul << 3ul, - NOT_USED = 1ul << 4ul, - ONLY_FULL_GROUP_BY = 1ul << 5ul, - NO_UNSIGNED_SUBTRACTION = 1ul << 6ul, - NO_DIR_IN_CREATE = 1ul << 7ul, - POSTGRESQL = 1ul << 8ul, - ORACLE = 1ul << 9ul, - MSSQL = 1ul << 10ul, - DB2 = 1ul << 11ul, - MAXDB = 1ul << 12ul, - NO_KEY_OPTIONS = 1ul << 13ul, - NO_TABLE_OPTIONS = 1ul << 14ul, - NO_FIELD_OPTIONS = 1ul << 15ul, - MYSQL323 = 1ul << 16ul, - MYSQL40 = 1ul << 17ul, - ANSI = 1ul << 18ul, - NO_AUTO_VALUE_ON_ZERO = 1ul << 19ul, - NO_BACK_SLASH_ESCAPES = 1ul << 20ul, - STRICT_TRANS_TABLES = 1ul << 21ul, - STRICT_ALL_TABLES = 1ul << 22ul, - NO_ZERO_IN_DATE = 1ul << 23ul, - NO_ZERO_DATE = 1ul << 24ul, - INVALID_DATES = 1ul << 25ul, - ERROR_FOR_DIVISION_BY_ZERO = 1ul << 26ul, - TRADITIONAL = 1ul << 27ul, - NO_AUTO_CREATE_USER = 1ul << 28ul, - HIGH_NOT_PRECEDENCE = 1ul << 29ul, - NO_ENGINE_SUBSTITUTION = 1ul << 30ul, - - // Duplicated with Flag::PAD_CHAR_TO_FULL_LENGTH - // PAD_CHAR_TO_FULL_LENGTH = 1ul << 31ul, - - ALLOW_INVALID_DATES = 1ul << 32ul, -}; -} // namespace - bool strictSqlMode(UInt64 sql_mode) { - return sql_mode & SqlMode::STRICT_ALL_TABLES || sql_mode & SqlMode::STRICT_TRANS_TABLES; + return sql_mode & TiDBSQLMode::STRICT_ALL_TABLES || sql_mode & TiDBSQLMode::STRICT_TRANS_TABLES; } bool DAGContext::allowZeroInDate() const { - return flags & Flag::IGNORE_ZERO_IN_DATE; + return flags & TiDBSQLFlags::IGNORE_ZERO_IN_DATE; } bool DAGContext::allowInvalidDate() const { - return sql_mode & SqlMode::ALLOW_INVALID_DATES; + return sql_mode & TiDBSQLMode::ALLOW_INVALID_DATES; } std::map & DAGContext::getProfileStreamsMap() @@ -100,7 +43,7 @@ std::unordered_map> & DAGContext::getQBIdToJoinAlias void DAGContext::handleTruncateError(const String & msg) { - if (!(flags & Flag::IGNORE_TRUNCATE || flags & Flag::TRUNCATE_AS_WARNING)) + if (!(flags & TiDBSQLFlags::IGNORE_TRUNCATE || flags & TiDBSQLFlags::TRUNCATE_AS_WARNING)) { throw TiFlashException("Truncate error " + msg, Errors::Types::Truncated); } @@ -109,7 +52,7 @@ void DAGContext::handleTruncateError(const String & msg) void DAGContext::handleOverflowError(const String & msg, const TiFlashError & error) { - if (!(flags & Flag::OVERFLOW_AS_WARNING)) + if (!(flags & TiDBSQLFlags::OVERFLOW_AS_WARNING)) { throw TiFlashException("Overflow error: " + msg, error); } @@ -118,11 +61,11 @@ void DAGContext::handleOverflowError(const String & msg, const TiFlashError & er void DAGContext::handleDivisionByZero() { - if (flags & Flag::IN_INSERT_STMT || flags & Flag::IN_UPDATE_OR_DELETE_STMT) + if (flags & TiDBSQLFlags::IN_INSERT_STMT || flags & TiDBSQLFlags::IN_UPDATE_OR_DELETE_STMT) { - if (!(sql_mode & SqlMode::ERROR_FOR_DIVISION_BY_ZERO)) + if (!(sql_mode & TiDBSQLMode::ERROR_FOR_DIVISION_BY_ZERO)) return; - if (strictSqlMode(sql_mode) && !(flags & Flag::DIVIDED_BY_ZERO_AS_WARNING)) + if (strictSqlMode(sql_mode) && !(flags & TiDBSQLFlags::DIVIDED_BY_ZERO_AS_WARNING)) { throw TiFlashException("Division by 0", Errors::Expression::DivisionByZero); } @@ -137,7 +80,7 @@ void DAGContext::handleInvalidTime(const String & msg, const TiFlashError & erro throw TiFlashException(msg, error); } handleTruncateError(msg); - if (strictSqlMode(sql_mode) && (flags & Flag::IN_INSERT_STMT || flags & Flag::IN_UPDATE_OR_DELETE_STMT)) + if (strictSqlMode(sql_mode) && (flags & TiDBSQLFlags::IN_INSERT_STMT || flags & TiDBSQLFlags::IN_UPDATE_OR_DELETE_STMT)) { throw TiFlashException(msg, error); } @@ -153,7 +96,7 @@ void DAGContext::appendWarning(const String & msg, int32_t code) bool DAGContext::shouldClipToZero() { - return flags & Flag::IN_INSERT_STMT || flags & Flag::IN_LOAD_DATA_STMT; + return flags & TiDBSQLFlags::IN_INSERT_STMT || flags & TiDBSQLFlags::IN_LOAD_DATA_STMT; } std::pair DAGContext::getTableScanThroughput() diff --git a/dbms/src/Flash/Coprocessor/DAGContext.h b/dbms/src/Flash/Coprocessor/DAGContext.h index c6aea677827..7cb45344ce2 100644 --- a/dbms/src/Flash/Coprocessor/DAGContext.h +++ b/dbms/src/Flash/Coprocessor/DAGContext.h @@ -29,6 +29,64 @@ UInt64 inline getMaxErrorCount(const tipb::DAGRequest &) /// todo max_error_count is a system variable in mysql, TiDB should put it into dag request, now use the default value instead return 1024; } +<<<<<<< HEAD +======= + +namespace TiDBSQLFlags +{ +constexpr UInt64 IGNORE_TRUNCATE = 1; +constexpr UInt64 TRUNCATE_AS_WARNING = 1u << 1u; +constexpr UInt64 PAD_CHAR_TO_FULL_LENGTH = 1u << 2u; +constexpr UInt64 IN_INSERT_STMT = 1u << 3u; +constexpr UInt64 IN_UPDATE_OR_DELETE_STMT = 1u << 4u; +constexpr UInt64 IN_SELECT_STMT = 1u << 5u; +constexpr UInt64 OVERFLOW_AS_WARNING = 1u << 6u; +constexpr UInt64 IGNORE_ZERO_IN_DATE = 1u << 7u; +constexpr UInt64 DIVIDED_BY_ZERO_AS_WARNING = 1u << 8u; +constexpr UInt64 IN_LOAD_DATA_STMT = 1u << 10u; +} // namespace TiDBSQLFlags + +namespace TiDBSQLMode +{ +constexpr UInt64 REAL_AS_FLOAT = 1ul; +constexpr UInt64 PIPES_AS_CONCAT = 1ul << 1ul; +constexpr UInt64 ANSI_QUOTES = 1ul << 2ul; +constexpr UInt64 IGNORE_SPACE = 1ul << 3ul; +constexpr UInt64 NOT_USED = 1ul << 4ul; +constexpr UInt64 ONLY_FULL_GROUP_BY = 1ul << 5ul; +constexpr UInt64 NO_UNSIGNED_SUBTRACTION = 1ul << 6ul; +constexpr UInt64 NO_DIR_IN_CREATE = 1ul << 7ul; +constexpr UInt64 POSTGRESQL = 1ul << 8ul; +constexpr UInt64 ORACLE = 1ul << 9ul; +constexpr UInt64 MSSQL = 1ul << 10ul; +constexpr UInt64 DB2 = 1ul << 11ul; +constexpr UInt64 MAXDB = 1ul << 12ul; +constexpr UInt64 NO_KEY_OPTIONS = 1ul << 13ul; +constexpr UInt64 NO_TABLE_OPTIONS = 1ul << 14ul; +constexpr UInt64 NO_FIELD_OPTIONS = 1ul << 15ul; +constexpr UInt64 MYSQL323 = 1ul << 16ul; +constexpr UInt64 MYSQL40 = 1ul << 17ul; +constexpr UInt64 ANSI = 1ul << 18ul; +constexpr UInt64 NO_AUTO_VALUE_ON_ZERO = 1ul << 19ul; +constexpr UInt64 NO_BACK_SLASH_ESCAPES = 1ul << 20ul; +constexpr UInt64 STRICT_TRANS_TABLES = 1ul << 21ul; +constexpr UInt64 STRICT_ALL_TABLES = 1ul << 22ul; +constexpr UInt64 NO_ZERO_IN_DATE = 1ul << 23ul; +constexpr UInt64 NO_ZERO_DATE = 1ul << 24ul; +constexpr UInt64 INVALID_DATES = 1ul << 25ul; +constexpr UInt64 ERROR_FOR_DIVISION_BY_ZERO = 1ul << 26ul; +constexpr UInt64 TRADITIONAL = 1ul << 27ul; +constexpr UInt64 NO_AUTO_CREATE_USER = 1ul << 28ul; +constexpr UInt64 HIGH_NOT_PRECEDENCE = 1ul << 29ul; +constexpr UInt64 NO_ENGINE_SUBSTITUTION = 1ul << 30ul; + +// Duplicated with Flag::PAD_CHAR_TO_FULL_LENGTH +// PAD_CHAR_TO_FULL_LENGTH = 1ul << 31ul; + +constexpr UInt64 ALLOW_INVALID_DATES = 1ul << 32ul; +} // namespace TiDBSQLMode + +>>>>>>> 6ea6c80198 (Fix cast to decimal overflow bug (#3922)) /// A context used to track the information that needs to be passed around during DAG planning. class DAGContext { @@ -125,7 +183,33 @@ class DAGContext BlockInputStreams & getRemoteInputStreams() { return remote_block_input_streams; } +<<<<<<< HEAD std::pair getTableScanThroughput(); +======= + UInt64 getFlags() const + { + return flags; + } + void setFlags(UInt64 f) + { + flags = f; + } + void addFlag(UInt64 f) + { + flags |= f; + } + void delFlag(UInt64 f) + { + flags &= (~f); + } + bool hasFlag(UInt64 f) const + { + return (flags & f); + } + + void initExchangeReceiverIfMPP(Context & context, size_t max_streams); + const std::unordered_map> & getMPPExchangeReceiverMap() const; +>>>>>>> 6ea6c80198 (Fix cast to decimal overflow bug (#3922)) size_t final_concurrency = 1; Int64 compile_time_ns; diff --git a/dbms/src/Flash/Coprocessor/tests/gtest_dag_context.cpp b/dbms/src/Flash/Coprocessor/tests/gtest_dag_context.cpp new file mode 100644 index 00000000000..2210a2bcd66 --- /dev/null +++ b/dbms/src/Flash/Coprocessor/tests/gtest_dag_context.cpp @@ -0,0 +1,27 @@ +#include +#include + +namespace DB +{ +namespace tests +{ +TEST(DAGContextTest, FlagsTest) +{ + DAGContext context(1024); + + ASSERT_EQ(context.getFlags(), static_cast(0)); + + UInt64 f = TiDBSQLFlags::TRUNCATE_AS_WARNING | TiDBSQLFlags::IN_LOAD_DATA_STMT; + context.setFlags(f); + ASSERT_EQ(context.getFlags(), f); + + UInt64 f1 = f | TiDBSQLFlags::OVERFLOW_AS_WARNING; + context.addFlag(TiDBSQLFlags::OVERFLOW_AS_WARNING); + ASSERT_EQ(context.getFlags(), f1); + + context.delFlag(TiDBSQLFlags::OVERFLOW_AS_WARNING); + ASSERT_EQ(context.getFlags(), f); +} + +} // namespace tests +} // namespace DB diff --git a/dbms/src/Functions/FunctionsTiDBConversion.h b/dbms/src/Functions/FunctionsTiDBConversion.h index b2d55fb4356..d9b615495d5 100644 --- a/dbms/src/Functions/FunctionsTiDBConversion.h +++ b/dbms/src/Functions/FunctionsTiDBConversion.h @@ -811,9 +811,13 @@ struct TiDBConvertToDecimal using FromFieldType = typename FromDataType::FieldType; template - static U toTiDBDecimalInternal(T value, PrecType prec, ScaleType scale, const Context & context) + static U toTiDBDecimalInternal(T int_value, PrecType prec, ScaleType scale, const Context & context) { + // int_value is the value that exposes to user. Such as cast(val to decimal), val is the int_value which used by user. + // And val * scale_mul is the scaled_value, which is stored in ColumnDecimal internally. + static_assert(std::is_integral_v); using UType = typename U::NativeType; +<<<<<<< HEAD auto maxValue = DecimalMaxValue::get(prec); if (value > maxValue || value < -maxValue) { @@ -822,10 +826,23 @@ struct TiDBConvertToDecimal return static_cast(maxValue); else return static_cast(-maxValue); - } +======= UType scale_mul = getScaleMultiplier(scale); - U result = static_cast(value) * scale_mul; - return result; + + Int256 scaled_value = static_cast(int_value) * static_cast(scale_mul); + Int256 scaled_max_value = DecimalMaxValue::get(prec); + + if (scaled_value > scaled_max_value || scaled_value < -scaled_max_value) + { + context.getDAGContext()->handleOverflowError("cast to decimal", Errors::Types::Truncated); + if (int_value > 0) + return static_cast(scaled_max_value); + else + return static_cast(-scaled_max_value); +>>>>>>> 6ea6c80198 (Fix cast to decimal overflow bug (#3922)) + } + + return static_cast(scaled_value); } template diff --git a/dbms/src/Functions/tests/gtest_tidb_conversion.cpp b/dbms/src/Functions/tests/gtest_tidb_conversion.cpp index 315fdaf5191..33981d3e74b 100644 --- a/dbms/src/Functions/tests/gtest_tidb_conversion.cpp +++ b/dbms/src/Functions/tests/gtest_tidb_conversion.cpp @@ -33,10 +33,731 @@ class TestTidbConversion : public DB::tests::FunctionTest TEST_F(TestTidbConversion, castTimestampAsReal) try { +<<<<<<< HEAD static const std::string func_name = "tidb_cast"; static const auto data_type_ptr = std::make_shared(6); static const Float64 datetime_float = 20211026160859; static const Float64 datetime_frac_float = 20211026160859.125; +======= + /// 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))")})); + + ASSERT_THROW(executeFunction(func_name, + {createColumn>({9999}), createCastTypeConstColumn("Nullable(Decimal(4, 1))")}), + TiFlashException); + + ASSERT_THROW(executeFunction(func_name, + {createColumn>({-9999}), createCastTypeConstColumn("Nullable(Decimal(4, 1))")}), + TiFlashException); + + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(4, 1), + {DecimalField32(static_cast(9990), 1)}), + executeFunction(func_name, + {createColumn>({999}), createCastTypeConstColumn("Nullable(Decimal(4, 1))")})); + + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(4, 1), + {DecimalField32(static_cast(-9990), 1)}), + executeFunction(func_name, + {createColumn>({-999}), createCastTypeConstColumn("Nullable(Decimal(4, 1))")})); + + DAGContext * dag_context = context.getDAGContext(); + UInt64 ori_flags = dag_context->getFlags(); + dag_context->addFlag(TiDBSQLFlags::OVERFLOW_AS_WARNING); + dag_context->clearWarnings(); + + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(4, 1), + {DecimalField32(static_cast(9999), 1)}), + executeFunction(func_name, + {createColumn>({9999}), createCastTypeConstColumn("Nullable(Decimal(4, 1))")})); + + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(4, 1), + {DecimalField32(static_cast(-9999), 1)}), + executeFunction(func_name, + {createColumn>({-9999}), createCastTypeConstColumn("Nullable(Decimal(4, 1))")})); + + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(2, 2), + {DecimalField32(static_cast(99), 2)}), + executeFunction(func_name, + {createColumn>({9999}), createCastTypeConstColumn("Nullable(Decimal(2, 2))")})); + + ASSERT_COLUMN_EQ( + createColumn>( + std::make_tuple(2, 2), + {DecimalField32(static_cast(-99), 2)}), + executeFunction(func_name, + {createColumn>({-9999}), createCastTypeConstColumn("Nullable(Decimal(2, 2))")})); + + dag_context->setFlags(ori_flags); +} +CATCH + +TEST_F(TestTidbConversion, castIntAsTime) +try +{ + ASSERT_COLUMN_EQ( + createDateTimeColumnNullable({{}, {{2021, 10, 26, 16, 8, 59, 0}}}, 6), + executeFunction(func_name, + {createColumn>({{}, 20211026160859}), + createCastTypeConstColumn("Nullable(MyDateTime(6))")})); + ASSERT_COLUMN_EQ( + createDateTimeColumnNullable({{}, {{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( + createDateTimeColumnNullable({{}}, 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; +>>>>>>> 6ea6c80198 (Fix cast to decimal overflow bug (#3922)) // cast datetime to float auto col_datetime1 = getDatetimeColumn();