summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/decimal.h8
-rw-r--r--sql/sql_show.cc4
-rw-r--r--strings/decimal.c28
3 files changed, 28 insertions, 12 deletions
diff --git a/include/decimal.h b/include/decimal.h
index 5b5b8c0b460..fddae1f54a6 100644
--- a/include/decimal.h
+++ b/include/decimal.h
@@ -51,13 +51,7 @@ int decimal_mul(decimal *from1, decimal *from2, decimal *to);
int decimal_div(decimal *from1, decimal *from2, decimal *to, int scale_incr);
int decimal_mod(decimal *from1, decimal *from2, decimal *to);
int decimal_round(decimal *from, decimal *to, int new_scale, decimal_round_mode mode);
-
-/*
- the following works only on special "zero" decimal, not on any
- decimal that happen to evaluate to zero
-*/
-
-#define decimal_is_zero(dec) ((dec)->intg1==1 && (dec)->frac1==0 && (dec)->buf[0]==0)
+int decimal_is_zero(decimal *from);
/* set a decimal to zero */
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index fd12c206e64..f30eeb2d206 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -2951,10 +2951,12 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
}
break;
default:
- if (!(item= new Item_string("", fields_info->field_length, cs)))
+ /* this should be changed when Item_empty_string is fixed(in 4.1) */
+ if (!(item= new Item_empty_string("", 0, cs)))
{
DBUG_RETURN(0);
}
+ item->max_length= fields_info->field_length * cs->mbmaxlen;
item->set_name(fields_info->field_name,
strlen(fields_info->field_name), cs);
break;
diff --git a/strings/decimal.c b/strings/decimal.c
index 224d75f6844..2dcc2c88ceb 100644
--- a/strings/decimal.c
+++ b/strings/decimal.c
@@ -901,19 +901,26 @@ int decimal_round(decimal *from, decimal *to, int scale, decimal_round_mode mode
if (scale >= from->frac)
goto done; /* nothing to do */
- DBUG_ASSERT(frac0+intg0 > 0);
buf0+=intg0+frac0-1;
buf1+=intg0+frac0-1;
if (scale == frac0*DIG_PER_DEC1)
{
+ DBUG_ASSERT(frac0+intg0 >= 0);
x=buf0[1]/DIG_MASK;
if (x > round_digit ||
- (round_digit == 5 && x == 5 && (mode == HALF_UP || *buf0 & 1)))
- (*buf1)++;
+ (round_digit == 5 && x == 5 && (mode == HALF_UP ||
+ (frac0+intg0 > 0 && *buf0 & 1))))
+ {
+ if (frac0+intg0>0)
+ (*buf1)++;
+ else
+ *(++buf1)=DIG_BASE;
+ }
}
else
{
int pos=frac0*DIG_PER_DEC1-scale-1;
+ DBUG_ASSERT(frac0+intg0 > 0);
x=*buf1 / powers10[pos];
y=x % 10;
if (y > round_digit ||
@@ -942,7 +949,7 @@ int decimal_round(decimal *from, decimal *to, int scale, decimal_round_mode mode
scale=frac0*DIG_PER_DEC1;
error=E_DEC_TRUNCATED; /* XXX */
}
- for (buf1=to->buf+frac0+intg0; buf1 > to->buf; buf1--)
+ for (buf1=to->buf+intg0+max(frac0,0); buf1 > to->buf; buf1--)
{
buf1[0]=buf1[-1];
}
@@ -1233,6 +1240,16 @@ int decimal_cmp(decimal *from1, decimal *from2)
return from1->sign > from2->sign ? -1 : 1;
}
+int decimal_is_zero(decimal *from)
+{
+ dec1 *buf1=from->buf,
+ *end=buf1+ROUND_UP(from->intg)+ROUND_UP(from->frac);
+ while (buf1 < end)
+ if (*buf1++)
+ return 0;
+ return 1;
+}
+
/*
multiply two decimals
@@ -2103,6 +2120,9 @@ main()
test_ro("15.4",-1,HALF_UP,"20");
test_ro("-15.4",-1,HALF_UP,"-20");
test_ro("5.4",-1,HALF_UP,"10");
+ test_ro(".999", 0, HALF_UP, "1");
+ memset(buf2, 33, sizeof(buf2));
+ test_ro("999999999", -9, HALF_UP, "1000000000");
test_ro("15.1",0,HALF_EVEN,"15");
test_ro("15.5",0,HALF_EVEN,"16");
test_ro("14.5",0,HALF_EVEN,"14");