summaryrefslogtreecommitdiff
path: root/strings
diff options
context:
space:
mode:
authorunknown <gkodinov@mysql.com>2006-07-06 13:18:05 +0300
committerunknown <gkodinov@mysql.com>2006-07-06 13:18:05 +0300
commit8e354677a81580fc7bd1ba4e3f6c7c426ed08c42 (patch)
tree2e3ef4ddaedcb26307cc9412256ab6f787169763 /strings
parent3cf92fb7d67b22f33f4846ecf68c3f56c301cc20 (diff)
downloadmariadb-git-8e354677a81580fc7bd1ba4e3f6c7c426ed08c42.tar.gz
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"
Diffstat (limited to 'strings')
-rw-r--r--strings/decimal.c13
1 files changed, 10 insertions, 3 deletions
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;