Skip to content

Commit 82490a9

Browse files
committed
MDEV-18150 Assertion `decimals_to_set <= 38' failed in Item_func_round::fix_length_and_dec_decimal
1 parent 2ffa11e commit 82490a9

File tree

5 files changed

+40
-25
lines changed

5 files changed

+40
-25
lines changed

mysql-test/main/func_math.result

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1316,5 +1316,12 @@ t2 CREATE TABLE `t2` (
13161316
DROP TABLE t1, t2;
13171317
SET sql_mode=DEFAULT;
13181318
#
1319+
# MDEV-18150 Assertion `decimals_to_set <= 38' failed in Item_func_round::fix_length_and_dec_decimal
1320+
#
1321+
CREATE TABLE t1 (i INT(23));
1322+
SELECT ROUND( i, 18446744073709551594 ) AS f FROM t1;
1323+
f
1324+
DROP TABLE t1;
1325+
#
13191326
# End of 10.3 tests
13201327
#

mysql-test/main/func_math.test

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,14 @@ DROP TABLE t1, t2;
919919
SET sql_mode=DEFAULT;
920920

921921

922+
--echo #
923+
--echo # MDEV-18150 Assertion `decimals_to_set <= 38' failed in Item_func_round::fix_length_and_dec_decimal
924+
--echo #
925+
926+
CREATE TABLE t1 (i INT(23));
927+
SELECT ROUND( i, 18446744073709551594 ) AS f FROM t1;
928+
DROP TABLE t1;
929+
922930
--echo #
923931
--echo # End of 10.3 tests
924932
--echo #

sql/item.h

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,20 +1062,6 @@ class Item: public Value_source,
10621062
unsigned_flag to check the sign of the item.
10631063
*/
10641064
inline ulonglong val_uint() { return (ulonglong) val_int(); }
1065-
/*
1066-
Adjust the result of val_int() to an unsigned number:
1067-
- NULL value is converted to 0. The caller can check "null_value"
1068-
to distinguish between 0 and NULL when necessary.
1069-
- Negative numbers are converted to 0.
1070-
- Positive numbers bigger than upper_bound are converted to upper_bound.
1071-
- Other numbers are returned as is.
1072-
*/
1073-
ulonglong val_uint_from_val_int(ulonglong upper_bound)
1074-
{
1075-
longlong nr= val_int();
1076-
return (null_value || (nr < 0 && !unsigned_flag)) ? 0 :
1077-
(ulonglong) nr > upper_bound ? upper_bound : (ulonglong) nr;
1078-
}
10791065

10801066
/*
10811067
Return string representation of this item object.

sql/item_func.cc

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2433,11 +2433,11 @@ void Item_func_round::fix_arg_decimal()
24332433
{
24342434
if (args[1]->const_item())
24352435
{
2436-
uint dec= (uint) args[1]->val_uint_from_val_int(DECIMAL_MAX_SCALE);
2436+
Longlong_hybrid dec= args[1]->to_longlong_hybrid();
24372437
if (args[1]->null_value)
24382438
fix_length_and_dec_double(NOT_FIXED_DEC);
24392439
else
2440-
fix_length_and_dec_decimal(dec);
2440+
fix_length_and_dec_decimal(dec.to_uint(DECIMAL_MAX_SCALE));
24412441
}
24422442
else
24432443
{
@@ -2453,8 +2453,9 @@ void Item_func_round::fix_arg_double()
24532453
{
24542454
if (args[1]->const_item())
24552455
{
2456-
uint dec= (uint) args[1]->val_uint_from_val_int(NOT_FIXED_DEC);
2457-
fix_length_and_dec_double(args[1]->null_value ? NOT_FIXED_DEC : dec);
2456+
Longlong_hybrid dec= args[1]->to_longlong_hybrid();
2457+
fix_length_and_dec_double(args[1]->null_value ? NOT_FIXED_DEC :
2458+
dec.to_uint(NOT_FIXED_DEC));
24582459
}
24592460
else
24602461
fix_length_and_dec_double(args[0]->decimals);
@@ -2465,25 +2466,22 @@ void Item_func_round::fix_arg_int()
24652466
{
24662467
if (args[1]->const_item())
24672468
{
2468-
longlong val1= args[1]->val_int();
2469-
bool val1_is_negative= val1 < 0 && !args[1]->unsigned_flag;
2470-
uint decimals_to_set= val1_is_negative ?
2471-
0 : (uint) MY_MIN(val1, DECIMAL_MAX_SCALE);
2469+
Longlong_hybrid val1= args[1]->to_longlong_hybrid();
24722470
if (args[1]->null_value)
24732471
fix_length_and_dec_double(NOT_FIXED_DEC);
2474-
else if ((!decimals_to_set && truncate) ||
2472+
else if ((!val1.to_uint(DECIMAL_MAX_SCALE) && truncate) ||
24752473
args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS)
24762474
{
24772475
// Length can increase in some cases: ROUND(9,-1) -> 10
2478-
int length_can_increase= MY_TEST(!truncate && val1_is_negative);
2476+
int length_can_increase= MY_TEST(!truncate && val1.neg());
24792477
max_length= args[0]->max_length + length_can_increase;
24802478
// Here we can keep INT_RESULT
24812479
unsigned_flag= args[0]->unsigned_flag;
24822480
decimals= 0;
24832481
set_handler(type_handler_long_or_longlong());
24842482
}
24852483
else
2486-
fix_length_and_dec_decimal(decimals_to_set);
2484+
fix_length_and_dec_decimal(val1.to_uint(DECIMAL_MAX_SCALE));
24872485
}
24882486
else
24892487
fix_length_and_dec_double(args[0]->decimals);

sql/sql_type_int.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,22 @@ class Longlong_hybrid
5252
return ((ulonglong) LONGLONG_MAX) + 1;
5353
return m_value < 0 ? -m_value : m_value;
5454
}
55+
/*
56+
Convert to an unsigned number:
57+
- Negative numbers are converted to 0.
58+
- Positive numbers bigger than upper_bound are converted to upper_bound.
59+
- Other numbers are returned as is.
60+
*/
61+
ulonglong to_ulonglong(ulonglong upper_bound) const
62+
{
63+
return neg() ? 0 :
64+
(ulonglong) m_value > upper_bound ? upper_bound :
65+
(ulonglong) m_value;
66+
}
67+
uint to_uint(uint upper_bound) const
68+
{
69+
return (uint) to_ulonglong(upper_bound);
70+
}
5571
int cmp(const Longlong_hybrid& other) const
5672
{
5773
if (m_unsigned == other.m_unsigned)

0 commit comments

Comments
 (0)