mirror of
https://github.com/postgres/postgres.git
synced 2025-04-27 22:56:53 +03:00
Fix numeric_mul() overflow due to too many digits after decimal point.
This fixes an overflow error when using the numeric * operator if the result has more than 16383 digits after the decimal point by rounding the result. Overflow errors should only occur if the result has too many digits *before* the decimal point. Discussion: https://postgr.es/m/CAEZATCUmeFWCrq2dNzZpRj5+6LfN85jYiDoqm+ucSXhb9U2TbA@mail.gmail.com
This commit is contained in:
parent
9ffad7ae7f
commit
06883d58ff
@ -233,6 +233,7 @@ struct NumericData
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define NUMERIC_DSCALE_MASK 0x3FFF
|
#define NUMERIC_DSCALE_MASK 0x3FFF
|
||||||
|
#define NUMERIC_DSCALE_MAX NUMERIC_DSCALE_MASK
|
||||||
|
|
||||||
#define NUMERIC_SIGN(n) \
|
#define NUMERIC_SIGN(n) \
|
||||||
(NUMERIC_IS_SHORT(n) ? \
|
(NUMERIC_IS_SHORT(n) ? \
|
||||||
@ -2955,7 +2956,11 @@ numeric_mul_opt_error(Numeric num1, Numeric num2, bool *have_error)
|
|||||||
* Unlike add_var() and sub_var(), mul_var() will round its result. In the
|
* Unlike add_var() and sub_var(), mul_var() will round its result. In the
|
||||||
* case of numeric_mul(), which is invoked for the * operator on numerics,
|
* case of numeric_mul(), which is invoked for the * operator on numerics,
|
||||||
* we request exact representation for the product (rscale = sum(dscale of
|
* we request exact representation for the product (rscale = sum(dscale of
|
||||||
* arg1, dscale of arg2)).
|
* arg1, dscale of arg2)). If the exact result has more digits after the
|
||||||
|
* decimal point than can be stored in a numeric, we round it. Rounding
|
||||||
|
* after computing the exact result ensures that the final result is
|
||||||
|
* correctly rounded (rounding in mul_var() using a truncated product
|
||||||
|
* would not guarantee this).
|
||||||
*/
|
*/
|
||||||
init_var_from_num(num1, &arg1);
|
init_var_from_num(num1, &arg1);
|
||||||
init_var_from_num(num2, &arg2);
|
init_var_from_num(num2, &arg2);
|
||||||
@ -2963,6 +2968,9 @@ numeric_mul_opt_error(Numeric num1, Numeric num2, bool *have_error)
|
|||||||
init_var(&result);
|
init_var(&result);
|
||||||
mul_var(&arg1, &arg2, &result, arg1.dscale + arg2.dscale);
|
mul_var(&arg1, &arg2, &result, arg1.dscale + arg2.dscale);
|
||||||
|
|
||||||
|
if (result.dscale > NUMERIC_DSCALE_MAX)
|
||||||
|
round_var(&result, NUMERIC_DSCALE_MAX);
|
||||||
|
|
||||||
res = make_result_opt_error(&result, have_error);
|
res = make_result_opt_error(&result, have_error);
|
||||||
|
|
||||||
free_var(&result);
|
free_var(&result);
|
||||||
|
@ -2145,6 +2145,12 @@ select 4769999999999999999999999999999999999999999999999999999999999999999999999
|
|||||||
47699999999999999999999999999999999999999999999999999999999999999999999999999999999999985230000000000000000000000000000000000000000000000000000000000000000000000000000000000001
|
47699999999999999999999999999999999999999999999999999999999999999999999999999999999999985230000000000000000000000000000000000000000000000000000000000000000000000000000000000001
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
select trim_scale((0.1 - 2e-16383) * (0.1 - 3e-16383));
|
||||||
|
trim_scale
|
||||||
|
------------
|
||||||
|
0.01
|
||||||
|
(1 row)
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Test some corner cases for division
|
-- Test some corner cases for division
|
||||||
--
|
--
|
||||||
|
@ -1044,6 +1044,8 @@ select 4770999999999999999999999999999999999999999999999999999999999999999999999
|
|||||||
|
|
||||||
select 4769999999999999999999999999999999999999999999999999999999999999999999999999999999999999 * 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999;
|
select 4769999999999999999999999999999999999999999999999999999999999999999999999999999999999999 * 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999;
|
||||||
|
|
||||||
|
select trim_scale((0.1 - 2e-16383) * (0.1 - 3e-16383));
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Test some corner cases for division
|
-- Test some corner cases for division
|
||||||
--
|
--
|
||||||
|
Loading…
x
Reference in New Issue
Block a user