diff options
Diffstat (limited to 'sql/item.cc')
-rw-r--r-- | sql/item.cc | 1739 |
1 files changed, 588 insertions, 1151 deletions
diff --git a/sql/item.cc b/sql/item.cc index 7f29915c965..43a443d61ba 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -45,6 +45,15 @@ const String my_null_string("NULL", 4, default_charset_info); const String my_default_string("DEFAULT", 7, default_charset_info); +/* + item_empty_name is used when calling Item::set_name with NULL + pointer, to make it easier to use the name in printf. + item_used_name is used when calling Item::set_name with a 0 length + string. +*/ +const char *item_empty_name=""; +const char *item_used_name= "\0"; + static int save_field_in_field(Field *, bool *, Field *, bool); @@ -302,6 +311,56 @@ bool Item::is_null_from_temporal() } +longlong Item::val_int_from_str(int *error) +{ + char buff[MAX_FIELD_WIDTH]; + String tmp(buff,sizeof(buff), &my_charset_bin), *res; + + /* + For a string result, we must first get the string and then convert it + to a longlong + */ + if (!(res= val_str(&tmp))) + { + *error= 0; + return 0; + } + Converter_strtoll10_with_warn cnv(NULL, Warn_filter_all(), + res->charset(), res->ptr(), res->length()); + *error= cnv.error(); + return cnv.result(); +} + + +longlong Item::val_int_signed_typecast_from_str() +{ + int error; + longlong value= val_int_from_str(&error); + if (!null_value && value < 0 && error == 0) + push_note_converted_to_negative_complement(current_thd); + return value; +} + + +longlong Item::val_int_unsigned_typecast_from_str() +{ + int error; + longlong value= val_int_from_str(&error); + if (!null_value && error < 0) + push_note_converted_to_positive_complement(current_thd); + return value; +} + + +longlong Item::val_int_unsigned_typecast_from_int() +{ + longlong value= val_int(); + if (!null_value && unsigned_flag == 0 && value < 0) + push_note_converted_to_positive_complement(current_thd); + return value; +} + + String *Item::val_string_from_date(String *str) { MYSQL_TIME ltime; @@ -419,21 +478,33 @@ longlong Item::val_int_from_decimal() return result; } -int Item::save_time_in_field(Field *field) + +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)) - return set_field_to_null_with_conversions(field, 0); + return set_field_to_null_with_conversions(field, no_conversions); field->set_notnull(); return field->store_time_dec(<ime, decimals); } -int Item::save_date_in_field(Field *field) +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))) - return set_field_to_null_with_conversions(field, 0); + return set_field_to_null_with_conversions(field, no_conversions); field->set_notnull(); return field->store_time_dec(<ime, decimals); } @@ -471,7 +542,7 @@ int Item::save_str_value_in_field(Field *field, String *result) Item::Item(THD *thd): - is_expensive_cache(-1), rsize(0), name(0), orig_name(0), name_length(0), + is_expensive_cache(-1), rsize(0), name(null_clex_str), orig_name(0), fixed(0), is_autogenerated_name(TRUE) { DBUG_ASSERT(thd); @@ -509,14 +580,13 @@ Item::Item(THD *thd): tables. */ Item::Item(THD *thd, Item *item): - Type_std_attributes(item), + Type_all_attributes(item), join_tab_idx(item->join_tab_idx), is_expensive_cache(-1), rsize(0), str_value(item->str_value), name(item->name), orig_name(item->orig_name), - name_length(item->name_length), marker(item->marker), maybe_null(item->maybe_null), in_rollup(item->in_rollup), @@ -533,49 +603,6 @@ Item::Item(THD *thd, Item *item): } -uint Item::decimal_precision() const -{ - Item_result restype= result_type(); - - if ((restype == DECIMAL_RESULT) || (restype == INT_RESULT)) - { - uint prec= - my_decimal_length_to_precision(max_char_length(), decimals, - unsigned_flag); - return MY_MIN(prec, DECIMAL_MAX_PRECISION); - } - uint res= max_char_length(); - /* - Return at least one decimal digit, even if Item::max_char_length() - returned 0. This is important to avoid attempts to create fields of types - INT(0) or DECIMAL(0,0) when converting NULL or empty strings to INT/DECIMAL: - CREATE TABLE t1 AS SELECT CONVERT(NULL,SIGNED) AS a; - */ - return res ? MY_MIN(res, DECIMAL_MAX_PRECISION) : 1; -} - - -uint Item::temporal_precision(enum_field_types type_arg) -{ - if (const_item() && result_type() == STRING_RESULT && - !is_temporal_type(field_type())) - { - MYSQL_TIME ltime; - String buf, *tmp; - MYSQL_TIME_STATUS status; - DBUG_ASSERT(fixed); - if ((tmp= val_str(&buf)) && - !(type_arg == MYSQL_TYPE_TIME ? - str_to_time(tmp->charset(), tmp->ptr(), tmp->length(), - <ime, TIME_TIME_ONLY, &status) : - str_to_datetime(tmp->charset(), tmp->ptr(), tmp->length(), - <ime, TIME_FUZZY_DATES, &status))) - return MY_MIN(status.precision, TIME_SECOND_PART_DIGITS); - } - return MY_MIN(decimals, TIME_SECOND_PART_DIGITS); -} - - void Item::print_parenthesised(String *str, enum_query_type query_type, enum precedence parent_prec) { @@ -598,11 +625,12 @@ void Item::print_item_w_name(String *str, enum_query_type query_type) { print(str, query_type); - if (name) + if (name.str) { + DBUG_ASSERT(name.length == strlen(name.str)); THD *thd= current_thd; str->append(STRING_WITH_LEN(" AS ")); - append_identifier(thd, str, name, (uint) strlen(name)); + append_identifier(thd, str, name.str, name.length); } } @@ -641,7 +669,10 @@ void Item::cleanup() marker= 0; join_tab_idx= MAX_TABLES; if (orig_name) - name= orig_name; + { + name.str= orig_name; + name.length= strlen(orig_name); + } DBUG_VOID_RETURN; } @@ -661,24 +692,6 @@ bool Item::cleanup_processor(void *arg) /** - rename item (used for views, cleanup() return original name). - - @param new_name new name of item; -*/ - -void Item::rename(char *new_name) -{ - /* - we can compare pointers to names here, because if name was not changed, - pointer will be same - */ - if (!orig_name && new_name != name) - orig_name= name; - name= new_name; -} - - -/** Traverse item tree possibly transforming it (replacing items). This function is designed to ease transformation of Item trees. @@ -747,29 +760,31 @@ Item* Item::set_expr_cache(THD *thd) Item_ident::Item_ident(THD *thd, Name_resolution_context *context_arg, const char *db_name_arg,const char *table_name_arg, - const char *field_name_arg) + const LEX_CSTRING *field_name_arg) :Item_result_field(thd), orig_db_name(db_name_arg), orig_table_name(table_name_arg), - orig_field_name(field_name_arg), context(context_arg), + orig_field_name(*field_name_arg), context(context_arg), db_name(db_name_arg), table_name(table_name_arg), - field_name(field_name_arg), + field_name(*field_name_arg), alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX), cached_table(0), depended_from(0), can_be_depended(TRUE) { - name = (char*) field_name_arg; + name= *field_name_arg; } -Item_ident::Item_ident(THD *thd, TABLE_LIST *view_arg, const char *field_name_arg) +Item_ident::Item_ident(THD *thd, TABLE_LIST *view_arg, + const LEX_CSTRING *field_name_arg) :Item_result_field(thd), orig_db_name(NullS), orig_table_name(view_arg->table_name), - orig_field_name(field_name_arg), context(&view_arg->view->select_lex.context), + orig_field_name(*field_name_arg), + context(&view_arg->view->select_lex.context), db_name(NullS), table_name(view_arg->alias), - field_name(field_name_arg), + field_name(*field_name_arg), alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX), cached_table(NULL), depended_from(NULL), can_be_depended(TRUE) { - name = (char*) field_name_arg; + name= *field_name_arg; } @@ -860,7 +875,8 @@ bool Item_ident::collect_outer_ref_processor(void *param) bool Item_field::collect_item_field_processor(void *arg) { DBUG_ENTER("Item_field::collect_item_field_processor"); - DBUG_PRINT("info", ("%s", field->field_name ? field->field_name : "noname")); + DBUG_PRINT("info", ("%s", field->field_name.str ? + field->field_name.str : "noname")); List<Item_field> *item_list= (List<Item_field>*) arg; List_iterator<Item_field> item_list_it(*item_list); Item_field *curr_item; @@ -877,7 +893,8 @@ bool Item_field::collect_item_field_processor(void *arg) bool Item_field::add_field_to_set_processor(void *arg) { DBUG_ENTER("Item_field::add_field_to_set_processor"); - DBUG_PRINT("info", ("%s", field->field_name ? field->field_name : "noname")); + DBUG_PRINT("info", ("%s", field->field_name.str ? field->field_name.str : + "noname")); TABLE *table= (TABLE *) arg; if (field->table == table) bitmap_set_bit(&table->tmp_set, field->field_index); @@ -995,6 +1012,13 @@ bool Item_field::check_field_expression_processor(void *arg) Field *org_field= (Field*) arg; if (field->flags & NO_DEFAULT_VALUE_FLAG) return 0; + if (field->flags & AUTO_INCREMENT_FLAG) + { + my_error(ER_EXPRESSION_REFERS_TO_UNINIT_FIELD, + MYF(0), + org_field->field_name.str, field->field_name.str); + return 1; + } if ((field->default_value && field->default_value->flags) || field->vcol_info) { if (field == org_field || @@ -1005,7 +1029,7 @@ bool Item_field::check_field_expression_processor(void *arg) { my_error(ER_EXPRESSION_REFERS_TO_UNINIT_FIELD, MYF(0), - org_field->field_name, field->field_name); + org_field->field_name.str, field->field_name.str); return 1; } } @@ -1035,14 +1059,18 @@ bool Item::check_cols(uint c) return 0; } - void Item::set_name(THD *thd, const char *str, uint length, CHARSET_INFO *cs) { if (!length) { - /* Empty string, used by AS or internal function like last_insert_id() */ - name= (char*) str; - name_length= 0; + /* + Null string are replaced by item_empty_name. This is used by AS or + internal function like last_insert_id() to detect if we need to + change the name later. + Used by sql_yacc.yy in select_alias handling + */ + name.str= str ? item_used_name : item_empty_name; + name.length= 0; return; } @@ -1084,13 +1112,13 @@ void Item::set_name(THD *thd, const char *str, uint length, CHARSET_INFO *cs) if (!my_charset_same(cs, system_charset_info)) { size_t res_length; - name= sql_strmake_with_convert(thd, str, length, cs, - MAX_ALIAS_NAME, system_charset_info, - &res_length); - name_length= res_length; + name.str= sql_strmake_with_convert(thd, str, length, cs, + MAX_ALIAS_NAME, system_charset_info, + &res_length); + name.length= res_length; } else - name= thd->strmake(str, (name_length= MY_MIN(length,MAX_ALIAS_NAME))); + name.str= thd->strmake(str, (name.length= MY_MIN(length,MAX_ALIAS_NAME))); } @@ -1100,28 +1128,13 @@ void Item::set_name_no_truncate(THD *thd, const char *str, uint length, if (!my_charset_same(cs, system_charset_info)) { size_t res_length; - name= sql_strmake_with_convert(thd, str, length, cs, - UINT_MAX, system_charset_info, - &res_length); - name_length= res_length; + name.str= sql_strmake_with_convert(thd, str, length, cs, + UINT_MAX, system_charset_info, + &res_length); + name.length= res_length; } else - name= thd->strmake(str, (name_length= length)); -} - - -void Item::set_name_for_rollback(THD *thd, const char *str, uint length, - CHARSET_INFO *cs) -{ - char *old_name, *new_name; - old_name= name; - set_name(thd, str, length, cs); - new_name= name; - if (old_name != new_name) - { - name= old_name; - thd->change_item_tree((Item **) &name, (Item *) new_name); - } + name.str= thd->strmake(str, (name.length= length)); } @@ -1139,8 +1152,9 @@ bool Item::eq(const Item *item, bool binary_cmp) const for all basic constants we have special checks, and Item_param's type() can be only among basic constant types. */ - return type() == item->type() && name && item->name && - !my_strcasecmp(system_charset_info,name,item->name); + return type() == item->type() && name.str && item->name.str && + name.length == item->name.length && + !my_strcasecmp(system_charset_info, name.str, item->name.str); } @@ -1482,24 +1496,18 @@ bool mark_unsupported_function(const char *w1, const char *w2, Item_sp_variable methods *****************************************************************************/ -Item_sp_variable::Item_sp_variable(THD *thd, char *sp_var_name_str, - uint sp_var_name_length): - Item(thd), m_thd(0) +Item_sp_variable::Item_sp_variable(THD *thd, const LEX_CSTRING *sp_var_name) + :Item(thd), m_thd(0), m_name(*sp_var_name) #ifndef DBUG_OFF , m_sp(0) #endif { - m_name.str= sp_var_name_str; - m_name.length= sp_var_name_length; } -bool Item_sp_variable::fix_fields(THD *thd, Item **) +bool Item_sp_variable::fix_fields_from_item(THD *thd, Item **, const Item *it) { - Item *it; - m_thd= thd; /* NOTE: this must be set before any this_xxx() */ - it= this_item(); DBUG_ASSERT(it->fixed); @@ -1584,16 +1592,26 @@ bool Item_sp_variable::is_null() return this_item()->is_null(); } +void Item_sp_variable::make_field(THD *thd, Send_field *field) +{ + Item *it= this_item(); + + it->make_field(thd, field); + if (name.str) + field->col_name= name; + else + field->col_name= m_name; +} /***************************************************************************** Item_splocal methods *****************************************************************************/ -Item_splocal::Item_splocal(THD *thd, const LEX_STRING &sp_var_name, +Item_splocal::Item_splocal(THD *thd, const LEX_CSTRING *sp_var_name, uint sp_var_idx, enum_field_types sp_var_type, uint pos_in_q, uint len_in_q): - Item_sp_variable(thd, sp_var_name.str, sp_var_name.length), + Item_sp_variable(thd, sp_var_name), Rewritable_query_parameter(pos_in_q, len_in_q), m_var_idx(sp_var_idx) { @@ -1605,11 +1623,19 @@ Item_splocal::Item_splocal(THD *thd, const LEX_STRING &sp_var_name, } +bool Item_splocal::fix_fields(THD *thd, Item **ref) +{ + Item *item= thd->spcont->get_item(m_var_idx); + set_handler(item->type_handler()); + return fix_fields_from_item(thd, ref, item); +} + + Item * Item_splocal::this_item() { DBUG_ASSERT(m_sp == m_thd->spcont->sp); - + DBUG_ASSERT(fixed); return m_thd->spcont->get_item(m_var_idx); } @@ -1617,7 +1643,7 @@ const Item * Item_splocal::this_item() const { DBUG_ASSERT(m_sp == m_thd->spcont->sp); - + DBUG_ASSERT(fixed); return m_thd->spcont->get_item(m_var_idx); } @@ -1626,7 +1652,7 @@ Item ** Item_splocal::this_item_addr(THD *thd, Item **) { DBUG_ASSERT(m_sp == thd->spcont->sp); - + DBUG_ASSERT(fixed); return thd->spcont->get_item_addr(m_var_idx); } @@ -1646,17 +1672,195 @@ bool Item_splocal::set_value(THD *thd, sp_rcontext *ctx, Item **it) } +/** + These two declarations are different: + x INT; + ROW(x INT); + A ROW with one elements should not be comparable to scalar value. + + TODO: Currently we don't support one argument with the function ROW(), so + this query returns a syntax error, meaning that more arguments are expected: + SELECT ROW(1); + + Therefore, all around the code we assume that cols()==1 means a scalar value + and cols()>1 means a ROW value. With adding ROW SP variables this + assumption is not true any more. ROW variables with one element are + now possible. + + To implement Item::check_cols() correctly, we now should extend it to + know if a ROW or a scalar value is being tested. For example, + these new prototypes should work: + virtual bool check_cols(Item_result result, uint c); + or + virtual bool check_cols(const Type_handler *type, uint c); + + The current implementation of Item_splocal::check_cols() is a compromise + that should be more or less fine until we extend check_cols(). + It disallows ROW variables to appear in a scalar context. + The "|| n == 1" part of the conditon is responsible for this. + For example, it disallows ROW variables to appear in SELECT list: + +DELIMITER $$; +CREATE PROCEDURE p1() +AS + a ROW (a INT); +BEGIN + SELECT a; +END; +$$ +DELIMITER ;$$ +--error ER_OPERAND_COLUMNS +CALL p1(); + + But is produces false negatives with ROW variables consisting of one element. + For example, this script fails: + +SET sql_mode=ORACLE; +DROP PROCEDURE IF EXISTS p1; +DELIMITER $$ +CREATE PROCEDURE p1 +AS + a ROW(a INT); + b ROW(a INT); +BEGIN + SELECT a=b; +END; +$$ +DELIMITER ; +CALL p1(); + + and returns "ERROR 1241 (21000): Operand should contain 1 column(s)". + This will be fixed that we change check_cols(). +*/ + +bool Item_splocal::check_cols(uint n) +{ + DBUG_ASSERT(m_thd->spcont); + if (Type_handler_hybrid_field_type::cmp_type() != ROW_RESULT) + return Item::check_cols(n); + + if (n != this_item()->cols() || n == 1) + { + my_error(ER_OPERAND_COLUMNS, MYF(0), n); + return true; + } + return false; +} + + +bool Item_splocal_row_field::fix_fields(THD *thd, Item **ref) +{ + Item *item= thd->spcont->get_item(m_var_idx)->element_index(m_field_idx); + return fix_fields_from_item(thd, ref, item); +} + + +Item * +Item_splocal_row_field::this_item() +{ + DBUG_ASSERT(m_sp == m_thd->spcont->sp); + DBUG_ASSERT(fixed); + return m_thd->spcont->get_item(m_var_idx)->element_index(m_field_idx); +} + + +const Item * +Item_splocal_row_field::this_item() const +{ + DBUG_ASSERT(m_sp == m_thd->spcont->sp); + DBUG_ASSERT(fixed); + return m_thd->spcont->get_item(m_var_idx)->element_index(m_field_idx); +} + + +Item ** +Item_splocal_row_field::this_item_addr(THD *thd, Item **) +{ + DBUG_ASSERT(m_sp == thd->spcont->sp); + DBUG_ASSERT(fixed); + return thd->spcont->get_item(m_var_idx)->addr(m_field_idx); +} + + +void Item_splocal_row_field::print(String *str, enum_query_type) +{ + str->reserve(m_name.length + m_field_name.length + 8); + str->append(m_name.str, m_name.length); + str->append('.'); + str->append(m_field_name.str, m_field_name.length); + str->append('@'); + str->qs_append(m_var_idx); + str->append('['); + str->qs_append(m_field_idx); + str->append(']'); +} + + +bool Item_splocal_row_field::set_value(THD *thd, sp_rcontext *ctx, Item **it) +{ + return ctx->set_variable_row_field(thd, m_var_idx, m_field_idx, it); +} + + +bool Item_splocal_row_field_by_name::fix_fields(THD *thd, Item **it) +{ + m_thd= thd; + Item *item, *row= m_thd->spcont->get_item(m_var_idx); + if (row->element_index_by_name(&m_field_idx, m_field_name)) + { + my_error(ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD, MYF(0), + m_name.str, m_field_name.str); + return true; + } + item= row->element_index(m_field_idx); + set_handler(item->type_handler()); + return fix_fields_from_item(thd, it, item); +} + + +void Item_splocal_row_field_by_name::print(String *str, enum_query_type) +{ + // +16 should be enough for .NNN@[""] + if (str->reserve(m_name.length + 2 * m_field_name.length + 16)) + return; + str->qs_append(m_name.str, m_name.length); + str->qs_append('.'); + str->qs_append(m_field_name.str, m_field_name.length); + str->qs_append('@'); + str->qs_append(m_var_idx); + str->qs_append("[\"", 2); + str->qs_append(m_field_name.str, m_field_name.length); + str->qs_append("\"]", 2); +} + + +bool Item_splocal_row_field_by_name::set_value(THD *thd, sp_rcontext *ctx, Item **it) +{ + DBUG_ASSERT(fixed); // Make sure m_field_idx is already set + return Item_splocal_row_field::set_value(thd, ctx, it); +} + + /***************************************************************************** Item_case_expr methods *****************************************************************************/ +LEX_CSTRING str_case_expr= { STRING_WITH_LEN("case_expr") }; + Item_case_expr::Item_case_expr(THD *thd, uint case_expr_id): - Item_sp_variable(thd, C_STRING_WITH_LEN("case_expr")), + Item_sp_variable(thd, &str_case_expr), m_case_expr_id(case_expr_id) { } +bool Item_case_expr::fix_fields(THD *thd, Item **ref) +{ + Item *item= thd->spcont->get_case_expr(m_case_expr_id); + return fix_fields_from_item(thd, ref, item); +} + + Item * Item_case_expr::this_item() { @@ -1824,7 +2028,7 @@ bool Item_name_const::fix_fields(THD *thd, Item **ref) } if (is_autogenerated_name) { - set_name(thd, item_name->ptr(), (uint) item_name->length(), + set_name(thd, item_name->c_ptr(), (uint) item_name->length(), system_charset_info); } collation.set(value_item->collation.collation, DERIVATION_IMPLICIT); @@ -1855,7 +2059,7 @@ class Item_aggregate_ref : public Item_ref public: Item_aggregate_ref(THD *thd, Name_resolution_context *context_arg, Item **item, const char *table_name_arg, - const char *field_name_arg): + const LEX_CSTRING *field_name_arg): Item_ref(thd, context_arg, item, table_name_arg, field_name_arg) {} virtual inline void print (String *str, enum_query_type query_type) @@ -1969,14 +2173,14 @@ void Item::split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array, already a reference. */ Item *real_itm= real_item(); - ref_pointer_array[el]= real_itm; if (type() == WINDOW_FUNC_ITEM) { if (!(item_ref= (new (thd->mem_root) Item_direct_ref(thd, - &thd->lex->current_select->context, - &ref_pointer_array[el], 0, name)))) + &thd->lex->current_select->context, + &ref_pointer_array[el], 0, + &name)))) return; // fatal_error is set } else if (type() == FUNC_ITEM && @@ -1987,7 +2191,8 @@ void Item::split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array, if (!(item_ref= (new (thd->mem_root) Item_aggregate_ref(thd, &thd->lex->current_select->context, - &ref_pointer_array[el], 0, name)))) + &ref_pointer_array[el], 0, + &name)))) return; // fatal_error is set } if (type() == SUM_FUNC_ITEM) @@ -2192,9 +2397,9 @@ void my_coll_agg_error(Item** args, uint count, const char *fname, } -bool Item_func_or_sum::agg_item_collations(DTCollation &c, const char *fname, - Item **av, uint count, - uint flags, int item_sep) +bool Type_std_attributes::agg_item_collations(DTCollation &c, const char *fname, + Item **av, uint count, + uint flags, int item_sep) { uint i; Item **arg; @@ -2239,10 +2444,10 @@ bool Item_func_or_sum::agg_item_collations(DTCollation &c, const char *fname, } -bool Item_func_or_sum::agg_item_set_converter(const DTCollation &coll, - const char *fname, - Item **args, uint nargs, - uint flags, int item_sep) +bool Type_std_attributes::agg_item_set_converter(const DTCollation &coll, + const char *fname, + Item **args, uint nargs, + uint flags, int item_sep) { Item **arg, *safe_args[2]= {NULL, NULL}; @@ -2401,7 +2606,6 @@ void Item_ident_for_show::make_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->charsetnr= field->charset()->number; tmp_field->length=field->field_length; tmp_field->type=field->type(); tmp_field->flags= field->table->maybe_null ? @@ -2412,7 +2616,7 @@ void Item_ident_for_show::make_field(THD *thd, Send_field *tmp_field) /**********************************************/ Item_field::Item_field(THD *thd, Field *f) - :Item_ident(thd, 0, NullS, *f->table_name, f->field_name), + :Item_ident(thd, 0, NullS, *f->table_name, &f->field_name), item_equal(0), have_privileges(0), any_privileges(0) { @@ -2421,7 +2625,8 @@ Item_field::Item_field(THD *thd, Field *f) field_name and table_name should not point to garbage if this item is to be reused */ - orig_table_name= orig_field_name= ""; + orig_table_name= ""; + orig_field_name= null_clex_str; with_field= 1; } @@ -2435,7 +2640,8 @@ Item_field::Item_field(THD *thd, Field *f) Item_field::Item_field(THD *thd, Name_resolution_context *context_arg, Field *f) - :Item_ident(thd, context_arg, f->table->s->db.str, *f->table_name, f->field_name), + :Item_ident(thd, context_arg, f->table->s->db.str, *f->table_name, + &f->field_name), item_equal(0), have_privileges(0), any_privileges(0) { @@ -2461,14 +2667,15 @@ Item_field::Item_field(THD *thd, Name_resolution_context *context_arg, orig_db_name= thd->strdup(db_name); if (table_name) orig_table_name= thd->strdup(table_name); - if (field_name) - orig_field_name= thd->strdup(field_name); + if (field_name.str) + thd->make_lex_string(&orig_field_name, field_name.str, + field_name.length); /* We don't restore 'name' in cleanup because it's not changed during execution. Still we need it to point to persistent memory if this item is to be reused. */ - name= (char*) orig_field_name; + name= orig_field_name; } set_field(f); with_field= 1; @@ -2477,7 +2684,7 @@ Item_field::Item_field(THD *thd, Name_resolution_context *context_arg, Item_field::Item_field(THD *thd, Name_resolution_context *context_arg, const char *db_arg,const char *table_name_arg, - const char *field_name_arg) + const LEX_CSTRING *field_name_arg) :Item_ident(thd, context_arg, db_arg, table_name_arg, field_name_arg), field(0), item_equal(0), have_privileges(0), any_privileges(0) @@ -2563,15 +2770,11 @@ void Item_field::set_field(Field *field_par) { field=result_field=field_par; // for easy coding with fields maybe_null=field->maybe_null(); - decimals= field->decimals(); + Type_std_attributes::set(field_par); table_name= *field_par->table_name; field_name= field_par->field_name; db_name= field_par->table->s->db.str; alias_name_used= field_par->table->alias_name_used; - unsigned_flag= MY_TEST(field_par->flags & UNSIGNED_FLAG); - collation.set(field_par->charset(), field_par->derivation(), - field_par->repertoire()); - fix_char_length(field_par->char_length()); max_length= adjust_max_effective_column_length(field_par, max_length); @@ -2591,7 +2794,7 @@ void Item_field::reset_field(Field *f) { set_field(f); /* 'name' is pointing at field->field_name of old field */ - name= (char*) f->field_name; + name= f->field_name; } @@ -2630,15 +2833,15 @@ bool Item_field::switch_to_nullable_fields_processor(void *arg) const char *Item_ident::full_name() const { char *tmp; - if (!table_name || !field_name) - return field_name ? field_name : name ? name : "tmp_field"; + if (!table_name || !field_name.str) + return field_name.str ? field_name.str : name.str ? name.str : "tmp_field"; if (db_name && db_name[0]) { THD *thd= current_thd; tmp=(char*) thd->alloc((uint) strlen(db_name)+(uint) strlen(table_name)+ - (uint) strlen(field_name)+3); - strxmov(tmp,db_name,".",table_name,".",field_name,NullS); + (uint) field_name.length+3); + strxmov(tmp,db_name,".",table_name,".",field_name.str,NullS); } else { @@ -2646,11 +2849,11 @@ const char *Item_ident::full_name() const { THD *thd= current_thd; tmp= (char*) thd->alloc((uint) strlen(table_name) + - (uint) strlen(field_name) + 2); - strxmov(tmp, table_name, ".", field_name, NullS); + field_name.length + 2); + strxmov(tmp, table_name, ".", field_name.str, NullS); } else - tmp= (char*) field_name; + return field_name.str; } return tmp; } @@ -2688,7 +2891,7 @@ void Item_ident::print(String *str, enum_query_type query_type) use_table_name= false; } - if (!field_name || !field_name[0]) + if (!field_name.str || !field_name.str[0]) { append_identifier(thd, str, STRING_WITH_LEN("tmp_field")); return; @@ -2722,7 +2925,7 @@ void Item_ident::print(String *str, enum_query_type query_type) append_identifier(thd, str, t_name, (uint) strlen(t_name)); str->append('.'); } - append_identifier(thd, str, field_name, (uint) strlen(field_name)); + append_identifier(thd, str, field_name.str, field_name.length); } /* ARGSUSED */ @@ -2853,8 +3056,8 @@ bool Item_field::eq(const Item *item, bool binary_cmp) const (In cases where we would choose wrong we would have to generate a ER_NON_UNIQ_ERROR). */ - return (!my_strcasecmp(system_charset_info, item_field->name, - field_name) && + return (!my_strcasecmp(system_charset_info, item_field->name.str, + field_name.str) && (!item_field->table_name || !table_name || (!my_strcasecmp(table_alias_charset, item_field->table_name, table_name) && @@ -2981,7 +3184,12 @@ Item_int::Item_int(THD *thd, const char *str_arg, uint length): int error; value= my_strtoll10(str_arg, &end_ptr, &error); max_length= (uint) (end_ptr - str_arg); - name= (char*) str_arg; + name.str= str_arg; + /* + We can't trust max_length as in show_routine_code we are using "Pos" as + the field name. + */ + name.length= !str_arg[max_length] ? max_length : strlen(str_arg); fixed= 1; } @@ -3011,7 +3219,7 @@ void Item_int::print(String *str, enum_query_type query_type) Item *Item_bool::neg_transformer(THD *thd) { value= !value; - name= 0; + name= null_clex_str; return this; } @@ -3052,7 +3260,8 @@ Item_decimal::Item_decimal(THD *thd, const char *str_arg, uint length, Item_num(thd) { str2my_decimal(E_DEC_FATAL_ERROR, str_arg, length, charset, &decimal_value); - name= (char*) str_arg; + 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 + @@ -3092,7 +3301,8 @@ Item_decimal::Item_decimal(THD *thd, const char *str, const my_decimal *val_arg, Item_num(thd) { my_decimal2decimal(val_arg, &decimal_value); - name= (char*) str; + name.str= str; + name.length= safe_strlen(str); decimals= (uint8) decimal_par; max_length= length; fixed= 1; @@ -3184,7 +3394,7 @@ void Item_decimal::set_decimal_value(my_decimal *value_par) Item *Item_decimal::clone_item(THD *thd) { - return new (thd->mem_root) Item_decimal(thd, name, &decimal_value, decimals, + return new (thd->mem_root) Item_decimal(thd, name.str, &decimal_value, decimals, max_length); } @@ -3209,7 +3419,7 @@ my_decimal *Item_float::val_decimal(my_decimal *decimal_value) Item *Item_float::clone_item(THD *thd) { - return new (thd->mem_root) Item_float(thd, name, value, decimals, + return new (thd->mem_root) Item_float(thd, name.str, value, decimals, max_length); } @@ -3320,7 +3530,7 @@ Item *Item_null::safe_charset_converter(THD *thd, CHARSET_INFO *tocs) Item *Item_null::clone_item(THD *thd) { - return new (thd->mem_root) Item_null(thd, name); + return new (thd->mem_root) Item_null(thd, name.str); } /*********************** Item_param related ******************************/ @@ -3339,10 +3549,11 @@ default_set_param_func(Item_param *param, } -Item_param::Item_param(THD *thd, uint pos_in_query_arg): +Item_param::Item_param(THD *thd, const LEX_CSTRING *name_arg, + uint pos_in_query_arg, uint len_in_query_arg): Item_basic_value(thd), - Rewritable_query_parameter(pos_in_query_arg, 1), - Type_handler_hybrid_field_type(MYSQL_TYPE_VARCHAR), + Rewritable_query_parameter(pos_in_query_arg, len_in_query_arg), + Type_handler_hybrid_field_type(&type_handler_varchar), state(NO_VALUE), /* Don't pretend to be a literal unless value for this item is set. */ item_type(PARAM_ITEM), @@ -3358,8 +3569,8 @@ Item_param::Item_param(THD *thd, uint pos_in_query_arg): */ m_is_settable_routine_parameter(true) { - name= (char*) "?"; - /* + name= *name_arg; + /* Since we can't say whenever this item can be NULL or cannot be NULL before mysql_stmt_execute(), so we assuming that it can be NULL until value is set. @@ -3618,47 +3829,10 @@ bool Item_param::set_from_item(THD *thd, Item *item) } } struct st_value tmp; - if (!item->store(&tmp, 0)) + if (!item->save_in_value(&tmp)) { - unsigned_flag= item->unsigned_flag; - switch (item->cmp_type()) { - case REAL_RESULT: - set_double(tmp.value.m_double); - set_handler_by_field_type(MYSQL_TYPE_DOUBLE); - break; - case INT_RESULT: - set_int(tmp.value.m_longlong, MY_INT64_NUM_DECIMAL_DIGITS); - set_handler_by_field_type(MYSQL_TYPE_LONGLONG); - break; - case STRING_RESULT: - { - value.cs_info.set(thd, item->collation.collation); - /* - Exact value of max_length is not known unless data is converted to - charset of connection, so we have to set it later. - */ - set_handler_by_field_type(MYSQL_TYPE_VARCHAR); - - if (set_str(tmp.m_string.ptr(), tmp.m_string.length())) - DBUG_RETURN(1); - break; - } - case DECIMAL_RESULT: - { - set_decimal(&tmp.m_decimal, unsigned_flag); - set_handler_by_field_type(MYSQL_TYPE_NEWDECIMAL); - break; - } - case TIME_RESULT: - { - set_time(&tmp.value.m_time, item->max_length, item->decimals); - set_handler(item->type_handler()); - break; - } - case ROW_RESULT: - DBUG_ASSERT(0); - set_null(); - } + if (item->type_handler()->Item_param_set_from_value(thd, this, item, &tmp)) + DBUG_RETURN(true); } else set_null(); @@ -4050,19 +4224,19 @@ Item_param::clone_item(THD *thd) invalid_default_param(); // fall through case NULL_VALUE: - return new (mem_root) Item_null(thd, name); + return new (mem_root) Item_null(thd, name.str); case INT_VALUE: return (unsigned_flag ? - new (mem_root) Item_uint(thd, name, value.integer, max_length) : - new (mem_root) Item_int(thd, name, value.integer, max_length)); + new (mem_root) Item_uint(thd, name.str, value.integer, max_length) : + new (mem_root) Item_int(thd, name.str, value.integer, max_length)); case REAL_VALUE: - return new (mem_root) Item_float(thd, name, value.real, decimals, + return new (mem_root) Item_float(thd, name.str, value.real, decimals, max_length); case DECIMAL_VALUE: return 0; // Should create Item_decimal. See MDEV-11361. case STRING_VALUE: case LONG_DATA_VALUE: - return new (mem_root) Item_string(thd, name, str_value.c_ptr_quick(), + return new (mem_root) Item_string(thd, name.str, str_value.c_ptr_quick(), str_value.length(), str_value.charset(), collation.derivation, collation.repertoire); @@ -4338,7 +4512,6 @@ void Item_param::make_field(THD *thd, Send_field *field) field->org_col_name= m_out_param_info->org_col_name; field->length= m_out_param_info->length; - field->charsetnr= m_out_param_info->charsetnr; field->flags= m_out_param_info->flags; field->decimals= m_out_param_info->decimals; field->type= m_out_param_info->type; @@ -4696,7 +4869,7 @@ static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current, ER_THD(thd,ER_WARN_FIELD_RESOLVED), db_name, (db_name[0] ? "." : ""), table_name, (table_name [0] ? "." : ""), - resolved_item->field_name, + resolved_item->field_name.str, current->select_number, last->select_number); } DBUG_RETURN(FALSE); @@ -4786,7 +4959,7 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list) { const char *db_name; const char *table_name; - const char *field_name; + LEX_CSTRING *field_name; ORDER *found_group= NULL; int found_match_degree= 0; char name_buff[SAFE_NAME_LEN+1]; @@ -4796,7 +4969,7 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list) { db_name= ((Item_ident*) find_item)->db_name; table_name= ((Item_ident*) find_item)->table_name; - field_name= ((Item_ident*) find_item)->field_name; + field_name= &((Item_ident*) find_item)->field_name; } else return NULL; @@ -4809,17 +4982,17 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list) db_name= name_buff; } - DBUG_ASSERT(field_name != 0); + DBUG_ASSERT(field_name->str != 0); for (ORDER *cur_group= group_list ; cur_group ; cur_group= cur_group->next) { int cur_match_degree= 0; /* SELECT list element with explicit alias */ - if ((*(cur_group->item))->name && + if ((*(cur_group->item))->name.str && !(*(cur_group->item))->is_autogenerated_name && !my_strcasecmp(system_charset_info, - (*(cur_group->item))->name, field_name)) + (*(cur_group->item))->name.str, field_name->str)) { ++cur_match_degree; } @@ -4830,12 +5003,12 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list) Item_ident *cur_field= (Item_ident*) *cur_group->item; const char *l_db_name= cur_field->db_name; const char *l_table_name= cur_field->table_name; - const char *l_field_name= cur_field->field_name; + LEX_CSTRING *l_field_name= &cur_field->field_name; - DBUG_ASSERT(l_field_name != 0); + DBUG_ASSERT(l_field_name->str != 0); if (!my_strcasecmp(system_charset_info, - l_field_name, field_name)) + l_field_name->str, field_name->str)) ++cur_match_degree; else continue; @@ -4971,7 +5144,7 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) the strict mode is enabled. */ my_error(ER_NON_GROUPING_FIELD_USED, MYF(0), - ref->name, "HAVING"); + ref->name.str, "HAVING"); return NULL; } if (select_ref != not_found_item || group_by_ref) @@ -4982,7 +5155,7 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) if (!select->ref_pointer_array[counter]) { my_error(ER_ILLEGAL_REFERENCE, MYF(0), - ref->name, "forward reference in item list"); + ref->name.str, "forward reference in item list"); return NULL; } DBUG_ASSERT((*select_ref)->fixed); @@ -5309,15 +5482,15 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) *ref= NULL; // Don't call set_properties() rf= (place == IN_HAVING ? new (thd->mem_root) - Item_ref(thd, context, ref, (char*) table_name, - (char*) field_name, alias_name_used) : + Item_ref(thd, context, ref, table_name, + &field_name, alias_name_used) : (!select->group_list.elements ? new (thd->mem_root) - Item_direct_ref(thd, context, ref, (char*) table_name, - (char*) field_name, alias_name_used) : + Item_direct_ref(thd, context, ref, table_name, + &field_name, alias_name_used) : new (thd->mem_root) - Item_outer_ref(thd, context, ref, (char*) table_name, - (char*) field_name, alias_name_used))); + Item_outer_ref(thd, context, ref, table_name, + &field_name, alias_name_used))); *ref= save; if (!rf) return -1; @@ -5361,9 +5534,10 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) if (last_checked_context->select_lex->having_fix_field) { Item_ref *rf; - rf= new (thd->mem_root) Item_ref(thd, context, (*from_field)->table->s->db.str, - (*from_field)->table->alias.c_ptr(), - (char*) field_name); + rf= new (thd->mem_root) Item_ref(thd, context, + (*from_field)->table->s->db.str, + (*from_field)->table->alias.c_ptr(), + &field_name); if (!rf) return -1; thd->change_item_tree(reference, rf); @@ -5481,7 +5655,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) if (new_field == NULL) { /* The column to which we link isn't valid. */ - my_error(ER_BAD_FIELD_ERROR, MYF(0), (*res)->name, + my_error(ER_BAD_FIELD_ERROR, MYF(0), (*res)->name.str, thd->where); return(1); } @@ -5502,8 +5676,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) Item_field created by the parser with the new Item_ref. */ Item_ref *rf= new (thd->mem_root) - Item_ref(thd, context, db_name, table_name, - field_name); + Item_ref(thd, context, db_name, table_name, &field_name); if (!rf) return 1; bool err= rf->fix_fields(thd, (Item **) &rf) || rf->check_cols(1); @@ -5601,16 +5774,16 @@ bool Item_field::fix_fields(THD *thd, Item **reference) #ifndef NO_EMBEDDED_ACCESS_CHECKS if (any_privileges) { - char *db, *tab; + const char *db, *tab; db= field->table->s->db.str; tab= field->table->s->table_name.str; if (!(have_privileges= (get_column_grant(thd, &field->table->grant, - db, tab, field_name) & + db, tab, field_name.str) & VIEW_ANY_ACL))) { my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), "ANY", thd->security_ctx->priv_user, - thd->security_ctx->host_or_ip, field_name, tab); + thd->security_ctx->host_or_ip, field_name.str, tab); goto error; } } @@ -5672,6 +5845,7 @@ error: return TRUE; } + /* @brief Mark virtual columns as used in a partitioning expression @@ -5862,7 +6036,8 @@ 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(cmp_type() == item_equal->compare_type()); + DBUG_ASSERT(type_handler()->type_handler_for_comparison()->cmp_type() == + item_equal->compare_type_handler()->cmp_type()); return const_item2; } Item_field *subst= @@ -5879,13 +6054,11 @@ Item *Item_field::replace_equal_field(THD *thd, uchar *arg) void Item::init_make_field(Send_field *tmp_field, enum enum_field_types field_type_arg) { - char *empty_name= (char*) ""; - tmp_field->db_name= empty_name; - tmp_field->org_table_name= empty_name; - tmp_field->org_col_name= empty_name; - tmp_field->table_name= empty_name; - tmp_field->col_name= name; - tmp_field->charsetnr= collation.collation->number; + tmp_field->db_name= ""; + tmp_field->org_table_name= ""; + tmp_field->org_col_name= empty_clex_str; + tmp_field->table_name= ""; + tmp_field->col_name= name; tmp_field->flags= (maybe_null ? 0 : NOT_NULL_FLAG) | (my_binary_compare(charset_for_protocol()) ? BINARY_FLAG : 0); @@ -5904,7 +6077,7 @@ void Item::make_field(THD *thd, Send_field *tmp_field) void Item_empty_string::make_field(THD *thd, Send_field *tmp_field) { - init_make_field(tmp_field, string_field_type()); + init_make_field(tmp_field, string_type_handler()->field_type()); } @@ -6038,180 +6211,16 @@ bool Item::eq_by_collation(Item *item, bool binary_cmp, CHARSET_INFO *cs) } -/** - Create a field to hold a string value from an item. - - If too_big_for_varchar() create a blob @n - If max_length > 0 create a varchar @n - If max_length == 0 create a CHAR(0) - - @param table Table for which the field is created -*/ - -Field *Item::make_string_field(TABLE *table) -{ - Field *field; - MEM_ROOT *mem_root= table->in_use->mem_root; - - DBUG_ASSERT(collation.collation); - /* - Note: the following check is repeated in - subquery_types_allow_materialization(): - */ - if (too_big_for_varchar()) - field= new (mem_root) - Field_blob(max_length, maybe_null, name, - collation.collation, TRUE); - /* Item_type_holder holds the exact type, do not change it */ - else if (max_length > 0 && - (type() != Item::TYPE_HOLDER || field_type() != MYSQL_TYPE_STRING)) - field= new (mem_root) - Field_varstring(max_length, maybe_null, name, table->s, - collation.collation); - else - field= new (mem_root) - Field_string(max_length, maybe_null, name, collation.collation); - if (field) - field->init(table); - return field; -} - - -/** - Create a field based on field_type of argument. - - For now, this is only used to create a field for - IFNULL(x,something) and time functions - - @retval - NULL error - @retval - \# Created field -*/ - -Field *Item::tmp_table_field_from_field_type(TABLE *table, - bool fixed_length, - bool set_blob_packlength) -{ - /* - The field functions defines a field to be not null if null_ptr is not 0 - */ - uchar *null_ptr= maybe_null ? (uchar*) "" : 0; - Field *field; - MEM_ROOT *mem_root= table->in_use->mem_root; - - switch (field_type()) { - case MYSQL_TYPE_DECIMAL: - case MYSQL_TYPE_NEWDECIMAL: - field= Field_new_decimal::create_from_item(mem_root, this); - break; - case MYSQL_TYPE_TINY: - field= new (mem_root) - Field_tiny((uchar*) 0, max_length, null_ptr, 0, Field::NONE, - name, 0, unsigned_flag); - break; - case MYSQL_TYPE_SHORT: - field= new (mem_root) - Field_short((uchar*) 0, max_length, null_ptr, 0, Field::NONE, - name, 0, unsigned_flag); - break; - case MYSQL_TYPE_LONG: - field= new (mem_root) - Field_long((uchar*) 0, max_length, null_ptr, 0, Field::NONE, - name, 0, unsigned_flag); - break; -#ifdef HAVE_LONG_LONG - case MYSQL_TYPE_LONGLONG: - field= new (mem_root) - Field_longlong((uchar*) 0, max_length, null_ptr, 0, Field::NONE, - name, 0, unsigned_flag); - break; -#endif - case MYSQL_TYPE_FLOAT: - field= new (mem_root) - Field_float((uchar*) 0, max_length, null_ptr, 0, Field::NONE, - name, decimals, 0, unsigned_flag); - break; - case MYSQL_TYPE_DOUBLE: - field= new (mem_root) - Field_double((uchar*) 0, max_length, null_ptr, 0, Field::NONE, - name, decimals, 0, unsigned_flag); - break; - case MYSQL_TYPE_INT24: - field= new (mem_root) - Field_medium((uchar*) 0, max_length, null_ptr, 0, Field::NONE, - name, 0, unsigned_flag); - break; - case MYSQL_TYPE_NEWDATE: - case MYSQL_TYPE_DATE: - field= new (mem_root) - Field_newdate(0, null_ptr, 0, Field::NONE, name); - break; - case MYSQL_TYPE_TIME: - field= new_Field_time(mem_root, 0, null_ptr, 0, Field::NONE, name, - decimals); - break; - case MYSQL_TYPE_TIMESTAMP: - field= new_Field_timestamp(mem_root, 0, null_ptr, 0, - Field::NONE, name, 0, decimals); - break; - case MYSQL_TYPE_DATETIME: - field= new_Field_datetime(mem_root, 0, null_ptr, 0, Field::NONE, name, - decimals); - break; - case MYSQL_TYPE_YEAR: - field= new (mem_root) - Field_year((uchar*) 0, max_length, null_ptr, 0, Field::NONE, name); - break; - case MYSQL_TYPE_BIT: - field= new (mem_root) - Field_bit_as_char(NULL, max_length, null_ptr, 0, Field::NONE, name); - break; - default: - /* This case should never be chosen */ - DBUG_ASSERT(0); - /* If something goes awfully wrong, it's better to get a string than die */ - case MYSQL_TYPE_NULL: - case MYSQL_TYPE_STRING: - if (fixed_length && !too_big_for_varchar()) - { - field= new (mem_root) - Field_string(max_length, maybe_null, name, collation.collation); - break; - } - /* Fall through to make_string_field() */ - case MYSQL_TYPE_ENUM: - case MYSQL_TYPE_SET: - case MYSQL_TYPE_VAR_STRING: - case MYSQL_TYPE_VARCHAR: - return make_string_field(table); - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_LONG_BLOB: - case MYSQL_TYPE_BLOB: - field= new (mem_root) - Field_blob(max_length, maybe_null, name, - collation.collation, set_blob_packlength); - break; // Blob handled outside of case -#ifdef HAVE_SPATIAL - case MYSQL_TYPE_GEOMETRY: - field= new (mem_root) - Field_geom(max_length, maybe_null, name, table->s, get_geometry_type()); -#endif /* HAVE_SPATIAL */ - } - if (field) - field->init(table); - return field; -} - - /* ARGSUSED */ void Item_field::make_field(THD *thd, Send_field *tmp_field) { field->make_field(tmp_field); DBUG_ASSERT(tmp_field->table_name != 0); - if (name) - tmp_field->col_name=name; // Use user supplied name + if (name.str) + { + DBUG_ASSERT(name.length == strlen(name.str)); + tmp_field->col_name= name; // Use user supplied name + } if (table_name) tmp_field->table_name= table_name; if (db_name) @@ -6359,54 +6368,62 @@ int Item_null::save_safe_in_field(Field *field) Note: all Item_XXX::val_str(str) methods must NOT assume that str != str_value. For example, see fix for bug #44743. */ +int Item::save_str_in_field(Field *field, bool no_conversions) +{ + String *result; + CHARSET_INFO *cs= collation.collation; + char buff[MAX_FIELD_WIDTH]; // Alloc buffer for small columns + str_value.set_quick(buff, sizeof(buff), cs); + result=val_str(&str_value); + if (null_value) + { + str_value.set_quick(0, 0, cs); + return set_field_to_null_with_conversions(field, no_conversions); + } -int Item::save_in_field(Field *field, bool no_conversions) + /* NOTE: If null_value == FALSE, "result" must be not NULL. */ + + field->set_notnull(); + int error= field->store(result->ptr(),result->length(),cs); + str_value.set_quick(0, 0, cs); + return error; +} + + +int Item::save_real_in_field(Field *field, bool no_conversions) { - int error; - if (result_type() == STRING_RESULT) - { - String *result; - CHARSET_INFO *cs= collation.collation; - char buff[MAX_FIELD_WIDTH]; // Alloc buffer for small columns - str_value.set_quick(buff, sizeof(buff), cs); - result=val_str(&str_value); - if (null_value) - { - str_value.set_quick(0, 0, cs); - return set_field_to_null_with_conversions(field, no_conversions); - } + double nr= val_real(); + if (null_value) + return set_field_to_null_with_conversions(field, no_conversions); + field->set_notnull(); + return field->store(nr); +} - /* NOTE: If null_value == FALSE, "result" must be not NULL. */ - field->set_notnull(); - error=field->store(result->ptr(),result->length(),cs); - str_value.set_quick(0, 0, cs); - } - else if (result_type() == REAL_RESULT) - { - double nr= val_real(); - if (null_value) - return set_field_to_null_with_conversions(field, no_conversions); - field->set_notnull(); - error=field->store(nr); - } - else if (result_type() == DECIMAL_RESULT) - { - my_decimal decimal_value; - my_decimal *value= val_decimal(&decimal_value); - if (null_value) - return set_field_to_null_with_conversions(field, no_conversions); - field->set_notnull(); - error=field->store_decimal(value); - } - else - { - longlong nr=val_int(); - if (null_value) - return set_field_to_null_with_conversions(field, no_conversions); - field->set_notnull(); - error=field->store(nr, unsigned_flag); - } +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) + return set_field_to_null_with_conversions(field, no_conversions); + field->set_notnull(); + return field->store_decimal(value); +} + + +int Item::save_int_in_field(Field *field, bool no_conversions) +{ + longlong nr= val_int(); + if (null_value) + return set_field_to_null_with_conversions(field, no_conversions); + field->set_notnull(); + return field->store(nr, unsigned_flag); +} + + +int Item::save_in_field(Field *field, bool no_conversions) +{ + int error= type_handler()->Item_save_in_field(this, field, no_conversions); return error ? error : (field->table->in_use->is_error() ? 1 : 0); } @@ -6428,7 +6445,7 @@ int Item_string::save_in_field(Field *field, bool no_conversions) Item *Item_string::clone_item(THD *thd) { return new (thd->mem_root) - Item_string(thd, name, str_value.ptr(), + Item_string(thd, name.str, str_value.ptr(), str_value.length(), collation.collation); } @@ -6451,7 +6468,7 @@ int Item_int::save_in_field(Field *field, bool no_conversions) Item *Item_int::clone_item(THD *thd) { - return new (thd->mem_root) Item_int(thd, name, value, max_length); + return new (thd->mem_root) Item_int(thd, name.str, value, max_length); } @@ -6487,9 +6504,9 @@ Item *Item_int_with_ref::clone_item(THD *thd) */ return (ref->unsigned_flag ? new (thd->mem_root) - Item_uint(thd, ref->name, ref->val_int(), ref->max_length) : + Item_uint(thd, ref->name.str, ref->val_int(), ref->max_length) : new (thd->mem_root) - Item_int(thd, ref->name, ref->val_int(), ref->max_length)); + Item_int(thd, ref->name.str, ref->val_int(), ref->max_length)); } @@ -6517,7 +6534,7 @@ Item *Item_int::neg(THD *thd) else if (value < 0 && max_length) max_length--; value= -value; - name= 0; + name= null_clex_str; return this; } @@ -6525,7 +6542,7 @@ Item *Item_decimal::neg(THD *thd) { my_decimal_neg(&decimal_value); unsigned_flag= 0; - name= 0; + name= null_clex_str; max_length= my_decimal_precision_to_length_no_truncation( decimal_value.intg + decimals, decimals, unsigned_flag); return this; @@ -6538,7 +6555,8 @@ Item *Item_float::neg(THD *thd) else if (value < 0 && max_length) max_length--; value= -value; - name= presentation= 0 ; + presentation= 0; + name= null_clex_str; return this; } @@ -6557,7 +6575,7 @@ Item *Item_uint::neg(THD *thd) Item *Item_uint::clone_item(THD *thd) { - return new (thd->mem_root) Item_uint(thd, name, value, max_length); + return new (thd->mem_root) Item_uint(thd, name.str, value, max_length); } static uint nr_of_decimals(const char *str, const char *end) @@ -6627,7 +6645,8 @@ Item_float::Item_float(THD *thd, const char *str_arg, uint length): my_snprintf(tmp, sizeof(tmp), "%.*s", length, str_arg); my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "double", tmp); } - presentation= name=(char*) str_arg; + presentation= name.str= str_arg; + name.length= strlen(str_arg); decimals=(uint8) nr_of_decimals(str_arg, str_arg+length); max_length=length; fixed= 1; @@ -6701,6 +6720,22 @@ void Item_hex_hybrid::print(String *str, enum_query_type query_type) } +uint Item_hex_hybrid::decimal_precision() const +{ + switch (max_length) {// HEX DEC + case 0: // ---- --- + case 1: return 3; // 0xFF 255 + case 2: return 5; // 0xFFFF 65535 + case 3: return 8; // 0xFFFFFF 16777215 + case 4: return 10; // 0xFFFFFFFF 4294967295 + case 5: return 13; // 0xFFFFFFFFFF 1099511627775 + case 6: return 15; // 0xFFFFFFFFFFFF 281474976710655 + case 7: return 17; // 0xFFFFFFFFFFFFFF 72057594037927935 + } + return 20; // 0xFFFFFFFFFFFFFFFF 18446744073709551615 +} + + void Item_hex_string::print(String *str, enum_query_type query_type) { str->append("X'"); @@ -6848,127 +6883,11 @@ bool Item_time_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) Pack data in buffer for sending. */ -bool Item_null::send(Protocol *protocol, String *packet) +bool Item_null::send(Protocol *protocol, st_value *buffer) { return protocol->store_null(); } -/** - This is only called from items that is not of type item_field. -*/ - -bool Item::send(Protocol *protocol, String *buffer) -{ - bool UNINIT_VAR(result); // Will be set if null_value == 0 - enum_field_types f_type; - - switch ((f_type=field_type())) { - default: - case MYSQL_TYPE_NULL: - case MYSQL_TYPE_DECIMAL: - case MYSQL_TYPE_ENUM: - case MYSQL_TYPE_SET: - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_LONG_BLOB: - case MYSQL_TYPE_BLOB: - case MYSQL_TYPE_GEOMETRY: - case MYSQL_TYPE_STRING: - case MYSQL_TYPE_VAR_STRING: - case MYSQL_TYPE_VARCHAR: - case MYSQL_TYPE_BIT: - case MYSQL_TYPE_NEWDECIMAL: - { - String *res; - if ((res=val_str(buffer))) - { - DBUG_ASSERT(!null_value); - result= protocol->store(res->ptr(),res->length(),res->charset()); - } - else - { - DBUG_ASSERT(null_value); - } - break; - } - case MYSQL_TYPE_TINY: - { - longlong nr; - nr= val_int(); - if (!null_value) - result= protocol->store_tiny(nr); - break; - } - case MYSQL_TYPE_SHORT: - case MYSQL_TYPE_YEAR: - { - longlong nr; - nr= val_int(); - if (!null_value) - result= protocol->store_short(nr); - break; - } - case MYSQL_TYPE_INT24: - case MYSQL_TYPE_LONG: - { - longlong nr; - nr= val_int(); - if (!null_value) - result= protocol->store_long(nr); - break; - } - case MYSQL_TYPE_LONGLONG: - { - longlong nr; - nr= val_int(); - if (!null_value) - result= protocol->store_longlong(nr, unsigned_flag); - break; - } - case MYSQL_TYPE_FLOAT: - { - float nr; - nr= (float) val_real(); - if (!null_value) - result= protocol->store(nr, decimals, buffer); - break; - } - case MYSQL_TYPE_DOUBLE: - { - double nr= val_real(); - if (!null_value) - result= protocol->store(nr, decimals, buffer); - break; - } - case MYSQL_TYPE_DATETIME: - case MYSQL_TYPE_DATE: - case MYSQL_TYPE_TIMESTAMP: - { - MYSQL_TIME tm; - get_date(&tm, sql_mode_for_dates(current_thd)); - if (!null_value) - { - if (f_type == MYSQL_TYPE_DATE) - return protocol->store_date(&tm); - else - result= protocol->store(&tm, decimals); - } - break; - } - case MYSQL_TYPE_TIME: - { - MYSQL_TIME tm; - get_time(&tm); - if (!null_value) - result= protocol->store_time(&tm, decimals); - break; - } - } - if (null_value) - result= protocol->store_null(); - return result; -} - /** Check if an item is a constant one and can be cached. @@ -7022,7 +6941,7 @@ Item* Item::cache_const_expr_transformer(THD *thd, uchar *arg) if (*(bool*)arg) { *((bool*)arg)= FALSE; - Item_cache *cache= Item_cache::get_cache(thd, this); + Item_cache *cache= get_cache(thd); if (!cache) return NULL; cache->setup(thd, this); @@ -7040,7 +6959,7 @@ bool Item::find_item_processor(void *arg) return (this == ((Item *) arg)); } -bool Item_field::send(Protocol *protocol, String *buffer) +bool Item_field::send(Protocol *protocol, st_value *buffer) { return protocol->store(result_field); } @@ -7113,7 +7032,7 @@ Item *Item_field::update_value_transformer(THD *thd, uchar *select_arg) all_fields->push_front((Item*)this, thd->mem_root); ref= new (thd->mem_root) Item_ref(thd, &select->context, &ref_pointer_array[el], - table_name, field_name); + table_name, &field_name); return ref; } return this; @@ -7131,7 +7050,7 @@ Item *Item_field::derived_field_transformer_for_having(THD *thd, uchar *arg) Item_ref *rf= new (thd->mem_root) Item_ref(thd, &sl->context, NullS, NullS, - ((Item_field*) this)->field_name); + &((Item_field*) this)->field_name); if (!rf) return 0; return rf; @@ -7149,7 +7068,8 @@ Item *Item_field::derived_field_transformer_for_having(THD *thd, uchar *arg) Item_ref *rf= new (thd->mem_root) Item_ref(thd, &sl->context, NullS, NullS, - ((Item_field*) (item->real_item()))->field_name); + &((Item_field*) (item->real_item()))-> + field_name); if (!rf) return 0; return rf; @@ -7247,6 +7167,26 @@ void Item_field::print(String *str, enum_query_type query_type) } +bool Item_field_row::element_index_by_name(uint *idx, + const LEX_CSTRING &name) const +{ + Field *field; + for (uint i= 0; (field= get_row_field(i)); i++) + { + // Use the same comparison style with sp_context::find_variable() + if (!my_strnncoll(system_charset_info, + (const uchar *) field->field_name.str, + field->field_name.length, + (const uchar *) name.str, name.length)) + { + *idx= i; + return false; + } + } + return true; +} + + void Item_temptable_field::print(String *str, enum_query_type query_type) { /* @@ -7259,7 +7199,7 @@ void Item_temptable_field::print(String *str, enum_query_type query_type) Item_ref::Item_ref(THD *thd, Name_resolution_context *context_arg, Item **item, const char *table_name_arg, - const char *field_name_arg, + const LEX_CSTRING *field_name_arg, bool alias_name_used_arg): Item_ident(thd, context_arg, NullS, table_name_arg, field_name_arg), ref(item), reference_trough_name(0) @@ -7304,7 +7244,8 @@ public: }; Item_ref::Item_ref(THD *thd, TABLE_LIST *view_arg, Item **item, - const char *field_name_arg, bool alias_name_used_arg): + const LEX_CSTRING *field_name_arg, + bool alias_name_used_arg): Item_ident(thd, view_arg, field_name_arg), ref(item), reference_trough_name(0) { @@ -7586,13 +7527,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 && + (((*ref)->with_sum_func && name.str && !(current_sel->linkage != GLOBAL_OPTIONS_TYPE && current_sel->having_fix_field)) || !(*ref)->fixed)) { my_error(ER_ILLEGAL_REFERENCE, MYF(0), - name, ((*ref)->with_sum_func? + name.str, ((*ref)->with_sum_func? "reference to group function": "forward reference in item list")); goto error; @@ -7734,11 +7675,11 @@ void Item_ref::print(String *str, enum_query_type query_type) if (ref) { if ((*ref)->type() != Item::CACHE_ITEM && ref_type() != VIEW_REF && - !table_name && name && alias_name_used) + !table_name && name.str && alias_name_used) { THD *thd= current_thd; - append_identifier(thd, str, (*ref)->real_item()->name, - strlen((*ref)->real_item()->name)); + append_identifier(thd, str, (*ref)->real_item()->name.str, + (*ref)->real_item()->name.length); } else (*ref)->print(str, query_type); @@ -7748,11 +7689,11 @@ void Item_ref::print(String *str, enum_query_type query_type) } -bool Item_ref::send(Protocol *prot, String *tmp) +bool Item_ref::send(Protocol *prot, st_value *buffer) { if (result_field) return prot->store(result_field); - return (*ref)->send(prot, tmp); + return (*ref)->send(prot, buffer); } @@ -7935,13 +7876,13 @@ void Item_ref::make_field(THD *thd, Send_field *field) { (*ref)->make_field(thd, field); /* Non-zero in case of a view */ - if (name) + if (name.str) field->col_name= name; if (table_name) field->table_name= table_name; if (db_name) field->db_name= db_name; - if (orig_field_name) + if (orig_field_name.str) field->org_col_name= orig_field_name; if (orig_table_name) field->org_table_name= orig_table_name; @@ -8047,10 +7988,9 @@ Item_cache_wrapper::Item_cache_wrapper(THD *thd, Item *item_arg): with_sum_func= orig_item->with_sum_func; with_field= orig_item->with_field; name= item_arg->name; - name_length= item_arg->name_length; with_subselect= orig_item->with_subselect; - if ((expr_value= Item_cache::get_cache(thd, orig_item))) + if ((expr_value= orig_item->get_cache(thd))) expr_value->setup(thd, orig_item); fixed= 1; @@ -8108,7 +8048,7 @@ bool Item_cache_wrapper::fix_fields(THD *thd __attribute__((unused)), return FALSE; } -bool Item_cache_wrapper::send(Protocol *protocol, String *buffer) +bool Item_cache_wrapper::send(Protocol *protocol, st_value *buffer) { if (result_field) return protocol->store(result_field); @@ -8439,7 +8379,7 @@ Item* Item_cache_wrapper::get_tmp_table_item(THD *thd) } -bool Item_direct_view_ref::send(Protocol *protocol, String *buffer) +bool Item_direct_view_ref::send(Protocol *protocol, st_value *buffer) { if (check_null_ref()) return protocol->store_null(); @@ -8728,14 +8668,15 @@ bool Item_default_value::fix_fields(THD *thd, Item **items) real_arg= arg->real_item(); if (real_arg->type() != FIELD_ITEM) { - my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), arg->name); + my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), arg->name.str); goto error; } field_arg= (Item_field *)real_arg; if ((field_arg->field->flags & NO_DEFAULT_VALUE_FLAG)) { - my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), field_arg->field->field_name); + my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), + field_arg->field->field_name.str); goto error; } if (!(def_field= (Field*) thd->alloc(field_arg->field->size_of()))) @@ -8815,7 +8756,7 @@ bool Item_default_value::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate) return Item_field::get_date(ltime, fuzzydate); } -bool Item_default_value::send(Protocol *protocol, String *buffer) +bool Item_default_value::send(Protocol *protocol, st_value *buffer) { calculate(); return Item_field::send(protocol, buffer); @@ -8922,7 +8863,7 @@ bool Item_ignore_value::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) return TRUE; } -bool Item_ignore_value::send(Protocol *protocol, String *buffer) +bool Item_ignore_value::send(Protocol *protocol, st_value *buffer) { DBUG_ASSERT(0); // never should be called return TRUE; @@ -8976,7 +8917,7 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items) { Field *tmp_field= field_arg->field; /* charset doesn't matter here, it's to avoid sigsegv only */ - tmp_field= new Field_null(0, 0, Field::NONE, field_arg->field->field_name, + tmp_field= new Field_null(0, 0, Field::NONE, &field_arg->field->field_name, &my_charset_bin); if (tmp_field) { @@ -9033,7 +8974,7 @@ void Item_trigger_field::setup_field(THD *thd, TABLE *table, Try to find field by its name and if it will be found set field_idx properly. */ - (void)find_field_in_table(thd, table, field_name, (uint) strlen(field_name), + (void)find_field_in_table(thd, table, field_name.str, field_name.length, 0, &field_idx); thd->mark_used_columns= save_mark_used_columns; triggers= table->triggers; @@ -9045,8 +8986,8 @@ bool Item_trigger_field::eq(const Item *item, bool binary_cmp) const { return item->type() == TRIGGER_FIELD_ITEM && row_version == ((Item_trigger_field *)item)->row_version && - !my_strcasecmp(system_charset_info, field_name, - ((Item_trigger_field *)item)->field_name); + !my_strcasecmp(system_charset_info, field_name.str, + ((Item_trigger_field *)item)->field_name.str); } @@ -9112,9 +9053,11 @@ bool Item_trigger_field::fix_fields(THD *thd, Item **items) { table_grants->want_privilege= want_privilege; - if (check_grant_column(thd, table_grants, triggers->trigger_table->s->db.str, - triggers->trigger_table->s->table_name.str, field_name, - strlen(field_name), thd->security_ctx)) + if (check_grant_column(thd, table_grants, + triggers->trigger_table->s->db.str, + triggers->trigger_table->s->table_name.str, + field_name.str, field_name.length, + thd->security_ctx)) return TRUE; } #endif // NO_EMBEDDED_ACCESS_CHECKS @@ -9126,7 +9069,7 @@ bool Item_trigger_field::fix_fields(THD *thd, Item **items) return FALSE; } - my_error(ER_BAD_FIELD_ERROR, MYF(0), field_name, + my_error(ER_BAD_FIELD_ERROR, MYF(0), field_name.str, (row_version == NEW_ROW) ? "NEW" : "OLD"); return TRUE; } @@ -9136,14 +9079,14 @@ void Item_trigger_field::print(String *str, enum_query_type query_type) { str->append((row_version == NEW_ROW) ? "NEW" : "OLD", 3); str->append('.'); - str->append(field_name); + str->append(&field_name); } bool Item_trigger_field::check_vcol_func_processor(void *arg) { const char *ver= row_version == NEW_ROW ? "NEW." : "OLD."; - return mark_unsupported_function(ver, field_name, arg, VCOL_IMPOSSIBLE); + return mark_unsupported_function(ver, field_name.str, arg, VCOL_IMPOSSIBLE); } @@ -9180,101 +9123,14 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) Item *item= *ref; if (item->basic_const_item()) return; // Can't be better - - Item *new_item= NULL; - Item_result res_type= item_cmp_type(comp_item, item); - char *name= item->name; // Alloced on THD::mem_root - MEM_ROOT *mem_root= thd->mem_root; - - switch (res_type) { - case TIME_RESULT: + Type_handler_hybrid_field_type cmp(comp_item->type_handler_for_comparison()); + if (!cmp.aggregate_for_comparison(item->type_handler_for_comparison())) { - bool is_null; - Item **ref_copy= ref; - /* the following call creates a constant and puts it in new_item */ - enum_field_types type= item->field_type_for_temporal_comparison(comp_item); - get_datetime_value(thd, &ref_copy, &new_item, type, &is_null); - if (is_null) - new_item= new (mem_root) Item_null(thd, name); - break; - } - case STRING_RESULT: - { - char buff[MAX_FIELD_WIDTH]; - String tmp(buff,sizeof(buff),&my_charset_bin),*result; - result=item->val_str(&tmp); - if (item->null_value) - new_item= new (mem_root) Item_null(thd, name); - else - { - uint length= result->length(); - char *tmp_str= thd->strmake(result->ptr(), length); - new_item= new (mem_root) Item_string(thd, name, tmp_str, length, result->charset()); - } - break; - } - case INT_RESULT: - { - longlong result=item->val_int(); - uint length=item->max_length; - bool null_value=item->null_value; - new_item= (null_value ? (Item*) new (mem_root) Item_null(thd, name) : - (Item*) new (mem_root) Item_int(thd, name, result, length)); - break; - } - case ROW_RESULT: - if (item->type() == Item::ROW_ITEM && comp_item->type() == Item::ROW_ITEM) - { - /* - Substitute constants only in Item_row's. Don't affect other Items - with ROW_RESULT (eg Item_singlerow_subselect). - - For such Items more optimal is to detect if it is constant and replace - it with Item_row. This would optimize queries like this: - SELECT * FROM t1 WHERE (a,b) = (SELECT a,b FROM t2 LIMIT 1); - */ - Item_row *item_row= (Item_row*) item; - Item_row *comp_item_row= (Item_row*) comp_item; - uint col; - new_item= 0; - /* - If item and comp_item are both Item_row's and have same number of cols - then process items in Item_row one by one. - We can't ignore NULL values here as this item may be used with <=>, in - which case NULL's are significant. - */ - DBUG_ASSERT(item->result_type() == comp_item->result_type()); - DBUG_ASSERT(item_row->cols() == comp_item_row->cols()); - col= item_row->cols(); - while (col-- > 0) - resolve_const_item(thd, item_row->addr(col), - comp_item_row->element_index(col)); - break; - } - /* Fallthrough */ - case REAL_RESULT: - { // It must REAL_RESULT - double result= item->val_real(); - uint length=item->max_length,decimals=item->decimals; - bool null_value=item->null_value; - new_item= (null_value ? (Item*) new (mem_root) Item_null(thd, name) : (Item*) - new (mem_root) Item_float(thd, name, result, decimals, length)); - break; - } - case DECIMAL_RESULT: - { - my_decimal decimal_value; - my_decimal *result= item->val_decimal(&decimal_value); - uint length= item->max_length, decimals= item->decimals; - bool null_value= item->null_value; - new_item= (null_value ? - (Item*) new (mem_root) Item_null(thd, name) : - (Item*) new (mem_root) Item_decimal(thd, name, result, length, decimals)); - break; - } + Item *new_item= cmp.type_handler()-> + make_const_item_for_comparison(thd, item, comp_item); + if (new_item) + thd->change_item_tree(ref, new_item); } - if (new_item) - thd->change_item_tree(ref, new_item); } /** @@ -9371,41 +9227,6 @@ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) return 0; } -Item_cache* Item_cache::get_cache(THD *thd, const Item *item) -{ - return get_cache(thd, item, item->cmp_type()); -} - - -/** - Get a cache item of given type. - - @param item value to be cached - @param type required type of cache - - @return cache item -*/ - -Item_cache* Item_cache::get_cache(THD *thd, const Item *item, - const Item_result type) -{ - MEM_ROOT *mem_root= thd->mem_root; - switch (type) { - case INT_RESULT: - return new (mem_root) Item_cache_int(thd, item->field_type()); - case REAL_RESULT: - return new (mem_root) Item_cache_real(thd); - case DECIMAL_RESULT: - return new (mem_root) Item_cache_decimal(thd); - case STRING_RESULT: - return new (mem_root) Item_cache_str(thd, item); - case ROW_RESULT: - return new (mem_root) Item_cache_row(thd); - case TIME_RESULT: - return new (mem_root) Item_cache_temporal(thd, item->field_type()); - } - return 0; // Impossible -} void Item_cache::store(Item *item) { @@ -9523,13 +9344,11 @@ Item *Item_cache_int::convert_to_basic_const_item(THD *thd) } -Item_cache_temporal::Item_cache_temporal(THD *thd, - enum_field_types field_type_arg): - Item_cache_int(thd, field_type_arg) +Item_cache_temporal::Item_cache_temporal(THD *thd, const Type_handler *handler) + :Item_cache_int(thd, handler) { - if (mysql_type_to_time_type(Item_cache_temporal::field_type()) == - MYSQL_TIMESTAMP_ERROR) - set_handler_by_field_type(MYSQL_TYPE_DATETIME); + if (mysql_timestamp_type() == MYSQL_TIMESTAMP_ERROR) + set_handler(&type_handler_datetime2); } @@ -9637,7 +9456,7 @@ bool Item_cache_temporal::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) } unpack_time(value, ltime); - ltime->time_type= mysql_type_to_time_type(field_type()); + ltime->time_type= mysql_timestamp_type(); if (ltime->time_type == MYSQL_TIMESTAMP_TIME) { ltime->hour+= (ltime->month*32+ltime->day)*24; @@ -9672,7 +9491,7 @@ void Item_cache_temporal::store_packed(longlong val_arg, Item *example_arg) Item *Item_cache_temporal::clone_item(THD *thd) { Item_cache_temporal *item= new (thd->mem_root) - Item_cache_temporal(thd, Item_cache_temporal::field_type()); + Item_cache_temporal(thd, Item_cache_temporal::type_handler()); item->store_packed(value, example); return item; } @@ -9930,7 +9749,7 @@ bool Item_cache_row::setup(THD *thd, Item *item) { Item *el= item->element_index(i); Item_cache *tmp; - if (!(tmp= values[i]= Item_cache::get_cache(thd, el))) + if (!(tmp= values[i]= el->get_cache(thd))) return 1; tmp->setup(thd, el); } @@ -10033,388 +9852,6 @@ void Item_cache_row::set_null() }; -Item_type_holder::Item_type_holder(THD *thd, Item *item) - :Item(thd, item), - Type_handler_hybrid_real_field_type(get_real_type(item)), - enum_set_typelib(0), - geometry_type(Field::GEOM_GEOMETRY) -{ - DBUG_ASSERT(item->fixed); - maybe_null= item->maybe_null; - collation.set(item->collation); - get_full_info(item); - /** - Field::result_merge_type(real_field_type()) should be equal to - result_type(), with one exception when "this" is a Item_field for - a BIT field: - - Field_bit::result_type() returns INT_RESULT, so does its Item_field. - - Field::result_merge_type(MYSQL_TYPE_BIT) returns STRING_RESULT. - Perhaps we need a new method in Type_handler to cover these type - merging rules for UNION. - */ - DBUG_ASSERT(real_field_type() == MYSQL_TYPE_BIT || - Item_type_holder::result_type() == - Field::result_merge_type(Item_type_holder::real_field_type())); - /* fix variable decimals which always is NOT_FIXED_DEC */ - if (Field::result_merge_type(real_field_type()) == INT_RESULT) - decimals= 0; - prev_decimal_int_part= item->decimal_int_part(); -#ifdef HAVE_SPATIAL - if (item->field_type() == MYSQL_TYPE_GEOMETRY) - geometry_type= item->get_geometry_type(); -#endif /* HAVE_SPATIAL */ -} - - -/** - Find real field type of item. - - @return - type of field which should be created to store item value -*/ - -enum_field_types Item_type_holder::get_real_type(Item *item) -{ - if (item->type() == REF_ITEM) - item= item->real_item(); - switch(item->type()) - { - case FIELD_ITEM: - { - /* - Item_field::field_type ask Field_type() but sometimes field return - a different type, like for enum/set, so we need to ask real type. - */ - Field *field= ((Item_field *) item)->field; - enum_field_types type= field->real_type(); - if (field->is_created_from_null_item) - return MYSQL_TYPE_NULL; - /* work around about varchar type field detection */ - if (type == MYSQL_TYPE_STRING && field->type() == MYSQL_TYPE_VAR_STRING) - return MYSQL_TYPE_VAR_STRING; - return type; - } - case SUM_FUNC_ITEM: - { - /* - Argument of aggregate function sometimes should be asked about field - type - */ - Item_sum *item_sum= (Item_sum *) item; - if (item_sum->keep_field_type()) - return get_real_type(item_sum->get_arg(0)); - break; - } - case FUNC_ITEM: - if (((Item_func *) item)->functype() == Item_func::GUSERVAR_FUNC) - { - /* - There are work around of problem with changing variable type on the - fly and variable always report "string" as field type to get - acceptable information for client in send_field, so we make field - type from expression type. - */ - switch (item->result_type()) { - case STRING_RESULT: - return MYSQL_TYPE_VARCHAR; - case INT_RESULT: - return MYSQL_TYPE_LONGLONG; - case REAL_RESULT: - return MYSQL_TYPE_DOUBLE; - case DECIMAL_RESULT: - return MYSQL_TYPE_NEWDECIMAL; - case ROW_RESULT: - case TIME_RESULT: - DBUG_ASSERT(0); - return MYSQL_TYPE_VARCHAR; - } - } - break; - case TYPE_HOLDER: - /* - Item_type_holder and Item_blob should not appear in this context. - In case they for some reasons do, returning field_type() is wrong anyway. - They must return Item_type_holder::real_field_type() instead, to make - the code in sql_type.cc and sql_type.h happy, as it expectes - Field::real_type()-compatible rather than Field::field_type()-compatible - valies in some places, and may in the future add some asserts preventing - use of field_type() instead of real_type() and the other way around. - */ - DBUG_ASSERT(0); - default: - break; - } - return item->field_type(); -} - -/** - Find field type which can carry current Item_type_holder type and - type of given Item. - - @param thd thread handler - @param item given item to join its parameters with this item ones - - @retval - TRUE error - types are incompatible - @retval - FALSE OK -*/ - -bool Item_type_holder::join_types(THD *thd, Item *item) -{ - uint max_length_orig= max_length; - uint decimals_orig= decimals; - DBUG_ENTER("Item_type_holder::join_types"); - DBUG_PRINT("info:", ("was type %d len %d, dec %d name %s", - real_field_type(), max_length, decimals, - (name ? name : "<NULL>"))); - DBUG_PRINT("info:", ("in type %d len %d, dec %d", - get_real_type(item), - item->max_length, item->decimals)); - set_handler_by_real_type(Field::field_type_merge(real_field_type(), - get_real_type(item))); - { - uint item_decimals= item->decimals; - /* fix variable decimals which always is NOT_FIXED_DEC */ - if (Field::result_merge_type(real_field_type()) == INT_RESULT) - item_decimals= 0; - decimals= MY_MAX(decimals, item_decimals); - } - - if (Item_type_holder::field_type() == FIELD_TYPE_GEOMETRY) - geometry_type= - Field_geom::geometry_type_merge(geometry_type, item->get_geometry_type()); - - if (Field::result_merge_type(real_field_type()) == DECIMAL_RESULT) - { - decimals= MY_MIN(MY_MAX(decimals, item->decimals), DECIMAL_MAX_SCALE); - int item_int_part= item->decimal_int_part(); - int item_prec = MY_MAX(prev_decimal_int_part, item_int_part) + decimals; - int precision= MY_MIN(item_prec, DECIMAL_MAX_PRECISION); - unsigned_flag&= item->unsigned_flag; - max_length= my_decimal_precision_to_length_no_truncation(precision, - decimals, - unsigned_flag); - } - - switch (Field::result_merge_type(real_field_type())) - { - case STRING_RESULT: - { - const char *old_cs, *old_derivation; - uint32 old_max_chars= max_length / collation.collation->mbmaxlen; - old_cs= collation.collation->name; - old_derivation= collation.derivation_name(); - if (collation.aggregate(item->collation, MY_COLL_ALLOW_CONV)) - { - my_error(ER_CANT_AGGREGATE_2COLLATIONS, MYF(0), - old_cs, old_derivation, - item->collation.collation->name, - item->collation.derivation_name(), - "UNION"); - DBUG_RETURN(TRUE); - } - /* - To figure out max_length, we have to take into account possible - expansion of the size of the values because of character set - conversions. - */ - if (collation.collation != &my_charset_bin) - { - max_length= MY_MAX(old_max_chars * collation.collation->mbmaxlen, - display_length(item) / - item->collation.collation->mbmaxlen * - collation.collation->mbmaxlen); - } - else - set_if_bigger(max_length, display_length(item)); - break; - } - case REAL_RESULT: - { - if (decimals != NOT_FIXED_DEC) - { - /* - For FLOAT(M,D)/DOUBLE(M,D) do not change precision - if both fields have the same M and D - */ - if (item->max_length != max_length_orig || - item->decimals != decimals_orig) - { - int delta1= max_length_orig - decimals_orig; - int delta2= item->max_length - item->decimals; - max_length= MY_MAX(delta1, delta2) + decimals; - if (Item_type_holder::real_field_type() == MYSQL_TYPE_FLOAT && - max_length > FLT_DIG + 2) - { - max_length= MAX_FLOAT_STR_LENGTH; - decimals= NOT_FIXED_DEC; - } - else if (Item_type_holder::real_field_type() == MYSQL_TYPE_DOUBLE && - max_length > DBL_DIG + 2) - { - max_length= MAX_DOUBLE_STR_LENGTH; - decimals= NOT_FIXED_DEC; - } - } - } - else - max_length= (Item_type_holder::field_type() == MYSQL_TYPE_FLOAT) ? - FLT_DIG+6 : DBL_DIG+7; - break; - } - default: - max_length= MY_MAX(max_length, display_length(item)); - }; - maybe_null|= item->maybe_null; - get_full_info(item); - - /* Remember decimal integer part to be used in DECIMAL_RESULT handleng */ - prev_decimal_int_part= decimal_int_part(); - DBUG_PRINT("info", ("become type: %d len: %u dec: %u", - (int) real_field_type(), max_length, (uint) decimals)); - DBUG_RETURN(FALSE); -} - -/** - Calculate lenth for merging result for given Item type. - - @param item Item for length detection - - @return - length -*/ - -uint32 Item_type_holder::display_length(Item *item) -{ - if (item->type() == Item::FIELD_ITEM) - return ((Item_field *)item)->max_disp_length(); - - switch (item->field_type()) - { - case MYSQL_TYPE_DECIMAL: - case MYSQL_TYPE_TIMESTAMP: - case MYSQL_TYPE_DATE: - case MYSQL_TYPE_TIME: - case MYSQL_TYPE_DATETIME: - case MYSQL_TYPE_YEAR: - case MYSQL_TYPE_NEWDATE: - case MYSQL_TYPE_VARCHAR: - case MYSQL_TYPE_BIT: - case MYSQL_TYPE_NEWDECIMAL: - case MYSQL_TYPE_ENUM: - case MYSQL_TYPE_SET: - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_LONG_BLOB: - case MYSQL_TYPE_BLOB: - case MYSQL_TYPE_VAR_STRING: - case MYSQL_TYPE_STRING: - case MYSQL_TYPE_GEOMETRY: - return item->max_length; - case MYSQL_TYPE_TINY: - return 4; - case MYSQL_TYPE_SHORT: - return 6; - case MYSQL_TYPE_LONG: - return MY_INT32_NUM_DECIMAL_DIGITS; - case MYSQL_TYPE_FLOAT: - return 25; - case MYSQL_TYPE_DOUBLE: - return 53; - case MYSQL_TYPE_NULL: - return 0; - case MYSQL_TYPE_LONGLONG: - return 20; - case MYSQL_TYPE_INT24: - return 8; - default: - DBUG_ASSERT(0); // we should never go there - return 0; - } -} - - -/** - Make temporary table field according collected information about type - of UNION result. - - @param table temporary table for which we create fields - - @return - created field -*/ - -Field *Item_type_holder::make_field_by_type(TABLE *table) -{ - /* - The field functions defines a field to be not null if null_ptr is not 0 - */ - uchar *null_ptr= maybe_null ? (uchar*) "" : 0; - Field *field; - - switch (Item_type_holder::real_field_type()) { - case MYSQL_TYPE_ENUM: - DBUG_ASSERT(enum_set_typelib); - field= new Field_enum((uchar *) 0, max_length, null_ptr, 0, - Field::NONE, name, - get_enum_pack_length(enum_set_typelib->count), - enum_set_typelib, collation.collation); - if (field) - field->init(table); - return field; - case MYSQL_TYPE_SET: - DBUG_ASSERT(enum_set_typelib); - field= new Field_set((uchar *) 0, max_length, null_ptr, 0, - Field::NONE, name, - get_set_pack_length(enum_set_typelib->count), - enum_set_typelib, collation.collation); - if (field) - field->init(table); - return field; - case MYSQL_TYPE_NULL: - return make_string_field(table); - default: - break; - } - return tmp_table_field_from_field_type(table, false, true); -} - - -/** - Get full information from Item about enum/set fields to be able to create - them later. - - @param item Item for information collection -*/ -void Item_type_holder::get_full_info(Item *item) -{ - if (Item_type_holder::real_field_type() == MYSQL_TYPE_ENUM || - Item_type_holder::real_field_type() == MYSQL_TYPE_SET) - { - if (item->type() == Item::SUM_FUNC_ITEM && - (((Item_sum*)item)->sum_func() == Item_sum::MAX_FUNC || - ((Item_sum*)item)->sum_func() == Item_sum::MIN_FUNC)) - item = ((Item_sum*)item)->get_arg(0); - /* - We can have enum/set type after merging only if we have one enum|set - field (or MIN|MAX(enum|set field)) and number of NULL fields - */ - DBUG_ASSERT((enum_set_typelib && - get_real_type(item) == MYSQL_TYPE_NULL) || - (!enum_set_typelib && - item->real_item()->type() == Item::FIELD_ITEM && - (get_real_type(item->real_item()) == MYSQL_TYPE_ENUM || - get_real_type(item->real_item()) == MYSQL_TYPE_SET) && - ((Field_enum*)((Item_field *) item->real_item())->field)->typelib)); - if (!enum_set_typelib) - { - enum_set_typelib= ((Field_enum*)((Item_field *) item->real_item())->field)->typelib; - } - } -} - - double Item_type_holder::val_real() { DBUG_ASSERT(0); // should never be called |