mirror of
https://github.com/MariaDB/server.git
synced 2026-10-23 18:49:29 +03:00
cleanup: remove explicit rounding before decimal2longlong
embed rounding into decimal2longlong instead. this avoid carry propagation loop on rounding. and allows decimal2longlong detect truncation correctly
This commit is contained in:
@@ -46,9 +46,9 @@ int decimal2string(const decimal_t *from, char *to, int *to_len,
|
||||
decimal_digits_t fixed_precision,
|
||||
decimal_digits_t fixed_decimals,
|
||||
char filler);
|
||||
int decimal2ulonglong(const decimal_t *from, ulonglong *to);
|
||||
int decimal2ulonglong(const decimal_t *from, ulonglong *to, decimal_round_mode);
|
||||
int ulonglong2decimal(ulonglong from, decimal_t *to);
|
||||
int decimal2longlong(const decimal_t *from, longlong *to);
|
||||
int decimal2longlong(const decimal_t *from, longlong *to, decimal_round_mode);
|
||||
int longlong2decimal(longlong from, decimal_t *to);
|
||||
int decimal2double(const decimal_t *from, double *to);
|
||||
int double2decimal(double from, decimal_t *to);
|
||||
|
||||
@@ -4041,7 +4041,7 @@ mariadb_dyncol_val_long(longlong *ll, DYNAMIC_COLUMN_VALUE *val)
|
||||
break;
|
||||
}
|
||||
case DYN_COL_DECIMAL:
|
||||
if (decimal2longlong(&val->x.decimal.value, ll) != E_DEC_OK)
|
||||
if (decimal2longlong(&val->x.decimal.value, ll,TRUNCATE) != E_DEC_OK)
|
||||
rc= ER_DYNCOL_TRUNCATED;
|
||||
break;
|
||||
case DYN_COL_DATETIME:
|
||||
|
||||
@@ -349,11 +349,8 @@ int my_decimal2int(uint mask, const decimal_t *d, bool is_unsigned,
|
||||
longlong *l, decimal_round_mode round_type)
|
||||
{
|
||||
int res;
|
||||
my_decimal rounded;
|
||||
/* decimal_round can return only E_DEC_TRUNCATED */
|
||||
decimal_round(d, &rounded, 0, round_type);
|
||||
res= is_unsigned ? decimal2ulonglong(&rounded, (ulonglong *) l)
|
||||
: decimal2longlong(&rounded, l);
|
||||
res= is_unsigned ? decimal2ulonglong(d, (ulonglong *) l, round_type)
|
||||
: decimal2longlong(d, l, round_type);
|
||||
if (res & mask)
|
||||
{
|
||||
char buff[DECIMAL_MAX_STR_LENGTH];
|
||||
|
||||
@@ -481,11 +481,10 @@ struct Master_info_file: Info_file
|
||||
return true; // ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE
|
||||
overprecise= decimal.frac > 3;
|
||||
// decomposed from my_decimal2int() to reduce a bit of computations
|
||||
auto rounded= my_decimal(), product= my_decimal();
|
||||
auto product= my_decimal();
|
||||
bool unexpected_error=
|
||||
decimal_round(&decimal, &rounded, 3, HALF_UP) ||
|
||||
decimal_mul(&rounded, &THOUSAND, &product) ||
|
||||
decimal2ulonglong(&product, &decimal_out);
|
||||
decimal_mul(&decimal, &THOUSAND, &product) ||
|
||||
(decimal2ulonglong(&product, &decimal_out, HALF_UP) > E_DEC_TRUNCATED);
|
||||
DBUG_ASSERT(!unexpected_error);
|
||||
if (unexpected_error)
|
||||
return true;
|
||||
|
||||
@@ -2828,7 +2828,7 @@ static inline int part_val_int(Item *item_expr, longlong *result)
|
||||
my_decimal buf;
|
||||
my_decimal *val= item_expr->val_decimal(&buf);
|
||||
if (val && my_decimal2int(E_DEC_FATAL_ERROR, val, item_expr->unsigned_flag,
|
||||
result, FLOOR) != E_DEC_OK)
|
||||
result, FLOOR) & E_DEC_FATAL_ERROR)
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1122,11 +1122,11 @@ int longlong2decimal(longlong from, decimal_t *to)
|
||||
return ull2dec(from, to);
|
||||
}
|
||||
|
||||
int decimal2ulonglong(const decimal_t *from, ulonglong *to)
|
||||
int decimal2ulonglong(const decimal_t *from, ulonglong *to, decimal_round_mode mode)
|
||||
{
|
||||
dec1 *buf=from->buf;
|
||||
ulonglong x=0;
|
||||
int intg, frac;
|
||||
int intg, frac= from->frac;
|
||||
|
||||
if (from->sign)
|
||||
{
|
||||
@@ -1152,18 +1152,38 @@ int decimal2ulonglong(const decimal_t *from, ulonglong *to)
|
||||
|
||||
x=x*DIG_BASE + *buf++;
|
||||
}
|
||||
*to=x;
|
||||
for (frac=from->frac; unlikely(frac > 0); frac-=DIG_PER_DEC1)
|
||||
if (*buf++)
|
||||
return E_DEC_TRUNCATED;
|
||||
return E_DEC_OK;
|
||||
|
||||
*to= x;
|
||||
if (frac > 0)
|
||||
{
|
||||
int carry= 0;
|
||||
|
||||
for (dec1 *b= buf; frac > 0 && !*b++; frac-=DIG_PER_DEC1) /* no-op */;
|
||||
|
||||
switch (mode) {
|
||||
case HALF_UP: carry= *buf >= 5*DIG_MASK; break;
|
||||
case HALF_EVEN: carry= *buf >= (6-(int)(x%2))*DIG_MASK; break;
|
||||
case CEILING: carry= frac > 0; break;
|
||||
case FLOOR: carry= 0; break;
|
||||
case TRUNCATE: carry= 0; break;
|
||||
default: DBUG_ASSERT(0);
|
||||
}
|
||||
if (carry)
|
||||
{
|
||||
if (x == ULONGLONG_MAX)
|
||||
return E_DEC_OVERFLOW;
|
||||
(*to)++;
|
||||
}
|
||||
}
|
||||
|
||||
return frac > 0 ? E_DEC_TRUNCATED : E_DEC_OK;
|
||||
}
|
||||
|
||||
int decimal2longlong(const decimal_t *from, longlong *to)
|
||||
int decimal2longlong(const decimal_t *from, longlong *to, decimal_round_mode mode)
|
||||
{
|
||||
dec1 *buf=from->buf;
|
||||
longlong x=0;
|
||||
int intg, frac;
|
||||
int intg, frac= from->frac;
|
||||
|
||||
for (intg=from->intg; intg > 0; intg-=DIG_PER_DEC1)
|
||||
{
|
||||
@@ -1191,6 +1211,31 @@ int decimal2longlong(const decimal_t *from, longlong *to)
|
||||
|
||||
x=x*DIG_BASE - *buf++;
|
||||
}
|
||||
if (frac > 0)
|
||||
{
|
||||
int carry= 0;
|
||||
|
||||
for (dec1 *b= buf; frac > 0 && !*b++; frac-=DIG_PER_DEC1) /* no-op */;
|
||||
|
||||
switch (mode) {
|
||||
case HALF_UP: carry= *buf >= 5*DIG_MASK; break;
|
||||
case HALF_EVEN: carry= *buf >= (6-x%2)*DIG_MASK; break;
|
||||
case CEILING: carry= frac > 0 && !from->sign; break;
|
||||
case FLOOR: carry= frac > 0 && from->sign; break;
|
||||
case TRUNCATE: carry= 0; break;
|
||||
default: DBUG_ASSERT(0);
|
||||
}
|
||||
if (carry)
|
||||
{
|
||||
if (x == LONGLONG_MIN)
|
||||
{
|
||||
*to= from->sign ? LONGLONG_MIN : LONGLONG_MAX;
|
||||
return E_DEC_OVERFLOW;
|
||||
}
|
||||
x--;
|
||||
}
|
||||
}
|
||||
|
||||
/* boundary case: 9223372036854775808 */
|
||||
if (unlikely(from->sign==0 && x == LONGLONG_MIN))
|
||||
{
|
||||
@@ -1199,10 +1244,7 @@ int decimal2longlong(const decimal_t *from, longlong *to)
|
||||
}
|
||||
|
||||
*to=from->sign ? x : -x;
|
||||
for (frac=from->frac; unlikely(frac > 0); frac-=DIG_PER_DEC1)
|
||||
if (*buf++)
|
||||
return E_DEC_TRUNCATED;
|
||||
return E_DEC_OK;
|
||||
return frac > 0 ? E_DEC_TRUNCATED : E_DEC_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -43,9 +43,9 @@ test_copy_and_compare()
|
||||
ok(my_decimal_cmp(&d3, &d1) == 0,"Pass");
|
||||
|
||||
ulonglong val1, val2, val3;
|
||||
ok(decimal2ulonglong(&d1, &val1) == 0, "Pass");
|
||||
ok(decimal2ulonglong(&d2, &val2) == 0,"Pass");
|
||||
ok(decimal2ulonglong(&d3, &val3) == 0,"Pass");
|
||||
ok(decimal2ulonglong(&d1, &val1, TRUNCATE) == 0, "Pass");
|
||||
ok(decimal2ulonglong(&d2, &val2, TRUNCATE) == 0,"Pass");
|
||||
ok(decimal2ulonglong(&d3, &val3, TRUNCATE) == 0,"Pass");
|
||||
|
||||
ok(val == val1,"Pass");
|
||||
ok(val == val2,"Pass");
|
||||
|
||||
Reference in New Issue
Block a user