diff options
Diffstat (limited to 'sql/item.cc')
-rw-r--r-- | sql/item.cc | 277 |
1 files changed, 186 insertions, 91 deletions
diff --git a/sql/item.cc b/sql/item.cc index 27cb6d49fd4..6e661afbd91 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -61,7 +61,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; } @@ -202,7 +202,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; } @@ -212,10 +212,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; } @@ -551,6 +548,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(byte *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) @@ -671,6 +685,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(), @@ -685,7 +700,9 @@ Item *Item_string::safe_charset_converter(CHARSET_INFO *tocs) */ return NULL; } - conv->str_value.copy(); + if (!(ptr= current_thd->memdup(cstr.ptr(), cstr.length() + 1 ))) + 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; @@ -793,14 +810,25 @@ 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); 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); return res; } @@ -1399,7 +1427,11 @@ bool agg_item_collations_for_comparison(DTCollation &c, const char *fname, bool agg_item_charsets(DTCollation &coll, const char *fname, Item **args, uint nargs, uint flags, int item_sep) { - Item **arg, *safe_args[2]; + Item **arg, **last, *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; @@ -1493,20 +1525,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) { @@ -1573,7 +1606,7 @@ void Item_field::set_field(Field *field_par) max_length= field_par->max_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(), DERIVATION_IMPLICIT); @@ -2036,7 +2069,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; } @@ -2389,7 +2422,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 @@ -2630,7 +2664,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); @@ -2670,7 +2704,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, @@ -3592,7 +3626,8 @@ bool Item_field::fix_fields(THD *thd, Item **reference) Item** res= find_item_in_list(this, thd->lex->current_select->item_list, &counter, REPORT_EXCEPT_NOT_FOUND, ¬_used); - if (res != (Item **)not_found_item && (*res)->type() == Item::FIELD_ITEM) + if (res != (Item **)not_found_item && + (*res)->type() == Item::FIELD_ITEM) { set_field((*((Item_field**)res))->field); return 0; @@ -3611,7 +3646,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) 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 @@ -3623,13 +3658,13 @@ bool Item_field::fix_fields(THD *thd, Item **reference) return FALSE; if (!outer_fixed && cached_table && cached_table->select_lex && - context->select_lex && - cached_table->select_lex != context->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) + if (!ret) return FALSE; } @@ -3640,13 +3675,29 @@ 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 + table->used_keys.intersect(field->part_of_key); + } + } } #ifndef NO_EMBEDDED_ACCESS_CHECKS if (any_privileges) @@ -3900,17 +3951,22 @@ enum_field_types Item::field_type() const 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; } @@ -3918,74 +3974,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((char*) 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((char*) 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((char*) 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((char*) 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((char*) 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((char*) 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((char*) 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((char*) 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((char*) 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_date(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((char*) 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); @@ -3995,13 +4074,15 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table) case MYSQL_TYPE_BLOB: case MYSQL_TYPE_GEOMETRY: 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 } + if (field) + field->init(table); + return field; } @@ -4284,7 +4365,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); } @@ -5237,8 +5318,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; @@ -5340,16 +5422,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; } @@ -5388,21 +5476,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; } @@ -5460,8 +5548,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->table->s->db, - triggers->table->s->table_name, field_name, + if (check_grant_column(thd, table_grants, triggers->table->s->db.str, + triggers->table->s->table_name.str, field_name, strlen(field_name), thd->security_ctx)) return TRUE; } @@ -5724,7 +5812,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; } @@ -6197,24 +6285,31 @@ 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((char *) 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((char *) 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; default: break; } - return tmp_table_field_from_field_type(table); + return tmp_table_field_from_field_type(table, 0); } |