MDEV-16910 Add class VDec

Adding classes VDec and VDec2_lazy, according to the task description.
This patch removes around 250 duplicate code lines.
This commit is contained in:
Alexander Barkov 2018-08-07 10:48:42 +04:00
commit cb7b5fbf1c
26 changed files with 595 additions and 847 deletions

View file

@ -1933,14 +1933,6 @@ Field::unpack(uchar* to, const uchar *from, const uchar *from_end,
}
my_decimal *Field::val_decimal(my_decimal *decimal)
{
/* This never have to be called */
DBUG_ASSERT(0);
return 0;
}
void Field_num::add_zerofill_and_unsigned(String &res) const
{
if (unsigned_flag)
@ -3170,7 +3162,7 @@ void Field_new_decimal::set_value_on_overflow(my_decimal *decimal_value,
Otherwise sets maximal number that can be stored in the field.
@param decimal_value my_decimal
@param [OUT] native_error the error returned by my_decimal2binary().
@param [OUT] native_error the error returned by my_decimal::to_binary().
@retval
0 ok
@ -3208,8 +3200,8 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value,
}
#endif
*native_error= my_decimal2binary(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
decimal_value, ptr, precision, dec);
*native_error= decimal_value->to_binary(ptr, precision, dec,
E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW);
if (unlikely(*native_error == E_DEC_OVERFLOW))
{
@ -3217,7 +3209,7 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value,
DBUG_PRINT("info", ("overflow"));
set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1);
set_value_on_overflow(&buff, decimal_value->sign());
my_decimal2binary(E_DEC_FATAL_ERROR, &buff, ptr, precision, dec);
buff.to_binary(ptr, precision, dec);
error= 1;
}
DBUG_EXECUTE("info", print_decimal_buff(decimal_value, (uchar *) ptr,
@ -3382,37 +3374,6 @@ int Field_new_decimal::store_time_dec(const MYSQL_TIME *ltime, uint dec_arg)
}
double Field_new_decimal::val_real(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
double dbl;
my_decimal decimal_value;
my_decimal2double(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), &dbl);
return dbl;
}
longlong Field_new_decimal::val_int(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
longlong i;
my_decimal decimal_value;
my_decimal2int(E_DEC_FATAL_ERROR, val_decimal(&decimal_value),
unsigned_flag, &i);
return i;
}
ulonglong Field_new_decimal::val_uint(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
longlong i;
my_decimal decimal_value;
my_decimal2int(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), true, &i);
return i;
}
my_decimal* Field_new_decimal::val_decimal(my_decimal *decimal_value)
{
ASSERT_COLUMN_MARKED_FOR_READ;
@ -3425,27 +3386,6 @@ my_decimal* Field_new_decimal::val_decimal(my_decimal *decimal_value)
}
String *Field_new_decimal::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
ASSERT_COLUMN_MARKED_FOR_READ;
my_decimal decimal_value;
uint fixed_precision= zerofill ? precision : 0;
my_decimal2string(E_DEC_FATAL_ERROR, val_decimal(&decimal_value),
fixed_precision, dec, '0', val_buffer);
val_buffer->set_charset(&my_charset_numeric);
return val_buffer;
}
bool Field_new_decimal::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
{
my_decimal value;
return decimal_to_datetime_with_warn(val_decimal(&value),
ltime, fuzzydate, field_name.str);
}
int Field_new_decimal::cmp(const uchar *a,const uchar*b)
{
return memcmp(a, b, bin_size);
@ -3600,8 +3540,8 @@ Item *Field_new_decimal::get_equal_const_item(THD *thd, const Context &ctx,
if (const_item->field_type() != MYSQL_TYPE_NEWDECIMAL ||
const_item->decimal_scale() != decimals())
{
my_decimal *val, val_buffer, val_buffer2;
if (!(val= const_item->val_decimal(&val_buffer)))
VDec val(const_item);
if (val.is_null())
{
DBUG_ASSERT(0);
return const_item;
@ -3611,9 +3551,9 @@ Item *Field_new_decimal::get_equal_const_item(THD *thd, const Context &ctx,
See comments about truncation in the same place in
Field_time::get_equal_const_item().
*/
my_decimal_round(E_DEC_FATAL_ERROR, val, decimals(), true, &val_buffer2);
return new (thd->mem_root) Item_decimal(thd, field_name.str,
&val_buffer2,
my_decimal tmp;
val.round_to(&tmp, decimals(), TRUNCATE);
return new (thd->mem_root) Item_decimal(thd, field_name.str, &tmp,
decimals(), field_length);
}
break;
@ -4853,13 +4793,6 @@ Converter_double_to_longlong::push_warning(THD *thd,
}
int Field_real::store_decimal(const my_decimal *dm)
{
double dbl;
my_decimal2double(E_DEC_FATAL_ERROR, dm, &dbl);
return store(dbl);
}
int Field_real::store_time_dec(const MYSQL_TIME *ltime, uint dec_arg)
{
return store(TIME_to_double(ltime));
@ -7115,9 +7048,8 @@ uint Field_str::is_equal(Create_field *new_field)
int Field_longstr::store_decimal(const my_decimal *d)
{
char buff[DECIMAL_MAX_STR_LENGTH+1];
String str(buff, sizeof(buff), &my_charset_numeric);
my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str);
StringBuffer<DECIMAL_MAX_STR_LENGTH+1> str;
d->to_string(&str);
return store(str.ptr(), str.length(), str.charset());
}

View file

@ -813,7 +813,7 @@ public:
return nr < 0 ? 0 : (ulonglong) nr;
}
virtual bool val_bool(void)= 0;
virtual my_decimal *val_decimal(my_decimal *);
virtual my_decimal *val_decimal(my_decimal *)=0;
inline String *val_str(String *str) { return val_str(str, str); }
/*
val_str(buf1, buf2) gets two buffers and should use them as follows:
@ -1956,7 +1956,7 @@ public:
return Field_num::memcpy_field_possible(from) &&
field_length >= from->field_length;
}
int store_decimal(const my_decimal *);
int store_decimal(const my_decimal *dec) { return store(dec->to_double()); }
int store_time_dec(const MYSQL_TIME *ltime, uint dec);
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
my_decimal *val_decimal(my_decimal *);
@ -2039,8 +2039,8 @@ public:
}
int save_in_field(Field *to)
{
my_decimal buff;
return to->store_decimal(val_decimal(&buff));
my_decimal tmp(ptr, precision, dec);
return to->store_decimal(&tmp);
}
bool memcpy_field_possible(const Field *from) const
{
@ -2056,17 +2056,33 @@ public:
int store(longlong nr, bool unsigned_val);
int store_time_dec(const MYSQL_TIME *ltime, uint dec);
int store_decimal(const my_decimal *);
double val_real(void);
longlong val_int(void);
ulonglong val_uint(void);
double val_real(void)
{
return my_decimal(ptr, precision, dec).to_double();
}
longlong val_int(void)
{
return my_decimal(ptr, precision, dec).to_longlong(unsigned_flag);
}
ulonglong val_uint(void)
{
return (ulonglong) my_decimal(ptr, precision, dec).to_longlong(true);
}
my_decimal *val_decimal(my_decimal *);
String *val_str(String*, String *);
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
String *val_str(String *val_buffer, String *val_ptr __attribute__((unused)))
{
uint fixed_precision= zerofill ? precision : 0;
return my_decimal(ptr, precision, dec).
to_string(val_buffer, fixed_precision, dec, '0');
}
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
{
return my_decimal(ptr, precision, dec).
to_datetime_with_warn(ltime, fuzzydate, field_name.str);
}
bool val_bool()
{
my_decimal decimal_value;
my_decimal *val= val_decimal(&decimal_value);
return val ? !my_decimal_is_zero(val) : 0;
return my_decimal(ptr, precision, dec).to_bool();
}
int cmp(const uchar *, const uchar *);
void sort_string(uchar *buff, uint length);

View file

@ -413,8 +413,8 @@ void Field::do_field_real(Copy_field *copy)
void Field::do_field_decimal(Copy_field *copy)
{
my_decimal value;
copy->to_field->store_decimal(copy->from_field->val_decimal(&value));
my_decimal value(copy->from_field);
copy->to_field->store_decimal(&value);
}

View file

@ -1114,8 +1114,7 @@ Type_handler_decimal_result::make_sort_key(uchar *to, Item *item,
}
*to++= 1;
}
my_decimal2binary(E_DEC_FATAL_ERROR, dec_val, to,
item->max_length - (item->decimals ? 1 : 0),
dec_val->to_binary(to, item->max_length - (item->decimals ? 1 : 0),
item->decimals);
}

View file

@ -253,17 +253,6 @@ String *Item::val_string_from_int(String *str)
}
String *Item::val_string_from_decimal(String *str)
{
my_decimal dec_buf, *dec= val_decimal(&dec_buf);
if (null_value)
return 0;
my_decimal_round(E_DEC_FATAL_ERROR, dec, decimals, FALSE, &dec_buf);
my_decimal2string(E_DEC_FATAL_ERROR, &dec_buf, 0, 0, 0, str);
return str;
}
longlong Item::val_int_from_str(int *error)
{
char buff[MAX_FIELD_WIDTH];
@ -345,41 +334,6 @@ my_decimal *Item::val_decimal_from_string(my_decimal *decimal_value)
}
double Item::val_real_from_decimal()
{
/* Note that fix_fields may not be called for Item_avg_field items */
double result;
my_decimal value_buff, *dec_val= val_decimal(&value_buff);
if (null_value)
return 0.0;
my_decimal2double(E_DEC_FATAL_ERROR, dec_val, &result);
return result;
}
longlong Item::val_int_from_decimal()
{
/* Note that fix_fields may not be called for Item_avg_field items */
longlong result;
my_decimal value, *dec_val= val_decimal(&value);
if (null_value)
return 0;
my_decimal2int(E_DEC_FATAL_ERROR, dec_val, unsigned_flag, &result);
return result;
}
longlong Item::val_int_unsigned_typecast_from_decimal()
{
longlong result;
my_decimal tmp, *dec= val_decimal(&tmp);
if (null_value)
return 0;
my_decimal2int(E_DEC_FATAL_ERROR, dec, 1, &result);
return result;
}
int Item::save_time_in_field(Field *field, bool no_conversions)
{
MYSQL_TIME ltime;
@ -1404,17 +1358,6 @@ bool Item::get_date_from_real(MYSQL_TIME *ltime, ulonglong fuzzydate)
}
bool Item::get_date_from_decimal(MYSQL_TIME *ltime, ulonglong fuzzydate)
{
my_decimal value, *res;
if (!(res= val_decimal(&value)) ||
decimal_to_datetime_with_warn(res, ltime, fuzzydate,
field_name_or_null()))
return null_value|= make_zero_date(ltime, fuzzydate);
return null_value= false;
}
bool Item::get_date_from_string(MYSQL_TIME *ltime, ulonglong fuzzydate)
{
char buff[40];
@ -1463,10 +1406,8 @@ bool Item::get_seconds(ulonglong *sec, ulong *sec_part)
*sec_part= 0;
return neg;
}
my_decimal tmp, *dec= val_decimal(&tmp);
if (!dec)
return 0;
return my_decimal2seconds(dec, sec, sec_part);
VDec tmp(this);
return tmp.is_null() ? 0 : my_decimal2seconds(tmp.ptr(), sec, sec_part);
}
const MY_LOCALE *Item::locale_from_val_str()
@ -3737,7 +3678,7 @@ Item_decimal::Item_decimal(THD *thd, const char *str, const my_decimal *val_arg,
}
Item_decimal::Item_decimal(THD *thd, my_decimal *value_par):
Item_decimal::Item_decimal(THD *thd, const my_decimal *value_par):
Item_num(thd)
{
my_decimal2decimal(value_par, &decimal_value);
@ -3750,44 +3691,15 @@ Item_decimal::Item_decimal(THD *thd, my_decimal *value_par):
Item_decimal::Item_decimal(THD *thd, const uchar *bin, int precision, int scale):
Item_num(thd)
Item_num(thd),
decimal_value(bin, precision, scale)
{
binary2my_decimal(E_DEC_FATAL_ERROR, bin,
&decimal_value, precision, scale);
decimals= (uint8) decimal_value.frac;
max_length= my_decimal_precision_to_length_no_truncation(precision, decimals,
unsigned_flag);
}
longlong Item_decimal::val_int()
{
longlong result;
my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &result);
return result;
}
double Item_decimal::val_real()
{
double result;
my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &result);
return result;
}
String *Item_decimal::val_str(String *result)
{
result->set_charset(&my_charset_numeric);
my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, result);
return result;
}
void Item_decimal::print(String *str, enum_query_type query_type)
{
my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, &str_value);
str->append(str_value);
}
void Item_decimal::set_decimal_value(my_decimal *value_par)
{
my_decimal2decimal(value_par, &decimal_value);
@ -4405,11 +4317,7 @@ double Item_param::PValue::val_real() const
case INT_RESULT:
return (double) integer;
case DECIMAL_RESULT:
{
double result;
my_decimal2double(E_DEC_FATAL_ERROR, &m_decimal, &result);
return result;
}
return m_decimal.to_double();
case STRING_RESULT:
return double_from_string_with_check(&m_string);
case TIME_RESULT:
@ -4434,11 +4342,7 @@ longlong Item_param::PValue::val_int(const Type_std_attributes *attr) const
case INT_RESULT:
return integer;
case DECIMAL_RESULT:
{
longlong i;
my_decimal2int(E_DEC_FATAL_ERROR, &m_decimal, attr->unsigned_flag, &i);
return i;
}
return m_decimal.to_longlong(attr->unsigned_flag);
case STRING_RESULT:
return longlong_from_string_with_check(&m_string);
case TIME_RESULT:
@ -4488,7 +4392,7 @@ String *Item_param::PValue::val_str(String *str,
str->set(integer, &my_charset_bin);
return str;
case DECIMAL_RESULT:
if (my_decimal2string(E_DEC_FATAL_ERROR, &m_decimal, 0, 0, 0, str) <= 1)
if (m_decimal.to_string_native(str, 0, 0, 0) <= 1)
return str;
return NULL;
case TIME_RESULT:
@ -4529,8 +4433,7 @@ const String *Item_param::value_query_val_str(THD *thd, String *str) const
str->set_real(value.real, NOT_FIXED_DEC, &my_charset_bin);
return str;
case DECIMAL_RESULT:
if (my_decimal2string(E_DEC_FATAL_ERROR, &value.m_decimal,
0, 0, 0, str) > 1)
if (value.m_decimal.to_string_native(str, 0, 0, 0) > 1)
return &my_null_string;
return str;
case TIME_RESULT:
@ -5093,37 +4996,19 @@ int Item_copy_decimal::save_in_field(Field *field, bool no_conversions)
String *Item_copy_decimal::val_str(String *result)
{
if (null_value)
return (String *) 0;
result->set_charset(&my_charset_bin);
my_decimal2string(E_DEC_FATAL_ERROR, &cached_value, 0, 0, 0, result);
return result;
return null_value ? NULL : cached_value.to_string(result);
}
double Item_copy_decimal::val_real()
{
if (null_value)
return 0.0;
else
{
double result;
my_decimal2double(E_DEC_FATAL_ERROR, &cached_value, &result);
return result;
}
return null_value ? 0.0 : cached_value.to_double();
}
longlong Item_copy_decimal::val_int()
{
if (null_value)
return 0;
else
{
longlong result;
my_decimal2int(E_DEC_FATAL_ERROR, &cached_value, unsigned_flag, &result);
return result;
}
return null_value ? 0 : cached_value.to_longlong(unsigned_flag);
}
@ -6797,12 +6682,11 @@ int Item::save_real_in_field(Field *field, bool no_conversions)
int Item::save_decimal_in_field(Field *field, bool no_conversions)
{
my_decimal decimal_value;
my_decimal *value= val_decimal(&decimal_value);
if (null_value)
VDec value(this);
if (value.is_null())
return set_field_to_null_with_conversions(field, no_conversions);
field->set_notnull();
return field->store_decimal(value);
return field->store_decimal(value.ptr());
}
@ -10168,30 +10052,18 @@ bool Item_cache_decimal::cache_value()
double Item_cache_decimal::val_real()
{
double res;
if (!has_value())
return 0.0;
my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &res);
return res;
return !has_value() ? 0.0 : decimal_value.to_double();
}
longlong Item_cache_decimal::val_int()
{
longlong res;
if (!has_value())
return 0;
my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &res);
return res;
return !has_value() ? 0 : decimal_value.to_longlong(unsigned_flag);
}
String* Item_cache_decimal::val_str(String *str)
{
if (!has_value())
return NULL;
my_decimal_round(E_DEC_FATAL_ERROR, &decimal_value, decimals, FALSE,
&decimal_value);
my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, str);
return str;
return !has_value() ? NULL :
decimal_value.to_string_round(str, decimals, &decimal_value);
}
my_decimal *Item_cache_decimal::val_decimal(my_decimal *val)
@ -10212,9 +10084,8 @@ Item *Item_cache_decimal::convert_to_basic_const_item(THD *thd)
new_item= (Item*) new (thd->mem_root) Item_null(thd);
else
{
my_decimal decimal_value;
my_decimal *result= val_decimal(&decimal_value);
new_item= (Item*) new (thd->mem_root) Item_decimal(thd, result);
VDec tmp(this);
new_item= (Item*) new (thd->mem_root) Item_decimal(thd, tmp.ptr());
}
return new_item;
}

View file

@ -863,6 +863,7 @@ protected:
null_value= MY_TEST(rc || item->null_value);
return rc;
}
public:
/*
This method is used if the item was not null but convertion to
TIME/DATE/DATETIME failed. We return a zero date if allowed,
@ -870,7 +871,6 @@ protected:
*/
bool make_zero_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
public:
/*
Cache val_str() into the own buffer, e.g. to evaluate constant
expressions with subqueries in the ORDER/GROUP clauses.
@ -1197,7 +1197,6 @@ public:
{
return cast_to_int_type_handler()->Item_val_int_unsigned_typecast(this);
}
longlong val_int_unsigned_typecast_from_decimal();
longlong val_int_unsigned_typecast_from_int();
longlong val_int_unsigned_typecast_from_str();
/*
@ -1378,18 +1377,15 @@ public:
/* Helper functions, see item_sum.cc */
String *val_string_from_real(String *str);
String *val_string_from_int(String *str);
String *val_string_from_decimal(String *str);
my_decimal *val_decimal_from_real(my_decimal *decimal_value);
my_decimal *val_decimal_from_int(my_decimal *decimal_value);
my_decimal *val_decimal_from_string(my_decimal *decimal_value);
longlong val_int_from_decimal();
longlong val_int_from_real()
{
DBUG_ASSERT(is_fixed());
return Converter_double_to_longlong_with_warn(val_real(), false).result();
}
longlong val_int_from_str(int *error);
double val_real_from_decimal();
int save_time_in_field(Field *field, bool no_conversions);
int save_date_in_field(Field *field, bool no_conversions);
@ -1613,7 +1609,6 @@ public:
bool get_date_from_int(MYSQL_TIME *ltime, ulonglong fuzzydate);
bool get_date_from_year(MYSQL_TIME *ltime, ulonglong fuzzydate);
bool get_date_from_real(MYSQL_TIME *ltime, ulonglong fuzzydate);
bool get_date_from_decimal(MYSQL_TIME *ltime, ulonglong fuzzydate);
bool get_date_from_string(MYSQL_TIME *ltime, ulonglong fuzzydate);
bool get_time(MYSQL_TIME *ltime)
{ return get_date(ltime, Time::flags_for_get_date()); }
@ -4068,20 +4063,24 @@ public:
CHARSET_INFO *charset);
Item_decimal(THD *thd, const char *str, const my_decimal *val_arg,
uint decimal_par, uint length);
Item_decimal(THD *thd, my_decimal *value_par);
Item_decimal(THD *thd, const my_decimal *value_par);
Item_decimal(THD *thd, longlong val, bool unsig);
Item_decimal(THD *thd, double val, int precision, int scale);
Item_decimal(THD *thd, const uchar *bin, int precision, int scale);
const Type_handler *type_handler() const { return &type_handler_newdecimal; }
longlong val_int();
double val_real();
String *val_str(String*);
longlong val_int() { return decimal_value.to_longlong(unsigned_flag); }
double val_real() { return decimal_value.to_double(); }
String *val_str(String *to) { return decimal_value.to_string(to); }
my_decimal *val_decimal(my_decimal *val) { return &decimal_value; }
const my_decimal *const_ptr_my_decimal() const { return &decimal_value; }
int save_in_field(Field *field, bool no_conversions);
Item *clone_item(THD *thd);
virtual void print(String *str, enum_query_type query_type);
virtual void print(String *str, enum_query_type query_type)
{
decimal_value.to_string(&str_value);
str->append(str_value);
}
Item *neg(THD *thd);
uint decimal_precision() const { return decimal_value.precision(); }
void set_decimal_value(my_decimal *value_par);
@ -5955,7 +5954,7 @@ public:
longlong val_int();
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
{
return get_date_from_decimal(ltime, fuzzydate);
return VDec(this).to_datetime_with_warn(ltime, fuzzydate, this);
}
void copy();
Item *get_copy(THD *thd)
@ -6637,7 +6636,7 @@ public:
String* val_str(String *str);
my_decimal *val_decimal(my_decimal *);
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
{ return get_date_from_decimal(ltime, fuzzydate); }
{ return VDec(this).to_datetime_with_warn(ltime, fuzzydate, this); }
bool cache_value();
Item *convert_to_basic_const_item(THD *thd);
Item *get_copy(THD *thd)

View file

@ -225,16 +225,15 @@ Cached_item_decimal::Cached_item_decimal(Item *it)
bool Cached_item_decimal::cmp()
{
my_decimal tmp;
my_decimal *ptmp= item->val_decimal(&tmp);
if (null_value != item->null_value ||
(!item->null_value && my_decimal_cmp(&value, ptmp)))
VDec tmp(item);
if (null_value != tmp.is_null() ||
(!tmp.is_null() && tmp.cmp(&value)))
{
null_value= item->null_value;
null_value= tmp.is_null();
/* Save only not null values */
if (!null_value)
{
my_decimal2decimal(ptmp, &value);
my_decimal2decimal(tmp.ptr(), &value);
return TRUE;
}
return FALSE;
@ -245,17 +244,9 @@ bool Cached_item_decimal::cmp()
int Cached_item_decimal::cmp_read_only()
{
my_decimal tmp;
my_decimal *ptmp= item->val_decimal(&tmp);
VDec tmp(item);
if (null_value)
{
if (item->null_value)
return 0;
else
return -1;
}
if (item->null_value)
return 1;
return my_decimal_cmp(&value, ptmp);
return tmp.is_null() ? 0 : -1;
return tmp.is_null() ? 1 : value.cmp(tmp.ptr());
}

View file

@ -795,17 +795,15 @@ int Arg_comparator::compare_real()
int Arg_comparator::compare_decimal()
{
my_decimal decimal1;
my_decimal *val1= (*a)->val_decimal(&decimal1);
if (!(*a)->null_value)
VDec val1(*a);
if (!val1.is_null())
{
my_decimal decimal2;
my_decimal *val2= (*b)->val_decimal(&decimal2);
if (!(*b)->null_value)
VDec val2(*b);
if (!val2.is_null())
{
if (set_null)
owner->null_value= 0;
return my_decimal_cmp(val1, val2);
return val1.cmp(val2);
}
}
if (set_null)
@ -824,12 +822,10 @@ int Arg_comparator::compare_e_real()
int Arg_comparator::compare_e_decimal()
{
my_decimal decimal1, decimal2;
my_decimal *val1= (*a)->val_decimal(&decimal1);
my_decimal *val2= (*b)->val_decimal(&decimal2);
if ((*a)->null_value || (*b)->null_value)
return MY_TEST((*a)->null_value && (*b)->null_value);
return MY_TEST(my_decimal_cmp(val1, val2) == 0);
VDec val1(*a), val2(*b);
if (val1.is_null() || val1.is_null())
return MY_TEST(val1.is_null() && val2.is_null());
return MY_TEST(val1.cmp(val2) == 0);
}
@ -1951,11 +1947,11 @@ longlong Item_func_interval::val_int()
((el->result_type() == DECIMAL_RESULT) ||
(el->result_type() == INT_RESULT)))
{
my_decimal e_dec_buf, *e_dec= el->val_decimal(&e_dec_buf);
VDec e_dec(el);
/* Skip NULL ranges. */
if (el->null_value)
if (e_dec.is_null())
continue;
if (my_decimal_cmp(e_dec, dec) > 0)
if (e_dec.cmp(dec) > 0)
return i - 1;
}
else
@ -2180,21 +2176,19 @@ bool Item_func_between::val_int_cmp_int_finalize(longlong value,
longlong Item_func_between::val_int_cmp_decimal()
{
my_decimal dec_buf, *dec= args[0]->val_decimal(&dec_buf),
a_buf, *a_dec, b_buf, *b_dec;
if ((null_value=args[0]->null_value))
VDec dec(args[0]);
if ((null_value= dec.is_null()))
return 0; /* purecov: inspected */
a_dec= args[1]->val_decimal(&a_buf);
b_dec= args[2]->val_decimal(&b_buf);
if (!args[1]->null_value && !args[2]->null_value)
return (longlong) ((my_decimal_cmp(dec, a_dec) >= 0 &&
my_decimal_cmp(dec, b_dec) <= 0) != negated);
if (args[1]->null_value && args[2]->null_value)
VDec a_dec(args[1]), b_dec(args[2]);
if (!a_dec.is_null() && !b_dec.is_null())
return (longlong) ((dec.cmp(a_dec) >= 0 &&
dec.cmp(b_dec) <= 0) != negated);
if (a_dec.is_null() && b_dec.is_null())
null_value= true;
else if (args[1]->null_value)
null_value= (my_decimal_cmp(dec, b_dec) <= 0);
else if (a_dec.is_null())
null_value= (dec.cmp(b_dec) <= 0);
else
null_value= (my_decimal_cmp(dec, a_dec) >= 0);
null_value= (dec.cmp(a_dec) >= 0);
return (longlong) (!null_value && negated);
}
@ -3971,9 +3965,8 @@ int cmp_item_decimal::cmp_not_null(const Value *val)
int cmp_item_decimal::cmp(Item *arg)
{
my_decimal tmp_buf, *tmp= arg->val_decimal(&tmp_buf);
return (m_null_value || arg->null_value) ?
UNKNOWN : (my_decimal_cmp(&value, tmp) != 0);
VDec tmp(arg);
return m_null_value || tmp.is_null() ? UNKNOWN : (tmp.cmp(&value) != 0);
}

View file

@ -809,50 +809,6 @@ bool Item_func_plus::fix_length_and_dec(void)
}
String *Item_func_hybrid_field_type::val_str_from_decimal_op(String *str)
{
my_decimal decimal_value, *val;
if (!(val= decimal_op_with_null_check(&decimal_value)))
return 0; // null is set
DBUG_ASSERT(!null_value);
my_decimal_round(E_DEC_FATAL_ERROR, val, decimals, FALSE, val);
str->set_charset(collation.collation);
my_decimal2string(E_DEC_FATAL_ERROR, val, 0, 0, 0, str);
return str;
}
double Item_func_hybrid_field_type::val_real_from_decimal_op()
{
my_decimal decimal_value, *val;
if (!(val= decimal_op_with_null_check(&decimal_value)))
return 0.0; // null is set
double result;
my_decimal2double(E_DEC_FATAL_ERROR, val, &result);
return result;
}
longlong Item_func_hybrid_field_type::val_int_from_decimal_op()
{
my_decimal decimal_value, *val;
if (!(val= decimal_op_with_null_check(&decimal_value)))
return 0; // null is set
longlong result;
my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &result);
return result;
}
bool Item_func_hybrid_field_type::get_date_from_decimal_op(MYSQL_TIME *ltime,
ulonglong fuzzydate)
{
my_decimal value, *res;
if (!(res= decimal_op_with_null_check(&value)) ||
decimal_to_datetime_with_warn(res, ltime, fuzzydate,
field_name_or_null()))
return make_zero_mysql_time(ltime, fuzzydate);
return (null_value= 0);
}
String *Item_func_hybrid_field_type::val_str_from_int_op(String *str)
{
longlong nr= int_op();
@ -1051,47 +1007,15 @@ void Item_func_unsigned::print(String *str, enum_query_type query_type)
}
String *Item_decimal_typecast::val_str(String *str)
{
my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf);
if (null_value)
return NULL;
my_decimal2string(E_DEC_FATAL_ERROR, tmp, 0, 0, 0, str);
return str;
}
double Item_decimal_typecast::val_real()
{
my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf);
double res;
if (null_value)
return 0.0;
my_decimal2double(E_DEC_FATAL_ERROR, tmp, &res);
return res;
}
longlong Item_decimal_typecast::val_int()
{
my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf);
longlong res;
if (null_value)
return 0;
my_decimal2int(E_DEC_FATAL_ERROR, tmp, unsigned_flag, &res);
return res;
}
my_decimal *Item_decimal_typecast::val_decimal(my_decimal *dec)
{
my_decimal tmp_buf, *tmp= args[0]->val_decimal(&tmp_buf);
VDec tmp(args[0]);
bool sign;
uint precision;
if ((null_value= args[0]->null_value))
if ((null_value= tmp.is_null()))
return NULL;
my_decimal_round(E_DEC_FATAL_ERROR, tmp, decimals, FALSE, dec);
tmp.round_to(dec, decimals, HALF_UP);
sign= dec->sign();
if (unsigned_flag)
{
@ -1275,17 +1199,13 @@ err:
my_decimal *Item_func_plus::decimal_op(my_decimal *decimal_value)
{
my_decimal value1, *val1;
my_decimal value2, *val2;
val1= args[0]->val_decimal(&value1);
if ((null_value= args[0]->null_value))
return 0;
val2= args[1]->val_decimal(&value2);
if (!(null_value= (args[1]->null_value ||
VDec2_lazy val(args[0], args[1]);
if (!(null_value= (val.has_null() ||
check_decimal_overflow(my_decimal_add(E_DEC_FATAL_ERROR &
~E_DEC_OVERFLOW,
decimal_value,
val1, val2)) > 3)))
val.m_a.ptr(),
val.m_b.ptr())) > 3)))
return decimal_value;
return 0;
}
@ -1415,18 +1335,13 @@ err:
my_decimal *Item_func_minus::decimal_op(my_decimal *decimal_value)
{
my_decimal value1, *val1;
my_decimal value2, *val2=
val1= args[0]->val_decimal(&value1);
if ((null_value= args[0]->null_value))
return 0;
val2= args[1]->val_decimal(&value2);
if (!(null_value= (args[1]->null_value ||
(check_decimal_overflow(my_decimal_sub(E_DEC_FATAL_ERROR &
VDec2_lazy val(args[0], args[1]);
if (!(null_value= (val.has_null() ||
check_decimal_overflow(my_decimal_sub(E_DEC_FATAL_ERROR &
~E_DEC_OVERFLOW,
decimal_value, val1,
val2)) > 3))))
decimal_value,
val.m_a.ptr(),
val.m_b.ptr())) > 3)))
return decimal_value;
return 0;
}
@ -1525,17 +1440,13 @@ err:
my_decimal *Item_func_mul::decimal_op(my_decimal *decimal_value)
{
my_decimal value1, *val1;
my_decimal value2, *val2;
val1= args[0]->val_decimal(&value1);
if ((null_value= args[0]->null_value))
return 0;
val2= args[1]->val_decimal(&value2);
if (!(null_value= (args[1]->null_value ||
(check_decimal_overflow(my_decimal_mul(E_DEC_FATAL_ERROR &
VDec2_lazy val(args[0], args[1]);
if (!(null_value= (val.has_null() ||
check_decimal_overflow(my_decimal_mul(E_DEC_FATAL_ERROR &
~E_DEC_OVERFLOW,
decimal_value, val1,
val2)) > 3))))
decimal_value,
val.m_a.ptr(),
val.m_b.ptr())) > 3)))
return decimal_value;
return 0;
}
@ -1586,21 +1497,15 @@ double Item_func_div::real_op()
my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value)
{
my_decimal value1, *val1;
my_decimal value2, *val2;
int err;
val1= args[0]->val_decimal(&value1);
if ((null_value= args[0]->null_value))
return 0;
val2= args[1]->val_decimal(&value2);
if ((null_value= args[1]->null_value))
VDec2_lazy val(args[0], args[1]);
if ((null_value= val.has_null()))
return 0;
if ((err= check_decimal_overflow(my_decimal_div(E_DEC_FATAL_ERROR &
~E_DEC_OVERFLOW &
~E_DEC_DIV_ZERO,
decimal_value,
val1, val2,
val.m_a.ptr(), val.m_b.ptr(),
prec_increment))) > 3)
{
if (err == E_DEC_DIV_ZERO)
@ -1690,20 +1595,14 @@ longlong Item_func_int_div::val_int()
if (args[0]->result_type() != INT_RESULT ||
args[1]->result_type() != INT_RESULT)
{
my_decimal tmp;
my_decimal *val0p= args[0]->val_decimal(&tmp);
if ((null_value= args[0]->null_value))
VDec2_lazy val(args[0], args[1]);
if ((null_value= val.has_null()))
return 0;
my_decimal val0= *val0p;
my_decimal *val1p= args[1]->val_decimal(&tmp);
if ((null_value= args[1]->null_value))
return 0;
my_decimal val1= *val1p;
int err;
my_decimal tmp;
if ((err= my_decimal_div(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, &tmp,
&val0, &val1, 0)) > 3)
val.m_a.ptr(), val.m_b.ptr(), 0)) > 3)
{
if (err == E_DEC_DIV_ZERO)
signal_divide_by_null();
@ -1711,8 +1610,7 @@ longlong Item_func_int_div::val_int()
}
my_decimal truncated;
const bool do_truncate= true;
if (my_decimal_round(E_DEC_FATAL_ERROR, &tmp, 0, do_truncate, &truncated))
if (tmp.round_to(&truncated, 0, TRUNCATE))
DBUG_ASSERT(false);
longlong res;
@ -1814,17 +1712,11 @@ double Item_func_mod::real_op()
my_decimal *Item_func_mod::decimal_op(my_decimal *decimal_value)
{
my_decimal value1, *val1;
my_decimal value2, *val2;
val1= args[0]->val_decimal(&value1);
if ((null_value= args[0]->null_value))
return 0;
val2= args[1]->val_decimal(&value2);
if ((null_value= args[1]->null_value))
VDec2_lazy val(args[0], args[1]);
if ((null_value= val.has_null()))
return 0;
switch (my_decimal_mod(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, decimal_value,
val1, val2)) {
val.m_a.ptr(), val.m_b.ptr())) {
case E_DEC_TRUNCATED:
case E_DEC_OK:
return decimal_value;
@ -1894,10 +1786,10 @@ longlong Item_func_neg::int_op()
my_decimal *Item_func_neg::decimal_op(my_decimal *decimal_value)
{
my_decimal val, *value= args[0]->val_decimal(&val);
if (!(null_value= args[0]->null_value))
VDec value(args[0]);
if (!(null_value= value.is_null()))
{
my_decimal2decimal(value, decimal_value);
my_decimal2decimal(value.ptr(), decimal_value);
my_decimal_neg(decimal_value);
return decimal_value;
}
@ -1992,10 +1884,10 @@ longlong Item_func_abs::int_op()
my_decimal *Item_func_abs::decimal_op(my_decimal *decimal_value)
{
my_decimal val, *value= args[0]->val_decimal(&val);
if (!(null_value= args[0]->null_value))
VDec value(args[0]);
if (!(null_value= value.is_null()))
{
my_decimal2decimal(value, decimal_value);
my_decimal2decimal(value.ptr(), decimal_value);
if (decimal_value->sign())
my_decimal_neg(decimal_value);
return decimal_value;
@ -2317,25 +2209,15 @@ bool Item_func_int_val::fix_length_and_dec()
longlong Item_func_ceiling::int_op()
{
longlong result;
switch (args[0]->result_type()) {
case INT_RESULT:
result= args[0]->val_int();
null_value= args[0]->null_value;
break;
return val_int_from_item(args[0]);
case DECIMAL_RESULT:
{
my_decimal dec_buf, *dec;
if ((dec= Item_func_ceiling::decimal_op(&dec_buf)))
my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result);
else
result= 0;
return VDec_op(this).to_longlong(unsigned_flag);
default:
break;
}
default:
result= (longlong)Item_func_ceiling::real_op();
};
return result;
return (longlong) Item_func_ceiling::real_op();
}
@ -2353,10 +2235,9 @@ double Item_func_ceiling::real_op()
my_decimal *Item_func_ceiling::decimal_op(my_decimal *decimal_value)
{
my_decimal val, *value= args[0]->val_decimal(&val);
if (!(null_value= (args[0]->null_value ||
my_decimal_ceiling(E_DEC_FATAL_ERROR, value,
decimal_value) > 1)))
VDec value(args[0]);
if (!(null_value= (value.is_null() ||
value.round_to(decimal_value, 0, CEILING) > 1)))
return decimal_value;
return 0;
}
@ -2364,25 +2245,19 @@ my_decimal *Item_func_ceiling::decimal_op(my_decimal *decimal_value)
longlong Item_func_floor::int_op()
{
longlong result;
switch (args[0]->result_type()) {
case INT_RESULT:
result= args[0]->val_int();
null_value= args[0]->null_value;
break;
return val_int_from_item(args[0]);
case DECIMAL_RESULT:
{
my_decimal dec_buf, *dec;
if ((dec= Item_func_floor::decimal_op(&dec_buf)))
my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result);
else
result= 0;
break;
return (!(dec= Item_func_floor::decimal_op(&dec_buf))) ? 0 :
dec->to_longlong(unsigned_flag);
}
default:
result= (longlong)Item_func_floor::real_op();
};
return result;
break;
}
return (longlong) Item_func_floor::real_op();
}
@ -2400,10 +2275,9 @@ double Item_func_floor::real_op()
my_decimal *Item_func_floor::decimal_op(my_decimal *decimal_value)
{
my_decimal val, *value= args[0]->val_decimal(&val);
if (!(null_value= (args[0]->null_value ||
my_decimal_floor(E_DEC_FATAL_ERROR, value,
decimal_value) > 1)))
VDec value(args[0]);
if (!(null_value= (value.is_null() ||
value.round_to(decimal_value, 0, FLOOR) > 1)))
return decimal_value;
return 0;
}
@ -2592,16 +2466,16 @@ longlong Item_func_round::int_op()
my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value)
{
my_decimal val, *value= args[0]->val_decimal(&val);
VDec value(args[0]);
longlong dec= args[1]->val_int();
if (dec >= 0 || args[1]->unsigned_flag)
dec= MY_MIN((ulonglong) dec, decimals);
else if (dec < INT_MIN)
dec= INT_MIN;
if (!(null_value= (args[0]->null_value || args[1]->null_value ||
my_decimal_round(E_DEC_FATAL_ERROR, value, (int) dec,
truncate, decimal_value) > 1)))
if (!(null_value= (value.is_null() || args[1]->null_value ||
value.round_to(decimal_value, dec,
truncate ? TRUNCATE : HALF_UP) > 1)))
return decimal_value;
return 0;
}
@ -3021,14 +2895,14 @@ longlong Item_func_field::val_int()
}
else if (cmp_type == DECIMAL_RESULT)
{
my_decimal dec_arg_buf, *dec_arg,
dec_buf, *dec= args[0]->val_decimal(&dec_buf);
if (args[0]->null_value)
VDec dec(args[0]);
if (dec.is_null())
return 0;
my_decimal dec_arg_buf;
for (uint i=1; i < arg_count; i++)
{
dec_arg= args[i]->val_decimal(&dec_arg_buf);
if (!args[i]->null_value && !my_decimal_cmp(dec_arg, dec))
my_decimal *dec_arg= args[i]->val_decimal(&dec_arg_buf);
if (!args[i]->null_value && !dec.cmp(dec_arg))
return (longlong) (i);
}
}
@ -3610,32 +3484,6 @@ String *Item_func_udf_int::val_str(String *str)
}
longlong Item_func_udf_decimal::val_int()
{
my_bool tmp_null_value;
longlong result;
my_decimal dec_buf, *dec= udf.val_decimal(&tmp_null_value, &dec_buf);
null_value= tmp_null_value;
if (null_value)
return 0;
my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result);
return result;
}
double Item_func_udf_decimal::val_real()
{
my_bool tmp_null_value;
double result;
my_decimal dec_buf, *dec= udf.val_decimal(&tmp_null_value, &dec_buf);
null_value= tmp_null_value;
if (null_value)
return 0.0;
my_decimal2double(E_DEC_FATAL_ERROR, dec, &result);
return result;
}
my_decimal *Item_func_udf_decimal::val_decimal(my_decimal *dec_buf)
{
my_decimal *res;
@ -3651,21 +3499,6 @@ my_decimal *Item_func_udf_decimal::val_decimal(my_decimal *dec_buf)
}
String *Item_func_udf_decimal::val_str(String *str)
{
my_bool tmp_null_value;
my_decimal dec_buf, *dec= udf.val_decimal(&tmp_null_value, &dec_buf);
null_value= tmp_null_value;
if (null_value)
return 0;
if (str->length() < DECIMAL_MAX_STR_LENGTH)
str->length(DECIMAL_MAX_STR_LENGTH);
my_decimal_round(E_DEC_FATAL_ERROR, dec, decimals, FALSE, &dec_buf);
my_decimal2string(E_DEC_FATAL_ERROR, &dec_buf, 0, 0, '0', str);
return str;
}
/* Default max_length is max argument length */
bool Item_func_udf_str::fix_length_and_dec()
@ -4763,11 +4596,7 @@ double user_var_entry::val_real(bool *null_value)
case INT_RESULT:
return (double) *(longlong*) value;
case DECIMAL_RESULT:
{
double result;
my_decimal2double(E_DEC_FATAL_ERROR, (my_decimal *)value, &result);
return result;
}
return ((my_decimal *)value)->to_double();
case STRING_RESULT:
return my_atof(value); // This is null terminated
case ROW_RESULT:
@ -4792,11 +4621,7 @@ longlong user_var_entry::val_int(bool *null_value) const
case INT_RESULT:
return *(longlong*) value;
case DECIMAL_RESULT:
{
longlong result;
my_decimal2int(E_DEC_FATAL_ERROR, (my_decimal *)value, 0, &result);
return result;
}
return ((my_decimal *)value)->to_longlong(false);
case STRING_RESULT:
{
int error;

View file

@ -679,12 +679,6 @@ class Item_func_hybrid_field_type: public Item_hybrid_func
DBUG_ASSERT((res != NULL) ^ null_value);
return res;
}
my_decimal *decimal_op_with_null_check(my_decimal *decimal_buffer)
{
my_decimal *res= decimal_op(decimal_buffer);
DBUG_ASSERT((res != NULL) ^ null_value);
return res;
}
bool make_zero_mysql_time(MYSQL_TIME *ltime, ulonglong fuzzydate)
{
bzero(ltime, sizeof(*ltime));
@ -697,10 +691,6 @@ public:
{
return str_op_with_null_check(&str_value);
}
my_decimal *val_decimal_from_decimal_op(my_decimal *dec)
{
return decimal_op_with_null_check(dec);
}
longlong val_int_from_int_op()
{
return int_op();
@ -711,7 +701,6 @@ public:
}
// Value methods that involve conversion
String *val_str_from_decimal_op(String *str);
String *val_str_from_real_op(String *str);
String *val_str_from_int_op(String *str);
String *val_str_from_date_op(String *str);
@ -725,19 +714,16 @@ public:
longlong val_int_from_str_op();
longlong val_int_from_real_op();
longlong val_int_from_decimal_op();
longlong val_int_from_date_op();
longlong val_int_from_time_op();
double val_real_from_str_op();
double val_real_from_decimal_op();
double val_real_from_date_op();
double val_real_from_time_op();
double val_real_from_int_op();
bool get_date_from_str_op(MYSQL_TIME *ltime, ulonglong fuzzydate);
bool get_date_from_real_op(MYSQL_TIME *ltime, ulonglong fuzzydate);
bool get_date_from_decimal_op(MYSQL_TIME *ltime, ulonglong fuzzydate);
bool get_date_from_int_op(MYSQL_TIME *ltime, ulonglong fuzzydate);
public:
@ -1179,12 +1165,12 @@ public:
fix_char_length(my_decimal_precision_to_length_no_truncation(len, dec,
unsigned_flag));
}
String *val_str(String *str);
double val_real();
longlong val_int();
String *val_str(String *str) { return VDec(this).to_string(str); }
double val_real() { return VDec(this).to_double(); }
longlong val_int() { return VDec(this).to_longlong(unsigned_flag); }
my_decimal *val_decimal(my_decimal*);
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
{ return get_date_from_decimal(ltime, fuzzydate); }
{ return VDec(this).to_datetime_with_warn(ltime, fuzzydate, this); }
const Type_handler *type_handler() const { return &type_handler_newdecimal; }
void fix_length_and_dec_generic() {}
bool fix_length_and_dec()
@ -2204,6 +2190,18 @@ protected:
udf_handler udf;
bool is_expensive_processor(void *arg) { return TRUE; }
class VDec_udf: public Dec_ptr_and_buffer
{
public:
VDec_udf(Item_udf_func *func, udf_handler *udf)
{
my_bool tmp_null_value;
m_ptr= udf->val_decimal(&tmp_null_value, &m_buffer);
DBUG_ASSERT(is_null() == tmp_null_value);
func->null_value= is_null();
}
};
public:
Item_udf_func(THD *thd, udf_func *udf_arg):
Item_func(thd), udf(udf_arg) {}
@ -2343,10 +2341,19 @@ public:
Item_udf_func(thd, udf_arg) {}
Item_func_udf_decimal(THD *thd, udf_func *udf_arg, List<Item> &list):
Item_udf_func(thd, udf_arg, list) {}
longlong val_int();
double val_real();
longlong val_int()
{
return VDec_udf(this, &udf).to_longlong(unsigned_flag);
}
double val_real()
{
return VDec_udf(this, &udf).to_double();
}
my_decimal *val_decimal(my_decimal *);
String *val_str(String *str);
String *val_str(String *str)
{
return VDec_udf(this, &udf).to_string_round(str, decimals);
}
const Type_handler *type_handler() const { return &type_handler_newdecimal; }
bool fix_length_and_dec() { fix_num_length_and_dec(); return FALSE; }
Item *get_copy(THD *thd)

View file

@ -2655,12 +2655,10 @@ String *Item_func_format::val_str_ascii(String *str)
if (args[0]->result_type() == DECIMAL_RESULT ||
args[0]->result_type() == INT_RESULT)
{
my_decimal dec_val, rnd_dec, *res;
res= args[0]->val_decimal(&dec_val);
if ((null_value=args[0]->null_value))
VDec res(args[0]);
if ((null_value= res.is_null()))
return 0; /* purecov: inspected */
my_decimal_round(E_DEC_FATAL_ERROR, res, dec, false, &rnd_dec);
my_decimal2string(E_DEC_FATAL_ERROR, &rnd_dec, 0, 0, 0, str);
res.to_string_round(str, dec);
str_length= str->length();
}
else

View file

@ -1640,12 +1640,7 @@ longlong Item_sum_sum::val_int()
if (aggr)
aggr->endup();
if (result_type() == DECIMAL_RESULT)
{
longlong result;
my_decimal2int(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, unsigned_flag,
&result);
return result;
}
return dec_buffs[curr_dec_buff].to_longlong(unsigned_flag);
return val_int_from_real();
}
@ -1656,7 +1651,7 @@ double Item_sum_sum::val_real()
if (aggr)
aggr->endup();
if (result_type() == DECIMAL_RESULT)
my_decimal2double(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, &sum);
sum= dec_buffs[curr_dec_buff].to_double();
return sum;
}
@ -1666,7 +1661,7 @@ String *Item_sum_sum::val_str(String *str)
if (aggr)
aggr->endup();
if (result_type() == DECIMAL_RESULT)
return val_string_from_decimal(str);
return VDec(this).to_string_round(str, decimals);
return val_string_from_real(str);
}
@ -2032,7 +2027,7 @@ String *Item_sum_avg::val_str(String *str)
if (aggr)
aggr->endup();
if (result_type() == DECIMAL_RESULT)
return val_string_from_decimal(str);
return VDec(this).to_string_round(str, decimals);
return val_string_from_real(str);
}
@ -2749,11 +2744,11 @@ void Item_sum_hybrid::reset_field()
}
case DECIMAL_RESULT:
{
my_decimal value_buff, *arg_dec= arg0->val_decimal(&value_buff);
VDec arg_dec(arg0);
if (maybe_null)
{
if (arg0->null_value)
if (arg_dec.is_null())
result_field->set_null();
else
result_field->set_notnull();
@ -2762,9 +2757,7 @@ void Item_sum_hybrid::reset_field()
We must store zero in the field as we will use the field value in
add()
*/
if (!arg_dec) // Null
arg_dec= &decimal_zero;
result_field->store_decimal(arg_dec);
result_field->store_decimal(arg_dec.ptr_or(&decimal_zero));
break;
}
case ROW_RESULT:
@ -2787,15 +2780,10 @@ void Item_sum_sum::reset_field()
DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR);
if (result_type() == DECIMAL_RESULT)
{
my_decimal value, *arg_val;
if (unlikely(direct_added))
arg_val= &direct_sum_decimal;
result_field->store_decimal(&direct_sum_decimal);
else
{
if (!(arg_val= args[0]->val_decimal(&value)))
arg_val= &decimal_zero; // Null
}
result_field->store_decimal(arg_val);
result_field->store_decimal(VDec(args[0]).ptr_or(&decimal_zero));
}
else
{
@ -2848,15 +2836,9 @@ void Item_sum_avg::reset_field()
if (result_type() == DECIMAL_RESULT)
{
longlong tmp;
my_decimal value, *arg_dec= args[0]->val_decimal(&value);
if (args[0]->null_value)
{
arg_dec= &decimal_zero;
tmp= 0;
}
else
tmp= 1;
my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec, res, f_precision, f_scale);
VDec value(args[0]);
tmp= value.is_null() ? 0 : 1;
value.to_binary(res, f_precision, f_scale);
res+= dec_bin_size;
int8store(res, tmp);
}
@ -2923,9 +2905,8 @@ void Item_sum_sum::update_field()
{
if (!result_field->is_null())
{
my_decimal field_value;
my_decimal *field_val= result_field->val_decimal(&field_value);
my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, arg_val, field_val);
my_decimal field_value(result_field);
my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, arg_val, &field_value);
result_field->store_decimal(dec_buffs);
}
else
@ -2992,15 +2973,14 @@ void Item_sum_avg::update_field()
if (result_type() == DECIMAL_RESULT)
{
my_decimal value, *arg_val= args[0]->val_decimal(&value);
if (!args[0]->null_value)
VDec tmp(args[0]);
if (!tmp.is_null())
{
binary2my_decimal(E_DEC_FATAL_ERROR, res,
dec_buffs + 1, f_precision, f_scale);
field_count= sint8korr(res + dec_bin_size);
my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, arg_val, dec_buffs + 1);
my_decimal2binary(E_DEC_FATAL_ERROR, dec_buffs,
res, f_precision, f_scale);
my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, tmp.ptr(), dec_buffs + 1);
dec_buffs->to_binary(res, f_precision, f_scale);
res+= dec_bin_size;
field_count++;
int8store(res, field_count);
@ -3195,9 +3175,7 @@ my_decimal *Item_avg_field_decimal::val_decimal(my_decimal *dec_buf)
if ((null_value= !count))
return 0;
my_decimal dec_count, dec_field;
binary2my_decimal(E_DEC_FATAL_ERROR,
field->ptr, &dec_field, f_precision, f_scale);
my_decimal dec_count, dec_field(field->ptr, f_precision, f_scale);
int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &dec_count);
my_decimal_div(E_DEC_FATAL_ERROR, dec_buf,
&dec_field, &dec_count, prec_increment);
@ -3311,24 +3289,6 @@ my_decimal *Item_sum_udf_float::val_decimal(my_decimal *dec)
}
String *Item_sum_udf_decimal::val_str(String *str)
{
return val_string_from_decimal(str);
}
double Item_sum_udf_decimal::val_real()
{
return val_real_from_decimal();
}
longlong Item_sum_udf_decimal::val_int()
{
return val_int_from_decimal();
}
my_decimal *Item_sum_udf_decimal::val_decimal(my_decimal *dec_buf)
{
my_decimal *res;

View file

@ -1450,9 +1450,18 @@ public:
dec_bin_size(item->dec_bin_size)
{ }
const Type_handler *type_handler() const { return &type_handler_newdecimal; }
double val_real() { return val_real_from_decimal(); }
longlong val_int() { return val_int_from_decimal(); }
String *val_str(String *str) { return val_string_from_decimal(str); }
double val_real()
{
return VDec(this).to_double();
}
longlong val_int()
{
return VDec(this).to_longlong(unsigned_flag);
}
String *val_str(String *str)
{
return VDec(this).to_string_round(str, decimals);
}
my_decimal *val_decimal(my_decimal *);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_avg_field_decimal>(thd, this); }
@ -1656,9 +1665,18 @@ public:
Item_udf_sum(thd, udf_arg, list) {}
Item_sum_udf_decimal(THD *thd, Item_sum_udf_decimal *item)
:Item_udf_sum(thd, item) {}
String *val_str(String *);
double val_real();
longlong val_int();
String *val_str(String *str)
{
return VDec(this).to_string_round(str, decimals);
}
double val_real()
{
return VDec(this).to_double();
}
longlong val_int()
{
return VDec(this).to_longlong(unsigned_flag);
}
my_decimal *val_decimal(my_decimal *);
const Type_handler *type_handler() const { return &type_handler_newdecimal; }
bool fix_length_and_dec() { fix_num_length_and_dec(); return FALSE; }

View file

@ -1334,16 +1334,16 @@ bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval)
bzero((char*) interval,sizeof(*interval));
if (int_type == INTERVAL_SECOND && args->decimals)
{
my_decimal decimal_value, *val;
VDec val(args);
ulonglong second;
ulong second_part;
if (!(val= args->val_decimal(&decimal_value)))
if (val.is_null())
return true;
interval->neg= my_decimal2seconds(val, &second, &second_part);
interval->neg= my_decimal2seconds(val.ptr(), &second, &second_part);
if (second == LONGLONG_MAX)
{
THD *thd= current_thd;
ErrConvDecimal err(val);
ErrConvDecimal err(val.ptr());
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE,
ER_THD(thd, ER_TRUNCATED_WRONG_VALUE), "DECIMAL",

View file

@ -513,11 +513,11 @@ void Item_sum_hybrid_simple::reset_field()
}
case DECIMAL_RESULT:
{
my_decimal value_buff, *arg_dec= args[0]->val_decimal(&value_buff);
VDec arg_dec(args[0]);
if (maybe_null)
{
if (args[0]->null_value)
if (arg_dec.is_null())
result_field->set_null();
else
result_field->set_notnull();
@ -526,9 +526,7 @@ void Item_sum_hybrid_simple::reset_field()
We must store zero in the field as we will use the field value in
add()
*/
if (!arg_dec) // Null
arg_dec= &decimal_zero;
result_field->store_decimal(arg_dec);
result_field->store_decimal(arg_dec.ptr_or(&decimal_zero));
break;
}
case ROW_RESULT:

View file

@ -2732,9 +2732,7 @@ log_event_print_value(IO_CACHE *file, PRINT_EVENT_INFO *print_event_info,
goto return_null;
uint bin_size= my_decimal_get_binary_size(precision, decimals);
my_decimal dec;
binary2my_decimal(E_DEC_FATAL_ERROR, (uchar*) ptr, &dec,
precision, decimals);
my_decimal dec((const uchar *) ptr, precision, decimals);
int length= DECIMAL_MAX_STR_LENGTH;
char buff[DECIMAL_MAX_STR_LENGTH + 1];
decimal2string(&dec, buff, &length, 0, 0, 0);
@ -9038,11 +9036,8 @@ void User_var_log_event::pack_info(Protocol* protocol)
String buf(buf_mem, sizeof(buf_mem), system_charset_info);
char buf2[DECIMAL_MAX_STR_LENGTH+1];
String str(buf2, sizeof(buf2), &my_charset_bin);
my_decimal dec;
buf.length(0);
binary2my_decimal(E_DEC_FATAL_ERROR, (uchar*) (val+2), &dec, val[0],
val[1]);
my_decimal2string(E_DEC_FATAL_ERROR, &dec, 0, 0, 0, &str);
my_decimal((const uchar *) (val + 2), val[0], val[1]).to_string(&str);
if (user_var_append_name_part(protocol->thd, &buf, name, name_len) ||
buf.append(buf2))
return;

View file

@ -20,6 +20,7 @@
#ifndef MYSQL_CLIENT
#include "sql_class.h" // THD
#include "field.h"
#endif
#define DIG_BASE 1000000000
@ -95,9 +96,8 @@ int decimal_operation_results(int result, const char *value, const char *type)
@retval E_DEC_OOM
*/
int my_decimal2string(uint mask, const my_decimal *d,
uint fixed_prec, uint fixed_dec,
char filler, String *str)
int my_decimal::to_string_native(String *str, uint fixed_prec, uint fixed_dec,
char filler, uint mask) const
{
/*
Calculate the size of the string: For DECIMAL(a,b), fixed_prec==a
@ -113,11 +113,11 @@ int my_decimal2string(uint mask, const my_decimal *d,
*/
int length= (fixed_prec
? (fixed_prec + ((fixed_prec == fixed_dec) ? 1 : 0) + 1)
: my_decimal_string_length(d));
: my_decimal_string_length(this));
int result;
if (str->alloc(length))
return check_result(mask, E_DEC_OOM);
result= decimal2string((decimal_t*) d, (char*) str->ptr(),
result= decimal2string(this, (char*) str->ptr(),
&length, (int)fixed_prec, fixed_dec,
filler);
str->length(length);
@ -156,8 +156,8 @@ str_set_decimal(uint mask, const my_decimal *val,
{
if (!(cs->state & MY_CS_NONASCII))
{
/* For ASCII-compatible character sets we can use my_decimal2string */
my_decimal2string(mask, val, fixed_prec, fixed_dec, filler, str);
// For ASCII-compatible character sets we can use to_string_native()
val->to_string_native(str, fixed_prec, fixed_dec, filler, mask);
str->set_charset(cs);
return FALSE;
}
@ -165,14 +165,13 @@ str_set_decimal(uint mask, const my_decimal *val,
{
/*
For ASCII-incompatible character sets (like UCS2) we
call my_decimal2string() on a temporary buffer first,
call my_string_native() on a temporary buffer first,
and then convert the result to the target character
with help of str->copy().
*/
uint errors;
char buf[DECIMAL_MAX_STR_LENGTH];
String tmp(buf, sizeof(buf), &my_charset_latin1);
my_decimal2string(mask, val, fixed_prec, fixed_dec, filler, &tmp);
StringBuffer<DECIMAL_MAX_STR_LENGTH> tmp;
val->to_string_native(&tmp, fixed_prec, fixed_dec, filler, mask);
return str->copy(tmp.ptr(), tmp.length(), &my_charset_latin1, cs, &errors);
}
}
@ -182,7 +181,7 @@ str_set_decimal(uint mask, const my_decimal *val,
Convert from decimal to binary representation
SYNOPSIS
my_decimal2binary()
to_binary()
mask error processing mask
d number for conversion
bin pointer to buffer where to write result
@ -199,12 +198,11 @@ str_set_decimal(uint mask, const my_decimal *val,
E_DEC_OVERFLOW
*/
int my_decimal2binary(uint mask, const my_decimal *d, uchar *bin, int prec,
int scale)
int my_decimal::to_binary(uchar *bin, int prec, int scale, uint mask) const
{
int err1= E_DEC_OK, err2;
my_decimal rounded;
my_decimal2decimal(d, &rounded);
my_decimal2decimal(this, &rounded);
rounded.frac= decimal_actual_fraction(&rounded);
if (scale < rounded.frac)
{
@ -368,6 +366,26 @@ int my_decimal2int(uint mask, const decimal_t *d, bool unsigned_flag,
}
longlong my_decimal::to_longlong(bool unsigned_flag) const
{
longlong result;
my_decimal2int(E_DEC_FATAL_ERROR, this, unsigned_flag, &result);
return result;
}
my_decimal::my_decimal(Field *field)
{
init();
DBUG_ASSERT(!field->is_null());
#ifndef DBUG_OFF
my_decimal *dec=
#endif
field->val_decimal(this);
DBUG_ASSERT(dec == this);
}
#ifndef DBUG_OFF
/* routines for debugging print */

View file

@ -39,6 +39,7 @@ C_MODE_START
C_MODE_END
class String;
class Field;
typedef struct st_mysql_time MYSQL_TIME;
/**
@ -63,6 +64,25 @@ inline int my_decimal_int_part(uint precision, uint decimals)
}
#ifndef MYSQL_CLIENT
int decimal_operation_results(int result, const char *value, const char *type);
#else
inline int decimal_operation_results(int result, const char *value,
const char *type)
{
return result;
}
#endif /*MYSQL_CLIENT*/
inline int check_result(uint mask, int result)
{
if (result & mask)
decimal_operation_results(result, "", "DECIMAL");
return result;
}
/**
my_decimal class limits 'decimal_t' type to what we need in MySQL.
@ -125,6 +145,12 @@ public:
{
init();
}
my_decimal(const uchar *bin, int prec, int scale)
{
init();
check_result(E_DEC_FATAL_ERROR, bin2decimal(bin, this, prec, scale));
}
my_decimal(Field *field);
~my_decimal()
{
sanity_check();
@ -141,7 +167,59 @@ public:
bool sign() const { return decimal_t::sign; }
void sign(bool s) { decimal_t::sign= s; }
uint precision() const { return intg + frac; }
void set_zero()
{
/*
We need the up-cast here, since my_decimal has sign() member functions,
which conflicts with decimal_t::sign
(and decimal_make_zero is a macro, rather than a funcion).
*/
decimal_make_zero(static_cast<decimal_t*>(this));
}
int cmp(const my_decimal *other) const
{
return decimal_cmp(this, other);
}
#ifndef MYSQL_CLIENT
bool to_bool() const
{
return !decimal_is_zero(this);
}
double to_double() const
{
double res;
decimal2double(this, &res);
return res;
}
longlong to_longlong(bool unsigned_flag) const;
// Convert to string returning decimal2string() error code
int to_string_native(String *to, uint prec, uint dec, char filler,
uint mask= E_DEC_FATAL_ERROR) const;
// Convert to string returning the String pointer
String *to_string(String *to, uint prec, uint dec, char filler) const
{
return to_string_native(to, prec, dec, filler) ? NULL : to;
}
String *to_string(String *to) const
{
return to_string(to, 0, 0, 0);
}
String *to_string_round(String *to, uint scale, my_decimal *round_buff) const
{
(void) round_to(round_buff, scale, HALF_UP); // QQ: check result?
return round_buff->to_string(to);
}
int round_to(my_decimal *to, uint scale, decimal_round_mode mode,
int mask= E_DEC_FATAL_ERROR) const
{
return check_result(mask, decimal_round(this, to, (int) scale, mode));
}
bool to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate,
const char *field_name);
int to_binary(uchar *bin, int prec, int scale,
uint mask= E_DEC_FATAL_ERROR) const;
#endif
/** Swap two my_decimal values */
void swap(my_decimal &rhs)
{
@ -164,16 +242,6 @@ bool str_set_decimal(uint mask, const my_decimal *val, uint fixed_prec,
extern my_decimal decimal_zero;
#ifndef MYSQL_CLIENT
int decimal_operation_results(int result, const char *value, const char *type);
#else
inline int decimal_operation_results(int result, const char *value,
const char *type)
{
return result;
}
#endif /*MYSQL_CLIENT*/
inline
void max_my_decimal(my_decimal *to, int precision, int frac)
{
@ -187,13 +255,6 @@ inline void max_internal_decimal(my_decimal *to)
max_my_decimal(to, DECIMAL_MAX_PRECISION, 0);
}
inline int check_result(uint mask, int result)
{
if (result & mask)
decimal_operation_results(result, "", "DECIMAL");
return result;
}
inline int check_result_and_overflow(uint mask, int result, my_decimal *val)
{
if (check_result(mask, result) & E_DEC_OVERFLOW)
@ -271,10 +332,6 @@ void my_decimal2decimal(const my_decimal *from, my_decimal *to)
}
int my_decimal2binary(uint mask, const my_decimal *d, uchar *bin, int prec,
int scale);
inline
int binary2my_decimal(uint mask, const uchar *bin, my_decimal *d, int prec,
int scale)
@ -286,12 +343,7 @@ int binary2my_decimal(uint mask, const uchar *bin, my_decimal *d, int prec,
inline
int my_decimal_set_zero(my_decimal *d)
{
/*
We need the up-cast here, since my_decimal has sign() member functions,
which conflicts with decimal_t::sign
(and decimal_make_zero is a macro, rather than a funcion).
*/
decimal_make_zero(static_cast<decimal_t*>(d));
d->set_zero();
return 0;
}
@ -303,40 +355,12 @@ bool my_decimal_is_zero(const my_decimal *decimal_value)
}
inline
int my_decimal_round(uint mask, const my_decimal *from, int scale,
bool truncate, my_decimal *to)
{
return check_result(mask, decimal_round(from, to, scale,
(truncate ? TRUNCATE : HALF_UP)));
}
inline
int my_decimal_floor(uint mask, const my_decimal *from, my_decimal *to)
{
return check_result(mask, decimal_round(from, to, 0, FLOOR));
}
inline
int my_decimal_ceiling(uint mask, const my_decimal *from, my_decimal *to)
{
return check_result(mask, decimal_round(from, to, 0, CEILING));
}
inline bool str_set_decimal(const my_decimal *val, String *str,
CHARSET_INFO *cs)
{
return str_set_decimal(E_DEC_FATAL_ERROR, val, 0, 0, 0, str, cs);
}
#ifndef MYSQL_CLIENT
class String;
int my_decimal2string(uint mask, const my_decimal *d, uint fixed_prec,
uint fixed_dec, char filler, String *str);
#endif
bool my_decimal2seconds(const my_decimal *d, ulonglong *sec, ulong *microsec);

View file

@ -1195,9 +1195,8 @@ bool Protocol_text::store_decimal(const my_decimal *d)
field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL);
field_pos++;
#endif
char buff[DECIMAL_MAX_STR_LENGTH];
String str(buff, sizeof(buff), &my_charset_bin);
(void) my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str);
StringBuffer<DECIMAL_MAX_STR_LENGTH> str;
(void) d->to_string(&str);
return net_store_data((uchar*) str.ptr(), str.length());
}
@ -1446,9 +1445,8 @@ bool Protocol_binary::store_decimal(const my_decimal *d)
field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL);
field_pos++;
#endif
char buff[DECIMAL_MAX_STR_LENGTH];
String str(buff, sizeof(buff), &my_charset_bin);
(void) my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str);
StringBuffer<DECIMAL_MAX_STR_LENGTH> str;
(void) d->to_string(&str);
return store(str.ptr(), str.length(), str.charset());
}

View file

@ -478,30 +478,28 @@ void field_real::add()
void field_decimal::add()
{
/*TODO - remove rounding stuff after decimal_div returns proper frac */
my_decimal dec_buf, *dec= item->val_decimal(&dec_buf);
my_decimal rounded;
VDec vdec(item);
uint length;
TREE_ELEMENT *element;
if (item->null_value)
if (vdec.is_null())
{
nulls++;
return;
}
my_decimal_round(E_DEC_FATAL_ERROR, dec, item->decimals, FALSE,&rounded);
dec= &rounded;
my_decimal dec;
vdec.round_to(&dec, item->decimals, HALF_UP);
length= my_decimal_string_length(dec);
length= my_decimal_string_length(&dec);
if (decimal_is_zero(dec))
if (decimal_is_zero(&dec))
empty++;
if (room_in_tree)
{
uchar buf[DECIMAL_MAX_FIELD_SIZE];
my_decimal2binary(E_DEC_FATAL_ERROR, dec, buf,
item->max_length, item->decimals);
dec.to_binary(buf, item->max_length, item->decimals);
if (!(element = tree_insert(&tree, (void*)buf, 0, tree.custom_arg)))
{
room_in_tree = 0; // Remove tree, out of RAM ?
@ -521,18 +519,18 @@ void field_decimal::add()
if (!found)
{
found = 1;
min_arg = max_arg = sum[0] = *dec;
my_decimal_mul(E_DEC_FATAL_ERROR, sum_sqr, dec, dec);
min_arg = max_arg = sum[0] = dec;
my_decimal_mul(E_DEC_FATAL_ERROR, sum_sqr, &dec, &dec);
cur_sum= 0;
min_length = max_length = length;
}
else if (!decimal_is_zero(dec))
else if (!decimal_is_zero(&dec))
{
int next_cur_sum= cur_sum ^ 1;
my_decimal sqr_buf;
my_decimal_add(E_DEC_FATAL_ERROR, sum+next_cur_sum, sum+cur_sum, dec);
my_decimal_mul(E_DEC_FATAL_ERROR, &sqr_buf, dec, dec);
my_decimal_add(E_DEC_FATAL_ERROR, sum+next_cur_sum, sum+cur_sum, &dec);
my_decimal_mul(E_DEC_FATAL_ERROR, &sqr_buf, &dec, &dec);
my_decimal_add(E_DEC_FATAL_ERROR,
sum_sqr+next_cur_sum, sum_sqr+cur_sum, &sqr_buf);
cur_sum= next_cur_sum;
@ -540,13 +538,13 @@ void field_decimal::add()
min_length = length;
if (length > max_length)
max_length = length;
if (my_decimal_cmp(dec, &min_arg) < 0)
if (dec.cmp(&min_arg) < 0)
{
min_arg= *dec;
min_arg= dec;
}
if (my_decimal_cmp(dec, &max_arg) > 0)
if (dec.cmp(&max_arg) > 0)
{
max_arg= *dec;
max_arg= dec;
}
}
}
@ -1000,7 +998,7 @@ void field_decimal::get_opt_type(String *answer,
uint length;
my_decimal_set_zero(&zero);
my_bool is_unsigned= (my_decimal_cmp(&zero, &min_arg) >= 0);
my_bool is_unsigned= (zero.cmp(&min_arg) >= 0);
length= sprintf(buff, "DECIMAL(%d, %d)",
(int) (max_length - (item->decimals ? 1 : 0)),
@ -1013,14 +1011,14 @@ void field_decimal::get_opt_type(String *answer,
String *field_decimal::get_min_arg(String *str)
{
my_decimal2string(E_DEC_FATAL_ERROR, &min_arg, 0, 0, '0', str);
min_arg.to_string_native(str, 0, 0, '0');
return str;
}
String *field_decimal::get_max_arg(String *str)
{
my_decimal2string(E_DEC_FATAL_ERROR, &max_arg, 0, 0, '0', str);
max_arg.to_string_native(str, 0, 0, '0');
return str;
}
@ -1038,10 +1036,10 @@ String *field_decimal::avg(String *s, ha_rows rows)
int2my_decimal(E_DEC_FATAL_ERROR, rows - nulls, FALSE, &num);
my_decimal_div(E_DEC_FATAL_ERROR, &avg_val, sum+cur_sum, &num, prec_increment);
/* TODO remove this after decimal_div returns proper frac */
my_decimal_round(E_DEC_FATAL_ERROR, &avg_val,
avg_val.round_to(&rounded_avg,
MY_MIN(sum[cur_sum].frac + prec_increment, DECIMAL_MAX_SCALE),
FALSE,&rounded_avg);
my_decimal2string(E_DEC_FATAL_ERROR, &rounded_avg, 0, 0, '0', s);
HALF_UP);
rounded_avg.to_string_native(s, 0, 0, '0');
return s;
}
@ -1054,7 +1052,6 @@ String *field_decimal::std(String *s, ha_rows rows)
return s;
}
my_decimal num, tmp, sum2, sum2d;
double std_sqr;
int prec_increment= current_thd->variables.div_precincrement;
int2my_decimal(E_DEC_FATAL_ERROR, rows - nulls, FALSE, &num);
@ -1062,7 +1059,7 @@ String *field_decimal::std(String *s, ha_rows rows)
my_decimal_div(E_DEC_FATAL_ERROR, &tmp, &sum2, &num, prec_increment);
my_decimal_sub(E_DEC_FATAL_ERROR, &sum2, sum_sqr+cur_sum, &tmp);
my_decimal_div(E_DEC_FATAL_ERROR, &tmp, &sum2, &num, prec_increment);
my_decimal2double(E_DEC_FATAL_ERROR, &tmp, &std_sqr);
double std_sqr= tmp.to_double();
s->set_real(((double) std_sqr <= 0.0 ? 0.0 : sqrt(std_sqr)),
MY_MIN(item->decimals + prec_increment, NOT_FIXED_DEC), my_thd_charset);
@ -1114,12 +1111,9 @@ int collect_decimal(uchar *element, element_count count,
info->str->append(',');
else
info->found = 1;
my_decimal dec;
binary2my_decimal(E_DEC_FATAL_ERROR, element, &dec,
info->item->max_length, info->item->decimals);
my_decimal dec(element, info->item->max_length, info->item->decimals);
info->str->append('\'');
my_decimal2string(E_DEC_FATAL_ERROR, &dec, 0, 0, '0', &s);
dec.to_string_native(&s, 0, 0, '0');
info->str->append(s);
info->str->append('\'');
return 0;

View file

@ -3587,18 +3587,15 @@ bool select_max_min_finder_subselect::cmp_int()
bool select_max_min_finder_subselect::cmp_decimal()
{
Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
my_decimal cval, *cvalue= cache->val_decimal(&cval);
my_decimal mval, *mvalue= maxmin->val_decimal(&mval);
VDec cvalue(cache), mvalue(maxmin);
/* Ignore NULLs for ANY and keep them for ALL subqueries */
if (cache->null_value)
return (is_all && !maxmin->null_value) || (!is_all && maxmin->null_value);
if (maxmin->null_value)
if (cvalue.is_null())
return (is_all && !mvalue.is_null()) || (!is_all && mvalue.is_null());
if (mvalue.is_null())
return !is_all;
if (fmax)
return (my_decimal_cmp(cvalue, mvalue) > 0) ;
return (my_decimal_cmp(cvalue,mvalue) < 0);
return fmax ? cvalue.cmp(mvalue) > 0 : cvalue.cmp(mvalue) < 0;
}
bool select_max_min_finder_subselect::cmp_str()

View file

@ -5298,16 +5298,8 @@ bool Protocol_local::store_longlong(longlong value, bool unsigned_flag)
bool Protocol_local::store_decimal(const my_decimal *value)
{
char buf[DECIMAL_MAX_STR_LENGTH];
String str(buf, sizeof (buf), &my_charset_bin);
int rc;
rc= my_decimal2string(E_DEC_FATAL_ERROR, value, 0, 0, 0, &str);
if (rc)
return TRUE;
return store_column(str.ptr(), str.length());
StringBuffer<DECIMAL_MAX_STR_LENGTH> str;
return value->to_string(&str) ? store_column(str.ptr(), str.length()) : true;
}

View file

@ -1511,3 +1511,10 @@ void unpack_time(longlong packed, MYSQL_TIME *my_time,
break;
}
}
bool my_decimal::to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate,
const char *field_name)
{
return decimal_to_datetime_with_warn(this, to, fuzzydate, field_name);
}

View file

@ -130,6 +130,37 @@ bool Type_handler_data::init()
Type_handler_data *type_handler_data= NULL;
void VDec::set(Item *item)
{
m_ptr= item->val_decimal(&m_buffer);
DBUG_ASSERT((m_ptr == NULL) == item->null_value);
}
VDec::VDec(Item *item)
{
m_ptr= item->val_decimal(&m_buffer);
DBUG_ASSERT((m_ptr == NULL) == item->null_value);
}
VDec_op::VDec_op(Item_func_hybrid_field_type *item)
{
m_ptr= item->decimal_op(&m_buffer);
DBUG_ASSERT((m_ptr == NULL) == item->null_value);
}
bool Dec_ptr::to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate,
Item *item)
{
if (to_datetime_with_warn(to, fuzzydate, item->field_name_or_null()))
return item->null_value|= item->make_zero_date(to, fuzzydate);
return item->null_value= false;
}
my_decimal *Temporal::to_decimal(my_decimal *to) const
{
return date2my_decimal(this, to);
@ -3419,15 +3450,6 @@ bool Type_handler_int_result::Item_val_bool(Item *item) const
return item->val_int() != 0;
}
bool Type_handler_decimal_result::Item_val_bool(Item *item) const
{
my_decimal decimal_value;
my_decimal *val= item->val_decimal(&decimal_value);
if (val)
return !my_decimal_is_zero(val);
return false;
}
bool Type_handler_temporal_result::Item_val_bool(Item *item) const
{
return item->val_real() != 0.0;
@ -3462,13 +3484,6 @@ bool Type_handler_real_result::Item_get_date(Item *item, MYSQL_TIME *ltime,
}
bool Type_handler_decimal_result::Item_get_date(Item *item, MYSQL_TIME *ltime,
ulonglong fuzzydate) const
{
return item->get_date_from_decimal(ltime, fuzzydate);
}
bool Type_handler_string_result::Item_get_date(Item *item, MYSQL_TIME *ltime,
ulonglong fuzzydate) const
{
@ -3532,12 +3547,6 @@ longlong Type_handler_int_result::
return item->val_int_unsigned_typecast_from_int();
}
longlong Type_handler_decimal_result::
Item_val_int_unsigned_typecast(Item *item) const
{
return item->val_int_unsigned_typecast_from_decimal();
}
longlong Type_handler_temporal_result::
Item_val_int_unsigned_typecast(Item *item) const
{
@ -3598,7 +3607,7 @@ Type_handler_decimal_result::Item_func_hybrid_field_type_val_str(
Item_func_hybrid_field_type *item,
String *str) const
{
return item->val_str_from_decimal_op(str);
return VDec_op(item).to_string_round(str, item->decimals);
}
@ -3607,7 +3616,7 @@ Type_handler_decimal_result::Item_func_hybrid_field_type_val_real(
Item_func_hybrid_field_type *item)
const
{
return item->val_real_from_decimal_op();
return VDec_op(item).to_double();
}
@ -3616,7 +3625,7 @@ Type_handler_decimal_result::Item_func_hybrid_field_type_val_int(
Item_func_hybrid_field_type *item)
const
{
return item->val_int_from_decimal_op();
return VDec_op(item).to_longlong(item->unsigned_flag);
}
@ -3625,7 +3634,7 @@ Type_handler_decimal_result::Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *item,
my_decimal *dec) const
{
return item->val_decimal_from_decimal_op(dec);
return VDec_op(item).to_decimal(dec);
}
@ -3635,7 +3644,7 @@ Type_handler_decimal_result::Item_func_hybrid_field_type_get_date(
MYSQL_TIME *ltime,
ulonglong fuzzydate) const
{
return item->get_date_from_decimal_op(ltime, fuzzydate);
return VDec_op(item).to_datetime_with_warn(ltime, fuzzydate, item);
}
@ -4182,7 +4191,7 @@ String *Type_handler_int_result::
String *Type_handler_decimal_result::
Item_func_min_max_val_str(Item_func_min_max *func, String *str) const
{
return func->val_string_from_decimal(str);
return VDec(func).to_string_round(str, func->decimals);
}
@ -5628,11 +5637,10 @@ Item *Type_handler_real_result::
Item *Type_handler_decimal_result::
make_const_item_for_comparison(THD *thd, Item *item, const Item *cmp) const
{
my_decimal decimal_value;
my_decimal *result= item->val_decimal(&decimal_value);
if (item->null_value)
VDec result(item);
if (result.is_null())
return new (thd->mem_root) Item_null(thd, item->name.str);
return new (thd->mem_root) Item_decimal(thd, item->name.str, result,
return new (thd->mem_root) Item_decimal(thd, item->name.str, result.ptr(),
item->max_length, item->decimals);
}
@ -6617,7 +6625,7 @@ Type_handler_decimal_result::Item_const_eq(const Item_const *a,
{
const my_decimal *da= a->const_ptr_my_decimal();
const my_decimal *db= b->const_ptr_my_decimal();
return !my_decimal_cmp(da, db) &&
return !da->cmp(db) &&
(!binary_cmp ||
a->get_type_all_attributes_from_const()->decimals ==
b->get_type_all_attributes_from_const()->decimals);
@ -6716,18 +6724,6 @@ bool Type_handler_string_result::Item_eq_value(THD *thd,
}
bool Type_handler_decimal_result::Item_eq_value(THD *thd,
const Type_cmp_attributes *attr,
Item *a, Item *b) const
{
my_decimal *va, *vb;
my_decimal cmp_value1, cmp_value2;
return (va= a->val_decimal(&cmp_value1)) &&
(vb= b->val_decimal(&cmp_value2)) &&
!my_decimal_cmp(va, vb);
}
/***************************************************************************/
void Type_handler_var_string::
@ -6823,19 +6819,6 @@ int Type_handler_int_result::stored_field_cmp_to_item(THD *thd,
}
int Type_handler_decimal_result::stored_field_cmp_to_item(THD *thd,
Field *field,
Item *item) const
{
my_decimal item_buf, *item_val, field_buf, *field_val;
item_val= item->val_decimal(&item_buf);
if (item->null_value)
return 0;
field_val= field->val_decimal(&field_buf);
return my_decimal_cmp(field_val, item_val);
}
int Type_handler_real_result::stored_field_cmp_to_item(THD *thd,
Field *field,
Item *item) const

View file

@ -90,6 +90,126 @@ enum scalar_comparison_op
};
class Dec_ptr
{
protected:
my_decimal *m_ptr;
Dec_ptr() { }
public:
bool is_null() const { return m_ptr == NULL; }
const my_decimal *ptr() const { return m_ptr; }
const my_decimal *ptr_or(const my_decimal *def) const
{
return m_ptr ? m_ptr : def;
}
my_decimal *to_decimal(my_decimal *to) const
{
if (!m_ptr)
return NULL;
*to= *m_ptr;
return to;
}
double to_double() const { return m_ptr ? m_ptr->to_double() : 0.0; }
longlong to_longlong(bool unsigned_flag)
{ return m_ptr ? m_ptr->to_longlong(unsigned_flag) : 0; }
bool to_bool() const { return m_ptr ? m_ptr->to_bool() : false; }
bool to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate,
const char *field_name)
{
return m_ptr ? m_ptr->to_datetime_with_warn(to, fuzzydate, field_name) :
true;
}
bool to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate, Item *item);
String *to_string(String *to) const
{
return m_ptr ? m_ptr->to_string(to) : NULL;
}
String *to_string(String *to, uint prec, uint dec, char filler)
{
return m_ptr ? m_ptr->to_string(to, prec, dec, filler) : NULL;
}
int to_binary(uchar *bin, int prec, int scale) const
{
return (m_ptr ? m_ptr : &decimal_zero)->to_binary(bin, prec, scale);
}
int cmp(const my_decimal *dec) const
{
DBUG_ASSERT(m_ptr);
DBUG_ASSERT(dec);
return m_ptr->cmp(dec);
}
int cmp(const Dec_ptr &other) const
{
return cmp(other.m_ptr);
}
};
// A helper class to handle results of val_decimal(), date_op(), etc.
class Dec_ptr_and_buffer: public Dec_ptr
{
protected:
my_decimal m_buffer;
public:
int round_to(my_decimal *to, uint scale, decimal_round_mode mode)
{
DBUG_ASSERT(m_ptr);
return m_ptr->round_to(to, scale, mode);
}
int round_self(uint scale, decimal_round_mode mode)
{
return round_to(&m_buffer, scale, mode);
}
String *to_string_round(String *to, uint dec)
{
/*
decimal_round() allows from==to
So it's save even if m_ptr points to m_buffer before this call:
*/
return m_ptr ? m_ptr->to_string_round(to, dec, &m_buffer) : NULL;
}
};
// A helper class to handle val_decimal() results.
class VDec: public Dec_ptr_and_buffer
{
public:
VDec(): Dec_ptr_and_buffer() { }
VDec(Item *item);
void set(Item *a);
};
// A helper class to handler decimal_op() results.
class VDec_op: public Dec_ptr_and_buffer
{
public:
VDec_op(Item_func_hybrid_field_type *item);
};
/*
Get and cache val_decimal() values for two items.
If the first value appears to be NULL, the second value is not evaluated.
*/
class VDec2_lazy
{
public:
VDec m_a;
VDec m_b;
VDec2_lazy(Item *a, Item *b) :m_a(a)
{
if (!m_a.is_null())
m_b.set(b);
}
bool has_null() const
{
return m_a.is_null() || m_b.is_null();
}
};
/*
A heler class to perform additive operations between
two MYSQL_TIME structures and return the result as a
@ -2289,7 +2409,11 @@ public:
Item_result cmp_type() const { return DECIMAL_RESULT; }
virtual ~Type_handler_decimal_result() {};
const Type_handler *type_handler_for_comparison() const;
int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const;
int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const
{
VDec item_val(item);
return item_val.is_null() ? 0 : my_decimal(field).cmp(item_val.ptr());
}
bool subquery_type_allows_materialization(const Item *inner,
const Item *outer) const;
Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const;
@ -2304,7 +2428,11 @@ public:
bool Item_const_eq(const Item_const *a, const Item_const *b,
bool binary_cmp) const;
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
Item *a, Item *b) const;
Item *a, Item *b) const
{
VDec va(a), vb(b);
return va.ptr() && vb.ptr() && !va.cmp(vb);
}
uint Item_decimal_precision(const Item *item) const;
bool Item_save_in_value(Item *item, st_value *value) const;
void Item_param_set_param_func(Item_param *param,
@ -2331,10 +2459,19 @@ public:
bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const;
bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const;
bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const;
bool Item_val_bool(Item *item) const;
bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const;
bool Item_val_bool(Item *item) const
{
return VDec(item).to_bool();
}
bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const
{
return VDec(item).to_datetime_with_warn(ltime, fuzzydate, item);
}
longlong Item_val_int_signed_typecast(Item *item) const;
longlong Item_val_int_unsigned_typecast(Item *item) const;
longlong Item_val_int_unsigned_typecast(Item *item) const
{
return VDec(item).to_longlong(true);
}
String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const;
String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
String *) const;

View file

@ -2745,14 +2745,10 @@ PFIL ha_connect::CondFilter(PGLOBAL g, Item *cond)
*((int*)pp->Value)= (int) Temporal_hybrid(pval).to_longlong();
break;
case REAL_RESULT:
pp->Type= TYPE_DOUBLE;
pp->Value= PlugSubAlloc(g, NULL, sizeof(double));
*((double*)pp->Value)= pval->val_real();
break;
case DECIMAL_RESULT:
pp->Type= TYPE_DOUBLE;
pp->Value= PlugSubAlloc(g, NULL, sizeof(double));
*((double*)pp->Value)= pval->val_real_from_decimal();
*((double*)pp->Value)= pval->val_real();
break;
case ROW_RESULT:
DBUG_ASSERT(0);