diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index 1bfa29e1b28..1667d8093f1 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -5789,9 +5789,15 @@ mul_var(NumericVar *var1, NumericVar *var2, NumericVar *result, * to avoid normalizing carries immediately. * * maxdig tracks the maximum possible value of any dig[] entry; when this - * threatens to exceed INT_MAX, we take the time to propagate carries. To - * avoid overflow in maxdig itself, it actually represents the max - * possible value divided by NBASE-1. + * threatens to exceed INT_MAX, we take the time to propagate carries. + * Furthermore, we need to ensure that overflow doesn't occur during the + * carry propagation passes either. The carry values could be as much as + * INT_MAX/NBASE, so really we must normalize when digits threaten to + * exceed INT_MAX - INT_MAX/NBASE. + * + * To avoid overflow in maxdig itself, it actually represents the max + * possible value divided by NBASE-1, ie, at the top of the loop it is + * known that no dig[] entry exceeds maxdig * (NBASE-1). */ dig = (int *) palloc0(res_ndigits * sizeof(int)); maxdig = 0; @@ -5806,7 +5812,7 @@ mul_var(NumericVar *var1, NumericVar *var2, NumericVar *result, /* Time to normalize? */ maxdig += var1digit; - if (maxdig > INT_MAX / (NBASE - 1)) + if (maxdig > (INT_MAX - INT_MAX / NBASE) / (NBASE - 1)) { /* Yes, do it */ carry = 0; diff --git a/src/test/regress/expected/numeric.out b/src/test/regress/expected/numeric.out index 9d6814564df..394cc72b645 100644 --- a/src/test/regress/expected/numeric.out +++ b/src/test/regress/expected/numeric.out @@ -1309,6 +1309,33 @@ SELECT * FROM num_input_test; NaN (7 rows) +-- +-- Test some corner cases for multiplication +-- +select 4790999999999999999999999999999999999999999999999999999999999999999999999999999999999999 * 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999; + ?column? +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + 47909999999999999999999999999999999999999999999999999999999999999999999999999999999999985209000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +(1 row) + +select 4789999999999999999999999999999999999999999999999999999999999999999999999999999999999999 * 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999; + ?column? +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + 47899999999999999999999999999999999999999999999999999999999999999999999999999999999999985210000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +(1 row) + +select 4770999999999999999999999999999999999999999999999999999999999999999999999999999999999999 * 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999; + ?column? +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + 47709999999999999999999999999999999999999999999999999999999999999999999999999999999999985229000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +(1 row) + +select 4769999999999999999999999999999999999999999999999999999999999999999999999999999999999999 * 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999; + ?column? +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + 47699999999999999999999999999999999999999999999999999999999999999999999999999999999999985230000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +(1 row) + -- -- Test some corner cases for division -- diff --git a/src/test/regress/sql/numeric.sql b/src/test/regress/sql/numeric.sql index 1633e4c3752..5405ffadc79 100644 --- a/src/test/regress/sql/numeric.sql +++ b/src/test/regress/sql/numeric.sql @@ -811,6 +811,18 @@ INSERT INTO num_input_test(n1) VALUES (' N aN '); SELECT * FROM num_input_test; +-- +-- Test some corner cases for multiplication +-- + +select 4790999999999999999999999999999999999999999999999999999999999999999999999999999999999999 * 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999; + +select 4789999999999999999999999999999999999999999999999999999999999999999999999999999999999999 * 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999; + +select 4770999999999999999999999999999999999999999999999999999999999999999999999999999999999999 * 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999; + +select 4769999999999999999999999999999999999999999999999999999999999999999999999999999999999999 * 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999; + -- -- Test some corner cases for division --