Commit 8e354677 authored by unknown's avatar unknown
Browse files

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). 


mysql-test/r/select.result:
  Bug #20569 Garbage in DECIMAL results from some mathematical functions
    * test suite for the bug
mysql-test/t/select.test:
  Bug #20569 Garbage in DECIMAL results from some mathematical functions
    * test suite for the bug
strings/decimal.c:
  Bug #20569 Garbage in DECIMAL results from some mathematical functions
    * fixed the overflow in adding decimal "digits"
parent 3cf92fb7
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -3395,3 +3395,6 @@ a t1.b + 0 t1.c + 0 a t2.b + 0 c d
1	0	1	1	0	1	NULL
2	0	1	NULL	NULL	NULL	NULL
drop table t1,t2;
SELECT 0.9888889889 * 1.011111411911;
0.9888889889 * 1.011111411911
0.9998769417899202067879
+5 −0
Original line number Diff line number Diff line
@@ -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;

drop table t1,t2;

#
# Bug #20569: Garbage in DECIMAL results from some mathematical functions
#
SELECT 0.9888889889 * 1.011111411911;
+10 −3
Original line number Diff line number Diff line
@@ -170,6 +170,7 @@ static const dec1 frac_max[DIG_PER_DEC1-1]={
#define ADD(to, from1, from2, carry)  /* assume carry <= 1 */           \
        do                                                              \
        {                                                               \
          DBUG_ASSERT((carry) <= 1);                                    \
          dec1 a=(from1)+(from2)+(carry);                               \
          if (((carry)= a >= DIG_BASE)) /* no division here! */         \
            a-=DIG_BASE;                                                \
@@ -179,7 +180,7 @@ static const dec1 frac_max[DIG_PER_DEC1-1]={
#define ADD2(to, from1, from2, carry)                                   \
        do                                                              \
        {                                                               \
          dec1 a=(from1)+(from2)+(carry);                               \
          dec2 a=((dec2)(from1))+(from2)+(carry);                       \
          if (((carry)= a >= DIG_BASE))                                 \
            a-=DIG_BASE;                                                \
          if (unlikely(a >= DIG_BASE))                                  \
@@ -187,7 +188,7 @@ static const dec1 frac_max[DIG_PER_DEC1-1]={
            a-=DIG_BASE;                                                \
            carry++;                                                    \
          }                                                             \
          (to)=a;                                                       \
          (to)=(dec1) a;                                                \
        } while(0)

#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)
      ADD2(*buf0, *buf0, lo, carry);
      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)
        return E_DEC_OVERFLOW;