Commit 732b175c authored by gkodinov@mysql.com's avatar gkodinov@mysql.com

Bug #20569 Garbage in DECIMAL results from some mathematical functions

  Adding decimal "digits" in multiplication resulted in signed overflow and
producing wrong results.

  Fixed by using large enough buffers and intermediary result types :
dec2 (currently longlong) to hold result of adding decimal "digits" 
(currently int32). 
parent 3cc6d95d
...@@ -3395,3 +3395,6 @@ a t1.b + 0 t1.c + 0 a t2.b + 0 c d ...@@ -3395,3 +3395,6 @@ a t1.b + 0 t1.c + 0 a t2.b + 0 c d
1 0 1 1 0 1 NULL 1 0 1 1 0 1 NULL
2 0 1 NULL NULL NULL NULL 2 0 1 NULL NULL NULL NULL
drop table t1,t2; drop table t1,t2;
SELECT 0.9888889889 * 1.011111411911;
0.9888889889 * 1.011111411911
0.9998769417899202067879
...@@ -2901,3 +2901,8 @@ from t1 left outer join t2 on t1.a = t2.c and t2.b <> 1 ...@@ -2901,3 +2901,8 @@ from t1 left outer join t2 on t1.a = t2.c and t2.b <> 1
where t1.b <> 1 order by t1.a; where t1.b <> 1 order by t1.a;
drop table t1,t2; drop table t1,t2;
#
# Bug #20569: Garbage in DECIMAL results from some mathematical functions
#
SELECT 0.9888889889 * 1.011111411911;
...@@ -170,6 +170,7 @@ static const dec1 frac_max[DIG_PER_DEC1-1]={ ...@@ -170,6 +170,7 @@ static const dec1 frac_max[DIG_PER_DEC1-1]={
#define ADD(to, from1, from2, carry) /* assume carry <= 1 */ \ #define ADD(to, from1, from2, carry) /* assume carry <= 1 */ \
do \ do \
{ \ { \
DBUG_ASSERT((carry) <= 1); \
dec1 a=(from1)+(from2)+(carry); \ dec1 a=(from1)+(from2)+(carry); \
if (((carry)= a >= DIG_BASE)) /* no division here! */ \ if (((carry)= a >= DIG_BASE)) /* no division here! */ \
a-=DIG_BASE; \ a-=DIG_BASE; \
...@@ -179,7 +180,7 @@ static const dec1 frac_max[DIG_PER_DEC1-1]={ ...@@ -179,7 +180,7 @@ static const dec1 frac_max[DIG_PER_DEC1-1]={
#define ADD2(to, from1, from2, carry) \ #define ADD2(to, from1, from2, carry) \
do \ do \
{ \ { \
dec1 a=(from1)+(from2)+(carry); \ dec2 a=((dec2)(from1))+(from2)+(carry); \
if (((carry)= a >= DIG_BASE)) \ if (((carry)= a >= DIG_BASE)) \
a-=DIG_BASE; \ a-=DIG_BASE; \
if (unlikely(a >= DIG_BASE)) \ if (unlikely(a >= DIG_BASE)) \
...@@ -187,7 +188,7 @@ static const dec1 frac_max[DIG_PER_DEC1-1]={ ...@@ -187,7 +188,7 @@ static const dec1 frac_max[DIG_PER_DEC1-1]={
a-=DIG_BASE; \ a-=DIG_BASE; \
carry++; \ carry++; \
} \ } \
(to)=a; \ (to)=(dec1) a; \
} while(0) } while(0)
#define SUB(to, from1, from2, carry) /* to=from1-from2 */ \ #define SUB(to, from1, from2, carry) /* to=from1-from2 */ \
...@@ -1998,7 +1999,13 @@ int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to) ...@@ -1998,7 +1999,13 @@ int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to)
ADD2(*buf0, *buf0, lo, carry); ADD2(*buf0, *buf0, lo, carry);
carry+=hi; carry+=hi;
} }
for (; carry; buf0--) if (carry)
{
if (buf0 < to->buf)
return E_DEC_OVERFLOW;
ADD2(*buf0, *buf0, 0, carry);
}
for (buf0--; carry; buf0--)
{ {
if (buf0 < to->buf) if (buf0 < to->buf)
return E_DEC_OVERFLOW; return E_DEC_OVERFLOW;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment