diff --git a/sql/item.h b/sql/item.h index 1ea76731fd3..461a3805080 100644 --- a/sql/item.h +++ b/sql/item.h @@ -31,12 +31,12 @@ public: static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); } static void operator delete(void *ptr,size_t size) {} /*lint -e715 */ - enum Type {FIELD_ITEM,FUNC_ITEM,SUM_FUNC_ITEM,STRING_ITEM, - INT_ITEM,REAL_ITEM,NULL_ITEM,VARBIN_ITEM, - COPY_STR_ITEM,FIELD_AVG_ITEM, DEFAULT_ITEM, - PROC_ITEM,COND_ITEM,REF_ITEM,FIELD_STD_ITEM, - FIELD_VARIANCE_ITEM,CONST_ITEM, - SUBSELECT_ITEM, ROW_ITEM}; + enum Type {FIELD_ITEM, FUNC_ITEM, SUM_FUNC_ITEM, STRING_ITEM, + INT_ITEM, REAL_ITEM, NULL_ITEM, VARBIN_ITEM, + COPY_STR_ITEM, FIELD_AVG_ITEM, DEFAULT_ITEM, + PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM, + FIELD_VARIANCE_ITEM, CONST_ITEM, + SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM}; enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE }; String str_value; /* used to store value */ @@ -381,7 +381,8 @@ public: name=(char*) str_value.ptr(); decimals=NOT_FIXED_DEC; } - Item_string(const char *name_par,const char *str,uint length,CHARSET_INFO *cs) + Item_string(const char *name_par, const char *str, uint length, + CHARSET_INFO *cs) { str_value.set(str,length,cs); max_length=length; @@ -392,11 +393,13 @@ public: enum Type type() const { return STRING_ITEM; } double val() { - return my_strntod(str_value.charset(),str_value.ptr(),str_value.length(),(char**)NULL); + return my_strntod(str_value.charset(), str_value.ptr(), + str_value.length(), (char**) 0); } longlong val_int() { - return my_strntoll(str_value.charset(),str_value.ptr(),str_value.length(),(char**) 0,10); + return my_strntoll(str_value.charset(), str_value.ptr(), + str_value.length(), (char**) 0, 10); } String *val_str(String*) { return (String*) &str_value; } int save_in_field(Field *field, bool no_conversions); @@ -706,6 +709,86 @@ public: bool cmp(void); }; +class Item_cache: public Item +{ +public: + virtual void store(Item *)= 0; + void set_len_n_dec(uint32 max_len, uint8 dec) + { + max_length= max_len; + decimals= dec; + } + enum Type type() const { return CACHE_ITEM; } +}; + +class Item_cache_int: public Item_cache +{ + longlong value; +public: + Item_cache_int() { fixed= 1; null_value= 1; } + + void store(Item *item) + { + value= item->val_int_result(); + null_value= item->null_value; + } + double val() { return (double) value; } + longlong val_int() { return value; } + String* val_str(String *str) { str->set(value, thd_charset()); return str; } + enum Item_result result_type() const { return INT_RESULT; } +}; + +class Item_cache_real: public Item_cache +{ + double value; +public: + Item_cache_real() { fixed= 1; null_value= 1; } + + void store(Item *item) + { + value= item->val_result(); + null_value= item->null_value; + } + double val() { return value; } + longlong val_int() { return (longlong) (value+(value > 0 ? 0.5 : -0.5)); } + String* val_str(String *str) + { + str->set(value, decimals, thd_charset()); + return str; + } + enum Item_result result_type() const { return REAL_RESULT; } +}; + +class Item_cache_str: public Item_cache +{ + char buffer[80]; + String *value; +public: + Item_cache_str() { fixed= 1; null_value= 1; } + + void store(Item *item) + { + str_value.set(buffer, sizeof(buffer), item->charset()); + value= item->str_result(&str_value); + // TODO remove if str_value charset have no side effect for now + str_value.set_charset(value->charset()); + null_value= item->null_value; + } + double val() + { + return my_strntod(value->charset(), value->ptr(), + value->length(), (char**)0); + } + longlong val_int() + { + return my_strntoll(value->charset(), value->ptr(), + value->length(), (char**) 0, 10); + } + String* val_str(String *) { return value; } + enum Item_result result_type() const { return STRING_RESULT; } + CHARSET_INFO *charset() const { return value->charset(); }; +}; + extern Item_buff *new_Item_buff(Item *item); extern Item_result item_cmp_type(Item_result a,Item_result b); extern Item *resolve_const_item(Item *item,Item *cmp_item); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index a8bbc433b7a..588be06a7e7 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -124,7 +124,7 @@ inline table_map Item_subselect::used_tables() const Item_singleval_subselect::Item_singleval_subselect(THD *thd, st_select_lex *select_lex): - Item_subselect() + Item_subselect(), value(0) { DBUG_ENTER("Item_singleval_subselect::Item_singleval_subselect"); init(thd, select_lex, new select_singleval_subselect(this)); @@ -133,10 +133,43 @@ Item_singleval_subselect::Item_singleval_subselect(THD *thd, DBUG_VOID_RETURN; } +void Item_singleval_subselect::reset() +{ + null_value= 1; + if (value) + value->null_value= 1; +} + +void Item_singleval_subselect::store(Item *item) +{ + value->store(item); +} + +enum Item_result Item_singleval_subselect::result_type() const +{ + return engine->type(); +} + void Item_singleval_subselect::fix_length_and_dec() { engine->fix_length_and_dec(); - res_type= engine->type(); + switch (engine->type()) + { + case INT_RESULT: + value= new Item_cache_int(); + break; + case REAL_RESULT: + value= new Item_cache_real(); + break; + case STRING_RESULT: + value= new Item_cache_str(); + break; + default: + // should never be in real life + DBUG_ASSERT(0); + return; + } + value->set_len_n_dec(max_length, decimals); } Item::Type Item_subselect::type() const @@ -146,32 +179,44 @@ Item::Type Item_subselect::type() const double Item_singleval_subselect::val () { - if (engine->exec()) + if (!engine->exec() && !value->null_value) + { + null_value= 0; + return value->val(); + } + else { reset(); return 0; } - return real_value; } longlong Item_singleval_subselect::val_int () { - if (engine->exec()) + if (!engine->exec() && !value->null_value) + { + null_value= 0; + return value->val_int(); + } + else { reset(); return 0; } - return int_value; } String *Item_singleval_subselect::val_str (String *str) { - if (engine->exec() || null_value) + if (!engine->exec() && !value->null_value) + { + null_value= 0; + return value->val_str(str); + } + else { reset(); return 0; } - return &string_value; } Item_exists_subselect::Item_exists_subselect(THD *thd, diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 0e6f939803d..a43caca22f2 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -90,44 +90,28 @@ public: /* single value subselect */ +class Item_cache; class Item_singleval_subselect :public Item_subselect { protected: - longlong int_value; /* Here stored integer value of this item */ - double real_value; /* Here stored real value of this item */ - /* - Here stored string value of this item. - (str_value used only as temporary buffer, because it can be changed - by Item::save_field) - */ - String string_value; - enum Item_result res_type; /* type of results */ + Item_cache *value; public: Item_singleval_subselect(THD *thd, st_select_lex *select_lex); Item_singleval_subselect(Item_singleval_subselect *item): Item_subselect(item) { - int_value= item->int_value; - real_value= item->real_value; - string_value.set(item->string_value, 0, item->string_value.length()); + value= item->value; max_length= item->max_length; decimals= item->decimals; - res_type= item->res_type; } - virtual void reset() - { - null_value= 1; - int_value= 0; - real_value= 0; - max_length= 4; - res_type= STRING_RESULT; - } - double val (); + void reset(); + void store(Item* item); + double val(); longlong val_int (); String *val_str (String *); Item *new_item() { return new Item_singleval_subselect(this); } - enum Item_result result_type() const { return res_type; } + enum Item_result result_type() const; void fix_length_and_dec(); friend class select_singleval_subselect; @@ -149,7 +133,7 @@ public: } Item_exists_subselect(): Item_subselect() {} - virtual void reset() + void reset() { value= 0; } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 9e0489edb28..50164aed342 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -932,31 +932,7 @@ bool select_singleval_subselect::send_data(List &items) } List_iterator_fast li(items); Item *val_item= li++; // Only one (single value subselect) - /* - Following val() call have to be first, because function AVG() & STD() - calculate value on it & determinate "is it NULL?". - */ - it->real_value= val_item->val_result(); - if ((it->null_value= val_item->null_value)) - { - it->reset(); - } - else - { - it->max_length= val_item->max_length; - it->decimals= val_item->decimals; - it->set_charset(val_item->charset()); - it->int_value= val_item->val_int_result(); - String *s= val_item->str_result(&it->string_value); - if (s != &it->string_value) - { - it->string_value.set(*s, 0, s->length()); - } - // TODO: remove when correct charset handling appeared for Item - it->str_value.set(*s, 0, s->length()); // store charset - - it->res_type= val_item->result_type(); - } + it->store(val_item); it->assigned(1); DBUG_RETURN(0); }