diff options
Diffstat (limited to 'sql/item.cc')
-rw-r--r-- | sql/item.cc | 462 |
1 files changed, 313 insertions, 149 deletions
diff --git a/sql/item.cc b/sql/item.cc index e3e17a3ceea..1dac5ed8c78 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -56,7 +56,7 @@ Hybrid_type_traits::val_decimal(Hybrid_type *val, my_decimal *to) const String * Hybrid_type_traits::val_str(Hybrid_type *val, String *to, uint8 decimals) const { - to->set(val->real, decimals, &my_charset_bin); + to->set_real(val->real, decimals, &my_charset_bin); return to; } @@ -161,6 +161,7 @@ Hybrid_type_traits_integer::fix_length_and_dec(Item *item, Item *arg) const void item_init(void) { item_user_lock_init(); + uuid_short_init(); } @@ -197,7 +198,7 @@ String *Item::val_string_from_real(String *str) double nr= val_real(); if (null_value) return 0; /* purecov: inspected */ - str->set(nr,decimals, &my_charset_bin); + str->set_real(nr,decimals, &my_charset_bin); return str; } @@ -207,10 +208,7 @@ String *Item::val_string_from_int(String *str) longlong nr= val_int(); if (null_value) return 0; - if (unsigned_flag) - str->set((ulonglong) nr, &my_charset_bin); - else - str->set(nr, &my_charset_bin); + str->set_int(nr, unsigned_flag, &my_charset_bin); return str; } @@ -466,7 +464,7 @@ void Item::cleanup() arg - a dummy parameter, is not used here */ -bool Item::cleanup_processor(byte *arg) +bool Item::cleanup_processor(uchar *arg) { if (fixed) cleanup(); @@ -529,7 +527,7 @@ void Item::rename(char *new_name) pointer to newly allocated item is returned. */ -Item* Item::transform(Item_transformer transformer, byte *arg) +Item* Item::transform(Item_transformer transformer, uchar *arg) { DBUG_ASSERT(!current_thd->is_stmt_prepare()); @@ -587,7 +585,7 @@ void Item_ident::cleanup() DBUG_VOID_RETURN; } -bool Item_ident::remove_dependence_processor(byte * arg) +bool Item_ident::remove_dependence_processor(uchar * arg) { DBUG_ENTER("Item_ident::remove_dependence_processor"); if (depended_from == (st_select_lex *) arg) @@ -618,7 +616,7 @@ bool Item_ident::remove_dependence_processor(byte * arg) for the subsequent items. */ -bool Item_field::collect_item_field_processor(byte *arg) +bool Item_field::collect_item_field_processor(uchar *arg) { DBUG_ENTER("Item_field::collect_item_field_processor"); DBUG_PRINT("info", ("%s", field->field_name ? field->field_name : "noname")); @@ -653,7 +651,7 @@ bool Item_field::collect_item_field_processor(byte *arg) FALSE otherwise */ -bool Item_field::find_item_in_field_list_processor(byte *arg) +bool Item_field::find_item_in_field_list_processor(uchar *arg) { KEY_PART_INFO *first_non_group_part= *((KEY_PART_INFO **) arg); KEY_PART_INFO *last_part= *(((KEY_PART_INFO **) arg) + 1); @@ -668,6 +666,23 @@ bool Item_field::find_item_in_field_list_processor(byte *arg) } +/* + Mark field in read_map + + NOTES + This is used by filesort to register used fields in a a temporary + column read set or to register used fields in a view +*/ + +bool Item_field::register_field_in_read_map(uchar *arg) +{ + TABLE *table= (TABLE *) arg; + if (field->table == table || !table) + bitmap_set_bit(field->table->read_set, field->field_index); + return 0; +} + + bool Item::check_cols(uint c) { if (c != 1) @@ -714,7 +729,7 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs) } if (!my_charset_same(cs, system_charset_info)) { - uint32 res_length; + size_t res_length; name= sql_strmake_with_convert(str, name_length= length, cs, MAX_ALIAS_NAME, system_charset_info, &res_length); @@ -794,6 +809,7 @@ Item *Item_string::safe_charset_converter(CHARSET_INFO *tocs) { Item_string *conv; uint conv_errors; + char *ptr; String tmp, cstr, *ostr= val_str(&tmp); cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(), tocs, &conv_errors); if (conv_errors || !(conv= new Item_string(cstr.ptr(), cstr.length(), @@ -808,7 +824,9 @@ Item *Item_string::safe_charset_converter(CHARSET_INFO *tocs) */ return NULL; } - conv->str_value.copy(); + if (!(ptr= current_thd->strmake(cstr.ptr(), cstr.length()))) + return NULL; + conv->str_value.set(ptr, cstr.length(), cstr.charset()); /* Ensure that no one is going to change the result string */ conv->str_value.mark_as_const(); return conv; @@ -934,16 +952,27 @@ CHARSET_INFO *Item::default_charset() } +/* + Save value in field, but don't give any warnings + + NOTES + This is used to temporary store and retrieve a value in a column, + for example in opt_range to adjust the key value to fit the column. +*/ + int Item::save_in_field_no_warnings(Field *field, bool no_conversions) { int res; - THD *thd= field->table->in_use; + TABLE *table= field->table; + THD *thd= table->in_use; enum_check_fields tmp= thd->count_cuted_fields; + my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set); ulong sql_mode= thd->variables.sql_mode; thd->variables.sql_mode&= ~(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE); thd->count_cuted_fields= CHECK_FIELD_IGNORE; res= save_in_field(field, no_conversions); thd->count_cuted_fields= tmp; + dbug_tmp_restore_column_map(table->write_set, old_map); thd->variables.sql_mode= sql_mode; return res; } @@ -1120,8 +1149,8 @@ bool Item_splocal::set_value(THD *thd, sp_rcontext *ctx, Item **it) Item_case_expr methods *****************************************************************************/ -Item_case_expr::Item_case_expr(int case_expr_id) - :Item_sp_variable((char *) STRING_WITH_LEN("case_expr")), +Item_case_expr::Item_case_expr(uint case_expr_id) + :Item_sp_variable( C_STRING_WITH_LEN("case_expr")), m_case_expr_id(case_expr_id) { } @@ -1157,6 +1186,8 @@ Item_case_expr::this_item_addr(THD *thd, Item **) void Item_case_expr::print(String *str) { + if (str->reserve(MAX_INT_WIDTH + sizeof("case_expr@"))) + return; /* purecov: inspected */ VOID(str->append(STRING_WITH_LEN("case_expr@"))); str->qs_append(m_case_expr_id); } @@ -1209,7 +1240,17 @@ bool Item_name_const::is_null() Item::Type Item_name_const::type() const { - return value_item->type(); + /* + 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. + */ + return valid_args ? value_item->type() : NULL_ITEM; } @@ -1221,14 +1262,14 @@ bool Item_name_const::fix_fields(THD *thd, Item **ref) s.length(0); if (value_item->fix_fields(thd, &value_item) || - name_item->fix_fields(thd, &name_item)) - return TRUE; - if (!(value_item->const_item() && name_item->const_item())) + name_item->fix_fields(thd, &name_item) || + !value_item->const_item() || + !name_item->const_item() || + !(item_name= name_item->val_str(&s))) // Can't have a NULL name + { + my_error(ER_RESERVED_SYNTAX, MYF(0), "NAME_CONST"); return TRUE; - - if (!(item_name= name_item->val_str(&s))) - return TRUE; /* Can't have a NULL name */ - + } set_name(item_name->ptr(), (uint) item_name->length(), system_charset_info); max_length= value_item->max_length; decimals= value_item->decimals; @@ -1588,6 +1629,10 @@ bool agg_item_charsets(DTCollation &coll, const char *fname, Item **args, uint nargs, uint flags, int item_sep) { Item **arg, *safe_args[2]; + + LINT_INIT(safe_args[0]); + LINT_INIT(safe_args[1]); + if (agg_item_collations(coll, fname, args, nargs, flags, item_sep)) return TRUE; @@ -1654,7 +1699,7 @@ bool agg_item_charsets(DTCollation &coll, const char *fname, been created in prepare. In this case register the change for rollback. */ - if (arena) + if (thd->is_stmt_prepare()) *arg= conv; else thd->change_item_tree(arg, conv); @@ -1687,20 +1732,21 @@ void Item_ident_for_show::make_field(Send_field *tmp_field) Item_field::Item_field(Field *f) :Item_ident(0, NullS, *f->table_name, f->field_name), - item_equal(0), no_const_subst(0), + item_equal(0), no_const_subst(0), have_privileges(0), any_privileges(0) { set_field(f); /* - field_name and talbe_name should not point to garbage + field_name and table_name should not point to garbage if this item is to be reused */ orig_table_name= orig_field_name= ""; } + Item_field::Item_field(THD *thd, Name_resolution_context *context_arg, Field *f) - :Item_ident(context_arg, f->table->s->db, *f->table_name, f->field_name), + :Item_ident(context_arg, f->table->s->db.str, *f->table_name, f->field_name), item_equal(0), no_const_subst(0), have_privileges(0), any_privileges(0) { @@ -1770,7 +1816,7 @@ void Item_field::set_field(Field *field_par) max_length= field_par->max_display_length(); table_name= *field_par->table_name; field_name= field_par->field_name; - db_name= field_par->table->s->db; + db_name= field_par->table->s->db.str; alias_name_used= field_par->table->alias_name_used; unsigned_flag=test(field_par->flags & UNSIGNED_FLAG); collation.set(field_par->charset(), field_par->derivation()); @@ -2043,6 +2089,11 @@ Item *Item_field::get_tmp_table_item(THD *thd) return new_item; } +longlong Item_field::val_int_endpoint(bool left_endp, bool *incl_endp) +{ + longlong res= val_int(); + return null_value? LONGLONG_MIN : res; +} /* Create an item from a string we KNOW points to a valid longlong @@ -2166,7 +2217,7 @@ Item_decimal::Item_decimal(my_decimal *value_par) } -Item_decimal::Item_decimal(const char *bin, int precision, int scale) +Item_decimal::Item_decimal(const uchar *bin, int precision, int scale) { binary2my_decimal(E_DEC_FATAL_ERROR, bin, &decimal_value, precision, scale); @@ -2237,7 +2288,7 @@ String *Item_float::val_str(String *str) { // following assert is redundant, because fixed=1 assigned in constructor DBUG_ASSERT(fixed == 1); - str->set(value,decimals,&my_charset_bin); + str->set_real(value,decimals,&my_charset_bin); return str; } @@ -2374,7 +2425,7 @@ default_set_param_func(Item_param *param, } -Item_param::Item_param(unsigned pos_in_query_arg) : +Item_param::Item_param(uint pos_in_query_arg) : strict_type(FALSE), state(NO_VALUE), item_result_type(STRING_RESULT), @@ -2587,7 +2638,8 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry) CHARSET_INFO *tocs= thd->variables.collation_connection; uint32 dummy_offset; - value.cs_info.character_set_of_placeholder= fromcs; + value.cs_info.character_set_of_placeholder= + value.cs_info.character_set_client= fromcs; /* Setup source and destination character sets so that they are different only if conversion is necessary: this will @@ -2828,7 +2880,7 @@ String *Item_param::val_str(String* str) case LONG_DATA_VALUE: return &str_value_ptr; case REAL_VALUE: - str->set(value.real, NOT_FIXED_DEC, &my_charset_bin); + str->set_real(value.real, NOT_FIXED_DEC, &my_charset_bin); return str; case INT_VALUE: str->set(value.integer, &my_charset_bin); @@ -2868,7 +2920,7 @@ const String *Item_param::query_val_str(String* str) const str->set(value.integer, &my_charset_bin); break; case REAL_VALUE: - str->set(value.real, NOT_FIXED_DEC, &my_charset_bin); + str->set_real(value.real, NOT_FIXED_DEC, &my_charset_bin); break; case DECIMAL_VALUE: if (my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, @@ -3356,7 +3408,7 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list) resolve_ref_in_select_and_group() thd current thread ref column reference being resolved - select the sub-select that ref is resolved against + select the select that ref is resolved against DESCRIPTION Resolve a column reference (usually inside a HAVING clause) against the @@ -3427,6 +3479,7 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) } if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && + select->having_fix_field && select_ref != not_found_item && !group_by_ref) { /* @@ -3821,7 +3874,9 @@ bool Item_field::fix_fields(THD *thd, Item **reference) context->first_name_resolution_table, context->last_name_resolution_table, reference, - IGNORE_EXCEPT_NON_UNIQUE, + thd->lex->use_only_table_context ? + REPORT_ALL_ERRORS : + IGNORE_EXCEPT_NON_UNIQUE, !any_privileges, TRUE)) == not_found_field) @@ -3844,15 +3899,15 @@ bool Item_field::fix_fields(THD *thd, Item **reference) if ((*res)->type() == Item::FIELD_ITEM) { /* - It's an Item_field referencing another Item_field in the select - list. - use the field from the Item_field in the select list and leave - the Item_field instance in place. + It's an Item_field referencing another Item_field in the select + list. + Use the field from the Item_field in the select list and leave + the Item_field instance in place. */ - Field *field= (*((Item_field**)res))->field; + Field *new_field= (*((Item_field**)res))->field; - if (field == NULL) + if (new_field == NULL) { /* The column to which we link isn't valid. */ my_error(ER_BAD_FIELD_ERROR, MYF(0), (*res)->name, @@ -3860,7 +3915,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) return(1); } - set_field(field); + set_field(new_field); return 0; } else @@ -3892,11 +3947,23 @@ bool Item_field::fix_fields(THD *thd, Item **reference) else if (!from_field) goto error; + if (!outer_fixed && cached_table && cached_table->select_lex && + context->select_lex && + cached_table->select_lex != context->select_lex) + { + int ret; + if ((ret= fix_outer_field(thd, &from_field, reference)) < 0) + goto error; + if (!ret) + return FALSE; + outer_fixed= 1; + } + /* if it is not expression from merged VIEW we will set this field. We can leave expression substituted from view for next PS/SP rexecution - (i.e. do not register this substitution for reverting on cleupup() + (i.e. do not register this substitution for reverting on cleanup() (register_item_tree_changing())), because this subtree will be fix_field'ed during setup_tables()->setup_underlying() (i.e. before all other expressions of query, and references on tables which do @@ -3907,18 +3974,6 @@ bool Item_field::fix_fields(THD *thd, Item **reference) if (from_field == view_ref_found) return FALSE; - if (!outer_fixed && cached_table && cached_table->select_lex && - context->select_lex && - cached_table->select_lex != context->select_lex) - { - int ret; - if ((ret= fix_outer_field(thd, &from_field, reference)) < 0) - goto error; - else if (!ret) - return FALSE; - outer_fixed= 1; - } - set_field(from_field); if (thd->lex->in_sum_func && thd->lex->in_sum_func->nest_level == @@ -3926,13 +3981,31 @@ bool Item_field::fix_fields(THD *thd, Item **reference) set_if_bigger(thd->lex->in_sum_func->max_arg_level, thd->lex->current_select->nest_level); } - else if (thd->set_query_id && field->query_id != thd->query_id) + else if (thd->mark_used_columns != MARK_COLUMNS_NONE) { - /* We only come here in unions */ - TABLE *table=field->table; - field->query_id=thd->query_id; - table->used_fields++; - table->used_keys.intersect(field->part_of_key); + TABLE *table= field->table; + MY_BITMAP *current_bitmap, *other_bitmap; + if (thd->mark_used_columns == MARK_COLUMNS_READ) + { + current_bitmap= table->read_set; + other_bitmap= table->write_set; + } + else + { + current_bitmap= table->write_set; + other_bitmap= table->read_set; + } + if (!bitmap_fast_test_and_set(current_bitmap, field->field_index)) + { + if (!bitmap_is_set(other_bitmap, field->field_index)) + { + /* First usage of column */ + table->used_fields++; // Used to optimize loops + /* purecov: begin inspected */ + table->covering_keys.intersect(field->part_of_key); + /* purecov: end */ + } + } } #ifndef NO_EMBEDDED_ACCESS_CHECKS if (any_privileges) @@ -4066,7 +4139,7 @@ Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal) FALSE otherwise */ -bool Item_field::subst_argument_checker(byte **arg) +bool Item_field::subst_argument_checker(uchar **arg) { return (result_type() != STRING_RESULT) || (*arg); } @@ -4122,7 +4195,7 @@ static void convert_zerofill_number_to_string(Item **item, Field_num *field) pointer to the field item, otherwise. */ -Item *Item_field::equal_fields_propagator(byte *arg) +Item *Item_field::equal_fields_propagator(uchar *arg) { if (no_const_subst) return this; @@ -4160,7 +4233,7 @@ Item *Item_field::equal_fields_propagator(byte *arg) See comments in Arg_comparator::set_compare_func() for details */ -bool Item_field::set_no_const_sub(byte *arg) +bool Item_field::set_no_const_sub(uchar *arg) { if (field->charset() != &my_charset_bin) no_const_subst=1; @@ -4195,7 +4268,7 @@ bool Item_field::set_no_const_sub(byte *arg) this - otherwise. */ -Item *Item_field::replace_equal_field(byte *arg) +Item *Item_field::replace_equal_field(uchar *arg) { if (item_equal) { @@ -4241,24 +4314,30 @@ void Item::make_field(Send_field *tmp_field) } -void Item_empty_string::make_field(Send_field *tmp_field) +enum_field_types Item::string_field_type() const { - enum_field_types f_type= FIELD_TYPE_VAR_STRING; + enum_field_types f_type= MYSQL_TYPE_VAR_STRING; if (max_length >= 16777216) - f_type= FIELD_TYPE_LONG_BLOB; + f_type= MYSQL_TYPE_LONG_BLOB; else if (max_length >= 65536) - f_type= FIELD_TYPE_MEDIUM_BLOB; - init_make_field(tmp_field, f_type); + f_type= MYSQL_TYPE_MEDIUM_BLOB; + return f_type; +} + + +void Item_empty_string::make_field(Send_field *tmp_field) +{ + init_make_field(tmp_field, string_field_type()); } enum_field_types Item::field_type() const { switch (result_type()) { - case STRING_RESULT: return MYSQL_TYPE_VARCHAR; - case INT_RESULT: return FIELD_TYPE_LONGLONG; - case DECIMAL_RESULT: return FIELD_TYPE_NEWDECIMAL; - case REAL_RESULT: return FIELD_TYPE_DOUBLE; + case STRING_RESULT: return string_field_type(); + case INT_RESULT: return MYSQL_TYPE_LONGLONG; + case DECIMAL_RESULT: return MYSQL_TYPE_NEWDECIMAL; + case REAL_RESULT: return MYSQL_TYPE_DOUBLE; case ROW_RESULT: default: DBUG_ASSERT(0); @@ -4322,6 +4401,49 @@ String *Item::check_well_formed_result(String *str, bool send_error) return str; } +/* + Compare two items using a given collation + + SYNOPSIS + eq_by_collation() + item item to compare with + binary_cmp TRUE <-> compare as binaries + cs collation to use when comparing strings + + DESCRIPTION + This method works exactly as Item::eq if the collation cs coincides with + the collation of the compared objects. Otherwise, first the collations that + differ from cs are replaced for cs and then the items are compared by + Item::eq. After the comparison the original collations of items are + restored. + + RETURN + 1 compared items has been detected as equal + 0 otherwise +*/ + +bool Item::eq_by_collation(Item *item, bool binary_cmp, CHARSET_INFO *cs) +{ + CHARSET_INFO *save_cs= 0; + CHARSET_INFO *save_item_cs= 0; + if (collation.collation != cs) + { + save_cs= collation.collation; + collation.collation= cs; + } + if (item->collation.collation != cs) + { + save_item_cs= item->collation.collation; + item->collation.collation= cs; + } + bool res= eq(item, binary_cmp); + if (save_cs) + collation.collation= save_cs; + if (save_item_cs) + item->collation.collation= save_item_cs; + return res; +} + /* Create a field to hold a string value from an item @@ -4339,17 +4461,22 @@ String *Item::check_well_formed_result(String *str, bool send_error) Field *Item::make_string_field(TABLE *table) { + Field *field; DBUG_ASSERT(collation.collation); if (max_length/collation.collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB) - return new Field_blob(max_length, maybe_null, name, table, + field= new Field_blob(max_length, maybe_null, name, collation.collation); /* Item_type_holder holds the exact type, do not change it */ - if (max_length > 0 && + else if (max_length > 0 && (type() != Item::TYPE_HOLDER || field_type() != MYSQL_TYPE_STRING)) - return new Field_varstring(max_length, maybe_null, name, table, + field= new Field_varstring(max_length, maybe_null, name, table->s, collation.collation); - return new Field_string(max_length, maybe_null, name, table, - collation.collation); + else + field= new Field_string(max_length, maybe_null, name, + collation.collation); + if (field) + field->init(table); + return field; } @@ -4357,74 +4484,97 @@ Field *Item::make_string_field(TABLE *table) Create a field based on field_type of argument For now, this is only used to create a field for - IFNULL(x,something) + IFNULL(x,something) and time functions RETURN 0 error # Created field */ -Field *Item::tmp_table_field_from_field_type(TABLE *table) +Field *Item::tmp_table_field_from_field_type(TABLE *table, bool fixed_length) { /* 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 (field_type()) { case MYSQL_TYPE_DECIMAL: case MYSQL_TYPE_NEWDECIMAL: - return new Field_new_decimal((char*) 0, max_length, null_ptr, 0, - Field::NONE, name, table, decimals, 0, + field= new Field_new_decimal((uchar*) 0, max_length, null_ptr, 0, + Field::NONE, name, decimals, 0, unsigned_flag); + break; case MYSQL_TYPE_TINY: - return new Field_tiny((char*) 0, max_length, null_ptr, 0, Field::NONE, - name, table, 0, unsigned_flag); + field= new Field_tiny((uchar*) 0, max_length, null_ptr, 0, Field::NONE, + name, 0, unsigned_flag); + break; case MYSQL_TYPE_SHORT: - return new Field_short((char*) 0, max_length, null_ptr, 0, Field::NONE, - name, table, 0, unsigned_flag); + field= new Field_short((uchar*) 0, max_length, null_ptr, 0, Field::NONE, + name, 0, unsigned_flag); + break; case MYSQL_TYPE_LONG: - return new Field_long((char*) 0, max_length, null_ptr, 0, Field::NONE, - name, table, 0, unsigned_flag); + field= new Field_long((uchar*) 0, max_length, null_ptr, 0, Field::NONE, + name, 0, unsigned_flag); + break; #ifdef HAVE_LONG_LONG case MYSQL_TYPE_LONGLONG: - return new Field_longlong((char*) 0, max_length, null_ptr, 0, Field::NONE, - name, table, 0, unsigned_flag); + field= new Field_longlong((uchar*) 0, max_length, null_ptr, 0, Field::NONE, + name, 0, unsigned_flag); + break; #endif case MYSQL_TYPE_FLOAT: - return new Field_float((char*) 0, max_length, null_ptr, 0, Field::NONE, - name, table, decimals, 0, unsigned_flag); + field= new Field_float((uchar*) 0, max_length, null_ptr, 0, Field::NONE, + name, decimals, 0, unsigned_flag); + break; case MYSQL_TYPE_DOUBLE: - return new Field_double((char*) 0, max_length, null_ptr, 0, Field::NONE, - name, table, decimals, 0, unsigned_flag); + field= new Field_double((uchar*) 0, max_length, null_ptr, 0, Field::NONE, + name, decimals, 0, unsigned_flag); + break; case MYSQL_TYPE_NULL: - return new Field_null((char*) 0, max_length, Field::NONE, - name, table, &my_charset_bin); + field= new Field_null((uchar*) 0, max_length, Field::NONE, + name, &my_charset_bin); + break; case MYSQL_TYPE_INT24: - return new Field_medium((char*) 0, max_length, null_ptr, 0, Field::NONE, - name, table, 0, unsigned_flag); + field= new Field_medium((uchar*) 0, max_length, null_ptr, 0, Field::NONE, + name, 0, unsigned_flag); + break; case MYSQL_TYPE_NEWDATE: case MYSQL_TYPE_DATE: - return new Field_date(maybe_null, name, table, &my_charset_bin); + field= new Field_newdate(maybe_null, name, &my_charset_bin); + break; case MYSQL_TYPE_TIME: - return new Field_time(maybe_null, name, table, &my_charset_bin); + field= new Field_time(maybe_null, name, &my_charset_bin); + break; case MYSQL_TYPE_TIMESTAMP: - return new Field_timestamp(maybe_null, name, table, &my_charset_bin); + field= new Field_timestamp(maybe_null, name, &my_charset_bin); + break; case MYSQL_TYPE_DATETIME: - return new Field_datetime(maybe_null, name, table, &my_charset_bin); + field= new Field_datetime(maybe_null, name, &my_charset_bin); + break; case MYSQL_TYPE_YEAR: - return new Field_year((char*) 0, max_length, null_ptr, 0, Field::NONE, - name, table); + field= new Field_year((uchar*) 0, max_length, null_ptr, 0, Field::NONE, + name); + break; case MYSQL_TYPE_BIT: - return new Field_bit_as_char(NULL, max_length, null_ptr, 0, - Field::NONE, name, table); + field= new 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_STRING: + if (fixed_length && max_length < CONVERT_IF_BIGGER_TO_BLOB) + { + field= new 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_STRING: case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_VARCHAR: return make_string_field(table); @@ -4433,18 +4583,20 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table) case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: if (this->type() == Item::TYPE_HOLDER) - return new Field_blob(max_length, maybe_null, name, table, - collation.collation, 1); + field= new Field_blob(max_length, maybe_null, name, collation.collation, + 1); else - return new Field_blob(max_length, maybe_null, name, table, - collation.collation); + field= new Field_blob(max_length, maybe_null, name, collation.collation); break; // Blob handled outside of case #ifdef HAVE_SPATIAL case MYSQL_TYPE_GEOMETRY: - return new Field_geom(max_length, maybe_null, - name, table, get_geometry_type()); + field= new Field_geom(max_length, maybe_null, + name, table->s, get_geometry_type()); #endif /* HAVE_SPATIAL */ } + if (field) + field->init(table); + return field; } @@ -4735,7 +4887,7 @@ void Item_float::print(String *str) } char buffer[20]; String num(buffer, sizeof(buffer), &my_charset_bin); - num.set(value, decimals, &my_charset_bin); + num.set_real(value, decimals, &my_charset_bin); str->append(num); } @@ -5083,7 +5235,7 @@ void Item_field::update_null_value() this field otherwise */ -Item *Item_field::update_value_transformer(byte *select_arg) +Item *Item_field::update_value_transformer(uchar *select_arg) { SELECT_LEX *select= (SELECT_LEX*)select_arg; DBUG_ASSERT(fixed); @@ -5842,8 +5994,9 @@ bool Item_default_value::fix_fields(THD *thd, Item **items) if (!(def_field= (Field*) sql_alloc(field_arg->field->size_of()))) goto error; memcpy(def_field, field_arg->field, field_arg->field->size_of()); - def_field->move_field(def_field->table->s->default_values - - def_field->table->record[0]); + def_field->move_field_offset((my_ptrdiff_t) + (def_field->table->s->default_values - + def_field->table->record[0])); set_field(def_field); return FALSE; @@ -5911,7 +6064,7 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions) same time it can replace some nodes in the tree */ -Item *Item_default_value::transform(Item_transformer transformer, byte *args) +Item *Item_default_value::transform(Item_transformer transformer, uchar *args) { DBUG_ASSERT(!current_thd->is_stmt_prepare()); @@ -5977,16 +6130,22 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items) if (!def_field) return TRUE; memcpy(def_field, field_arg->field, field_arg->field->size_of()); - def_field->move_field(def_field->table->insert_values - - def_field->table->record[0]); + def_field->move_field_offset((my_ptrdiff_t) + (def_field->table->insert_values - + def_field->table->record[0])); set_field(def_field); } else { Field *tmp_field= field_arg->field; /* charset doesn't matter here, it's to avoid sigsegv only */ - set_field(new Field_null(0, 0, Field::NONE, tmp_field->field_name, - tmp_field->table, &my_charset_bin)); + tmp_field= new Field_null(0, 0, Field::NONE, field_arg->field->field_name, + &my_charset_bin); + if (tmp_field) + { + tmp_field->init(field_arg->field->table); + set_field(tmp_field); + } } return FALSE; } @@ -6025,21 +6184,21 @@ void Item_trigger_field::setup_field(THD *thd, TABLE *table, GRANT_INFO *table_grant_info) { /* - There is no sense in marking fields used by trigger with current value - of THD::query_id since it is completely unrelated to the THD::query_id - value for statements which will invoke trigger. So instead we use - Table_triggers_list::mark_fields_used() method which is called during - execution of these statements. + It is too early to mark fields used here, because before execution + of statement that will invoke trigger other statements may use same + TABLE object, so all such mark-up will be wiped out. + So instead we do it in Table_triggers_list::mark_fields_used() + method which is called during execution of these statements. */ - bool save_set_query_id= thd->set_query_id; - thd->set_query_id= 0; + enum_mark_columns save_mark_used_columns= thd->mark_used_columns; + thd->mark_used_columns= MARK_COLUMNS_NONE; /* 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), 0, &field_idx); - thd->set_query_id= save_set_query_id; + thd->mark_used_columns= save_mark_used_columns; triggers= table->triggers; table_grants= table_grant_info; } @@ -6097,9 +6256,8 @@ 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, - triggers->trigger_table->s->table_name, - field_name, + 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)) return TRUE; } @@ -6137,11 +6295,6 @@ void Item_trigger_field::cleanup() } -/* - If item is a const function, calculate it and return a const item - The original item is freed if not returned -*/ - Item_result item_cmp_type(Item_result a,Item_result b) { if (a == STRING_RESULT && b == STRING_RESULT) @@ -6371,7 +6524,7 @@ longlong Item_cache_real::val_int() String* Item_cache_real::val_str(String *str) { DBUG_ASSERT(fixed == 1); - str->set(value, decimals, default_charset()); + str->set_real(value, decimals, default_charset()); return str; } @@ -6629,6 +6782,8 @@ enum_field_types Item_type_holder::get_real_type(Item *item) */ 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; @@ -6866,24 +7021,33 @@ 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; - switch (fld_type) - { + Field *field; + + switch (fld_type) { case MYSQL_TYPE_ENUM: DBUG_ASSERT(enum_set_typelib); - return new Field_enum((char *) 0, max_length, null_ptr, 0, + field= new Field_enum((uchar *) 0, max_length, null_ptr, 0, Field::NONE, name, - table, get_enum_pack_length(enum_set_typelib->count), + 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); - return new Field_set((char *) 0, max_length, null_ptr, 0, + field= new Field_set((uchar *) 0, max_length, null_ptr, 0, Field::NONE, name, - table, get_set_pack_length(enum_set_typelib->count), + 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); + return tmp_table_field_from_field_type(table, 0); } |