diff --git a/libs/libcommon/include/common/arithmeticOverflow.h b/libs/libcommon/include/common/arithmeticOverflow.h index 38a1482e1c4..b80b98b218c 100644 --- a/libs/libcommon/include/common/arithmeticOverflow.h +++ b/libs/libcommon/include/common/arithmeticOverflow.h @@ -1,4 +1,5 @@ #pragma once +#include "types.h" namespace common { @@ -99,11 +100,11 @@ inline bool mulOverflow(__int128 x, __int128 y, __int128 & res) if (!x || !y) return false; - unsigned __int128 a = (x > 0) ? x : -x; - unsigned __int128 b = (y > 0) ? y : -y; - return (a * b) / b != a; + return res / x != y; /// whether overflow int128 } +/// Int256 doesn't use the complement representation to express negative values, but uses an extra bit to express the sign flag, +/// the actual range of Int256 is from -(2^256 - 1) to 2^256 - 1, so 2^255 ~ 2^256-1 do not overflow Int256. template <> inline bool mulOverflow(Int256 x, Int256 y, Int256 & res) { diff --git a/libs/libcommon/src/tests/CMakeLists.txt b/libs/libcommon/src/tests/CMakeLists.txt index ceb88c12502..0b434473a2b 100644 --- a/libs/libcommon/src/tests/CMakeLists.txt +++ b/libs/libcommon/src/tests/CMakeLists.txt @@ -23,6 +23,7 @@ add_executable (gtests_libcommon gtest_mem_utils.cpp gtest_crc64.cpp gtest_logger.cpp + gtest_arithmetic_overflow.cpp ) target_link_libraries (gtests_libcommon gtest_main common) add_check(gtests_libcommon) diff --git a/libs/libcommon/src/tests/gtest_arithmetic_overflow.cpp b/libs/libcommon/src/tests/gtest_arithmetic_overflow.cpp new file mode 100644 index 00000000000..c3bc3b243bc --- /dev/null +++ b/libs/libcommon/src/tests/gtest_arithmetic_overflow.cpp @@ -0,0 +1,53 @@ +// Copyright 2022 PingCAP, Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +TEST(OVERFLOW_Suite, SimpleTest) +{ + /// mul int128 + __int128 res128; + bool is_overflow; + /// 2^126 + static constexpr __int128 int_126 = __int128(__int128(1) << 126); + + /// 2^126 << 0 = 2^126 + is_overflow = common::mulOverflow(int_126, __int128(1), res128); + ASSERT_EQ(is_overflow, false); + + /// 2^126 << 1 = 2^127 + is_overflow = common::mulOverflow(int_126, __int128(2), res128); + ASSERT_EQ(is_overflow, true); + + /// 2^126 << 2 = 2^128 + is_overflow = common::mulOverflow(int_126, __int128(4), res128); + ASSERT_EQ(is_overflow, true); + + /// mul int256 + Int256 res256; + /// 2^254 + static constexpr Int256 int_254 = Int256((Int256(0x1) << 254)); + /// 2^254 << 0 = 2^254 + is_overflow = common::mulOverflow(int_254, Int256(1), res256); + ASSERT_EQ(is_overflow, false); + + /// 2^254 << 1 = 2^255 + is_overflow = common::mulOverflow(int_254, Int256(2), res256); + ASSERT_EQ(is_overflow, false); /// because the sign flag is processed by an extra bit, excluding from 256 bits of Int256. + + /// 2^254 << 2 = 2^256 + is_overflow = common::mulOverflow(int_254, Int256(4), res256); + ASSERT_EQ(is_overflow, true); +} diff --git a/tests/tidb-ci/fullstack-test-dt/expr_push_down.test b/tests/tidb-ci/fullstack-test-dt/expr_push_down.test index 60d2fe0fc68..a3ee5bb1d16 100644 --- a/tests/tidb-ci/fullstack-test-dt/expr_push_down.test +++ b/tests/tidb-ci/fullstack-test-dt/expr_push_down.test @@ -96,3 +96,25 @@ mysql> use test; set @@tidb_isolation_read_engines='tiflash,tidb'; set @@tidb_al | NULL | NULL | NULL | NULL | NULL | NULL | NULL | 2 | | 平凯xingchen公司 | | 平 | | 平凯xingchen公司 | NULL | NULL | 1 | +----------------------+------+------+------+----------------------+------+------------+----------+ + +## test overflow int128, uint128 or not. +mysql> drop table if exists test.t; +mysql> CREATE TABLE test.t (v1 decimal(20,20),v2 decimal(30,0)); +mysql> insert into test.t values (0.00000000000000000000 , 2585910611040796672),(0.00000000000000000000 , -1901644942657191936), (0.00000000000000000000 , -11901644942657191936),(0.00000000000000000000 , 25859106110407966722),(0.00000000000000000000 , 2585912),(0.00000000000000000000 , -190); +mysql> alter table test.t set tiflash replica 1; + +mysql> analyze table test.t; + +func> wait_table test t + +mysql> use test; set @@tidb_isolation_read_engines='tiflash,tidb'; set @@tidb_enforce_mpp=1; select v1,v2,v1>v2,v1>=v2, v1v2 | v1>=v2 | v1