Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

expression: check Overflow int128 (#4762) #4945

Merged
21 changes: 18 additions & 3 deletions libs/libcommon/include/common/arithmeticOverflow.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include "types.h"

namespace common
{
Expand Down Expand Up @@ -99,8 +100,22 @@ 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)
{
try
{
res = x * y;
}
catch (std::overflow_error &)
{
return true;
}
return false;
}
} // namespace common
3 changes: 2 additions & 1 deletion libs/libcommon/src/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ target_link_libraries (date_lut_default_timezone common ${PLATFORM_LIBS})
target_link_libraries (multi_version common)
add_check(multi_version)

add_executable (gtests_libcommon gtest_json_test.cpp gtest_strong_typedef.cpp)
add_executable (gtests_libcommon gtest_json_test.cpp gtest_strong_typedef.cpp gtest_arithmetic_overflow.cpp)

target_link_libraries (gtests_libcommon gtest_main common)
add_check(gtests_libcommon)

Expand Down
53 changes: 53 additions & 0 deletions libs/libcommon/src/tests/gtest_arithmetic_overflow.cpp
Original file line number Diff line number Diff line change
@@ -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 <common/arithmeticOverflow.h>
#include <common/types.h>
#include <gtest/gtest.h>
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);
}
22 changes: 22 additions & 0 deletions tests/tidb-ci/fullstack-test-dt/expr_push_down.test
Original file line number Diff line number Diff line change
Expand Up @@ -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, v1<v2,v1<=v2 from test.t;
+------------------------+-----------------------+-------+--------+-------+--------+
| v1 | v2 | v1>v2 | v1>=v2 | v1<v2 | v1<=v2 |
+------------------------+-----------------------+-------+--------+-------+--------+
| 0.00000000000000000000 | 2585910611040796672 | 0 | 0 | 1 | 1 |
| 0.00000000000000000000 | -1901644942657191936 | 1 | 1 | 0 | 0 |
| 0.00000000000000000000 | -11901644942657191936 | 1 | 1 | 0 | 0 |
| 0.00000000000000000000 | 25859106110407966722 | 0 | 0 | 1 | 1 |
| 0.00000000000000000000 | 2585912 | 0 | 0 | 1 | 1 |
| 0.00000000000000000000 | -190 | 1 | 1 | 0 | 0 |
+------------------------+-----------------------+-------+--------+-------+--------+