summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/select.result3
-rw-r--r--mysql-test/t/select.test5
-rw-r--r--strings/decimal.c13
3 files changed, 18 insertions, 3 deletions
diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result
index e6c590489a0..7f01d453906 100644
--- a/mysql-test/r/select.result
+++ b/mysql-test/r/select.result
@@ -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
diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test
index b75d0dd8bb6..b44f682c02e 100644
--- a/mysql-test/t/select.test
+++ b/mysql-test/t/select.test
@@ -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;
diff --git a/strings/decimal.c b/strings/decimal.c
index 8786a513945..ecd92a54cc9 100644
--- a/strings/decimal.c
+++ b/strings/decimal.c
@@ -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;