diff options
-rw-r--r-- | mysql-test/r/func_math.result | 6 | ||||
-rw-r--r-- | mysql-test/t/func_math.test | 7 | ||||
-rw-r--r-- | strings/decimal.c | 29 |
3 files changed, 38 insertions, 4 deletions
diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result index c7674c57c8d..b7188092b41 100644 --- a/mysql-test/r/func_math.result +++ b/mysql-test/r/func_math.result @@ -146,3 +146,9 @@ drop table t1; select round(150, 2); round(150, 2) 150.00 +select ceil(0.09); +ceil(0.09) +1 +select ceil(0.000000000000000009); +ceil(0.000000000000000009) +1 diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test index 03057af6911..da4b8335e07 100644 --- a/mysql-test/t/func_math.test +++ b/mysql-test/t/func_math.test @@ -84,3 +84,10 @@ drop table t1; # Bug #10083 (round doesn't increase decimals) # select round(150, 2); + +# +# Bug @10632 (Ceiling function returns wrong answer) +# +select ceil(0.09); +select ceil(0.000000000000000009); + diff --git a/strings/decimal.c b/strings/decimal.c index de64933466d..18f920badd3 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -1490,11 +1490,31 @@ decimal_round(decimal_t *from, decimal_t *to, int scale, buf1+=intg0+frac0-1; if (scale == frac0*DIG_PER_DEC1) { + int do_inc= FALSE; DBUG_ASSERT(frac0+intg0 >= 0); - x=buf0[1]/DIG_MASK; - if (x > round_digit || - (round_digit == 5 && x == 5 && (mode == HALF_UP || - (frac0+intg0 > 0 && *buf0 & 1)))) + switch (round_digit) + { + case 0: + { + dec1 *p0= buf0 + (frac1-frac0); + for (; p0 > buf0; p0--) + if (*p0) + { + do_inc= TRUE; + break; + }; + break; + } + case 5: + { + x= buf0[1]/DIG_MASK; + do_inc= (x>5) || ((x == 5) && + (mode == HALF_UP || (frac0+intg0 > 0 && *buf0 & 1))); + break; + }; + default:; + }; + if (do_inc) { if (frac0+intg0>0) (*buf1)++; @@ -1509,6 +1529,7 @@ decimal_round(decimal_t *from, decimal_t *to, int scale, } else { + /* TODO - fix this code as it won't work for CEILING mode */ int pos=frac0*DIG_PER_DEC1-scale-1; DBUG_ASSERT(frac0+intg0 > 0); x=*buf1 / powers10[pos]; |