diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.cc | 212 | ||||
-rw-r--r-- | sql/item.h | 199 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 10 | ||||
-rw-r--r-- | sql/sql_select.cc | 10 |
4 files changed, 390 insertions, 41 deletions
diff --git a/sql/item.cc b/sql/item.cc index 420efb2a4ee..768af47d660 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3269,9 +3269,57 @@ Item_param::set_param_type_and_swap_value(Item_param *src) } /**************************************************************************** + Item_copy +****************************************************************************/ +Item_copy *Item_copy::create (Item *item) +{ + switch (item->result_type()) + { + case STRING_RESULT: + return new Item_copy_string (item); + case REAL_RESULT: + return new Item_copy_float (item); + case INT_RESULT: + return item->unsigned_flag ? + new Item_copy_uint (item) : new Item_copy_int (item); + case DECIMAL_RESULT: + return new Item_copy_decimal (item); + + case ROW_RESULT: + DBUG_ASSERT (0); + } + /* should not happen */ + return NULL; +} + +/**************************************************************************** Item_copy_string ****************************************************************************/ +double Item_copy_string::val_real() +{ + int err_not_used; + char *end_not_used; + return (null_value ? 0.0 : + my_strntod(str_value.charset(), (char*) str_value.ptr(), + str_value.length(), &end_not_used, &err_not_used)); +} + +longlong Item_copy_string::val_int() +{ + int err; + return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(), + str_value.length(),10, (char**) 0, + &err); +} + + +int Item_copy_string::save_in_field(Field *field, bool no_conversions) +{ + return save_str_value_in_field(field, &str_value); +} + + void Item_copy_string::copy() { String *res=item->val_str(&str_value); @@ -3294,12 +3342,163 @@ my_decimal *Item_copy_string::val_decimal(my_decimal *decimal_value) { // Item_copy_string is used without fix_fields call if (null_value) - return 0; + return (my_decimal *) 0; string2my_decimal(E_DEC_FATAL_ERROR, &str_value, decimal_value); return (decimal_value); } +/**************************************************************************** + Item_copy_int +****************************************************************************/ + +void Item_copy_int::copy() +{ + cached_value= item->val_int(); + null_value=item->null_value; +} + +static int save_int_value_in_field (Field *field, longlong nr, + bool null_value, bool unsigned_flag); + +int Item_copy_int::save_in_field(Field *field, bool no_conversions) +{ + return save_int_value_in_field(field, cached_value, + null_value, unsigned_flag); +} + + +String *Item_copy_int::val_str(String *str) +{ + if (null_value) + return (String *) 0; + + str->set(cached_value, &my_charset_bin); + return str; +} + + +my_decimal *Item_copy_int::val_decimal(my_decimal *decimal_value) +{ + if (null_value) + return (my_decimal *) 0; + + int2my_decimal(E_DEC_FATAL_ERROR, cached_value, unsigned_flag, decimal_value); + return decimal_value; +} + + +/**************************************************************************** + Item_copy_uint +****************************************************************************/ + +String *Item_copy_uint::val_str(String *str) +{ + if (null_value) + return (String *) 0; + + str->set((ulonglong) cached_value, &my_charset_bin); + return str; +} + + +/**************************************************************************** + Item_copy_float +****************************************************************************/ + +String *Item_copy_float::val_str(String *str) +{ + if (null_value) + return (String *) 0; + else + { + double nr= val_real(); + str->set_real(nr,decimals, &my_charset_bin); + return str; + } +} + + +my_decimal *Item_copy_float::val_decimal(my_decimal *decimal_value) +{ + if (null_value) + return (my_decimal *) 0; + else + { + double nr= val_real(); + double2my_decimal(E_DEC_FATAL_ERROR, nr, decimal_value); + return decimal_value; + } +} + + +int Item_copy_float::save_in_field(Field *field, bool no_conversions) +{ + if (null_value) + return set_field_to_null(field); + field->set_notnull(); + return field->store(cached_value); +} + + +/**************************************************************************** + Item_copy_decimal +****************************************************************************/ + +int Item_copy_decimal::save_in_field(Field *field, bool no_conversions) +{ + if (null_value) + return set_field_to_null(field); + field->set_notnull(); + return field->store_decimal(&cached_value); +} + + +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; +} + + +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; + } +} + + +longlong Item_copy_decimal::val_int() +{ + if (null_value) + return LL(0); + else + { + longlong result; + my_decimal2int(E_DEC_FATAL_ERROR, &cached_value, unsigned_flag, &result); + return result; + } +} + + +void Item_copy_decimal::copy() +{ + my_decimal *nr= item->val_decimal(&cached_value); + if (nr && nr != &cached_value) + memcpy (&cached_value, nr, sizeof (my_decimal)); + null_value= item->null_value; +} + + /* Functions to convert item to field (for send_fields) */ @@ -4947,10 +5146,9 @@ int Item_uint::save_in_field(Field *field, bool no_conversions) return Item_int::save_in_field(field, no_conversions); } - -int Item_int::save_in_field(Field *field, bool no_conversions) +static int save_int_value_in_field (Field *field, longlong nr, + bool null_value, bool unsigned_flag) { - longlong nr=val_int(); if (null_value) return set_field_to_null(field); field->set_notnull(); @@ -4958,6 +5156,12 @@ int Item_int::save_in_field(Field *field, bool no_conversions) } +int Item_int::save_in_field(Field *field, bool no_conversions) +{ + return save_int_value_in_field (field, val_int(), null_value, unsigned_flag); +} + + int Item_decimal::save_in_field(Field *field, bool no_conversions) { field->set_notnull(); diff --git a/sql/item.h b/sql/item.h index 96a4e9f7a31..3dfcd7c2612 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2443,48 +2443,203 @@ public: #include "item_xmlfunc.h" #endif -class Item_copy_string :public Item +/** + Base class to implement typed value caching Item classes + + Item_copy_ classes are very similar to the corresponding Item_ + classes (e.g. Item_copy_int is similar to Item_int) but they add + the following additional functionality to Item_ : + 1. Nullability + 2. Possibility to store the value not only on instantiation time, + but also later. + Item_copy_ classes are a functionality subset of Item_cache_ + classes, as e.g. they don't support comparisons with the original Item + as Item_cache_ classes do. + Item_copy_ classes are used in GROUP BY calculation. + TODO: Item_copy should be made an abstract interface and Item_copy_ + classes should inherit both the respective Item_ class and the interface. + Ideally we should drop Item_copy_ classes altogether and merge + their functionality to Item_cache_ (and these should be made to inherit + from Item_). +*/ + +class Item_copy :public Item { +protected: + + /** + Stores the type of the resulting field that would be used to store the data + in the cache. This is to avoid calls to the original item. + */ enum enum_field_types cached_field_type; -public: + + /** The original item that is copied */ Item *item; - Item_copy_string(Item *i) :item(i) + + /** + Stores the result type of the original item, so it can be returned + without calling the original item's method + */ + Item_result cached_result_type; + + /** + Constructor of the Item_copy class + + stores metadata information about the original class as well as a + pointer to it. + */ + Item_copy(Item *i) { + item= i; null_value=maybe_null=item->maybe_null; decimals=item->decimals; max_length=item->max_length; name=item->name; cached_field_type= item->field_type(); + cached_result_type= item->result_type(); + unsigned_flag= item->unsigned_flag; } + +public: + /** + Factory method to create the appropriate subclass dependent on the type of + the original item. + + @param item the original item. + */ + static Item_copy *create (Item *item); + + /** + Update the cache with the value of the original item + + This is the method that updates the cached value. + It must be explicitly called by the user of this class to store the value + of the orginal item in the cache. + */ + virtual void copy() = 0; + + Item *get_item() { return item; } + /** All of the subclasses should have the same type tag */ enum Type type() const { return COPY_STR_ITEM; } - enum Item_result result_type () const { return STRING_RESULT; } enum_field_types field_type() const { return cached_field_type; } - double val_real() + enum Item_result result_type () const { return cached_result_type; } + + void make_field(Send_field *field) { item->make_field(field); } + table_map used_tables() const { return (table_map) 1L; } + bool const_item() const { return 0; } + bool is_null() { return null_value; } + + /* + Override the methods below as pure virtual to make sure all the + sub-classes implement them. + */ + + virtual String *val_str(String*) = 0; + virtual my_decimal *val_decimal(my_decimal *) = 0; + virtual double val_real() = 0; + virtual longlong val_int() = 0; + virtual int save_in_field(Field *field, bool no_conversions) = 0; +}; + +/** + Implementation of a string cache. + + Uses Item::str_value for storage +*/ +class Item_copy_string : public Item_copy +{ +public: + Item_copy_string (Item *item) : Item_copy(item) {} + + String *val_str(String*); + my_decimal *val_decimal(my_decimal *); + double val_real(); + longlong val_int(); + void copy(); + int save_in_field(Field *field, bool no_conversions); +}; + + +class Item_copy_int : public Item_copy +{ +protected: + longlong cached_value; +public: + Item_copy_int (Item *i) : Item_copy(i) {} + int save_in_field(Field *field, bool no_conversions); + + virtual String *val_str(String*); + virtual my_decimal *val_decimal(my_decimal *); + virtual double val_real() { - int err_not_used; - char *end_not_used; - return (null_value ? 0.0 : - my_strntod(str_value.charset(), (char*) str_value.ptr(), - str_value.length(), &end_not_used, &err_not_used)); + return null_value ? 0.0 : (double) cached_value; } - longlong val_int() + virtual longlong val_int() + { + return null_value ? LL(0) : cached_value; + } + virtual void copy(); +}; + + +class Item_copy_uint : public Item_copy_int +{ +public: + Item_copy_uint (Item *item) : Item_copy_int(item) + { + unsigned_flag= 1; + } + + String *val_str(String*); + double val_real() { - int err; - return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(), - str_value.length(),10, (char**) 0, - &err); + return null_value ? 0.0 : (double) (ulonglong) cached_value; } +}; + + +class Item_copy_float : public Item_copy +{ +protected: + double cached_value; +public: + Item_copy_float (Item *i) : Item_copy(i) {} + int save_in_field(Field *field, bool no_conversions); + String *val_str(String*); my_decimal *val_decimal(my_decimal *); - void make_field(Send_field *field) { item->make_field(field); } - void copy(); - int save_in_field(Field *field, bool no_conversions) + double val_real() { - return save_str_value_in_field(field, &str_value); + return null_value ? 0.0 : cached_value; } - table_map used_tables() const { return (table_map) 1L; } - bool const_item() const { return 0; } - bool is_null() { return null_value; } + longlong val_int() + { + return (longlong) rint(val_real()); + } + void copy() + { + cached_value= item->val_real(); + null_value= item->null_value; + } +}; + + +class Item_copy_decimal : public Item_copy +{ +protected: + my_decimal cached_value; +public: + Item_copy_decimal (Item *i) : Item_copy(i) {} + int save_in_field(Field *field, bool no_conversions); + + String *val_str(String*); + my_decimal *val_decimal(my_decimal *) + { + return null_value ? NULL: &cached_value; + } + double val_real(); + longlong val_int(); + void copy(); }; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index a9bfea1b806..ee823517df8 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2724,16 +2724,6 @@ void Item_func_case::fix_length_and_dec() nagg++; if (!(found_types= collect_cmp_types(agg, nagg))) return; - if (with_sum_func || current_thd->lex->current_select->group_list.elements) - { - /* - See TODO commentary in the setup_copy_fields function: - item in a group may be wrapped with an Item_copy_string item. - That item has a STRING_RESULT result type, so we need - to take this type into account. - */ - found_types |= (1 << item_cmp_type(left_result_type, STRING_RESULT)); - } for (i= 0; i <= (uint)DECIMAL_RESULT; i++) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index ab9c060c69c..fad533986d6 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13855,7 +13855,7 @@ SORT_FIELD *make_unireg_sortorder(ORDER *order, uint *length, pos->field= ((Item_sum*) item)->get_tmp_table_field(); else if (item->type() == Item::COPY_STR_ITEM) { // Blob patch - pos->item= ((Item_copy_string*) item)->item; + pos->item= ((Item_copy*) item)->get_item(); } else pos->item= *order->item; @@ -14926,7 +14926,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, pos= item; if (item->field->flags & BLOB_FLAG) { - if (!(pos= new Item_copy_string(pos))) + if (!(pos= Item_copy::create(pos))) goto err; /* Item_copy_string::copy for function can call @@ -14980,7 +14980,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, on how the value is to be used: In some cases this may be an argument in a group function, like: IF(ISNULL(col),0,COUNT(*)) */ - if (!(pos=new Item_copy_string(pos))) + if (!(pos= Item_copy::create(pos))) goto err; if (i < border) // HAVING, ORDER and GROUP BY { @@ -15033,8 +15033,8 @@ copy_fields(TMP_TABLE_PARAM *param) (*ptr->do_copy)(ptr); List_iterator_fast<Item> it(param->copy_funcs); - Item_copy_string *item; - while ((item = (Item_copy_string*) it++)) + Item_copy *item; + while ((item = (Item_copy*) it++)) item->copy(); } |