summaryrefslogtreecommitdiff
path: root/sql/item.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item.cc')
-rw-r--r--sql/item.cc811
1 files changed, 728 insertions, 83 deletions
diff --git a/sql/item.cc b/sql/item.cc
index 2fb2f5e91e2..310e6994c7d 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -28,6 +28,9 @@
const String my_null_string("NULL", 4, default_charset_info);
+static int save_field_in_field(Field *from, bool *null_value,
+ Field *to, bool no_conversions);
+
/****************************************************************************/
/* Hybrid_type_traits {_real} */
@@ -374,8 +377,8 @@ int Item::save_str_value_in_field(Field *field, String *result)
Item::Item():
- rsize(0), name(0), orig_name(0), name_length(0), fixed(0),
- is_autogenerated_name(TRUE),
+ is_expensive_cache(-1), rsize(0), name(0), orig_name(0), name_length(0),
+ fixed(0), is_autogenerated_name(TRUE),
collation(&my_charset_bin, DERIVATION_COERCIBLE)
{
marker= 0;
@@ -412,6 +415,7 @@ Item::Item():
tables.
*/
Item::Item(THD *thd, Item *item):
+ is_expensive_cache(-1),
rsize(0),
str_value(item->str_value),
name(item->name),
@@ -543,6 +547,36 @@ Item* Item::transform(Item_transformer transformer, uchar *arg)
}
+/**
+ Create and set up an expression cache for this item
+
+ @param thd Thread handle
+ @param depends_on List of the expression parameters
+
+ @details
+ The function creates an expression cache for an item and its parameters
+ specified by the 'depends_on' list. Then the expression cache is placed
+ into a cache wrapper that is returned as the result of the function.
+
+ @returns
+ A pointer to created wrapper item if successful, NULL - otherwise
+*/
+
+Item* Item::set_expr_cache(THD *thd, List<Item *> &depends_on)
+{
+ DBUG_ENTER("Item::set_expr_cache");
+ Item_cache_wrapper *wrapper;
+ if ((wrapper= new Item_cache_wrapper(this)) &&
+ !wrapper->fix_fields(thd, (Item**)&wrapper))
+ {
+ if (wrapper->set_cache(thd, depends_on))
+ DBUG_RETURN(NULL);
+ DBUG_RETURN(wrapper);
+ }
+ DBUG_RETURN(NULL);
+}
+
+
Item_ident::Item_ident(Name_resolution_context *context_arg,
const char *db_name_arg,const char *table_name_arg,
const char *field_name_arg)
@@ -551,7 +585,7 @@ Item_ident::Item_ident(Name_resolution_context *context_arg,
db_name(db_name_arg), table_name(table_name_arg),
field_name(field_name_arg),
alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX),
- cached_table(0), depended_from(0)
+ cached_table(0), depended_from(0), can_be_depended(TRUE)
{
name = (char*) field_name_arg;
}
@@ -563,7 +597,7 @@ Item_ident::Item_ident(TABLE_LIST *view_arg, const char *field_name_arg)
db_name(NullS), table_name(view_arg->alias),
field_name(field_name_arg),
alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX),
- cached_table(NULL), depended_from(NULL)
+ cached_table(NULL), depended_from(NULL), can_be_depended(TRUE)
{
name = (char*) field_name_arg;
}
@@ -585,7 +619,8 @@ Item_ident::Item_ident(THD *thd, Item_ident *item)
alias_name_used(item->alias_name_used),
cached_field_index(item->cached_field_index),
cached_table(item->cached_table),
- depended_from(item->depended_from)
+ depended_from(item->depended_from),
+ can_be_depended(item->can_be_depended)
{}
void Item_ident::cleanup()
@@ -603,7 +638,8 @@ void Item_ident::cleanup()
db_name= orig_db_name;
table_name= orig_table_name;
field_name= orig_field_name;
- depended_from= 0;
+ /* Store if this Item was depended */
+ can_be_depended= test(depended_from);
DBUG_VOID_RETURN;
}
@@ -652,6 +688,16 @@ bool Item_field::collect_item_field_processor(uchar *arg)
}
+bool Item_field::add_field_to_set_processor(uchar *arg)
+{
+ DBUG_ENTER("Item_field::add_field_to_set_processor");
+ DBUG_PRINT("info", ("%s", field->field_name ? field->field_name : "noname"));
+ TABLE *table= (TABLE *) arg;
+ if (field->table == table)
+ bitmap_set_bit(&table->tmp_set, field->field_index);
+ DBUG_RETURN(FALSE);
+}
+
/**
Check if an Item_field references some field from a list of fields.
@@ -737,7 +783,8 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs)
}
if (cs->ctype)
{
- uint orig_len= length;
+ const char *str_start= str;
+
/*
This will probably need a better implementation in the future:
a function in CHARSET_INFO structure.
@@ -747,16 +794,20 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs)
length--;
str++;
}
- if (orig_len != length && !is_autogenerated_name)
+ if (str != str_start && !is_autogenerated_name)
{
+ char buff[SAFE_NAME_LEN];
+ strmake(buff, str_start,
+ min(sizeof(buff)-1, length + (int) (str-str_start)));
+
if (length == 0)
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_NAME_BECOMES_EMPTY, ER(ER_NAME_BECOMES_EMPTY),
- str + length - orig_len);
+ buff);
else
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_REMOVED_SPACES, ER(ER_REMOVED_SPACES),
- str + length - orig_len);
+ buff);
}
}
if (!my_charset_same(cs, system_charset_info))
@@ -1416,7 +1467,7 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array,
/* An item of type Item_sum is registered <=> ref_by != 0 */
if (type() == SUM_FUNC_ITEM && skip_registered &&
((Item_sum *) this)->ref_by)
- return;
+ return;
if ((type() != SUM_FUNC_ITEM && with_sum_func) ||
(type() == FUNC_ITEM &&
(((Item_func *) this)->functype() == Item_func::ISNOTNULLTEST_FUNC ||
@@ -1737,7 +1788,10 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname,
subselect transformation does not happen in view_prepare_mode
and thus val_...() methods can not be called for const items.
*/
- bool resolve_const= ((*arg)->type() == Item::SUBSELECT_ITEM &&
+ bool resolve_const= (((*arg)->type() == Item::SUBSELECT_ITEM ||
+ ((*arg)->get_cached_item() &&
+ (*arg)->get_cached_item()->type() ==
+ Item::SUBSELECT_ITEM)) &&
thd->lex->view_prepare_mode) ? FALSE : TRUE;
conv= new Item_func_conv_charset(*arg, coll.collation, resolve_const);
}
@@ -1963,7 +2017,7 @@ void Item_field::reset_field(Field *f)
bool Item_field::enumerate_field_refs_processor(uchar *arg)
{
Field_enumerator *fe= (Field_enumerator*)arg;
- fe->visit_field(field);
+ fe->visit_field(this);
return FALSE;
}
@@ -2123,6 +2177,12 @@ bool Item_field::get_time(MYSQL_TIME *ltime)
return 0;
}
+void Item_field::save_result(Field *to)
+{
+ save_field_in_field(result_field, &null_value, to, TRUE);
+}
+
+
double Item_field::val_result()
{
if ((null_value=result_field->is_null()))
@@ -2216,6 +2276,24 @@ table_map Item_field::used_tables() const
}
+void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref)
+{
+ if (new_parent == depended_from)
+ depended_from= NULL;
+ Name_resolution_context *ctx= new Name_resolution_context();
+ ctx->outer_context= NULL; // We don't build a complete name resolver
+ ctx->table_list= NULL; // We rely on first_name_resolution_table instead
+ ctx->select_lex= new_parent;
+ ctx->first_name_resolution_table= context->first_name_resolution_table;
+ ctx->last_name_resolution_table= context->last_name_resolution_table;
+ ctx->error_processor= context->error_processor;
+ ctx->error_processor_data= context->error_processor_data;
+ ctx->resolve_in_select_list= context->resolve_in_select_list;
+ ctx->security_ctx= context->security_ctx;
+ this->context=ctx;
+}
+
+
Item *Item_field::get_tmp_table_item(THD *thd)
{
Item_field *new_item= new Item_field(thd, this);
@@ -2495,14 +2573,12 @@ double_from_string_with_check (CHARSET_INFO *cs, const char *cptr, char *end)
tmp= my_strntod(cs, (char*) cptr, end - cptr, &end, &error);
if (error || (end != org_end && !check_if_only_end_space(cs, end, org_end)))
{
- /*
- We can use str_value.ptr() here as Item_string is gurantee to put an
- end \0 here.
- */
+ char buff[80];
+ strmake(buff, cptr, min(sizeof(buff)-1, (size_t) (org_end-cptr)));
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE,
ER(ER_TRUNCATED_WRONG_VALUE), "DOUBLE",
- cptr);
+ buff);
}
return tmp;
}
@@ -2511,8 +2587,10 @@ double_from_string_with_check (CHARSET_INFO *cs, const char *cptr, char *end)
double Item_string::val_real()
{
DBUG_ASSERT(fixed == 1);
- return double_from_string_with_check (str_value.charset(), str_value.ptr(),
- (char *) str_value.ptr() + str_value.length());
+ return double_from_string_with_check(str_value.charset(),
+ str_value.ptr(),
+ (char *) str_value.ptr() +
+ str_value.length());
}
@@ -3570,6 +3648,15 @@ bool Item::fix_fields(THD *thd, Item **ref)
return FALSE;
}
+
+void Item_ref_null_helper::save_val(Field *to)
+{
+ DBUG_ASSERT(fixed == 1);
+ (*ref)->save_val(to);
+ owner->was_null|= null_value= (*ref)->null_value;
+}
+
+
double Item_ref_null_helper::val_real()
{
DBUG_ASSERT(fixed == 1);
@@ -3633,7 +3720,7 @@ bool Item_ref_null_helper::get_date(MYSQL_TIME *ltime, uint fuzzydate)
substitution)
*/
-static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
+static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
Item_ident *resolved_item,
Item_ident *mark_item)
{
@@ -3642,9 +3729,11 @@ static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
const char *table_name= (resolved_item->table_name ?
resolved_item->table_name : "");
/* store pointer on SELECT_LEX from which item is dependent */
- if (mark_item)
+ if (mark_item && mark_item->can_be_depended)
mark_item->depended_from= last;
- current->mark_as_dependent(last, resolved_item);
+ if (current->mark_as_dependent(thd, last, /** resolved_item psergey-thu
+ **/mark_item))
+ return TRUE;
if (thd->lex->describe & DESCRIBE_EXTENDED)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
@@ -3654,6 +3743,7 @@ static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
resolved_item->field_name,
current->select_number, last->select_number);
}
+ return FALSE;
}
@@ -4105,6 +4195,9 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
((ref_type == REF_ITEM || ref_type == FIELD_ITEM) ?
(Item_ident*) (*reference) :
0));
+ context->select_lex->
+ register_dependency_item(last_checked_context->select_lex,
+ reference);
/*
A reference to a view field had been found and we
substituted it instead of this Item (find_field_in_tables
@@ -4203,8 +4296,12 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
return -1;
mark_as_dependent(thd, last_checked_context->select_lex,
- context->select_lex, this,
+ context->select_lex, rf,
rf);
+ context->select_lex->
+ register_dependency_item(last_checked_context->select_lex,
+ reference);
+
return 0;
}
else
@@ -4212,6 +4309,9 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex,
this, (Item_ident*)*reference);
+ context->select_lex->
+ register_dependency_item(last_checked_context->select_lex,
+ reference);
if (last_checked_context->select_lex->having_fix_field)
{
Item_ref *rf;
@@ -4518,6 +4618,7 @@ void Item_field::cleanup()
{
DBUG_ENTER("Item_field::cleanup");
Item_ident::cleanup();
+ depended_from= NULL;
/*
Even if this object was created by direct link to field in setup_wild()
it will be linked correctly next time by name of field and table alias.
@@ -4746,7 +4847,7 @@ Item *Item_field::replace_equal_field(uchar *arg)
return this;
return const_item;
}
- Item_field *subst= item_equal->get_first();
+ Item_field *subst= item_equal->get_first(this);
if (subst && field->table != subst->field->table && !field->eq(subst->field))
return subst;
}
@@ -5076,47 +5177,69 @@ void Item_field::make_field(Send_field *tmp_field)
/**
- Set a field's value from a item.
-*/
+ Save a field value in another field
-void Item_field::save_org_in_field(Field *to)
-{
- if (field->is_null())
- {
- null_value=1;
- set_field_to_null_with_conversions(to, 1);
- }
- else
- {
- to->set_notnull();
- field_conv(to,field);
- null_value=0;
- }
-}
+ @param from Field to take the value from
+ @param [out] null_value Pointer to the null_value flag to set
+ @param to Field to save the value in
+ @param no_conversions How to deal with NULL value
-int Item_field::save_in_field(Field *to, bool no_conversions)
+ @details
+ The function takes the value of the field 'from' and, if this value
+ is not null, it saves in the field 'to' setting off the flag referenced
+ by 'null_value'. Otherwise this flag is set on and field 'to' is
+ also set to null possibly with conversion.
+
+ @note
+ This function is used by the functions Item_field::save_in_field,
+ Item_field::save_org_in_field and Item_ref::save_in_field
+
+ @retval FALSE OK
+ @retval TRUE Error
+
+*/
+
+static int save_field_in_field(Field *from, bool *null_value,
+ Field *to, bool no_conversions)
{
int res;
- if (result_field->is_null())
+ DBUG_ENTER("save_field_in_field");
+ if (from->is_null())
{
- null_value=1;
- return set_field_to_null_with_conversions(to, no_conversions);
+ (*null_value)= 1;
+ DBUG_RETURN(set_field_to_null_with_conversions(to, no_conversions));
}
to->set_notnull();
/*
If we're setting the same field as the one we're reading from there's
nothing to do. This can happen in 'SET x = x' type of scenarios.
- */
- if (to == result_field)
+ */
+ if (to == from)
{
- null_value=0;
- return 0;
+ (*null_value)= 0;
+ DBUG_RETURN(0);
}
- res= field_conv(to,result_field);
- null_value=0;
- return res;
+ res= field_conv(to, from);
+ (*null_value)= 0;
+ DBUG_RETURN(res);
+}
+
+
+/**
+ Set a field's value from a item.
+*/
+
+void Item_field::save_org_in_field(Field *to)
+{
+ save_field_in_field(field, &null_value, to, TRUE);
+}
+
+
+int Item_field::save_in_field(Field *to, bool no_conversions)
+{
+ return save_field_in_field(result_field, &null_value, to, no_conversions);
}
@@ -5789,6 +5912,35 @@ Item_ref::Item_ref(Name_resolution_context *context_arg,
set_properties();
}
+/*
+ A Field_enumerator-compatible class that invokes mark_as_dependent() for
+ each field that is a reference to some ancestor of current_select.
+*/
+class Dependency_marker: public Field_enumerator
+{
+public:
+ THD *thd;
+ st_select_lex *current_select;
+ virtual void visit_field(Item_field *item)
+ {
+ // Find which select the field is in. This is achieved by walking up
+ // the select tree and looking for the table of interest.
+ st_select_lex *sel;
+ for (sel= current_select; sel; sel= sel->outer_select())
+ {
+ TABLE_LIST *tbl;
+ for (tbl= sel->leaf_tables; tbl; tbl= tbl->next_leaf)
+ {
+ if (tbl->table == item->field->table)
+ {
+ if (sel != current_select)
+ mark_as_dependent(thd, sel, current_select, item, item);
+ return;
+ }
+ }
+ }
+ }
+};
Item_ref::Item_ref(TABLE_LIST *view_arg, Item **item,
const char *field_name_arg, bool alias_name_used_arg)
@@ -5977,6 +6129,9 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
refer_type == FIELD_ITEM) ?
(Item_ident*) (*reference) :
0));
+ context->select_lex->
+ register_dependency_item(last_checked_context->select_lex,
+ reference);
/*
view reference found, we substituted it instead of this
Item, so can quit
@@ -6026,7 +6181,10 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
goto error;
thd->change_item_tree(reference, fld);
mark_as_dependent(thd, last_checked_context->select_lex,
- thd->lex->current_select, this, fld);
+ thd->lex->current_select, fld, fld);
+ context->select_lex->
+ register_dependency_item(last_checked_context->select_lex,
+ reference);
/*
A reference is resolved to a nest level that's outer or the same as
the nest level of the enclosing set function : adjust the value of
@@ -6050,6 +6208,9 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
DBUG_ASSERT(*ref && (*ref)->fixed);
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex, this, this);
+ context->select_lex->
+ register_dependency_item(last_checked_context->select_lex,
+ reference);
/*
A reference is resolved to a nest level that's outer or the same as
the nest level of the enclosing set function : adjust the value of
@@ -6062,6 +6223,24 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
last_checked_context->select_lex->nest_level);
}
}
+ else
+ {
+ if (depended_from && reference)
+ {
+ DBUG_ASSERT(context->select_lex != depended_from);
+ context->select_lex->register_dependency_item(depended_from, reference);
+ }
+ /*
+ It could be that we're referring to something that's in ancestor selects.
+ We must make an appropriate mark_as_dependent() call for each such
+ outside reference.
+ */
+ Dependency_marker dep_marker;
+ dep_marker.current_select= current_sel;
+ dep_marker.thd= thd;
+ (*ref)->walk(&Item::enumerate_field_refs_processor, FALSE,
+ (uchar*)&dep_marker);
+ }
DBUG_ASSERT(*ref);
/*
@@ -6241,6 +6420,25 @@ bool Item_ref::val_bool_result()
}
+void Item_ref::save_result(Field *to)
+{
+ if (result_field)
+ {
+ save_field_in_field(result_field, &null_value, to, TRUE);
+ return;
+ }
+ (*ref)->save_result(to);
+ null_value= (*ref)->null_value;
+}
+
+
+void Item_ref::save_val(Field *to)
+{
+ (*ref)->save_result(to);
+ null_value= (*ref)->null_value;
+}
+
+
double Item_ref::val_real()
{
DBUG_ASSERT(fixed);
@@ -6358,6 +6556,13 @@ void Item_ref_null_helper::print(String *str, enum_query_type query_type)
}
+void Item_direct_ref::save_val(Field *to)
+{
+ (*ref)->save_val(to);
+ null_value=(*ref)->null_value;
+}
+
+
double Item_direct_ref::val_real()
{
double tmp=(*ref)->val_real();
@@ -6410,6 +6615,385 @@ bool Item_direct_ref::get_date(MYSQL_TIME *ltime,uint fuzzydate)
}
+Item_cache_wrapper::~Item_cache_wrapper()
+{
+ delete expr_cache;
+ /* expr_value is Item so it will be destroyed from list of Items */
+}
+
+
+Item_cache_wrapper::Item_cache_wrapper(Item *item_arg)
+:orig_item(item_arg), expr_cache(NULL), expr_value(NULL)
+{
+ DBUG_ASSERT(orig_item->fixed);
+ max_length= orig_item->max_length;
+ maybe_null= orig_item->maybe_null;
+ decimals= orig_item->decimals;
+ collation.set(orig_item->collation);
+ with_sum_func= orig_item->with_sum_func;
+ unsigned_flag= orig_item->unsigned_flag;
+ name= item_arg->name;
+ name_length= item_arg->name_length;
+
+ if ((expr_value= Item_cache::get_cache(orig_item)))
+ expr_value->setup(orig_item);
+
+ fixed= 1;
+}
+
+
+void Item_cache_wrapper::print(String *str, enum_query_type query_type)
+{
+ str->append(func_name());
+ if (expr_cache)
+ expr_cache->print(str, query_type);
+ else
+ str->append(STRING_WITH_LEN("<<DISABLED>>"));
+ str->append('(');
+ orig_item->print(str, query_type);
+ str->append(')');
+}
+
+
+/**
+ Prepare the expression cache wrapper (do nothing)
+
+ @retval FALSE OK
+*/
+
+bool Item_cache_wrapper::fix_fields(THD *thd __attribute__((unused)),
+ Item **it __attribute__((unused)))
+{
+ DBUG_ASSERT(orig_item->fixed);
+ DBUG_ASSERT(fixed);
+ return FALSE;
+}
+
+
+/**
+ Clean the expression cache wrapper up before reusing it.
+*/
+
+void Item_cache_wrapper::cleanup()
+{
+ delete expr_cache;
+ expr_cache= 0;
+ // expr_value is Item so it will be destroyed from list of Items
+ expr_value= 0;
+}
+
+
+/**
+ Create an expression cache that uses a temporary table
+
+ @param thd Thread handle
+ @param depends_on Parameters of the expression to create cache for
+
+ @details
+ The function takes 'depends_on' as the list of all parameters for
+ the expression wrapped into this object and creates an expression
+ cache in a temporary table containing the field for the parameters
+ and the result of the expression.
+
+ @retval FALSE OK
+ @retval TRUE Error
+*/
+
+bool Item_cache_wrapper::set_cache(THD *thd, List<Item*> &depends_on)
+{
+ DBUG_ENTER("Item_cache_wrapper::set_cache");
+ expr_cache= new Expression_cache_tmptable(thd, depends_on, expr_value);
+ DBUG_RETURN(expr_cache == NULL);
+}
+
+
+/**
+ Check if the current values of the parameters are in the expression cache
+
+ @details
+ The function checks whether the current set of the parameters of the
+ referenced item can be found in the expression cache. If so the function
+ returns the item by which the result of the expression can be easily
+ extracted from the cache with the corresponding val_* method.
+
+ @retval NULL - parameters are not in the cache
+ @retval <item*> - item providing the result of the expression found in cache
+*/
+
+Item *Item_cache_wrapper::check_cache()
+{
+ DBUG_ENTER("Item_cache_wrapper::check_cache");
+ if (expr_cache)
+ {
+ Expression_cache_tmptable::result res;
+ Item *cached_value;
+ res= expr_cache->check_value(&cached_value);
+ if (res == Expression_cache_tmptable::HIT)
+ DBUG_RETURN(cached_value);
+ }
+ DBUG_RETURN(NULL);
+}
+
+
+/**
+ Get the value of the cached expression and put it in the cache
+*/
+
+inline void Item_cache_wrapper::cache()
+{
+ expr_value->store(orig_item);
+ expr_value->cache_value();
+ expr_cache->put_value(expr_value); // put in expr_cache
+}
+
+
+/**
+ Get the value of the possibly cached item into the field.
+*/
+
+void Item_cache_wrapper::save_val(Field *to)
+{
+ Item *cached_value;
+ DBUG_ENTER("Item_cache_wrapper::val_int");
+ if (!expr_cache)
+ {
+ orig_item->save_val(to);
+ null_value= orig_item->null_value;
+ DBUG_VOID_RETURN;
+ }
+
+ if ((cached_value= check_cache()))
+ {
+ cached_value->save_val(to);
+ null_value= cached_value->null_value;
+ DBUG_VOID_RETURN;
+ }
+ cache();
+ null_value= expr_value->null_value;
+ expr_value->save_val(to);
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ Get the integer value of the possibly cached item.
+*/
+
+longlong Item_cache_wrapper::val_int()
+{
+ Item *cached_value;
+ DBUG_ENTER("Item_cache_wrapper::val_int");
+ if (!expr_cache)
+ {
+ longlong tmp= orig_item->val_int();
+ null_value= orig_item->null_value;
+ DBUG_RETURN(tmp);
+ }
+
+ if ((cached_value= check_cache()))
+ {
+ longlong tmp= cached_value->val_int();
+ null_value= cached_value->null_value;
+ DBUG_RETURN(tmp);
+ }
+ cache();
+ null_value= expr_value->null_value;
+ DBUG_RETURN(expr_value->val_int());
+}
+
+
+/**
+ Get the real value of the possibly cached item
+*/
+
+double Item_cache_wrapper::val_real()
+{
+ Item *cached_value;
+ DBUG_ENTER("Item_cache_wrapper::val_real");
+ if (!expr_cache)
+ {
+ double tmp= orig_item->val_real();
+ null_value= orig_item->null_value;
+ DBUG_RETURN(tmp);
+ }
+
+ if ((cached_value= check_cache()))
+ {
+ double tmp= cached_value->val_real();
+ null_value= cached_value->null_value;
+ DBUG_RETURN(tmp);
+ }
+ cache();
+ null_value= expr_value->null_value;
+ DBUG_RETURN(expr_value->val_real());
+}
+
+
+/**
+ Get the string value of the possibly cached item
+*/
+
+String *Item_cache_wrapper::val_str(String* str)
+{
+ Item *cached_value;
+ DBUG_ENTER("Item_cache_wrapper::val_str");
+ if (!expr_cache)
+ {
+ String *tmp= orig_item->val_str(str);
+ null_value= orig_item->null_value;
+ DBUG_RETURN(tmp);
+ }
+
+ if ((cached_value= check_cache()))
+ {
+ String *tmp= cached_value->val_str(str);
+ null_value= cached_value->null_value;
+ DBUG_RETURN(tmp);
+ }
+ cache();
+ if ((null_value= expr_value->null_value))
+ DBUG_RETURN(NULL);
+ DBUG_RETURN(expr_value->val_str(str));
+}
+
+
+/**
+ Get the decimal value of the possibly cached item
+*/
+
+my_decimal *Item_cache_wrapper::val_decimal(my_decimal* decimal_value)
+{
+ Item *cached_value;
+ DBUG_ENTER("Item_cache_wrapper::val_decimal");
+ if (!expr_cache)
+ {
+ my_decimal *tmp= orig_item->val_decimal(decimal_value);
+ null_value= orig_item->null_value;
+ DBUG_RETURN(tmp);
+ }
+
+ if ((cached_value= check_cache()))
+ {
+ my_decimal *tmp= cached_value->val_decimal(decimal_value);
+ null_value= cached_value->null_value;
+ DBUG_RETURN(tmp);
+ }
+ cache();
+ if ((null_value= expr_value->null_value))
+ DBUG_RETURN(NULL);
+ DBUG_RETURN(expr_value->val_decimal(decimal_value));
+}
+
+
+/**
+ Get the boolean value of the possibly cached item
+*/
+
+bool Item_cache_wrapper::val_bool()
+{
+ Item *cached_value;
+ DBUG_ENTER("Item_cache_wrapper::val_bool");
+ if (!expr_cache)
+ {
+ bool tmp= orig_item->val_bool();
+ null_value= orig_item->null_value;
+ DBUG_RETURN(tmp);
+ }
+
+ if ((cached_value= check_cache()))
+ {
+ bool tmp= cached_value->val_bool();
+ null_value= cached_value->null_value;
+ DBUG_RETURN(tmp);
+ }
+ cache();
+ null_value= expr_value->null_value;
+ DBUG_RETURN(expr_value->val_bool());
+}
+
+
+/**
+ Check for NULL the value of the possibly cached item
+*/
+
+bool Item_cache_wrapper::is_null()
+{
+ Item *cached_value;
+ DBUG_ENTER("Item_cache_wrapper::is_null");
+ if (!expr_cache)
+ {
+ bool tmp= orig_item->is_null();
+ null_value= orig_item->null_value;
+ DBUG_RETURN(tmp);
+ }
+
+ if ((cached_value= check_cache()))
+ {
+ bool tmp= cached_value->is_null();
+ null_value= cached_value->null_value;
+ DBUG_RETURN(tmp);
+ }
+ cache();
+ DBUG_RETURN((null_value= expr_value->null_value));
+}
+
+
+/**
+ Get the date value of the possibly cached item
+*/
+
+bool Item_cache_wrapper::get_date(MYSQL_TIME *ltime, uint fuzzydate)
+{
+ Item *cached_value;
+ DBUG_ENTER("Item_cache_wrapper::get_date");
+ if (!expr_cache)
+ DBUG_RETURN((null_value= orig_item->get_date(ltime, fuzzydate)));
+
+ if ((cached_value= check_cache()))
+ DBUG_RETURN((null_value= cached_value->get_date(ltime, fuzzydate)));
+
+ cache();
+ DBUG_RETURN((null_value= expr_value->get_date(ltime, fuzzydate)));
+}
+
+
+/**
+ Get the time value of the possibly cached item
+*/
+
+bool Item_cache_wrapper::get_time(MYSQL_TIME *ltime)
+{
+ Item *cached_value;
+ DBUG_ENTER("Item_cache_wrapper::get_time");
+ if (!expr_cache)
+ DBUG_RETURN((null_value= orig_item->get_time(ltime)));
+
+ if ((cached_value= check_cache()))
+ DBUG_RETURN((null_value= cached_value->get_time(ltime)));
+
+ cache();
+ DBUG_RETURN((null_value= expr_value->get_time(ltime)));
+}
+
+
+int Item_cache_wrapper::save_in_field(Field *to, bool no_conversions)
+{
+ int res;
+ DBUG_ASSERT(!result_field);
+ res= orig_item->save_in_field(to, no_conversions);
+ null_value= orig_item->null_value;
+ return res;
+}
+
+
+Item* Item_cache_wrapper::get_tmp_table_item(THD *thd_arg)
+{
+ if (!orig_item->with_sum_func && !orig_item->const_item())
+ return new Item_field(result_field);
+ return copy_or_same(thd_arg);
+}
+
+
/**
Prepare referenced field then call usual Item_direct_ref::fix_fields .
@@ -6478,6 +7062,23 @@ bool Item_outer_ref::fix_fields(THD *thd, Item **reference)
}
+void Item_outer_ref::fix_after_pullout(st_select_lex *new_parent, Item **ref)
+{
+ if (depended_from == new_parent)
+ {
+ *ref= outer_ref;
+ (*ref)->fix_after_pullout(new_parent, ref);
+ }
+}
+
+void Item_ref::fix_after_pullout(st_select_lex *new_parent, Item **refptr)
+{
+ (*ref)->fix_after_pullout(new_parent, ref);
+ if (depended_from == new_parent)
+ depended_from= NULL;
+}
+
+
/**
Mark references from inner selects used in group by clause
@@ -7156,8 +7757,11 @@ void Item_cache_int::store_longlong(Item *item, longlong val_arg)
String *Item_cache_int::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- if (!value_cached && !cache_value())
+ if ((!value_cached && !cache_value()) || null_value)
+ {
+ null_value= TRUE;
return NULL;
+ }
str->set(value, default_charset());
return str;
}
@@ -7166,8 +7770,11 @@ 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())
+ if ((!value_cached && !cache_value()) || null_value)
+ {
+ null_value= TRUE;
return NULL;
+ }
int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_val);
return decimal_val;
}
@@ -7175,16 +7782,22 @@ my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val)
double Item_cache_int::val_real()
{
DBUG_ASSERT(fixed == 1);
- if (!value_cached && !cache_value())
+ if ((!value_cached && !cache_value()) || null_value)
+ {
+ null_value= TRUE;
return 0.0;
+ }
return (double) value;
}
longlong Item_cache_int::val_int()
{
DBUG_ASSERT(fixed == 1);
- if (!value_cached && !cache_value())
+ if ((!value_cached && !cache_value()) || null_value)
+ {
+ null_value= TRUE;
return 0;
+ }
return value;
}
@@ -7202,16 +7815,22 @@ bool Item_cache_real::cache_value()
double Item_cache_real::val_real()
{
DBUG_ASSERT(fixed == 1);
- if (!value_cached && !cache_value())
+ if ((!value_cached && !cache_value()) || null_value)
+ {
+ null_value= TRUE;
return 0.0;
+ }
return value;
}
longlong Item_cache_real::val_int()
{
DBUG_ASSERT(fixed == 1);
- if (!value_cached && !cache_value())
+ if ((!value_cached && !cache_value()) || null_value)
+ {
+ null_value= TRUE;
return 0;
+ }
return (longlong) rint(value);
}
@@ -7219,8 +7838,11 @@ longlong Item_cache_real::val_int()
String* Item_cache_real::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- if (!value_cached && !cache_value())
+ if ((!value_cached && !cache_value()) || null_value)
+ {
+ null_value= TRUE;
return NULL;
+ }
str->set_real(value, decimals, default_charset());
return str;
}
@@ -7229,8 +7851,11 @@ 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())
+ if ((!value_cached && !cache_value()) || null_value)
+ {
+ null_value= TRUE;
return NULL;
+ }
double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val);
return decimal_val;
}
@@ -7251,8 +7876,11 @@ double Item_cache_decimal::val_real()
{
DBUG_ASSERT(fixed);
double res;
- if (!value_cached && !cache_value())
+ if ((!value_cached && !cache_value()) || null_value)
+ {
+ null_value= TRUE;
return 0.0;
+ }
my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &res);
return res;
}
@@ -7261,8 +7889,11 @@ longlong Item_cache_decimal::val_int()
{
DBUG_ASSERT(fixed);
longlong res;
- if (!value_cached && !cache_value())
+ if ((!value_cached && !cache_value()) || null_value)
+ {
+ null_value= TRUE;
return 0;
+ }
my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &res);
return res;
}
@@ -7270,8 +7901,11 @@ longlong Item_cache_decimal::val_int()
String* Item_cache_decimal::val_str(String *str)
{
DBUG_ASSERT(fixed);
- if (!value_cached && !cache_value())
+ if ((!value_cached && !cache_value()) || null_value)
+ {
+ null_value= TRUE;
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);
@@ -7281,8 +7915,11 @@ 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())
+ if ((!value_cached && !cache_value()) || null_value)
+ {
+ null_value= TRUE;
return NULL;
+ }
return &decimal_value;
}
@@ -7317,12 +7954,13 @@ 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_cached && !cache_value()) || null_value)
+ {
+ null_value= TRUE;
return 0.0;
- if (value)
- return my_strntod(value->charset(), (char*) value->ptr(),
- value->length(), &end_not_used, &err_not_used);
- return (double) 0;
+ }
+ return my_strntod(value->charset(), (char*) value->ptr(),
+ value->length(), &end_not_used, &err_not_used);
}
@@ -7330,21 +7968,24 @@ longlong Item_cache_str::val_int()
{
DBUG_ASSERT(fixed == 1);
int err;
- if (!value_cached && !cache_value())
+ if ((!value_cached && !cache_value()) || null_value)
+ {
+ null_value= TRUE;
return 0;
- if (value)
- return my_strntoll(value->charset(), value->ptr(),
- value->length(), 10, (char**) 0, &err);
- else
- return (longlong)0;
+ }
+ return my_strntoll(value->charset(), value->ptr(),
+ value->length(), 10, (char**) 0, &err);
}
String* Item_cache_str::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- if (!value_cached && !cache_value())
+ if ((!value_cached && !cache_value()) || null_value)
+ {
+ null_value= TRUE;
return 0;
+ }
return value;
}
@@ -7352,20 +7993,24 @@ String* Item_cache_str::val_str(String *str)
my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val)
{
DBUG_ASSERT(fixed == 1);
- if (!value_cached && !cache_value())
+ if ((!value_cached && !cache_value()) || null_value)
+ {
+ null_value= TRUE;
return NULL;
- if (value)
- string2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val);
- else
- decimal_val= 0;
+ }
+ string2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val);
return decimal_val;
}
int Item_cache_str::save_in_field(Field *field, bool no_conversions)
{
- if (!value_cached && !cache_value())
+ if ((!value_cached && !cache_value()) || null_value)
+ {
+ field->set_notnull();
+ null_value= TRUE;
return 0;
+ }
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;