diff options
Diffstat (limited to 'sql/item.cc')
-rw-r--r-- | sql/item.cc | 260 |
1 files changed, 242 insertions, 18 deletions
diff --git a/sql/item.cc b/sql/item.cc index 21e06eee589..7de32423927 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5025,7 +5025,7 @@ Field *Item::make_string_field(TABLE *table) DBUG_ASSERT(collation.collation); if (max_length/collation.collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB) field= new Field_blob(max_length, maybe_null, name, - collation.collation); + collation.collation, TRUE); /* Item_type_holder holds the exact type, do not change it */ else if (max_length > 0 && (type() != Item::TYPE_HOLDER || field_type() != MYSQL_TYPE_STRING)) @@ -5766,6 +5766,67 @@ bool Item::send(Protocol *protocol, String *buffer) } +/** + Check if an item is a constant one and can be cached. + + @param arg [out] TRUE <=> Cache this item. + + @return TRUE Go deeper in item tree. + @return FALSE Don't go deeper in item tree. +*/ + +bool Item::cache_const_expr_analyzer(uchar **arg) +{ + bool *cache_flag= (bool*)*arg; + if (!*cache_flag) + { + Item *item= real_item(); + /* + Cache constant items unless it's a basic constant, constant field or + a subselect (they use their own cache). + */ + if (const_item() && + !(item->basic_const_item() || item->type() == Item::FIELD_ITEM || + item->type() == SUBSELECT_ITEM || + /* + Do not cache GET_USER_VAR() function as its const_item() may + return TRUE for the current thread but it still may change + during the execution. + */ + (item->type() == Item::FUNC_ITEM && + ((Item_func*)item)->functype() == Item_func::GUSERVAR_FUNC))) + *cache_flag= TRUE; + return TRUE; + } + return FALSE; +} + + +/** + Cache item if needed. + + @param arg TRUE <=> Cache this item. + + @return cache if cache needed. + @return this otherwise. +*/ + +Item* Item::cache_const_expr_transformer(uchar *arg) +{ + if (*(bool*)arg) + { + *((bool*)arg)= FALSE; + Item_cache *cache= Item_cache::get_cache(this); + if (!cache) + return NULL; + cache->setup(this); + cache->store(this); + return cache; + } + return this; +} + + bool Item_field::send(Protocol *protocol, String *buffer) { return protocol->store(result_field); @@ -7104,7 +7165,22 @@ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) Item_cache* Item_cache::get_cache(const Item *item) { - switch (item->result_type()) { + return get_cache(item, item->result_type()); +} + + +/** + Get a cache item of given type. + + @param item value to be cached + @param type required type of cache + + @return cache item +*/ + +Item_cache* Item_cache::get_cache(const Item *item, const Item_result type) +{ + switch (type) { case INT_RESULT: return new Item_cache_int(); case REAL_RESULT: @@ -7112,6 +7188,10 @@ Item_cache* Item_cache::get_cache(const Item *item) case DECIMAL_RESULT: return new Item_cache_decimal(); case STRING_RESULT: + if (item->field_type() == MYSQL_TYPE_DATE || + item->field_type() == MYSQL_TYPE_DATETIME || + item->field_type() == MYSQL_TYPE_TIME) + return new Item_cache_datetime(item->field_type()); return new Item_cache_str(item); case ROW_RESULT: return new Item_cache_row(); @@ -7122,6 +7202,12 @@ Item_cache* Item_cache::get_cache(const Item *item) } } +void Item_cache::store(Item *item) +{ + if (item) + example= item; + value_cached= FALSE; +} void Item_cache::print(String *str, enum_query_type query_type) { @@ -7133,17 +7219,19 @@ void Item_cache::print(String *str, enum_query_type query_type) str->append(')'); } - -void Item_cache_int::store(Item *item) +void Item_cache_int::cache_value() { - value= item->val_int_result(); - null_value= item->null_value; - unsigned_flag= item->unsigned_flag; + value_cached= TRUE; + value= example->val_int_result(); + null_value= example->null_value; + unsigned_flag= example->unsigned_flag; } void Item_cache_int::store(Item *item, longlong val_arg) { + /* An explicit values is given, save it. */ + value_cached= TRUE; value= val_arg; null_value= item->null_value; unsigned_flag= item->unsigned_flag; @@ -7153,6 +7241,8 @@ void Item_cache_int::store(Item *item, longlong val_arg) String *Item_cache_int::val_str(String *str) { DBUG_ASSERT(fixed == 1); + if (!value_cached) + cache_value(); str->set(value, default_charset()); return str; } @@ -7161,21 +7251,115 @@ String *Item_cache_int::val_str(String *str) my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val) { DBUG_ASSERT(fixed == 1); + if (!value_cached) + cache_value(); int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_val); return decimal_val; } +double Item_cache_int::val_real() +{ + DBUG_ASSERT(fixed == 1); + if (!value_cached) + cache_value(); + return (double) value; +} + +longlong Item_cache_int::val_int() +{ + DBUG_ASSERT(fixed == 1); + if (!value_cached) + cache_value(); + return value; +} + +void Item_cache_datetime::cache_value_int() +{ + value_cached= TRUE; + /* Assume here that the underlying item will do correct conversion.*/ + int_value= example->val_int_result(); + null_value= example->null_value; + unsigned_flag= example->unsigned_flag; +} -void Item_cache_real::store(Item *item) + +void Item_cache_datetime::cache_value() { - value= item->val_result(); + str_value_cached= TRUE; + /* Assume here that the underlying item will do correct conversion.*/ + String *res= example->str_result(&str_value); + if (res && res != &str_value) + str_value.copy(*res); + null_value= example->null_value; + unsigned_flag= example->unsigned_flag; +} + + +void Item_cache_datetime::store(Item *item, longlong val_arg) +{ + /* An explicit values is given, save it. */ + value_cached= TRUE; + int_value= val_arg; null_value= item->null_value; + unsigned_flag= item->unsigned_flag; +} + + +String *Item_cache_datetime::val_str(String *str) +{ + DBUG_ASSERT(fixed == 1); + if (!str_value_cached) + cache_value(); + return &str_value; +} + + +my_decimal *Item_cache_datetime::val_decimal(my_decimal *decimal_val) +{ + DBUG_ASSERT(fixed == 1); + if (!value_cached) + cache_value_int(); + int2my_decimal(E_DEC_FATAL_ERROR, int_value, unsigned_flag, decimal_val); + return decimal_val; +} + +double Item_cache_datetime::val_real() +{ + DBUG_ASSERT(fixed == 1); + if (!value_cached) + cache_value_int(); + return (double) int_value; } +longlong Item_cache_datetime::val_int() +{ + DBUG_ASSERT(fixed == 1); + if (!value_cached) + cache_value_int(); + return int_value; +} + +void Item_cache_real::cache_value() +{ + value_cached= TRUE; + value= example->val_result(); + null_value= example->null_value; +} + + +double Item_cache_real::val_real() +{ + DBUG_ASSERT(fixed == 1); + if (!value_cached) + cache_value(); + return value; +} longlong Item_cache_real::val_int() { DBUG_ASSERT(fixed == 1); + if (!value_cached) + cache_value(); return (longlong) rint(value); } @@ -7183,6 +7367,8 @@ longlong Item_cache_real::val_int() String* Item_cache_real::val_str(String *str) { DBUG_ASSERT(fixed == 1); + if (!value_cached) + cache_value(); str->set_real(value, decimals, default_charset()); return str; } @@ -7191,15 +7377,18 @@ String* Item_cache_real::val_str(String *str) my_decimal *Item_cache_real::val_decimal(my_decimal *decimal_val) { DBUG_ASSERT(fixed == 1); + if (!value_cached) + cache_value(); double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val); return decimal_val; } -void Item_cache_decimal::store(Item *item) +void Item_cache_decimal::cache_value() { - my_decimal *val= item->val_decimal_result(&decimal_value); - if (!(null_value= item->null_value) && val != &decimal_value) + value_cached= TRUE; + my_decimal *val= example->val_decimal_result(&decimal_value); + if (!(null_value= example->null_value) && val != &decimal_value) my_decimal2decimal(val, &decimal_value); } @@ -7207,6 +7396,8 @@ double Item_cache_decimal::val_real() { DBUG_ASSERT(fixed); double res; + if (!value_cached) + cache_value(); my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &res); return res; } @@ -7215,6 +7406,8 @@ longlong Item_cache_decimal::val_int() { DBUG_ASSERT(fixed); longlong res; + if (!value_cached) + cache_value(); my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &res); return res; } @@ -7222,6 +7415,8 @@ longlong Item_cache_decimal::val_int() String* Item_cache_decimal::val_str(String *str) { DBUG_ASSERT(fixed); + if (!value_cached) + cache_value(); 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); @@ -7231,15 +7426,18 @@ String* Item_cache_decimal::val_str(String *str) my_decimal *Item_cache_decimal::val_decimal(my_decimal *val) { DBUG_ASSERT(fixed); + if (!value_cached) + cache_value(); return &decimal_value; } -void Item_cache_str::store(Item *item) +void Item_cache_str::cache_value() { - value_buff.set(buffer, sizeof(buffer), item->collation.collation); - value= item->str_result(&value_buff); - if ((null_value= item->null_value)) + value_cached= TRUE; + value_buff.set(buffer, sizeof(buffer), example->collation.collation); + value= example->str_result(&value_buff); + if ((null_value= example->null_value)) value= 0; else if (value != &value_buff) { @@ -7261,6 +7459,8 @@ double Item_cache_str::val_real() DBUG_ASSERT(fixed == 1); int err_not_used; char *end_not_used; + if (!value_cached) + cache_value(); if (value) return my_strntod(value->charset(), (char*) value->ptr(), value->length(), &end_not_used, &err_not_used); @@ -7272,6 +7472,8 @@ longlong Item_cache_str::val_int() { DBUG_ASSERT(fixed == 1); int err; + if (!value_cached) + cache_value(); if (value) return my_strntoll(value->charset(), value->ptr(), value->length(), 10, (char**) 0, &err); @@ -7279,9 +7481,21 @@ longlong Item_cache_str::val_int() return (longlong)0; } + +String* Item_cache_str::val_str(String *str) +{ + DBUG_ASSERT(fixed == 1); + if (!value_cached) + cache_value(); + return value; +} + + my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val) { DBUG_ASSERT(fixed == 1); + if (!value_cached) + cache_value(); if (value) string2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val); else @@ -7292,6 +7506,8 @@ my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val) int Item_cache_str::save_in_field(Field *field, bool no_conversions) { + if (!value_cached) + cache_value(); int res= Item_cache::save_in_field(field, no_conversions); return (is_varbinary && field->type() == MYSQL_TYPE_STRING && value->length() < field->field_length) ? 1 : res; @@ -7326,11 +7542,19 @@ bool Item_cache_row::setup(Item * item) void Item_cache_row::store(Item * item) { + for (uint i= 0; i < item_count; i++) + values[i]->store(item->element_index(i)); +} + + +void Item_cache_row::cache_value() +{ + value_cached= TRUE; null_value= 0; - item->bring_value(); + example->bring_value(); for (uint i= 0; i < item_count; i++) { - values[i]->store(item->element_index(i)); + values[i]->cache_value(); null_value|= values[i]->null_value; } } |