diff options
Diffstat (limited to 'sql/item.cc')
-rw-r--r-- | sql/item.cc | 1647 |
1 files changed, 752 insertions, 895 deletions
diff --git a/sql/item.cc b/sql/item.cc index 757f09dec01..630a408b13f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2018, Oracle and/or its affiliates. - Copyright (c) 2010, 2021, MariaDB Corporation. + Copyright (c) 2010, 2022, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -124,60 +124,31 @@ void Item::push_note_converted_to_positive_complement(THD *thd) } -longlong Item::val_datetime_packed_result() +longlong Item::val_datetime_packed_result(THD *thd) { MYSQL_TIME ltime, tmp; - if (get_date_result(<ime, TIME_FUZZY_DATES | TIME_INVALID_DATES)) + if (get_date_result(thd, <ime, Datetime::Options_cmp(thd))) return 0; if (ltime.time_type != MYSQL_TIMESTAMP_TIME) return pack_time(<ime); - if ((null_value= time_to_datetime_with_warn(current_thd, <ime, &tmp, 0))) + if ((null_value= time_to_datetime_with_warn(thd, <ime, &tmp, + TIME_CONV_NONE))) return 0; return pack_time(&tmp); } -/** - Get date/time/datetime. - If DATETIME or DATE result is returned, it's converted to TIME. -*/ -bool Item::get_time_with_conversion(THD *thd, MYSQL_TIME *ltime, - ulonglong fuzzydate) +longlong Item::val_time_packed_result(THD *thd) { - if (get_date(ltime, fuzzydate)) - return true; - if (ltime->time_type != MYSQL_TIMESTAMP_TIME) - { - MYSQL_TIME ltime2; - if ((thd->variables.old_behavior & OLD_MODE_ZERO_DATE_TIME_CAST) && - (ltime->year || ltime->day || ltime->month)) - { - /* - Old mode conversion from DATETIME with non-zero YYYYMMDD part - to TIME works very inconsistently. Possible variants: - - truncate the YYYYMMDD part - - add (MM*33+DD)*24 to hours - - add (MM*31+DD)*24 to hours - Let's return TRUE here, to disallow equal field propagation. - Note, If we start to use this method in more pieces of the code other - than equal field propagation, we should probably return - TRUE only if some flag in fuzzydate is set. - */ - return true; - } - if (datetime_to_time_with_warn(thd, ltime, <ime2, TIME_SECOND_PART_DIGITS)) - { - /* - If the time difference between CURRENT_DATE and ltime - did not fit into the supported TIME range, then we set the - difference to the maximum possible value in the supported TIME range - */ - DBUG_ASSERT(0); - return (null_value= true); - } - *ltime= ltime2; - } - return false; + MYSQL_TIME ltime; + if (get_date_result(thd, <ime, Time::Options_cmp(thd))) + return 0; + if (ltime.time_type == MYSQL_TIMESTAMP_TIME) + return pack_time(<ime); + int warn= 0; + Time tmp(&warn, <ime, 0); + DBUG_ASSERT(tmp.is_valid_time()); + return tmp.to_packed(); } @@ -262,36 +233,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; -} - - -/* - All val_xxx_from_date() must call this method, to expose consistent behaviour - regarding SQL_MODE when converting DATE/DATETIME to other data types. -*/ -bool Item::get_temporal_with_sql_mode(MYSQL_TIME *ltime) -{ - return get_date(ltime, field_type() == MYSQL_TYPE_TIME - ? TIME_TIME_ONLY - : sql_mode_for_dates(current_thd)); -} - - -bool Item::is_null_from_temporal() -{ - MYSQL_TIME ltime; - return get_temporal_with_sql_mode(<ime); -} - - longlong Item::val_int_from_str(int *error) { char buff[MAX_FIELD_WIDTH]; @@ -333,12 +274,37 @@ longlong Item::val_int_unsigned_typecast_from_str() } -longlong Item::val_int_unsigned_typecast_from_int() +longlong Item::val_int_signed_typecast_from_real() { - longlong value= val_int(); - if (!null_value && unsigned_flag == 0 && value < 0) - push_note_converted_to_positive_complement(current_thd); - return value; + double nr= val_real(); + if (null_value) + return 0; + Converter_double_to_longlong conv(nr, false); + if (conv.error()) + { + THD *thd= current_thd; + push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, + ER_DATA_OVERFLOW, ER_THD(thd, ER_DATA_OVERFLOW), + ErrConvDouble(nr).ptr(), "SIGNED BIGINT"); + } + return conv.result(); +} + + +longlong Item::val_int_unsigned_typecast_from_real() +{ + double nr= val_real(); + if (null_value) + return 0; + Converter_double_to_longlong conv(nr, true); + if (conv.error()) + { + THD *thd= current_thd; + push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, + ER_DATA_OVERFLOW, ER_THD(thd, ER_DATA_OVERFLOW), + ErrConvDouble(nr).ptr(), "UNSIGNED BIGINT"); + } + return conv.result(); } @@ -351,18 +317,12 @@ longlong Item::val_int_signed_typecast_from_int() } -String *Item::val_string_from_date(String *str) +longlong Item::val_int_unsigned_typecast_from_int() { - MYSQL_TIME ltime; - if (get_temporal_with_sql_mode(<ime) || - str->alloc(MAX_DATE_STRING_REP_LENGTH)) - { - null_value= 1; - return (String *) 0; - } - str->length(my_TIME_to_str(<ime, const_cast<char*>(str->ptr()), decimals)); - str->set_charset(&my_charset_numeric); - return str; + longlong value= val_int(); + if (!null_value && unsigned_flag == 0 && value < 0) + push_note_converted_to_positive_complement(current_thd); + return value; } @@ -397,93 +357,10 @@ my_decimal *Item::val_decimal_from_string(my_decimal *decimal_value) } -my_decimal *Item::val_decimal_from_date(my_decimal *decimal_value) -{ - DBUG_ASSERT(fixed == 1); - MYSQL_TIME ltime; - if (get_temporal_with_sql_mode(<ime)) - { - my_decimal_set_zero(decimal_value); - null_value= 1; // set NULL, stop processing - return 0; - } - return date2my_decimal(<ime, decimal_value); -} - - -my_decimal *Item::val_decimal_from_time(my_decimal *decimal_value) -{ - DBUG_ASSERT(fixed == 1); - MYSQL_TIME ltime; - if (get_time(<ime)) - { - my_decimal_set_zero(decimal_value); - return 0; - } - return date2my_decimal(<ime, decimal_value); -} - - -longlong Item::val_int_from_date() -{ - DBUG_ASSERT(fixed == 1); - MYSQL_TIME ltime; - if (get_temporal_with_sql_mode(<ime)) - return 0; - longlong v= TIME_to_ulonglong(<ime); - return ltime.neg ? -v : v; -} - - -double Item::val_real_from_date() -{ - DBUG_ASSERT(fixed == 1); - MYSQL_TIME ltime; - if (get_temporal_with_sql_mode(<ime)) - return 0; - return TIME_to_double(<ime); -} - - -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; - if (get_time(<ime)) + if (get_time(field->table->in_use, <ime)) return set_field_to_null_with_conversions(field, no_conversions); field->set_notnull(); return field->store_time_dec(<ime, decimals); @@ -493,7 +370,8 @@ int Item::save_time_in_field(Field *field, bool no_conversions) int Item::save_date_in_field(Field *field, bool no_conversions) { MYSQL_TIME ltime; - if (get_date(<ime, sql_mode_for_dates(field->table->in_use))) + THD *thd= field->table->in_use; + if (get_date(thd, <ime, Datetime::Options(thd))) return set_field_to_null_with_conversions(field, no_conversions); field->set_notnull(); return field->store_time_dec(<ime, decimals); @@ -533,11 +411,11 @@ int Item::save_str_value_in_field(Field *field, String *result) Item::Item(THD *thd): is_expensive_cache(-1), rsize(0), name(null_clex_str), orig_name(0), - fixed(0), is_autogenerated_name(TRUE) + is_autogenerated_name(TRUE) { DBUG_ASSERT(thd); marker= 0; - maybe_null=null_value=with_sum_func=with_window_func=with_field=0; + maybe_null= null_value= with_window_func= with_field= false; in_rollup= 0; with_param= 0; @@ -590,11 +468,9 @@ Item::Item(THD *thd, Item *item): maybe_null(item->maybe_null), in_rollup(item->in_rollup), null_value(item->null_value), - with_sum_func(item->with_sum_func), with_param(item->with_param), with_window_func(item->with_window_func), with_field(item->with_field), - fixed(item->fixed), is_autogenerated_name(item->is_autogenerated_name) { next= thd->free_list; // Put in free list @@ -664,7 +540,6 @@ void Item::cleanup() { DBUG_ENTER("Item::cleanup"); DBUG_PRINT("enter", ("this: %p", this)); - fixed= 0; marker= 0; join_tab_idx= MAX_TABLES; if (orig_name) @@ -684,7 +559,7 @@ void Item::cleanup() bool Item::cleanup_processor(void *arg) { - if (fixed) + if (is_fixed()) cleanup(); return FALSE; } @@ -776,7 +651,8 @@ Item_ident::Item_ident(THD *thd, TABLE_LIST *view_arg, :Item_result_field(thd), orig_db_name(NullS), orig_table_name(view_arg->table_name.str), orig_field_name(*field_name_arg), - context(&view_arg->view->select_lex.context), + /* TODO: suspicious use of first_select_lex */ + context(&view_arg->view->first_select_lex()->context), db_name(NullS), table_name(view_arg->alias.str), field_name(*field_name_arg), alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX), @@ -969,12 +845,15 @@ bool Item_field::register_field_in_read_map(void *arg) { TABLE *table= (TABLE *) arg; int res= 0; + if (table && table != field->table) + return res; + if (field->vcol_info && - !bitmap_fast_test_and_set(field->table->vcol_set, field->field_index)) + !bitmap_fast_test_and_set(field->table->read_set, field->field_index)) { res= field->vcol_info->expr->walk(&Item::register_field_in_read_map,1,arg); } - if (field->table == table || !table) + else bitmap_set_bit(field->table->read_set, field->field_index); return res; } @@ -1201,7 +1080,7 @@ bool Item::check_type_scalar(const char *opname) const This hack in Item_outer_ref should probably be refactored eventually. Discuss with Sanja. */ - DBUG_ASSERT(fixed || type() == REF_ITEM); + DBUG_ASSERT(is_fixed() || type() == REF_ITEM); const Type_handler *handler= type_handler(); if (handler->is_scalar_type()) return false; @@ -1406,7 +1285,6 @@ Item *Item_cache::safe_charset_converter(THD *thd, CHARSET_INFO *tocs) unlikely(!(cache= new (thd->mem_root) Item_cache_str(thd, conv)))) return NULL; // Safe conversion is not possible, or OEM cache->setup(thd, conv); - cache->fixed= false; // Make Item::fix_fields() happy return cache; } @@ -1457,7 +1335,7 @@ Item *Item::const_charset_converter(THD *thd, CHARSET_INFO *tocs, const char *func_name) { DBUG_ASSERT(const_item()); - DBUG_ASSERT(fixed); + DBUG_ASSERT(is_fixed()); StringBuffer<64>tmp; String *s= val_str(&tmp); MEM_ROOT *mem_root= thd->mem_root; @@ -1525,116 +1403,37 @@ Item *Item_param::safe_charset_converter(THD *thd, CHARSET_INFO *tocs) As a extra convenience the time structure is reset on error or NULL values! */ -bool Item::get_date_from_int(MYSQL_TIME *ltime, ulonglong fuzzydate) +bool Item::get_date_from_int(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - longlong value= val_int(); - bool neg= !unsigned_flag && value < 0; - if (null_value || int_to_datetime_with_warn(neg, neg ? -value : value, - ltime, fuzzydate, - field_table_or_null(), - field_name_or_null())) - return null_value|= make_zero_date(ltime, fuzzydate); - return null_value= false; -} - - -bool Item::get_date_from_year(MYSQL_TIME *ltime, ulonglong fuzzydate) -{ - longlong value= val_int(); - DBUG_ASSERT(unsigned_flag || value >= 0); - if (max_length == 2) - { - if (value < 70) - value+= 2000; - else if (value <= 1900) - value+= 1900; - } - value*= 10000; /* make it YYYYMMHH */ - if (null_value || int_to_datetime_with_warn(false, value, - ltime, fuzzydate, - field_table_or_null(), - field_name_or_null())) - return null_value|= make_zero_date(ltime, fuzzydate); - return null_value= false; -} - - -bool Item::get_date_from_real(MYSQL_TIME *ltime, ulonglong fuzzydate) -{ - double value= val_real(); - if (null_value || double_to_datetime_with_warn(value, ltime, fuzzydate, + Longlong_hybrid value(val_int(), unsigned_flag); + return null_value || int_to_datetime_with_warn(thd, value, + ltime, fuzzydate, field_table_or_null(), - field_name_or_null())) - return null_value|= make_zero_date(ltime, fuzzydate); - return null_value= false; + field_name_or_null()); } -bool Item::get_date_from_decimal(MYSQL_TIME *ltime, ulonglong fuzzydate) +bool Item::get_date_from_real(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - my_decimal value, *res; - if (!(res= val_decimal(&value)) || - decimal_to_datetime_with_warn(res, ltime, fuzzydate, - field_table_or_null(), - 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]; - String tmp(buff,sizeof(buff), &my_charset_bin),*res; - if (!(res=val_str(&tmp)) || - str_to_datetime_with_warn(res->charset(), res->ptr(), res->length(), - ltime, fuzzydate)) - return null_value|= make_zero_date(ltime, fuzzydate); - return null_value= false; + double value= val_real(); + return null_value || double_to_datetime_with_warn(thd, value, + ltime, fuzzydate, + field_table_or_null(), + field_name_or_null()); } -bool Item::make_zero_date(MYSQL_TIME *ltime, ulonglong fuzzydate) +bool Item::get_date_from_string(THD *thd, MYSQL_TIME *to, date_mode_t mode) { - /* - if the item was not null and conversion failed, we return a zero date - if allowed, otherwise - null. - */ - bzero((char*) ltime,sizeof(*ltime)); - if (fuzzydate & TIME_TIME_ONLY) - { - /* - In the following scenario: - - The caller expected to get a TIME value - - Item returned a not NULL string or numeric value - - But then conversion from string or number to TIME failed - we need to change the default time_type from MYSQL_TIMESTAMP_DATE - (which was set in bzero) to MYSQL_TIMESTAMP_TIME and therefore - return TIME'00:00:00' rather than DATE'0000-00-00'. - If we don't do this, methods like Item::get_time_with_conversion() - will erroneously subtract CURRENT_DATE from '0000-00-00 00:00:00' - and return TIME'-838:59:59' instead of TIME'00:00:00' as a result. - */ - ltime->time_type= MYSQL_TIMESTAMP_TIME; - } - return !(fuzzydate & TIME_FUZZY_DATES); + StringBuffer<40> tmp; + const TABLE_SHARE *s = field_table_or_null(); + Temporal::Warn_push warn(thd, s ? s->db.str : nullptr, + s ? s->table_name.str : nullptr, + field_name_or_null(), to, mode); + Temporal_hybrid *t= new(to) Temporal_hybrid(thd, &warn, val_str(&tmp), mode); + return !t->is_valid_temporal(); } -bool Item::get_seconds(ulonglong *sec, ulong *sec_part) -{ - if (decimals == 0) - { // optimize for an important special case - longlong val= val_int(); - bool neg= val < 0 && !unsigned_flag; - *sec= neg ? -val : val; - *sec_part= 0; - return neg; - } - my_decimal tmp, *dec= val_decimal(&tmp); - if (!dec) - return 0; - return my_decimal2seconds(dec, sec, sec_part); -} const MY_LOCALE *Item::locale_from_val_str() { @@ -1773,7 +1572,7 @@ Query_fragment::Query_fragment(THD *thd, sp_head *sphead, *****************************************************************************/ Item_sp_variable::Item_sp_variable(THD *thd, const LEX_CSTRING *sp_var_name) - :Item(thd), m_thd(0), m_name(*sp_var_name) + :Item_fixed_hybrid(thd), m_thd(0), m_name(*sp_var_name) #ifndef DBUG_OFF , m_sp(0) #endif @@ -1785,7 +1584,7 @@ bool Item_sp_variable::fix_fields_from_item(THD *thd, Item **, const Item *it) { m_thd= thd; /* NOTE: this must be set before any this_xxx() */ - DBUG_ASSERT(it->fixed); + DBUG_ASSERT(it->is_fixed()); max_length= it->max_length; decimals= it->decimals; @@ -1856,6 +1655,12 @@ String *Item_sp_variable::val_str(String *sp) } +bool Item_sp_variable::val_native(THD *thd, Native *to) +{ + return val_native_from_item(thd, this_item(), to); +} + + my_decimal *Item_sp_variable::val_decimal(my_decimal *decimal_value) { DBUG_ASSERT(fixed); @@ -1866,11 +1671,11 @@ my_decimal *Item_sp_variable::val_decimal(my_decimal *decimal_value) } -bool Item_sp_variable::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) +bool Item_sp_variable::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { DBUG_ASSERT(fixed); Item *it= this_item(); - bool val= it->get_date(ltime, fuzzydate); + bool val= it->get_date(thd, ltime, fuzzydate); null_value= it->null_value; return val; } @@ -1906,10 +1711,10 @@ Item_splocal::Item_splocal(THD *thd, Rewritable_query_parameter(pos_in_q, len_in_q), Type_handler_hybrid_field_type(handler), m_rcontext_handler(rh), - m_var_idx(sp_var_idx) + m_var_idx(sp_var_idx), + m_type(handler == &type_handler_row ? ROW_ITEM : CONST_ITEM) { maybe_null= TRUE; - m_type= sp_map_item_type(handler); } @@ -2247,14 +2052,19 @@ my_decimal *Item_name_const::val_decimal(my_decimal *decimal_value) return val; } -bool Item_name_const::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) +bool Item_name_const::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { DBUG_ASSERT(fixed); - bool rc= value_item->get_date(ltime, fuzzydate); + bool rc= value_item->get_date(thd, ltime, fuzzydate); null_value= value_item->null_value; return rc; } +bool Item_name_const::val_native(THD *thd, Native *to) +{ + return val_native_from_item(thd, value_item, to); +} + bool Item_name_const::is_null() { return value_item->is_null(); @@ -2262,58 +2072,30 @@ bool Item_name_const::is_null() Item_name_const::Item_name_const(THD *thd, Item *name_arg, Item *val): - Item(thd), value_item(val), name_item(name_arg) + Item_fixed_hybrid(thd), value_item(val), name_item(name_arg) { StringBuffer<128> name_buffer; String *name_str; Item::maybe_null= TRUE; - valid_args= true; - if (!name_item->basic_const_item() || - !(name_str= name_item->val_str(&name_buffer))) // Can't have a NULL name - goto err; - set_name(thd, name_str->ptr(), name_str->length(), name_str->charset()); - - if (value_item->basic_const_item()) - return; // ok - - if (value_item->type() == FUNC_ITEM) - { - Item_func *value_func= (Item_func *) value_item; - if (value_func->functype() != Item_func::COLLATE_FUNC && - value_func->functype() != Item_func::NEG_FUNC) - goto err; - - if (value_func->key_item()->basic_const_item()) - return; // ok - } - -err: - valid_args= false; - my_error(ER_WRONG_ARGUMENTS, MYF(0), "NAME_CONST"); + if (name_item->basic_const_item() && + (name_str= name_item->val_str(&name_buffer))) // Can't have a NULL name + set_name(thd, name_str->ptr(), name_str->length(), name_str->charset()); } Item::Type Item_name_const::type() const { /* - As - 1. one can try to create the Item_name_const passing non-constant - arguments, although it's incorrect and - 2. the type() method can be called before the fix_fields() to get - type information for a further type cast, e.g. - if (item->type() == FIELD_ITEM) - ((Item_field *) item)->... - we return NULL_ITEM in the case to avoid wrong casting. - - valid_args guarantees value_item->basic_const_item(); if type is - FUNC_ITEM, then we have a fudged item_func_neg() on our hands - and return the underlying type. + + We are guarenteed that value_item->basic_const_item(), if not + an error is thrown that WRONG ARGUMENTS are supplied to + NAME_CONST function. + If type is FUNC_ITEM, then we have a fudged item_func_neg() + on our hands and return the underlying type. For Item_func_set_collation() e.g. NAME_CONST('name', 'value' COLLATE collation) we return its 'value' argument type. */ - if (!valid_args) - return NULL_ITEM; Item::Type value_type= value_item->type(); if (value_type == FUNC_ITEM) { @@ -2333,10 +2115,8 @@ Item::Type Item_name_const::type() const bool Item_name_const::fix_fields(THD *thd, Item **ref) { - if ((!value_item->fixed && - value_item->fix_fields(thd, &value_item)) || - (!name_item->fixed && - name_item->fix_fields(thd, &name_item)) || + if (value_item->fix_fields_if_needed(thd, &value_item) || + name_item->fix_fields_if_needed(thd, &name_item) || !value_item->const_item() || !name_item->const_item()) { @@ -2447,7 +2227,7 @@ void Item::split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array, else { /* Not a SUM() function */ - if (unlikely((!with_sum_func && !(split_flags & SPLIT_SUM_SELECT)))) + if (unlikely((!with_sum_func() && !(split_flags & SPLIT_SUM_SELECT)))) { /* This is not a SUM function and there are no SUM functions inside. @@ -2455,7 +2235,7 @@ void Item::split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array, */ return; } - if (likely(with_sum_func || + if (likely(with_sum_func() || (type() == FUNC_ITEM && (((Item_func *) this)->functype() == Item_func::ISNOTNULLTEST_FUNC || @@ -2808,7 +2588,7 @@ bool Type_std_attributes::agg_item_set_converter(const DTCollation &coll, thd->change_item_tree(arg, conv); - if (conv->fix_fields(thd, arg)) + if (conv->fix_fields_if_needed(thd, arg)) { res= TRUE; break; // we cannot return here, we need to restore "arena". @@ -2873,9 +2653,7 @@ Item_sp::Item_sp(THD *thd, Name_resolution_context *context_arg, dummy_table= (TABLE*) thd->calloc(sizeof(TABLE) + sizeof(TABLE_SHARE) + sizeof(Query_arena)); dummy_table->s= (TABLE_SHARE*) (dummy_table + 1); - /* TODO(cvicentiu) Move this sp_query_arena in the class as a direct member. - Currently it can not be done due to header include dependencies. */ - sp_query_arena= (Query_arena *) (dummy_table->s + 1); + sp_query_arena= new(dummy_table->s + 1) Query_arena(); memset(&sp_mem_root, 0, sizeof(sp_mem_root)); } @@ -2886,7 +2664,7 @@ Item_sp::Item_sp(THD *thd, Item_sp *item): dummy_table= (TABLE*) thd->calloc(sizeof(TABLE)+ sizeof(TABLE_SHARE) + sizeof(Query_arena)); dummy_table->s= (TABLE_SHARE*) (dummy_table+1); - sp_query_arena= (Query_arena *) (dummy_table->s + 1); + sp_query_arena= new(dummy_table->s + 1) Query_arena(); memset(&sp_mem_root, 0, sizeof(sp_mem_root)); } @@ -2975,7 +2753,7 @@ bool Item_sp::execute(THD *thd, bool *null_value, Item **args, uint arg_count) if (unlikely(execute_impl(thd, args, arg_count))) { *null_value= 1; - context->process_error(thd); + process_error(thd); if (thd->killed) thd->send_kill_message(); return true; @@ -3008,7 +2786,7 @@ Item_sp::execute_impl(THD *thd, Item **args, uint arg_count) DBUG_ENTER("Item_sp::execute_impl"); - if (context->security_ctx) + if (context && context->security_ctx) { /* Set view definer security context */ thd->security_ctx= context->security_ctx; @@ -3167,18 +2945,6 @@ Item* Item_ref::build_clone(THD *thd) } -void Item_ident_for_show::make_send_field(THD *thd, Send_field *tmp_field) -{ - tmp_field->table_name= tmp_field->org_table_name= table_name; - tmp_field->db_name= db_name; - tmp_field->col_name= tmp_field->org_col_name= field->field_name; - tmp_field->length=field->field_length; - tmp_field->type=field->type(); - tmp_field->flags= field->table->maybe_null ? - (field->flags & ~NOT_NULL_FLAG) : field->flags; - tmp_field->decimals= field->decimals(); -} - /**********************************************/ Item_field::Item_field(THD *thd, Field *f) @@ -3187,7 +2953,10 @@ Item_field::Item_field(THD *thd, Field *f) have_privileges(0), any_privileges(0) { set_field(f); - + /* + field_name and table_name should not point to garbage + if this item is to be reused + */ orig_table_name= table_name; orig_field_name= field_name; with_field= 1; @@ -3504,7 +3273,7 @@ String *Item_field::str_result(String *str) return result_field->val_str(str,&str_value); } -bool Item_field::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate) +bool Item_field::get_date(THD *thd, MYSQL_TIME *ltime,date_mode_t fuzzydate) { if ((null_value=field->is_null()) || field->get_date(ltime,fuzzydate)) { @@ -3514,7 +3283,7 @@ bool Item_field::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate) return 0; } -bool Item_field::get_date_result(MYSQL_TIME *ltime, ulonglong fuzzydate) +bool Item_field::get_date_result(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { if ((null_value= result_field->is_null()) || result_field->get_date(ltime, fuzzydate)) @@ -3526,6 +3295,36 @@ bool Item_field::get_date_result(MYSQL_TIME *ltime, ulonglong fuzzydate) } +bool Item_field::val_native(THD *thd, Native *to) +{ + return val_native_from_field(field, to); +} + + +bool Item_field::val_native_result(THD *thd, Native *to) +{ + return val_native_from_field(result_field, to); +} + + +longlong Item_field::val_datetime_packed(THD *thd) +{ + DBUG_ASSERT(fixed == 1); + if ((null_value= field->is_null())) + return 0; + return field->val_datetime_packed(thd); +} + + +longlong Item_field::val_time_packed(THD *thd) +{ + DBUG_ASSERT(fixed == 1); + if ((null_value= field->is_null())) + return 0; + return field->val_time_packed(thd); +} + + void Item_field::save_result(Field *to) { save_field_in_field(result_field, &null_value, to, TRUE); @@ -3724,6 +3523,60 @@ longlong Item_field::val_int_endpoint(bool left_endp, bool *incl_endp) return null_value? LONGLONG_MIN : res; } + +bool Item_basic_value::eq(const Item *item, bool binary_cmp) const +{ + const Item_const *c0, *c1; + const Type_handler *h0, *h1; + /* + - Test get_item_const() for NULL filters out Item_param + bound in a way that needs a data type conversion + (e.g. non-integer value in a LIMIT clause). + Item_param::get_item_const() return NULL in such cases. + - Test for type_handler_for_comparison() equality makes sure + that values of different data type groups do not get detected + as equal (e.g. numbers vs strings, time vs datetime). + - Test for cast_to_int_type_handler() equality distinguishes + values with dual properties. For example, VARCHAR 'abc' and hex + hybrid 0x616263 are equal in string context, but they are not equal + if the hybrid appears in integer context (it behaves as integer then). + Here we have no full information about the context, so treat them + as not equal. + QQ: We could pass Value_source::Context here instead of + "bool binary_cmp", to make substitution more delicate. + See Field::get_equal_const_item(). + */ + bool res= (c0= get_item_const()) && + (c1= item->get_item_const()) && + (h0= type_handler())->type_handler_for_comparison() == + (h1= item->type_handler())->type_handler_for_comparison() && + h0->cast_to_int_type_handler()->type_handler_for_comparison() == + h1->cast_to_int_type_handler()->type_handler_for_comparison(); + if (res) + { + switch (c0->const_is_null() + c1->const_is_null()) { + case 2: // Two NULLs + res= true; + break; + case 1: // NULL and non-NULL + res= false; + break; + case 0: // Two non-NULLs + res= h0->Item_const_eq(c0, c1, binary_cmp); + } + } + DBUG_EXECUTE_IF("Item_basic_value", + push_warning_printf(current_thd, + Sql_condition::WARN_LEVEL_NOTE, + ER_UNKNOWN_ERROR, "%seq=%d a=%s b=%s", + binary_cmp ? "bin_" : "", (int) res, + DbugStringItemTypeValue(current_thd, this).c_ptr(), + DbugStringItemTypeValue(current_thd, item).c_ptr() + );); + return res; +} + + /** Create an item from a string we KNOW points to a valid longlong end \\0 terminated number string. @@ -3743,7 +3596,6 @@ Item_int::Item_int(THD *thd, const char *str_arg, size_t length): the field name. */ name.length= !str_arg[max_length] ? max_length : strlen(str_arg); - fixed= 1; } @@ -3755,8 +3607,6 @@ my_decimal *Item_int::val_decimal(my_decimal *decimal_value) String *Item_int::val_str(String *str) { - // following assert is redundant, because fixed=1 assigned in constructor - DBUG_ASSERT(fixed == 1); str->set_int(value, unsigned_flag, collation.collation); return str; } @@ -3793,8 +3643,6 @@ Item_uint::Item_uint(THD *thd, const char *str_arg, longlong i, uint length): String *Item_uint::val_str(String *str) { - // following assert is redundant, because fixed=1 assigned in constructor - DBUG_ASSERT(fixed == 1); str->set((ulonglong) value, collation.collation); return str; } @@ -3816,7 +3664,6 @@ Item_decimal::Item_decimal(THD *thd, const char *str_arg, size_t length, name.str= str_arg; name.length= safe_strlen(str_arg); decimals= (uint8) decimal_value.frac; - fixed= 1; max_length= my_decimal_precision_to_length_no_truncation(decimal_value.intg + decimals, decimals, @@ -3828,7 +3675,6 @@ Item_decimal::Item_decimal(THD *thd, longlong val, bool unsig): { int2my_decimal(E_DEC_FATAL_ERROR, val, unsig, &decimal_value); decimals= (uint8) decimal_value.frac; - fixed= 1; max_length= my_decimal_precision_to_length_no_truncation(decimal_value.intg + decimals, decimals, @@ -3841,7 +3687,6 @@ Item_decimal::Item_decimal(THD *thd, double val, int precision, int scale): { double2my_decimal(E_DEC_FATAL_ERROR, val, &decimal_value); decimals= (uint8) decimal_value.frac; - fixed= 1; max_length= my_decimal_precision_to_length_no_truncation(decimal_value.intg + decimals, decimals, @@ -3858,16 +3703,14 @@ Item_decimal::Item_decimal(THD *thd, const char *str, const my_decimal *val_arg, name.length= safe_strlen(str); decimals= (uint8) decimal_par; max_length= length; - fixed= 1; } -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); decimals= (uint8) decimal_value.frac; - fixed= 1; max_length= my_decimal_precision_to_length_no_truncation(decimal_value.intg + decimals, decimals, @@ -3876,63 +3719,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; - fixed= 1; 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); -} - - -bool Item_decimal::eq(const Item *item, bool binary_cmp) const -{ - if (type() == item->type() && item->basic_const_item()) - { - /* - We need to cast off const to call val_decimal(). This should - be OK for a basic constant. Additionally, we can pass 0 as - a true decimal constant will return its internal decimal - storage and ignore the argument. - */ - Item *arg= (Item*) item; - my_decimal *value= arg->val_decimal(0); - return !my_decimal_cmp(&decimal_value, value); - } - return 0; -} - - void Item_decimal::set_decimal_value(my_decimal *value_par) { my_decimal2decimal(value_par, &decimal_value); @@ -3954,8 +3749,6 @@ Item *Item_decimal::clone_item(THD *thd) String *Item_float::val_str(String *str) { - // following assert is redundant, because fixed=1 assigned in constructor - DBUG_ASSERT(fixed == 1); str->set_real(value, decimals, &my_charset_numeric); return str; } @@ -3963,8 +3756,6 @@ String *Item_float::val_str(String *str) my_decimal *Item_float::val_decimal(my_decimal *decimal_value) { - // following assert is redundant, because fixed=1 assigned in constructor - DBUG_ASSERT(fixed == 1); double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_value); return (decimal_value); } @@ -4065,7 +3856,6 @@ void Item_string::print(String *str, enum_query_type query_type) double Item_string::val_real() { - DBUG_ASSERT(fixed == 1); return double_from_string_with_check(&str_value); } @@ -4076,7 +3866,6 @@ double Item_string::val_real() */ longlong Item_string::val_int() { - DBUG_ASSERT(fixed == 1); return longlong_from_string_with_check(&str_value); } @@ -4089,23 +3878,17 @@ my_decimal *Item_string::val_decimal(my_decimal *decimal_value) double Item_null::val_real() { - // following assert is redundant, because fixed=1 assigned in constructor - DBUG_ASSERT(fixed == 1); null_value=1; return 0.0; } longlong Item_null::val_int() { - // following assert is redundant, because fixed=1 assigned in constructor - DBUG_ASSERT(fixed == 1); null_value=1; return 0; } /* ARGSUSED */ String *Item_null::val_str(String *str) { - // following assert is redundant, because fixed=1 assigned in constructor - DBUG_ASSERT(fixed == 1); null_value=1; return 0; } @@ -4116,25 +3899,23 @@ my_decimal *Item_null::val_decimal(my_decimal *decimal_value) } -longlong Item_null::val_datetime_packed() +longlong Item_null::val_datetime_packed(THD *) { null_value= true; return 0; } -longlong Item_null::val_time_packed() +longlong Item_null::val_time_packed(THD *) { null_value= true; return 0; } -bool Item_null::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) +bool Item_null::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - // following assert is redundant, because fixed=1 assigned in constructor - DBUG_ASSERT(fixed == 1); - make_zero_date(ltime, fuzzydate); + set_zero_time(ltime, MYSQL_TIMESTAMP_NONE); return (null_value= true); } @@ -4183,8 +3964,6 @@ Item_param::Item_param(THD *thd, const LEX_CSTRING *name_arg, */ Type_handler_hybrid_field_type(&type_handler_null), state(NO_VALUE), - /* Don't pretend to be a literal unless value for this item is set. */ - item_type(PARAM_ITEM), m_empty_string_is_null(false), indicator(STMT_INDICATOR_NONE), m_out_param_info(NULL), @@ -4243,7 +4022,6 @@ void Item_param::sync_clones() c->Type_geometry_attributes::operator=(*this); c->state= state; - c->item_type= item_type; c->m_empty_string_is_null= m_empty_string_is_null; c->value.PValue_simple::operator=(value); @@ -4278,7 +4056,6 @@ void Item_param::set_null() max_length= 0; decimals= 0; state= NULL_VALUE; - fix_type(Item::NULL_ITEM); DBUG_VOID_RETURN; } @@ -4293,7 +4070,6 @@ void Item_param::set_int(longlong i, uint32 max_length_arg) decimals= 0; maybe_null= 0; null_value= 0; - fix_type(Item::INT_ITEM); DBUG_VOID_RETURN; } @@ -4308,7 +4084,6 @@ void Item_param::set_double(double d) decimals= NOT_FIXED_DEC; maybe_null= 0; null_value= 0; - fix_type(Item::REAL_ITEM); DBUG_VOID_RETURN; } @@ -4341,7 +4116,6 @@ void Item_param::set_decimal(const char *str, ulong length) decimals, unsigned_flag); maybe_null= 0; null_value= 0; - fix_type(Item::DECIMAL_ITEM); DBUG_VOID_RETURN; } @@ -4359,7 +4133,6 @@ void Item_param::set_decimal(const my_decimal *dv, bool unsigned_arg) decimals, unsigned_flag); maybe_null= 0; null_value= 0; - fix_type(Item::DECIMAL_ITEM); } @@ -4371,7 +4144,6 @@ void Item_param::fix_temporal(uint32 max_length_arg, uint decimals_arg) decimals= decimals_arg; maybe_null= 0; null_value= 0; - fix_type(Item::DATE_ITEM); } @@ -4456,7 +4228,6 @@ bool Item_param::set_str(const char *str, ulong length, null_value= 0; /* max_length and decimals are set after charset conversion */ /* sic: str may be not null-terminated, don't add DBUG_PRINT here */ - fix_type(Item::STRING_ITEM); DBUG_RETURN(FALSE); } @@ -4490,7 +4261,6 @@ bool Item_param::set_longdata(const char *str, ulong length) state= LONG_DATA_VALUE; maybe_null= 0; null_value= 0; - fix_type(Item::STRING_ITEM); DBUG_RETURN(FALSE); } @@ -4554,7 +4324,7 @@ bool Item_param::set_from_item(THD *thd, Item *item) } } struct st_value tmp; - if (!item->save_in_value(&tmp)) + if (!item->save_in_value(thd, &tmp)) { const Type_handler *h= item->type_handler(); set_handler(h); @@ -4592,16 +4362,6 @@ void Item_param::reset() state= NO_VALUE; maybe_null= 1; null_value= 0; - fixed= false; - /* - Don't reset item_type to PARAM_ITEM: it's only needed to guard - us from item optimizations at prepare stage, when item doesn't yet - contain a literal of some kind. - In all other cases when this object is accessed its value is - set (this assumption is guarded by 'state' and - DBUG_ASSERTS(state != NO_VALUE) in all Item_param::get_* - methods). - */ DBUG_VOID_RETURN; } @@ -4684,7 +4444,7 @@ void Item_param::invalid_default_param() const } -bool Item_param::get_date(MYSQL_TIME *res, ulonglong fuzzydate) +bool Item_param::get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate) { /* LIMIT clause parameter should not call get_date() @@ -4698,7 +4458,7 @@ bool Item_param::get_date(MYSQL_TIME *res, ulonglong fuzzydate) *res= value.time; return 0; } - return type_handler()->Item_get_date(this, res, fuzzydate); + return type_handler()->Item_get_date_with_warn(thd, this, res, fuzzydate); } @@ -4712,11 +4472,7 @@ double Item_param::PValue::val_real(const Type_std_attributes *attr) const ? (double) (ulonglong) integer : (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: @@ -4741,11 +4497,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: @@ -4795,7 +4547,7 @@ String *Item_param::PValue::val_str(String *str, str->set_int(integer, attr->unsigned_flag, &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: @@ -4836,8 +4588,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: @@ -4942,11 +4693,20 @@ bool Item_param::convert_str_value(THD *thd) bool Item_param::basic_const_item() const { - DBUG_ASSERT(fixed || state == NO_VALUE); - if (state == NO_VALUE || - (state == SHORT_DATA_VALUE && type_handler()->cmp_type() == TIME_RESULT)) - return FALSE; - return TRUE; + switch (state) { + case LONG_DATA_VALUE: + case NULL_VALUE: + return true; + case SHORT_DATA_VALUE: + return type_handler()->cmp_type() != TIME_RESULT; + case DEFAULT_VALUE: + case IGNORE_VALUE: + invalid_default_param(); + return false; + case NO_VALUE: + break; + } + return false; } @@ -5007,48 +4767,6 @@ Item_param::clone_item(THD *thd) } -bool Item_param::value_eq(const Item *item, bool binary_cmp) const -{ - switch (value.type_handler()->cmp_type()) { - case INT_RESULT: - return int_eq(value.integer, item); - case REAL_RESULT: - return real_eq(value.real, item); - case STRING_RESULT: - return str_eq(&value.m_string, item, binary_cmp); - case DECIMAL_RESULT: - case TIME_RESULT: - case ROW_RESULT: - break; - } - return false; -} - - -bool -Item_param::eq(const Item *item, bool binary_cmp) const -{ - if (!basic_const_item()) - return FALSE; - - // There's no "default". See comments in Item_param::save_in_field(). - switch (state) { - case IGNORE_VALUE: - case DEFAULT_VALUE: - invalid_default_param(); - return false; - case NULL_VALUE: - return null_eq(item); - case SHORT_DATA_VALUE: - case LONG_DATA_VALUE: - return value_eq(item, binary_cmp); - case NO_VALUE: - return false; - } - DBUG_ASSERT(0); // Garbage - return FALSE; -} - /* End of Item_param related */ void Item_param::print(String *str, enum_query_type query_type) @@ -5102,12 +4820,10 @@ Item_param::set_param_type_and_swap_value(Item_param *src) { Type_std_attributes::set(src); set_handler(src->type_handler()); - item_type= src->item_type; maybe_null= src->maybe_null; null_value= src->null_value; state= src->state; - fixed= src->fixed; value.swap(src->value); } @@ -5117,7 +4833,6 @@ void Item_param::set_default() { m_is_settable_routine_parameter= false; state= DEFAULT_VALUE; - fixed= true; /* When Item_param is set to DEFAULT_VALUE: - its val_str() and val_decimal() return NULL @@ -5133,7 +4848,6 @@ void Item_param::set_ignore() { m_is_settable_routine_parameter= false; state= IGNORE_VALUE; - fixed= true; null_value= true; } @@ -5162,7 +4876,7 @@ Item_param::set_value(THD *thd, sp_rcontext *ctx, Item **it) correctly fetches the value from the client-server protocol, using set_param_func(). */ - if (arg->save_in_value(&tmp) || + if (arg->save_in_value(thd, &tmp) || set_value(thd, arg, &tmp, arg->type_handler())) { set_null(); @@ -5187,7 +4901,7 @@ void Item_param::set_out_param_info(Send_field *info) { m_out_param_info= info; - set_handler_by_field_type(m_out_param_info->type); + set_handler(m_out_param_info->type_handler()); } @@ -5228,16 +4942,7 @@ void Item_param::make_send_field(THD *thd, Send_field *field) OUT-parameter info to fill out the names. */ - field->db_name= m_out_param_info->db_name; - field->table_name= m_out_param_info->table_name; - field->org_table_name= m_out_param_info->org_table_name; - field->col_name= m_out_param_info->col_name; - field->org_col_name= m_out_param_info->org_col_name; - - field->length= m_out_param_info->length; - field->flags= m_out_param_info->flags; - field->decimals= m_out_param_info->decimals; - field->type= m_out_param_info->type; + *field= *m_out_param_info; } bool Item_param::append_for_log(THD *thd, String *str) @@ -5308,17 +5013,6 @@ my_decimal *Item_copy_string::val_decimal(my_decimal *decimal_value) Functions to convert item to field (for send_result_set_metadata) */ -/* ARGSUSED */ -bool Item::fix_fields(THD *thd, Item **ref) -{ - - // We do not check fields which are fixed during construction - DBUG_ASSERT(fixed == 0 || basic_const_item()); - fixed= 1; - return FALSE; -} - - void Item_ref_null_helper::save_val(Field *to) { DBUG_ASSERT(fixed == 1); @@ -5372,9 +5066,15 @@ String* Item_ref_null_helper::val_str(String* s) } -bool Item_ref_null_helper::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) +bool Item_ref_null_helper::val_native(THD *thd, Native *to) +{ + return (owner->was_null|= val_native_from_item(thd, *ref, to)); +} + + +bool Item_ref_null_helper::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - return (owner->was_null|= null_value= (*ref)->get_date_result(ltime, fuzzydate)); + return (owner->was_null|= null_value= (*ref)->get_date_result(thd, ltime, fuzzydate)); } @@ -5676,7 +5376,7 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) ref->alias_name_used= TRUE; /* If this is a non-aggregated field inside HAVING, search in GROUP BY. */ - if (select->having_fix_field && !ref->with_sum_func && group_list) + if (select->having_fix_field && !ref->with_sum_func() && group_list) { group_by_ref= find_field_in_group_list(ref, group_list); @@ -5718,7 +5418,7 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) ref->name.str, "forward reference in item list"); return NULL; } - DBUG_ASSERT((*select_ref)->fixed); + DBUG_ASSERT((*select_ref)->is_fixed()); return &select->ref_pointer_array[counter]; } if (group_by_ref) @@ -5841,8 +5541,9 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) Name_resolution_context *outer_context= 0; SELECT_LEX *select= 0; /* Currently derived tables cannot be correlated */ - if (current_sel->master_unit()->first_select()->linkage != - DERIVED_TABLE_TYPE) + if ((current_sel->master_unit()->first_select()->get_linkage() != + DERIVED_TABLE_TYPE) && + current_sel->master_unit()->outer_select()) outer_context= context->outer_context; /* @@ -5997,7 +5698,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) return -1; /* Some error occurred (e.g. ambiguous names). */ if (ref != not_found_item) { - DBUG_ASSERT(*ref && (*ref)->fixed); + DBUG_ASSERT(*ref && (*ref)->is_fixed()); prev_subselect_item->used_tables_and_const_cache_join(*ref); break; } @@ -6039,7 +5740,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) Item_ref *rf; /* Should have been checked in resolve_ref_in_select_and_group(). */ - DBUG_ASSERT(*ref && (*ref)->fixed); + DBUG_ASSERT(*ref && (*ref)->is_fixed()); /* Here, a subset of actions performed by Item_ref::set_properties is not enough. So we pass ptr to NULL into Item_[direct]_ref @@ -6616,23 +6317,25 @@ Item *Item_field::replace_equal_field(THD *thd, uchar *arg) comparison context, and it's safe to replace it to the constant from item_equal. */ - DBUG_ASSERT(type_handler()->type_handler_for_comparison()->cmp_type() == + DBUG_ASSERT(type_handler_for_comparison()->cmp_type() == item_equal->compare_type_handler()->cmp_type()); return const_item2; } - Item_field *subst= - (Item_field *)(item_equal->get_first(param->context_tab, this)); + Item_ident *subst= + (Item_ident *) (item_equal->get_first(param->context_tab, this)); if (subst) - subst= (Item_field *) (subst->real_item()); - if (subst && !field->eq(subst->field)) - return subst; + { + Item_field *subst2= (Item_field *) (subst->real_item()); + if (subst2 && !field->eq(subst2->field)) + return subst2; + } } return this; } void Item::init_make_send_field(Send_field *tmp_field, - enum enum_field_types field_type_arg) + const Type_handler *h) { tmp_field->db_name= ""; tmp_field->org_table_name= ""; @@ -6642,7 +6345,7 @@ void Item::init_make_send_field(Send_field *tmp_field, tmp_field->flags= (maybe_null ? 0 : NOT_NULL_FLAG) | (my_binary_compare(charset_for_protocol()) ? BINARY_FLAG : 0); - tmp_field->type= field_type_arg; + tmp_field->set_handler(h); tmp_field->length=max_length; tmp_field->decimals=decimals; if (unsigned_flag) @@ -6651,13 +6354,13 @@ void Item::init_make_send_field(Send_field *tmp_field, void Item::make_send_field(THD *thd, Send_field *tmp_field) { - init_make_send_field(tmp_field, field_type()); + init_make_send_field(tmp_field, type_handler()); } void Item_empty_string::make_send_field(THD *thd, Send_field *tmp_field) { - init_make_send_field(tmp_field, string_type_handler()->field_type()); + init_make_send_field(tmp_field, string_type_handler()); } @@ -6988,12 +6691,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()); } @@ -7060,14 +6762,18 @@ Item_string::make_string_literal_concat(THD *thd, const LEX_CSTRING *str) */ Item *Item_string::make_odbc_literal(THD *thd, const LEX_CSTRING *typestr) { - enum_field_types type= odbc_temporal_literal_type(typestr); - Item *res= type == MYSQL_TYPE_STRING ? this : - create_temporal_literal(thd, val_str(NULL), type, false); + Item_literal *res; + const Type_handler *h; + if (collation.repertoire == MY_REPERTOIRE_ASCII && + str_value.length() < MAX_DATE_STRING_REP_LENGTH * 4 && + (h= Type_handler::odbc_literal_type_handler(typestr)) && + (res= h->create_literal_item(thd, val_str(NULL), false))) + return res; /* - create_temporal_literal() returns NULL if failed to parse the string, + h->create_literal_item() returns NULL if failed to parse the string, or the string format did not match the type, e.g.: {d'2001-01-01 10:10:10'} */ - return res ? res : this; + return this; } @@ -7270,7 +6976,6 @@ Item_float::Item_float(THD *thd, const char *str_arg, size_t length): name.length= strlen(str_arg); decimals=(uint8) nr_of_decimals(str_arg, str_arg+length); max_length=(uint32)length; - fixed= 1; } @@ -7326,7 +7031,6 @@ void Item_hex_constant::hex_string_init(THD *thd, const char *str, size_t str_le } *ptr=0; // Keep purify happy collation.set(&my_charset_bin, DERIVATION_COERCIBLE); - fixed= 1; unsigned_flag= 1; } @@ -7405,7 +7109,6 @@ Item_bin_string::Item_bin_string(THD *thd, const char *str, size_t str_length): ptr[0]= 0; collation.set(&my_charset_bin, DERIVATION_COERCIBLE); - fixed= 1; } @@ -7428,20 +7131,11 @@ void Item_bin_string::print(String *str, enum_query_type query_type) } -bool Item_temporal_literal::eq(const Item *item, bool binary_cmp) const -{ - return - item->basic_const_item() && type() == item->type() && - field_type() == ((Item_temporal_literal *) item)->field_type() && - !my_time_compare(&cached_time, - &((Item_temporal_literal *) item)->cached_time); -} - void Item_date_literal::print(String *str, enum_query_type query_type) { str->append("DATE'"); char buf[MAX_DATE_STRING_REP_LENGTH]; - my_date_to_str(&cached_time, buf); + my_date_to_str(cached_time.get_mysql_time(), buf); str->append(buf); str->append('\''); } @@ -7453,12 +7147,11 @@ Item *Item_date_literal::clone_item(THD *thd) } -bool Item_date_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) +bool Item_date_literal::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - DBUG_ASSERT(fixed); - fuzzy_date |= sql_mode_for_dates(current_thd); - *ltime= cached_time; - return (null_value= check_date_with_warn(ltime, fuzzy_date, + fuzzydate |= sql_mode_for_dates(thd); + cached_time.copy_to_mysql_time(ltime); + return (null_value= check_date_with_warn(thd, ltime, fuzzydate, MYSQL_TIMESTAMP_ERROR)); } @@ -7467,7 +7160,7 @@ void Item_datetime_literal::print(String *str, enum_query_type query_type) { str->append("TIMESTAMP'"); char buf[MAX_DATE_STRING_REP_LENGTH]; - my_datetime_to_str(&cached_time, buf, decimals); + my_datetime_to_str(cached_time.get_mysql_time(), buf, decimals); str->append(buf); str->append('\''); } @@ -7479,12 +7172,11 @@ Item *Item_datetime_literal::clone_item(THD *thd) } -bool Item_datetime_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) +bool Item_datetime_literal::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - DBUG_ASSERT(fixed); - fuzzy_date |= sql_mode_for_dates(current_thd); - *ltime= cached_time; - return (null_value= check_date_with_warn(ltime, fuzzy_date, + fuzzydate |= sql_mode_for_dates(thd); + cached_time.copy_to_mysql_time(ltime); + return (null_value= check_date_with_warn(thd, ltime, fuzzydate, MYSQL_TIMESTAMP_ERROR)); } @@ -7493,7 +7185,7 @@ void Item_time_literal::print(String *str, enum_query_type query_type) { str->append("TIME'"); char buf[MAX_DATE_STRING_REP_LENGTH]; - my_time_to_str(&cached_time, buf, decimals); + my_time_to_str(cached_time.get_mysql_time(), buf, decimals); str->append(buf); str->append('\''); } @@ -7505,13 +7197,12 @@ Item *Item_time_literal::clone_item(THD *thd) } -bool Item_time_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) +bool Item_time_literal::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - DBUG_ASSERT(fixed); - *ltime= cached_time; - if (fuzzy_date & TIME_TIME_ONLY) + cached_time.copy_to_mysql_time(ltime); + if (fuzzydate & TIME_TIME_ONLY) return (null_value= false); - return (null_value= check_date_with_warn(ltime, fuzzy_date, + return (null_value= check_date_with_warn(thd, ltime, fuzzydate, MYSQL_TIMESTAMP_ERROR)); } @@ -7627,7 +7318,7 @@ void Item_field::update_null_value() no_errors= thd->no_errors; thd->no_errors= 1; - Item::update_null_value(); + type_handler()->Item_update_null_value(this); thd->no_errors= no_errors; } @@ -7678,6 +7369,198 @@ Item *Item_field::update_value_transformer(THD *thd, uchar *select_arg) } +/** + @brief + Prepare AND/OR formula for extraction of a pushable condition + + @param checker the checker callback function to be applied to the nodes + of the tree of the object + @param arg parameter to be passed to the checker + + @details + This method recursively traverses this AND/OR condition and for each + subformula of the condition it checks whether it can be usable for the + extraction of a pushable condition. The criteria of pushability of + a subformula is checked by the callback function 'checker' with one + parameter arg. The subformulas that are not usable are marked with + the flag NO_EXTRACTION_FL. + @note + This method is called before any call of build_pushable_cond. + The flag NO_EXTRACTION_FL set in a subformula allows to avoid building + clones for the subformulas that are not used in the pushable condition. + @note + This method is called for pushdown conditions into materialized + derived tables/views optimization. + Item::pushable_cond_checker_for_derived() is passed as the actual callback + function. + Also it is called for pushdown conditions in materialized IN subqueries. + Item::pushable_cond_checker_for_subquery is passed as the actual + callback function. +*/ + +void Item::check_pushable_cond(Pushdown_checker checker, uchar *arg) +{ + clear_extraction_flag(); + if (type() == Item::COND_ITEM) + { + bool and_cond= ((Item_cond*) this)->functype() == Item_func::COND_AND_FUNC; + List_iterator<Item> li(*((Item_cond*) this)->argument_list()); + uint count= 0; + Item *item; + while ((item=li++)) + { + item->check_pushable_cond(checker, arg); + if (item->get_extraction_flag() != NO_EXTRACTION_FL) + count++; + else if (!and_cond) + break; + } + if ((and_cond && count == 0) || item) + { + set_extraction_flag(NO_EXTRACTION_FL); + if (and_cond) + li.rewind(); + while ((item= li++)) + item->clear_extraction_flag(); + } + } + else if (!((this->*checker) (arg))) + set_extraction_flag(NO_EXTRACTION_FL); +} + + +/** + @brief + Build condition extractable from this condition for pushdown + + @param thd the thread handle + @param checker the checker callback function to be applied to the nodes + of the tree of the object to check if multiple equality + elements can be used to create equalities + @param arg parameter to be passed to the checker + + @details + This method finds out what condition that can be pushed down can be + extracted from this condition. If such condition C exists the + method builds the item for it. The method uses the flag NO_EXTRACTION_FL + set by the preliminary call of the method check_pushable_cond() to figure + out whether a subformula is pushable or not. + In the case when this item is a multiple equality a checker method is + called to find the equal fields to build a new equality that can be + pushed down. + @note + The built condition C is always implied by the condition cond + (cond => C). The method tries to build the most restrictive such + condition (i.e. for any other condition C' such that cond => C' + we have C => C'). + @note + The build item is not ready for usage: substitution for the field items + has to be done and it has to be re-fixed. + @note + This method is called for pushdown conditions into materialized + derived tables/views optimization. + Item::pushable_equality_checker_for_derived() is passed as the actual + callback function. + Also it is called for pushdown conditions into materialized IN subqueries. + Item::pushable_equality_checker_for_subquery() is passed as the actual + callback function. + + @retval + the built condition pushable into if such a condition exists + NULL if there is no such a condition +*/ + +Item *Item::build_pushable_cond(THD *thd, + Pushdown_checker checker, + uchar *arg) +{ + bool is_multiple_equality= type() == Item::FUNC_ITEM && + ((Item_func*) this)->functype() == Item_func::MULT_EQUAL_FUNC; + + if (get_extraction_flag() == NO_EXTRACTION_FL) + return 0; + + if (type() == Item::COND_ITEM) + { + bool cond_and= false; + Item_cond *new_cond; + if (((Item_cond*) this)->functype() == Item_func::COND_AND_FUNC) + { + cond_and= true; + new_cond= new (thd->mem_root) Item_cond_and(thd); + } + else + new_cond= new (thd->mem_root) Item_cond_or(thd); + if (!new_cond) + return 0; + List_iterator<Item> li(*((Item_cond*) this)->argument_list()); + Item *item; + bool is_fix_needed= false; + + while ((item=li++)) + { + if (item->get_extraction_flag() == NO_EXTRACTION_FL) + { + if (!cond_and) + return 0; + continue; + } + Item *fix= item->build_pushable_cond(thd, checker, arg); + if (!fix && !cond_and) + return 0; + if (!fix) + continue; + + if (fix->type() == Item::COND_ITEM && + ((Item_cond*) fix)->functype() == Item_func::COND_AND_FUNC) + is_fix_needed= true; + + if (new_cond->argument_list()->push_back(fix, thd->mem_root)) + return 0; + } + if (is_fix_needed && new_cond->fix_fields(thd, 0)) + return 0; + + switch (new_cond->argument_list()->elements) + { + case 0: + return 0; + case 1: + return new_cond->argument_list()->head(); + default: + return new_cond; + } + } + else if (is_multiple_equality) + { + List<Item> equalities; + Item *new_cond= NULL; + if (((Item_equal *)this)->create_pushable_equalities(thd, &equalities, + checker, arg, true) || + (equalities.elements == 0)) + return 0; + + switch (equalities.elements) + { + case 0: + return 0; + case 1: + new_cond= equalities.head(); + break; + default: + new_cond= new (thd->mem_root) Item_cond_and(thd, equalities); + break; + } + if (new_cond && new_cond->fix_fields(thd, &new_cond)) + return 0; + return new_cond; + } + else if (get_extraction_flag() != NO_EXTRACTION_FL) + return build_clone(thd); + return 0; +} + + static Item *get_field_item_for_having(THD *thd, Item *item, st_select_lex *sel) { @@ -7811,50 +7694,15 @@ Item *Item_direct_view_ref::derived_field_transformer_for_where(THD *thd, return (*ref); } -static -Grouping_tmp_field *find_matching_grouping_field(Item *item, - st_select_lex *sel) -{ - DBUG_ASSERT(item->type() == Item::FIELD_ITEM || - (item->type() == Item::REF_ITEM && - ((Item_ref *) item)->ref_type() == Item_ref::VIEW_REF)); - List_iterator<Grouping_tmp_field> li(sel->grouping_tmp_fields); - Grouping_tmp_field *gr_field; - Item_field *field_item= (Item_field *) (item->real_item()); - while ((gr_field= li++)) - { - if (field_item->field == gr_field->tmp_field) - return gr_field; - } - Item_equal *item_equal= item->get_item_equal(); - if (item_equal) - { - Item_equal_fields_iterator it(*item_equal); - Item *equal_item; - while ((equal_item= it++)) - { - field_item= (Item_field *) (equal_item->real_item()); - li.rewind(); - while ((gr_field= li++)) - { - if (field_item->field == gr_field->tmp_field) - return gr_field; - } - } - } - return NULL; -} - -Item *Item_field::derived_grouping_field_transformer_for_where(THD *thd, - uchar *arg) +Item *Item_field::grouping_field_transformer_for_where(THD *thd, uchar *arg) { st_select_lex *sel= (st_select_lex *)arg; - Grouping_tmp_field *gr_field= find_matching_grouping_field(this, sel); + Field_pair *gr_field= find_matching_field_pair(this, sel->grouping_tmp_fields); if (gr_field) { Item *producing_clone= - gr_field->producing_item->build_clone(thd); + gr_field->corresponding_item->build_clone(thd); if (producing_clone) producing_clone->marker|= SUBSTITUTION_FL; return producing_clone; @@ -7864,8 +7712,8 @@ Item *Item_field::derived_grouping_field_transformer_for_where(THD *thd, Item * -Item_direct_view_ref::derived_grouping_field_transformer_for_where(THD *thd, - uchar *arg) +Item_direct_view_ref::grouping_field_transformer_for_where(THD *thd, + uchar *arg) { if ((*ref)->marker & SUBSTITUTION_FL) { @@ -7875,8 +7723,9 @@ Item_direct_view_ref::derived_grouping_field_transformer_for_where(THD *thd, if (!item_equal) return this; st_select_lex *sel= (st_select_lex *)arg; - Grouping_tmp_field *gr_field= find_matching_grouping_field(this, sel); - return gr_field->producing_item->build_clone(thd); + Field_pair *gr_field= find_matching_field_pair(this, + sel->grouping_tmp_fields); + return gr_field->corresponding_item->build_clone(thd); } void Item_field::print(String *str, enum_query_type query_type) @@ -7912,7 +7761,7 @@ Item_ref::Item_ref(THD *thd, Name_resolution_context *context_arg, /* This constructor used to create some internals references over fixed items */ - if ((set_properties_only= (ref && *ref && (*ref)->fixed))) + if ((set_properties_only= (ref && *ref && (*ref)->is_fixed()))) set_properties(); } @@ -7961,7 +7810,7 @@ Item_ref::Item_ref(THD *thd, TABLE_LIST *view_arg, Item **item, /* This constructor is used to create some internal references over fixed items */ - if ((set_properties_only= (ref && *ref && (*ref)->fixed))) + if ((set_properties_only= (ref && *ref && (*ref)->is_fixed()))) set_properties(); } @@ -8043,8 +7892,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) else if (!ref || ref == not_found_item) { DBUG_ASSERT(reference_trough_name != 0); - if (!(ref= resolve_ref_in_select_and_group(thd, this, - context->select_lex))) + if (!(ref= resolve_ref_in_select_and_group(thd, this, context->select_lex))) goto error; /* Some error occurred (e.g. ambiguous names). */ if (ref == not_found_item) /* This reference was not resolved. */ @@ -8057,8 +7905,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) if (unlikely(!outer_context)) { /* The current reference cannot be resolved in this query. */ - my_error(ER_BAD_FIELD_ERROR,MYF(0), - this->full_name(), thd->where); + my_error(ER_BAD_FIELD_ERROR,MYF(0), full_name(), thd->where); goto error; } @@ -8087,7 +7934,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) goto error; /* Some error occurred (e.g. ambiguous names). */ if (ref != not_found_item) { - DBUG_ASSERT(*ref && (*ref)->fixed); + DBUG_ASSERT(*ref && (*ref)->is_fixed()); prev_subselect_item->used_tables_and_const_cache_join(*ref); break; } @@ -8211,7 +8058,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) goto error; } /* Should be checked in resolve_ref_in_select_and_group(). */ - DBUG_ASSERT(*ref && (*ref)->fixed); + DBUG_ASSERT(*ref && (*ref)->is_fixed()); mark_as_dependent(thd, last_checked_context->select_lex, context->select_lex, this, this, false); /* @@ -8237,13 +8084,13 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) */ if (!((*ref)->type() == REF_ITEM && ((Item_ref *)(*ref))->ref_type() == OUTER_REF) && - (((*ref)->with_sum_func && name.str && - !(current_sel->linkage != GLOBAL_OPTIONS_TYPE && + (((*ref)->with_sum_func() && name.str && + !(current_sel->get_linkage() != GLOBAL_OPTIONS_TYPE && current_sel->having_fix_field)) || - !(*ref)->fixed)) + !(*ref)->is_fixed())) { my_error(ER_ILLEGAL_REFERENCE, MYF(0), - name.str, ((*ref)->with_sum_func? + name.str, ((*ref)->with_sum_func() ? "reference to group function": "forward reference in item list")); goto error; @@ -8269,7 +8116,7 @@ void Item_ref::set_properties() We have to remember if we refer to a sum function, to ensure that split_sum_func() doesn't try to change the reference. */ - with_sum_func= (*ref)->with_sum_func; + copy_with_sum_func(*ref); with_param= (*ref)->with_param; with_window_func= (*ref)->with_window_func; with_field= (*ref)->with_field; @@ -8455,6 +8302,14 @@ String *Item_ref::str_result(String* str) } +bool Item_ref::val_native_result(THD *thd, Native *to) +{ + return result_field ? + val_native_from_field(result_field, to) : + val_native(thd, to); +} + + my_decimal *Item_ref::val_decimal_result(my_decimal *decimal_value) { if (result_field) @@ -8543,25 +8398,31 @@ bool Item_ref::is_null() } -bool Item_ref::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate) +bool Item_ref::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - return (null_value=(*ref)->get_date_result(ltime,fuzzydate)); + return (null_value=(*ref)->get_date_result(thd, ltime, fuzzydate)); } -longlong Item_ref::val_datetime_packed() +bool Item_ref::val_native(THD *thd, Native *to) +{ + return val_native_from_item(thd, *ref, to); +} + + +longlong Item_ref::val_datetime_packed(THD *thd) { DBUG_ASSERT(fixed); - longlong tmp= (*ref)->val_datetime_packed_result(); + longlong tmp= (*ref)->val_datetime_packed_result(thd); null_value= (*ref)->null_value; return tmp; } -longlong Item_ref::val_time_packed() +longlong Item_ref::val_time_packed(THD *thd) { DBUG_ASSERT(fixed); - longlong tmp= (*ref)->val_time_packed_result(); + longlong tmp= (*ref)->val_time_packed_result(thd); null_value= (*ref)->null_value; return tmp; } @@ -8698,23 +8559,29 @@ bool Item_direct_ref::is_null() } -bool Item_direct_ref::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate) +bool Item_direct_ref::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) +{ + return (null_value=(*ref)->get_date(thd, ltime, fuzzydate)); +} + + +bool Item_direct_ref::val_native(THD *thd, Native *to) { - return (null_value=(*ref)->get_date(ltime,fuzzydate)); + return val_native_from_item(thd, *ref, to); } -longlong Item_direct_ref::val_time_packed() +longlong Item_direct_ref::val_time_packed(THD *thd) { - longlong tmp = (*ref)->val_time_packed(); + longlong tmp = (*ref)->val_time_packed(thd); null_value= (*ref)->null_value; return tmp; } -longlong Item_direct_ref::val_datetime_packed() +longlong Item_direct_ref::val_datetime_packed(THD *thd) { - longlong tmp = (*ref)->val_datetime_packed(); + longlong tmp = (*ref)->val_datetime_packed(thd); null_value= (*ref)->null_value; return tmp; } @@ -8728,10 +8595,10 @@ Item_cache_wrapper::~Item_cache_wrapper() Item_cache_wrapper::Item_cache_wrapper(THD *thd, Item *item_arg): Item_result_field(thd), orig_item(item_arg), expr_cache(NULL), expr_value(NULL) { - DBUG_ASSERT(orig_item->fixed); + DBUG_ASSERT(orig_item->is_fixed()); Type_std_attributes::set(orig_item); maybe_null= orig_item->maybe_null; - with_sum_func= orig_item->with_sum_func; + copy_with_sum_func(orig_item); with_param= orig_item->with_param; with_field= orig_item->with_field; name= item_arg->name; @@ -8791,7 +8658,7 @@ void Item_cache_wrapper::print(String *str, enum_query_type query_type) bool Item_cache_wrapper::fix_fields(THD *thd __attribute__((unused)), Item **it __attribute__((unused))) { - DBUG_ASSERT(orig_item->fixed); + DBUG_ASSERT(orig_item->is_fixed()); DBUG_ASSERT(fixed); return FALSE; } @@ -9010,6 +8877,28 @@ String *Item_cache_wrapper::val_str(String* str) /** + Get the native value of the possibly cached item +*/ + +bool Item_cache_wrapper::val_native(THD *thd, Native* to) +{ + Item *cached_value; + DBUG_ENTER("Item_cache_wrapper::val_native"); + if (!expr_cache) + DBUG_RETURN(val_native_from_item(thd, orig_item, to)); + + if ((cached_value= check_cache())) + DBUG_RETURN(val_native_from_item(thd, cached_value, to)); + + cache(); + if ((null_value= expr_value->null_value)) + DBUG_RETURN(true); + DBUG_RETURN(expr_value->val_native(thd, to)); +} + + + +/** Get the decimal value of the possibly cached item */ @@ -9094,18 +8983,18 @@ bool Item_cache_wrapper::is_null() Get the date value of the possibly cached item */ -bool Item_cache_wrapper::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) +bool Item_cache_wrapper::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { Item *cached_value; DBUG_ENTER("Item_cache_wrapper::get_date"); if (!expr_cache) - DBUG_RETURN((null_value= orig_item->get_date(ltime, fuzzydate))); + DBUG_RETURN((null_value= orig_item->get_date(thd, ltime, fuzzydate))); if ((cached_value= check_cache())) - DBUG_RETURN((null_value= cached_value->get_date(ltime, fuzzydate))); + DBUG_RETURN((null_value= cached_value->get_date(thd, ltime, fuzzydate))); cache(); - DBUG_RETURN((null_value= expr_value->get_date(ltime, fuzzydate))); + DBUG_RETURN((null_value= expr_value->get_date(thd, ltime, fuzzydate))); } @@ -9121,7 +9010,7 @@ int Item_cache_wrapper::save_in_field(Field *to, bool no_conversions) Item* Item_cache_wrapper::get_tmp_table_item(THD *thd) { - if (!orig_item->with_sum_func && !orig_item->const_item()) + if (!orig_item->with_sum_func() && !orig_item->const_item()) return new (thd->mem_root) Item_temptable_field(thd, result_field); return copy_or_same(thd); } @@ -9151,7 +9040,7 @@ bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference) /* view fild reference must be defined */ DBUG_ASSERT(*ref); /* (*ref)->check_cols() will be made in Item_direct_ref::fix_fields */ - if ((*ref)->fixed) + if ((*ref)->is_fixed()) { Item *ref_item= (*ref)->real_item(); if (ref_item->type() == Item::FIELD_ITEM) @@ -9347,6 +9236,19 @@ Item *Item_direct_view_ref::propagate_equal_fields(THD *thd, } +Item *Item_ref::propagate_equal_fields(THD *thd, const Context &ctx, + COND_EQUAL *cond) +{ + Item *field_item= real_item(); + if (field_item->type() != FIELD_ITEM) + return this; + Item *item= field_item->propagate_equal_fields(thd, ctx, cond); + if (item != field_item) + return item; + return this; +} + + /** Replace an Item_direct_view_ref for an equal Item_field evaluated earlier (if any). @@ -9389,6 +9291,20 @@ Item *Item_direct_view_ref::replace_equal_field(THD *thd, uchar *arg) } +bool Item_field::excl_dep_on_table(table_map tab_map) +{ + return used_tables() == tab_map || + (item_equal && (item_equal->used_tables() & tab_map)); +} + + +bool +Item_field::excl_dep_on_grouping_fields(st_select_lex *sel) +{ + return find_matching_field_pair(this, sel->grouping_tmp_fields) != NULL; +} + + bool Item_direct_view_ref::excl_dep_on_table(table_map tab_map) { table_map used= used_tables(); @@ -9404,17 +9320,34 @@ bool Item_direct_view_ref::excl_dep_on_table(table_map tab_map) return (*ref)->excl_dep_on_table(tab_map); } + bool Item_direct_view_ref::excl_dep_on_grouping_fields(st_select_lex *sel) { if (item_equal) { DBUG_ASSERT(real_item()->type() == Item::FIELD_ITEM); - return find_matching_grouping_field(this, sel) != NULL; + return (find_matching_field_pair(this, sel->grouping_tmp_fields) != NULL); } return (*ref)->excl_dep_on_grouping_fields(sel); } +bool Item_args::excl_dep_on_grouping_fields(st_select_lex *sel) +{ + for (uint i= 0; i < arg_count; i++) + { + if (args[i]->type() == Item::FUNC_ITEM && + ((Item_func *)args[i])->functype() == Item_func::UDF_FUNC) + return false; + if (args[i]->const_item()) + continue; + if (!args[i]->excl_dep_on_grouping_fields(sel)) + return false; + } + return true; +} + + double Item_direct_view_ref::val_result() { double tmp=(*ref)->val_result(); @@ -9563,6 +9496,12 @@ void Item_default_value::calculate() DEBUG_SYNC(field->table->in_use, "after_Item_default_value_calculate"); } +bool Item_default_value::val_native(THD *thd, Native *to) +{ + calculate(); + return Item_field::val_native(thd, to); +} + String *Item_default_value::val_str(String *str) { calculate(); @@ -9587,10 +9526,10 @@ my_decimal *Item_default_value::val_decimal(my_decimal *decimal_value) return Item_field::val_decimal(decimal_value); } -bool Item_default_value::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate) +bool Item_default_value::get_date(THD *thd, MYSQL_TIME *ltime,date_mode_t fuzzydate) { calculate(); - return Item_field::get_date(ltime, fuzzydate); + return Item_field::get_date(thd, ltime, fuzzydate); } bool Item_default_value::send(Protocol *protocol, st_value *buffer) @@ -9605,6 +9544,12 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions) return Item_field::save_in_field(field_arg, no_conversions); } +void Item_default_value::save_in_result_field(bool no_conversions) +{ + calculate(); + Item_field::save_in_result_field(no_conversions); +} + double Item_default_value::val_result() { calculate(); @@ -9641,10 +9586,17 @@ my_decimal *Item_default_value::val_decimal_result(my_decimal *decimal_value) return Item_field::val_decimal_result(decimal_value); } -bool Item_default_value::get_date_result(MYSQL_TIME *ltime,ulonglong fuzzydate) +bool Item_default_value::get_date_result(THD *thd, MYSQL_TIME *ltime, + date_mode_t fuzzydate) { calculate(); - return Item_field::get_date_result(ltime, fuzzydate); + return Item_field::get_date_result(thd, ltime, fuzzydate); +} + +bool Item_default_value::val_native_result(THD *thd, Native *to) +{ + calculate(); + return Item_field::val_native_result(thd, to); } @@ -9657,6 +9609,23 @@ table_map Item_default_value::used_tables() const return field->default_value->expr->used_tables(); } +bool Item_default_value::register_field_in_read_map(void *arg) +{ + TABLE *table= (TABLE *) arg; + int res= 0; + if (!table || (table && table == field->table)) + { + if (field->default_value && field->default_value->expr) + res= field->default_value->expr->walk(&Item::register_field_in_read_map,1,arg); + } + else if (result_field && table == result_field->table) + { + bitmap_set_bit(table->read_set, result_field->field_index); + } + + return res; +} + /** This method like the walk method traverses the item tree, but at the same time it can replace some nodes in the tree. @@ -9695,7 +9664,7 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items) { DBUG_ASSERT(fixed == 0); /* We should only check that arg is in first table */ - if (!arg->fixed) + if (!arg->is_fixed()) { bool res; TABLE_LIST *orig_next_table= context->last_name_resolution_table; @@ -9909,7 +9878,7 @@ void Item_trigger_field::cleanup() Since special nature of Item_trigger_field we should not do most of things from Item_field::cleanup() or Item_ident::cleanup() here. */ - Item::cleanup(); + Item_fixed_hybrid::cleanup(); } @@ -9968,73 +9937,14 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) { - Item_result res_type=item_cmp_type(field->result_type(), - item->result_type()); - /* - We have to check field->cmp_type() instead of res_type, - as result_type() - and thus res_type - can never be TIME_RESULT (yet). - */ - if (field->cmp_type() == TIME_RESULT) - { - MYSQL_TIME field_time, item_time, item_time2, *item_time_cmp= &item_time; - if (field->type() == MYSQL_TYPE_TIME) - { - field->get_time(&field_time); - item->get_time(&item_time); - } - else - { - field->get_date(&field_time, TIME_INVALID_DATES); - item->get_date(&item_time, TIME_INVALID_DATES); - if (item_time.time_type == MYSQL_TIMESTAMP_TIME) - if (time_to_datetime(thd, &item_time, item_time_cmp= &item_time2)) - return 1; - } - return my_time_compare(&field_time, item_time_cmp); - } - if (res_type == STRING_RESULT) - { - char item_buff[MAX_FIELD_WIDTH]; - char field_buff[MAX_FIELD_WIDTH]; - - String item_tmp(item_buff,sizeof(item_buff),&my_charset_bin); - String field_tmp(field_buff,sizeof(field_buff),&my_charset_bin); - String *item_result= item->val_str(&item_tmp); - /* - Some implementations of Item::val_str(String*) actually modify - the field Item::null_value, hence we can't check it earlier. - */ - if (item->null_value) - return 0; - String *field_result= field->val_str(&field_tmp); - return sortcmp(field_result, item_result, field->charset()); - } - if (res_type == INT_RESULT) - return 0; // Both are of type int - if (res_type == DECIMAL_RESULT) + Type_handler_hybrid_field_type cmp(field->type_handler_for_comparison()); + if (cmp.aggregate_for_comparison(item->type_handler_for_comparison())) { - 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); - } - /* - The patch for Bug#13463415 started using this function for comparing - BIGINTs. That uncovered a bug in Visual Studio 32bit optimized mode. - Prefixing the auto variables with volatile fixes the problem.... - */ - volatile double result= item->val_real(); - if (item->null_value) + // At fix_fields() time we checked that "field" and "item" are comparable + DBUG_ASSERT(0); return 0; - volatile double field_result= field->val_real(); - if (field_result < result) - return -1; - else if (field_result > result) - return 1; - return 0; + } + return cmp.type_handler()->stored_field_cmp_to_item(thd, field, item); } @@ -10097,7 +10007,6 @@ bool Item_cache_int::cache_value() String *Item_cache_int::val_str(String *str) { - DBUG_ASSERT(fixed == 1); if (!has_value()) return NULL; str->set_int(value, unsigned_flag, default_charset()); @@ -10107,7 +10016,6 @@ String *Item_cache_int::val_str(String *str) my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val) { - DBUG_ASSERT(fixed == 1); if (!has_value()) return NULL; int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_val); @@ -10116,7 +10024,6 @@ my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val) double Item_cache_int::val_real() { - DBUG_ASSERT(fixed == 1); if (!has_value()) return 0.0; return (double) value; @@ -10124,7 +10031,6 @@ double Item_cache_int::val_real() longlong Item_cache_int::val_int() { - DBUG_ASSERT(fixed == 1); if (!has_value()) return 0; return value; @@ -10164,88 +10070,12 @@ Item_cache_temporal::Item_cache_temporal(THD *thd, const Type_handler *handler) } -longlong Item_cache_temporal::val_datetime_packed() -{ - DBUG_ASSERT(fixed == 1); - if (Item_cache_temporal::field_type() == MYSQL_TYPE_TIME) - return Item::val_datetime_packed(); // TIME-to-DATETIME conversion needed - if ((!value_cached && !cache_value()) || null_value) - { - null_value= TRUE; - return 0; - } - return value; -} - - -longlong Item_cache_temporal::val_time_packed() -{ - DBUG_ASSERT(fixed == 1); - if (Item_cache_temporal::field_type() != MYSQL_TYPE_TIME) - return Item::val_time_packed(); // DATETIME-to-TIME conversion needed - if ((!value_cached && !cache_value()) || null_value) - { - null_value= TRUE; - return 0; - } - return value; -} - - -String *Item_cache_temporal::val_str(String *str) -{ - DBUG_ASSERT(fixed == 1); - if (!has_value()) - { - null_value= true; - return NULL; - } - return val_string_from_date(str); -} - - -my_decimal *Item_cache_temporal::val_decimal(my_decimal *decimal_value) -{ - DBUG_ASSERT(fixed == 1); - if ((!value_cached && !cache_value()) || null_value) - { - null_value= true; - return NULL; - } - return val_decimal_from_date(decimal_value); -} - - -longlong Item_cache_temporal::val_int() -{ - DBUG_ASSERT(fixed == 1); - if ((!value_cached && !cache_value()) || null_value) - { - null_value= true; - return 0; - } - return val_int_from_date(); -} - - -double Item_cache_temporal::val_real() -{ - DBUG_ASSERT(fixed == 1); - if ((!value_cached && !cache_value()) || null_value) - { - null_value= true; - return 0; - } - return val_real_from_date(); -} - - bool Item_cache_temporal::cache_value() { if (!example) return false; value_cached= true; - value= example->val_datetime_packed_result(); + value= example->val_datetime_packed_result(current_thd); null_value_inside= null_value= example->null_value; return true; } @@ -10256,16 +10086,14 @@ bool Item_cache_time::cache_value() if (!example) return false; value_cached= true; - value= example->val_time_packed_result(); + value= example->val_time_packed_result(current_thd); null_value_inside= null_value= example->null_value; return true; } -bool Item_cache_temporal::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) +bool Item_cache_temporal::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - ErrConvInteger str(value); - if (!has_value()) { bzero((char*) ltime,sizeof(*ltime)); @@ -10280,7 +10108,8 @@ bool Item_cache_temporal::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) int Item_cache_temporal::save_in_field(Field *field, bool no_conversions) { MYSQL_TIME ltime; - if (get_date(<ime, 0)) + // This is a temporal type. No nanoseconds, so round mode is not important. + if (get_date(field->get_thd(), <ime, TIME_CONV_NONE | TIME_FRAC_NONE)) return set_field_to_null_with_conversions(field, no_conversions); field->set_notnull(); int error= field->store_time_dec(<ime, decimals); @@ -10322,25 +10151,78 @@ Item *Item_cache_temporal::convert_to_basic_const_item(THD *thd) Item *Item_cache_datetime::make_literal(THD *thd) { - MYSQL_TIME ltime; - unpack_time(val_datetime_packed(), <ime, MYSQL_TIMESTAMP_DATETIME); - return new (thd->mem_root) Item_datetime_literal(thd, <ime, decimals); + Datetime dt(thd, this, TIME_CONV_NONE | TIME_FRAC_NONE); + return new (thd->mem_root) Item_datetime_literal(thd, &dt, decimals); } Item *Item_cache_date::make_literal(THD *thd) { - MYSQL_TIME ltime; - unpack_time(val_datetime_packed(), <ime, MYSQL_TIMESTAMP_DATE); - return new (thd->mem_root) Item_date_literal(thd, <ime); + Date d(thd, this, TIME_CONV_NONE | TIME_FRAC_NONE); + return new (thd->mem_root) Item_date_literal(thd, &d); } Item *Item_cache_time::make_literal(THD *thd) { - MYSQL_TIME ltime; - unpack_time(val_time_packed(), <ime, MYSQL_TIMESTAMP_TIME); - return new (thd->mem_root) Item_time_literal(thd, <ime, decimals); + Time t(thd, this); + return new (thd->mem_root) Item_time_literal(thd, &t, decimals); +} + + +int Item_cache_timestamp::save_in_field(Field *field, bool no_conversions) +{ + if (!has_value()) + return set_field_to_null_with_conversions(field, no_conversions); + return m_native.save_in_field(field, decimals); +} + + +bool Item_cache_timestamp::val_native(THD *thd, Native *to) +{ + if (!has_value()) + { + null_value= true; + return true; + } + return null_value= to->copy(m_native); } + +Datetime Item_cache_timestamp::to_datetime(THD *thd) +{ + DBUG_ASSERT(is_fixed() == 1); + if (!has_value()) + { + null_value= true; + return Datetime(); + } + return m_native.to_datetime(thd); +} + + +bool Item_cache_timestamp::get_date(THD *thd, MYSQL_TIME *ltime, + date_mode_t fuzzydate) +{ + if (!has_value()) + { + set_zero_time(ltime, MYSQL_TIMESTAMP_DATETIME); + return true; + } + Timestamp_or_zero_datetime tm(m_native); + return (null_value= tm.to_TIME(thd, ltime, fuzzydate)); +} + + +bool Item_cache_timestamp::cache_value() +{ + if (!example) + return false; + value_cached= true; + null_value= example->val_native_with_conversion_result(current_thd, &m_native, + type_handler()); + return true; +} + + bool Item_cache_real::cache_value() { if (!example) @@ -10354,7 +10236,6 @@ bool Item_cache_real::cache_value() double Item_cache_real::val_real() { - DBUG_ASSERT(fixed == 1); if (!has_value()) return 0.0; return value; @@ -10362,7 +10243,6 @@ double Item_cache_real::val_real() longlong Item_cache_real::val_int() { - DBUG_ASSERT(fixed == 1); if (!has_value()) return 0; return Converter_double_to_longlong(value, unsigned_flag).result(); @@ -10371,7 +10251,6 @@ longlong Item_cache_real::val_int() String* Item_cache_double::val_str(String *str) { - DBUG_ASSERT(fixed == 1); if (!has_value()) return NULL; str->set_real(value, decimals, default_charset()); @@ -10381,7 +10260,6 @@ String* Item_cache_double::val_str(String *str) String* Item_cache_float::val_str(String *str) { - DBUG_ASSERT(fixed == 1); if (!has_value()) return NULL; Float(value).to_string(str, decimals); @@ -10391,7 +10269,6 @@ String* Item_cache_float::val_str(String *str) my_decimal *Item_cache_real::val_decimal(my_decimal *decimal_val) { - DBUG_ASSERT(fixed == 1); if (!has_value()) return NULL; double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val); @@ -10427,38 +10304,22 @@ bool Item_cache_decimal::cache_value() double Item_cache_decimal::val_real() { - DBUG_ASSERT(fixed); - 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() { - DBUG_ASSERT(fixed); - 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) { - DBUG_ASSERT(fixed); - 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) { - DBUG_ASSERT(fixed); if (!has_value()) return NULL; return &decimal_value; @@ -10475,9 +10336,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; } @@ -10515,7 +10375,6 @@ bool Item_cache_str::cache_value() double Item_cache_str::val_real() { - DBUG_ASSERT(fixed == 1); if (!has_value()) return 0.0; return value ? double_from_string_with_check(value) : 0.0; @@ -10524,7 +10383,6 @@ double Item_cache_str::val_real() longlong Item_cache_str::val_int() { - DBUG_ASSERT(fixed == 1); if (!has_value()) return 0; return value ? longlong_from_string_with_check(value) : 0; @@ -10533,7 +10391,6 @@ longlong Item_cache_str::val_int() String* Item_cache_str::val_str(String *str) { - DBUG_ASSERT(fixed == 1); if (!has_value()) return 0; return value; @@ -10542,7 +10399,6 @@ String* Item_cache_str::val_str(String *str) my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val) { - DBUG_ASSERT(fixed == 1); if (!has_value()) return NULL; return value ? decimal_from_string_with_check(decimal_val, value) : 0; @@ -10735,7 +10591,7 @@ String *Item_type_holder::val_str(String*) return 0; } -bool Item_type_holder::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) +bool Item_type_holder::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { DBUG_ASSERT(0); // should never be called return true; @@ -10744,7 +10600,7 @@ bool Item_type_holder::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) void Item_result_field::cleanup() { DBUG_ENTER("Item_result_field::cleanup()"); - Item::cleanup(); + Item_fixed_hybrid::cleanup(); result_field= 0; DBUG_VOID_RETURN; } @@ -10934,17 +10790,6 @@ const char *dbug_print(SELECT_LEX_UNIT *x) { return dbug_print_unit(x); } #endif /*DBUG_OFF*/ -bool Item_field::excl_dep_on_table(table_map tab_map) -{ - return used_tables() == tab_map || - (item_equal && (item_equal->used_tables() & tab_map)); -} - -bool -Item_field::excl_dep_on_grouping_fields(st_select_lex *sel) -{ - return find_matching_grouping_field(this, sel) != NULL; -} void Item::register_in(THD *thd) @@ -10952,3 +10797,15 @@ void Item::register_in(THD *thd) next= thd->free_list; thd->free_list= this; } + + +bool Item::cleanup_excluding_immutables_processor (void *arg) +{ + if (!(get_extraction_flag() == IMMUTABLE_FL)) + return cleanup_processor(arg); + else + { + clear_extraction_flag(); + return false; + } +} |