From a836df5d535e01de2694cd50d23113519131c047 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 7 Jun 2025 20:28:29 +0800 Subject: [PATCH] branch-2.1: [fix](decimal)Fix the issue where decimal multiplication produces incorrect results due to mul_overflow error #51533 (#51563) Cherry-picked from #51533 Co-authored-by: Mryange <2319153948@qq.com> --- be/src/vec/common/arithmetic_overflow.h | 8 +- be/test/common/check_overflow.cpp | 92 +++++++++++++++++++ .../decimalv3/test_decimalv3_cast3.out | 9 ++ .../decimalv3/test_decimalv3_cast3.groovy | 7 ++ 4 files changed, 109 insertions(+), 7 deletions(-) create mode 100644 be/test/common/check_overflow.cpp diff --git a/be/src/vec/common/arithmetic_overflow.h b/be/src/vec/common/arithmetic_overflow.h index 6a586a8f68..e030957c60 100644 --- a/be/src/vec/common/arithmetic_overflow.h +++ b/be/src/vec/common/arithmetic_overflow.h @@ -117,13 +117,7 @@ inline bool mul_overflow(long long x, long long y, long long& res) { template <> inline bool mul_overflow(__int128 x, __int128 y, __int128& res) { - res = static_cast(x) * - static_cast(y); /// Avoid signed integer overflow. - if (!x || !y) return false; - - unsigned __int128 a = (x > 0) ? x : -x; - unsigned __int128 b = (y > 0) ? y : -y; - return ((a * b) / b != a) || (x > 0 && y > 0 && res < 0) || (x < 0 && y < 0 && res < 0); + return __builtin_mul_overflow(x, y, &res); } template <> diff --git a/be/test/common/check_overflow.cpp b/be/test/common/check_overflow.cpp new file mode 100644 index 0000000000..8c6d5cde52 --- /dev/null +++ b/be/test/common/check_overflow.cpp @@ -0,0 +1,92 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 "vec/core/types.h" +#include "vec/io/io_helper.h" +#include "vec/io/reader_buffer.h" + +namespace doris::vectorized { + +struct CheckOverFlowTest : public testing::Test { + void SetUp() override { + // This function is called before each test. + } + + void TearDown() override { + // This function is called after each test. + } + + Int128 to_i128(std::string str) { + ReadBuffer rb = ReadBuffer(str.data(), str.size()); + Int128 val; + EXPECT_TRUE(read_int_text_impl(val, rb)); + return val; + }; + + wide::Int256 to_i256(std::string str) { return wide::Int256::_impl::from_str(str.c_str()); }; +}; + +TEST_F(CheckOverFlowTest, test_overflow_int128) { + { + Int128 a = to_i128("-15687000000000000000000"); + Int128 b = to_i128("11000000000000000"); + Int128 c; + EXPECT_TRUE(common::mul_overflow(a, b, c)); + } + + { + Int128 a = to_i128("-15687000000000000000000"); + Int128 b = to_i128("-11000000000000000"); + Int128 c; + EXPECT_TRUE(common::mul_overflow(a, b, c)); + } + + { + Int128 a = to_i128("1000"); + Int128 b = to_i128("12000"); + Int128 c; + EXPECT_FALSE(common::mul_overflow(a, b, c)); + } +} + +TEST_F(CheckOverFlowTest, test_overflow_int256) { + { + wide::Int256 a = + to_i256("-11579208923731619542357098500868790785326998466564056403945758400791"); + wide::Int256 b = to_i256("1157920892373161954235709850086879078532699846656405640394575"); + wide::Int256 c; + EXPECT_TRUE(common::mul_overflow(a, b, c)); + } + + { + wide::Int256 a = to_i256("-1157920892373161954235709850086879078532699846656405640394"); + wide::Int256 b = to_i256("-1157920892373161954235709850086879078532699846656405640394"); + wide::Int256 c; + EXPECT_TRUE(common::mul_overflow(a, b, c)); + } + + { + wide::Int256 a = to_i256("1000"); + wide::Int256 b = to_i256("12000"); + wide::Int256 c; + EXPECT_FALSE(common::mul_overflow(a, b, c)); + } +} + +} // namespace doris::vectorized diff --git a/regression-test/data/datatype_p0/decimalv3/test_decimalv3_cast3.out b/regression-test/data/datatype_p0/decimalv3/test_decimalv3_cast3.out index 93460a101f..b2500accd7 100644 --- a/regression-test/data/datatype_p0/decimalv3/test_decimalv3_cast3.out +++ b/regression-test/data/datatype_p0/decimalv3/test_decimalv3_cast3.out @@ -134,3 +134,12 @@ -170141183460469231731687303715884105728 170141183460469231731687303715884105727 +-- !sql -- +-172.557000000000000000000000000000000 + +-- !sql -- +-172.557000000000000000000000000000000 + +-- !sql -- +-172.557000000000000000000000000000000 + diff --git a/regression-test/suites/datatype_p0/decimalv3/test_decimalv3_cast3.groovy b/regression-test/suites/datatype_p0/decimalv3/test_decimalv3_cast3.groovy index d57f3b029c..4e7b362915 100644 --- a/regression-test/suites/datatype_p0/decimalv3/test_decimalv3_cast3.groovy +++ b/regression-test/suites/datatype_p0/decimalv3/test_decimalv3_cast3.groovy @@ -505,4 +505,11 @@ suite("test_decimalv3_cast3") { exception "Arithmetic overflow" } sql "set enable_decimal256=false;" + + + sql """ set debug_skip_fold_constant = true;""" + qt_sql """ select -15687.000000000000000000 * 0.01100000000000000; """ + qt_sql """ select -15687.000000000000000000 * 0.011000000000000000; """ + qt_sql """ select -15687.000000000000000000 * 0.0110000000000000000; """ + sql """ set debug_skip_fold_constant = false;""" } \ No newline at end of file