diff options
author | Alexander Barkov <bar@mariadb.com> | 2018-08-07 10:48:42 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.com> | 2018-08-07 10:48:42 +0400 |
commit | cb7b5fbf1cf7c5bcd0509e428a53a8b8d6fbba0f (patch) | |
tree | 97a2de6b50c55fdecbaacbde75775196ff347421 | |
parent | 01e4426a6352740973ff275eac60ddacc90da119 (diff) | |
download | mariadb-git-cb7b5fbf1cf7c5bcd0509e428a53a8b8d6fbba0f.tar.gz |
MDEV-16910 Add class VDec
Adding classes VDec and VDec2_lazy, according to the task description.
This patch removes around 250 duplicate code lines.
-rw-r--r-- | sql/field.cc | 90 | ||||
-rw-r--r-- | sql/field.h | 40 | ||||
-rw-r--r-- | sql/field_conv.cc | 4 | ||||
-rw-r--r-- | sql/filesort.cc | 5 | ||||
-rw-r--r-- | sql/item.cc | 171 | ||||
-rw-r--r-- | sql/item.h | 25 | ||||
-rw-r--r-- | sql/item_buff.cc | 25 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 55 | ||||
-rw-r--r-- | sql/item_func.cc | 305 | ||||
-rw-r--r-- | sql/item_func.h | 49 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 8 | ||||
-rw-r--r-- | sql/item_sum.cc | 78 | ||||
-rw-r--r-- | sql/item_sum.h | 30 | ||||
-rw-r--r-- | sql/item_timefunc.cc | 8 | ||||
-rw-r--r-- | sql/item_windowfunc.cc | 8 | ||||
-rw-r--r-- | sql/log_event.cc | 9 | ||||
-rw-r--r-- | sql/my_decimal.cc | 48 | ||||
-rw-r--r-- | sql/my_decimal.h | 134 | ||||
-rw-r--r-- | sql/protocol.cc | 10 | ||||
-rw-r--r-- | sql/sql_analyse.cc | 56 | ||||
-rw-r--r-- | sql/sql_class.cc | 13 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 12 | ||||
-rw-r--r-- | sql/sql_time.cc | 7 | ||||
-rw-r--r-- | sql/sql_type.cc | 99 | ||||
-rw-r--r-- | sql/sql_type.h | 147 | ||||
-rw-r--r-- | storage/connect/ha_connect.cc | 6 |
26 files changed, 595 insertions, 847 deletions
diff --git a/sql/field.cc b/sql/field.cc index 97b61853a90..ced7d0656df 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -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()); } diff --git a/sql/field.h b/sql/field.h index c821c921962..909ee218f71 100644 --- a/sql/field.h +++ b/sql/field.h @@ -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); diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 64d0bc6c452..f413dec82be 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -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); } diff --git a/sql/filesort.cc b/sql/filesort.cc index e62c4a9780d..1855430b944 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -1114,9 +1114,8 @@ 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), - item->decimals); + dec_val->to_binary(to, item->max_length - (item->decimals ? 1 : 0), + item->decimals); } diff --git a/sql/item.cc b/sql/item.cc index 0089cbfa29e..f51994bee06 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -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; } diff --git a/sql/item.h b/sql/item.h index 64881543155..f18315fa838 100644 --- a/sql/item.h +++ b/sql/item.h @@ -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) diff --git a/sql/item_buff.cc b/sql/item_buff.cc index 4d03462d7c3..3467fda79c7 100644 --- a/sql/item_buff.cc +++ b/sql/item_buff.cc @@ -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()); } diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index afe05445f38..b62e71d84fa 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -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); } diff --git a/sql/item_func.cc b/sql/item_func.cc index 1f4d60b9c6c..4e6876239f4 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -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 & - ~E_DEC_OVERFLOW, - decimal_value, val1, - val2)) > 3)))) + 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, + 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 & - ~E_DEC_OVERFLOW, - decimal_value, val1, - val2)) > 3)))) + 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, + 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)) - return 0; - my_decimal val0= *val0p; - - my_decimal *val1p= args[1]->val_decimal(&tmp); - if ((null_value= args[1]->null_value)) + VDec2_lazy val(args[0], args[1]); + if ((null_value= val.has_null())) 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; diff --git a/sql/item_func.h b/sql/item_func.h index 947d1c8cc9d..fc51a41e9b6 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -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) diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 5333750d908..12618d68c27 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -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 diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 6de33d22c63..98a3f6116a6 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -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; diff --git a/sql/item_sum.h b/sql/item_sum.h index 769d4f2f26c..fe055673328 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -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; } diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 3ac0342e89a..cbb3e844871 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -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", diff --git a/sql/item_windowfunc.cc b/sql/item_windowfunc.cc index 49ee14bed20..a17f9482ea0 100644 --- a/sql/item_windowfunc.cc +++ b/sql/item_windowfunc.cc @@ -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: diff --git a/sql/log_event.cc b/sql/log_event.cc index fcaa7672bf6..13690a8be60 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -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; diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc index 338f78d8f08..de7018c53cb 100644 --- a/sql/my_decimal.cc +++ b/sql/my_decimal.cc @@ -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 */ diff --git a/sql/my_decimal.h b/sql/my_decimal.h index 22800c24338..d035641cfa6 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -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); diff --git a/sql/protocol.cc b/sql/protocol.cc index d29d2fe853d..29004fe24e4 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -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()); } diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index 0990379add7..a7cfaca0d0e 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -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; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index e732ca13f4d..0bbfdba88c7 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -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() diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 2419fd2d85e..c615356b354 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -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; } diff --git a/sql/sql_time.cc b/sql/sql_time.cc index c748cd54415..c8bf4df2c87 100644 --- a/sql/sql_time.cc +++ b/sql/sql_time.cc @@ -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); +} diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 0a9f4544919..9bf2ab63a39 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -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 diff --git a/sql/sql_type.h b/sql/sql_type.h index f617a963ca3..ea744a989ea 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -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; diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index d7e3aebbe21..d78ee9ecc44 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -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); |