Skip to content

Commit

Permalink
Fix cast to decimal overflow bug (#3922) (#4082)
Browse files Browse the repository at this point in the history
close #3920
  • Loading branch information
ti-chi-bot authored Apr 26, 2022
1 parent 89187f3 commit 06e5081
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 9 deletions.
24 changes: 15 additions & 9 deletions dbms/src/Functions/FunctionsTiDBConversion.h
Original file line number Diff line number Diff line change
Expand Up @@ -816,21 +816,27 @@ struct TiDBConvertToDecimal
using FromFieldType = typename FromDataType::FieldType;

template <typename T, typename U>
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<T>);
using UType = typename U::NativeType;
auto max_value = DecimalMaxValue::get(prec);
if (value > max_value || value < -max_value)
UType scale_mul = getScaleMultiplier<U>(scale);

Int256 scaled_value = static_cast<Int256>(int_value) * static_cast<Int256>(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 (value > 0)
return static_cast<UType>(max_value);
if (int_value > 0)
return static_cast<UType>(scaled_max_value);
else
return static_cast<UType>(-max_value);
return static_cast<UType>(-scaled_max_value);
}
UType scale_mul = getScaleMultiplier<U>(scale);
U result = static_cast<UType>(value) * scale_mul;
return result;

return static_cast<UType>(scaled_value);
}

template <typename U>
Expand Down
22 changes: 22 additions & 0 deletions dbms/src/Functions/tests/gtest_tidb_conversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,28 @@ try
executeFunction(func_name,
{createColumn<Nullable<UInt64>>({MAX_INT64, {}}),
createCastTypeConstColumn("Nullable(Decimal(65,0))")}));

ASSERT_THROW(executeFunction(func_name,
{createColumn<Nullable<Int32>>({9999}), createCastTypeConstColumn("Nullable(Decimal(4, 1))")}),
TiFlashException);

ASSERT_THROW(executeFunction(func_name,
{createColumn<Nullable<Int32>>({-9999}), createCastTypeConstColumn("Nullable(Decimal(4, 1))")}),
TiFlashException);

ASSERT_COLUMN_EQ(
createColumn<Nullable<Decimal32>>(
std::make_tuple(4, 1),
{DecimalField32(static_cast<Int32>(9990), 1)}),
executeFunction(func_name,
{createColumn<Nullable<Int32>>({999}), createCastTypeConstColumn("Nullable(Decimal(4, 1))")}));

ASSERT_COLUMN_EQ(
createColumn<Nullable<Decimal32>>(
std::make_tuple(4, 1),
{DecimalField32(static_cast<Int32>(-9990), 1)}),
executeFunction(func_name,
{createColumn<Nullable<Int32>>({-999}), createCastTypeConstColumn("Nullable(Decimal(4, 1))")}));
}
CATCH

Expand Down
18 changes: 18 additions & 0 deletions tests/fullstack-test/expr/cast_as_decimal.test
Original file line number Diff line number Diff line change
@@ -1,4 +1,21 @@
mysql> drop table if exists test.t1;
mysql> create table test.t1(c1 int);
mysql> insert into test.t1 values(9999), (-9999), (99), (-99);
mysql> alter table test.t1 set tiflash replica 1;
func> wait_table test t1
mysql> set @@tidb_isolation_read_engines='tiflash'; select cast(c1 as decimal(4, 1)) from test.t1 order by 1;
cast(c1 as decimal(4, 1))
-999.9
-99.0
99.0
999.9
mysql> set @@tidb_isolation_read_engines='tiflash'; select cast(c1 as decimal(2, 2)) from test.t1 order by 1;
cast(c1 as decimal(2, 2))
-0.99
-0.99
0.99
0.99
mysql> drop table if exists test.t1;
mysql> create table test.t1(c1 datetime(5));
mysql> insert into test.t1 values('2022-10-10 10:10:10.12345');
mysql> alter table test.t1 set tiflash replica 1;
Expand All @@ -21,3 +38,4 @@ mysql> set @@tidb_isolation_read_engines='tiflash'; set @@tidb_enforce_mpp = 1;
+------------------------------------+
| 20221010101010.123 |
+------------------------------------+

0 comments on commit 06e5081

Please sign in to comment.