diff options
Diffstat (limited to 'sql')
57 files changed, 889 insertions, 412 deletions
diff --git a/sql/debug_sync.cc b/sql/debug_sync.cc index 2580d526b52..23a649a89fa 100644 --- a/sql/debug_sync.cc +++ b/sql/debug_sync.cc @@ -1903,4 +1903,42 @@ void debug_sync(THD *thd, const char *sync_point_name, size_t name_len) DBUG_VOID_RETURN; } +/** + Define debug sync action. + + @param[in] thd thread handle + @param[in] action_str action string + + @return status + @retval FALSE ok + @retval TRUE error + + @description + The function is similar to @c debug_sync_eval_action but is + to be called immediately from the server code rather than + to be triggered by setting a value to DEBUG_SYNC system variable. + + @note + The input string is copied prior to be fed to + @c debug_sync_eval_action to let the latter modify it. + + Caution. + The function allocates in THD::mem_root and therefore + is not recommended to be deployed inside big loops. +*/ + +bool debug_sync_set_action(THD *thd, const char *action_str, size_t len) +{ + bool rc; + char *value; + DBUG_ENTER("debug_sync_set_action"); + DBUG_ASSERT(thd); + DBUG_ASSERT(action_str); + + value= strmake_root(thd->mem_root, action_str, len); + rc= debug_sync_eval_action(thd, value); + DBUG_RETURN(rc); +} + + #endif /* defined(ENABLED_DEBUG_SYNC) */ diff --git a/sql/debug_sync.h b/sql/debug_sync.h index f4cd0b364cf..9ac7da39d4d 100644 --- a/sql/debug_sync.h +++ b/sql/debug_sync.h @@ -50,6 +50,7 @@ extern void debug_sync_end(void); extern void debug_sync_init_thread(THD *thd); extern void debug_sync_end_thread(THD *thd); extern void debug_sync(THD *thd, const char *sync_point_name, size_t name_len); +extern bool debug_sync_set_action(THD *thd, const char *action_str, size_t len); #else /* defined(ENABLED_DEBUG_SYNC) */ diff --git a/sql/events.cc b/sql/events.cc index 4c6dd0f35d1..afae512c61d 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -362,7 +362,9 @@ create_query_string(THD *thd, String *buf) /* Append definer */ append_definer(thd, buf, &(thd->lex->definer->user), &(thd->lex->definer->host)); /* Append the left part of thd->query after "DEFINER" part */ - if (buf->append(thd->lex->stmt_definition_begin)) + if (buf->append(thd->lex->stmt_definition_begin, + thd->lex->stmt_definition_end - + thd->lex->stmt_definition_begin)) return 1; return 0; diff --git a/sql/field.cc b/sql/field.cc index 15ee9c4a86c..b6323d7b839 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1373,12 +1373,14 @@ bool Field::send_binary(Protocol *protocol) to the size of this field (the slave or destination). @param field_metadata Encoded size in field metadata + @param mflags Flags from the table map event for the table. @retval 0 if this field's size is < the source field's size @retval 1 if this field's size is >= the source field's size */ int Field::compatible_field_size(uint field_metadata, - const Relay_log_info *rli_arg __attribute__((unused))) + const Relay_log_info *rli_arg __attribute__((unused)), + uint16 mflags __attribute__((unused))) { uint const source_size= pack_length_from_metadata(field_metadata); uint const destination_size= row_pack_length(); @@ -2879,7 +2881,8 @@ uint Field_new_decimal::pack_length_from_metadata(uint field_metadata) @retval 1 if this field's size is >= the source field's size */ int Field_new_decimal::compatible_field_size(uint field_metadata, - const Relay_log_info * __attribute__((unused))) + const Relay_log_info * __attribute__((unused)), + uint16 mflags __attribute__((unused))) { int compatible= 0; uint const source_precision= (field_metadata >> 8U) & 0x00ff; @@ -2944,16 +2947,16 @@ Field_new_decimal::unpack(uchar* to, a decimal and write that to the raw data buffer. */ decimal_digit_t dec_buf[DECIMAL_MAX_PRECISION]; - decimal_t dec; - dec.len= from_precision; - dec.buf= dec_buf; + decimal_t dec_val; + dec_val.len= from_precision; + dec_val.buf= dec_buf; /* Note: bin2decimal does not change the length of the field. So it is just the first step the resizing operation. The second step does the resizing using the precision and decimals from the slave. */ - bin2decimal((uchar *)from, &dec, from_precision, from_decimal); - decimal2bin(&dec, to, precision, decimals()); + bin2decimal((uchar *)from, &dec_val, from_precision, from_decimal); + decimal2bin(&dec_val, to, precision, decimals()); } else memcpy(to, from, len); // Sizes are the same, just copy the data. @@ -6334,7 +6337,7 @@ check_string_copy_error(Field_str *field, SYNOPSIS Field_longstr::report_if_important_data() - ptr - Truncated rest of string + pstr - Truncated rest of string end - End of truncated string count_spaces - Treat traling spaces as important data @@ -6350,12 +6353,12 @@ check_string_copy_error(Field_str *field, */ int -Field_longstr::report_if_important_data(const char *ptr, const char *end, +Field_longstr::report_if_important_data(const char *pstr, const char *end, bool count_spaces) { - if ((ptr < end) && table->in_use->count_cuted_fields) + if ((pstr < end) && table->in_use->count_cuted_fields) { - if (test_if_important_data(field_charset, ptr, end)) + if (test_if_important_data(field_charset, pstr, end)) { if (table->in_use->abort_on_warning) set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1); @@ -6655,7 +6658,8 @@ check_field_for_37426(const void *param_arg) #endif int Field_string::compatible_field_size(uint field_metadata, - const Relay_log_info *rli_arg) + const Relay_log_info *rli_arg, + uint16 mflags __attribute__((unused))) { #ifdef HAVE_REPLICATION const Check_field_param check_param = { this }; @@ -6663,7 +6667,7 @@ int Field_string::compatible_field_size(uint field_metadata, check_field_for_37426, &check_param)) return FALSE; // Not compatible field sizes #endif - return Field::compatible_field_size(field_metadata, rli_arg); + return Field::compatible_field_size(field_metadata, rli_arg, mflags); } @@ -7008,9 +7012,8 @@ const uint Field_varstring::MAX_SIZE= UINT_MAX16; */ int Field_varstring::do_save_field_metadata(uchar *metadata_ptr) { - char *ptr= (char *)metadata_ptr; DBUG_ASSERT(field_length <= 65535); - int2store(ptr, field_length); + int2store((char*)metadata_ptr, field_length); return 2; } @@ -9214,8 +9217,13 @@ uint Field_bit::get_key_image(uchar *buff, uint length, imagetype type_arg) */ int Field_bit::do_save_field_metadata(uchar *metadata_ptr) { - *metadata_ptr= bit_len; - *(metadata_ptr + 1)= bytes_in_rec; + /* + Since this class and Field_bit_as_char have different ideas of + what should be stored here, we compute the values of the metadata + explicitly using the field_length. + */ + metadata_ptr[0]= field_length % 8; + metadata_ptr[1]= field_length / 8; return 2; } @@ -9255,20 +9263,26 @@ uint Field_bit::pack_length_from_metadata(uint field_metadata) @retval 1 if this field's size is >= the source field's size */ int Field_bit::compatible_field_size(uint field_metadata, - const Relay_log_info * __attribute__((unused))) + const Relay_log_info * __attribute__((unused)), + uint16 mflags) { - int compatible= 0; - uint const source_size= pack_length_from_metadata(field_metadata); - uint const destination_size= row_pack_length(); - uint const from_bit_len= field_metadata & 0x00ff; - uint const from_len= (field_metadata >> 8U) & 0x00ff; - if ((bit_len == 0) || (from_bit_len == 0)) - compatible= (source_size <= destination_size); - else if (from_bit_len > bit_len) - compatible= (from_len < bytes_in_rec); - else - compatible= ((from_bit_len <= bit_len) && (from_len <= bytes_in_rec)); - return (compatible); + uint from_bit_len= 8 * (field_metadata >> 8) + (field_metadata & 0xff); + uint to_bit_len= max_display_length(); + + /* + If the bit length exact flag is clear, we are dealing with an old + master, so we allow some less strict behaviour if replicating by + moving both bit lengths to an even multiple of 8. + + We do this by computing the number of bytes to store the field + instead, and then compare the result. + */ + if (!(mflags & Table_map_log_event::TM_BIT_LEN_EXACT_F)) { + from_bit_len= (from_bit_len + 7) / 8; + to_bit_len= (to_bit_len + 7) / 8; + } + + return from_bit_len <= to_bit_len; } diff --git a/sql/field.h b/sql/field.h index 55604193687..cbdfa686ff8 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008, 2009 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -11,7 +11,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* Because of the function new_field() all field classes that have static @@ -55,7 +55,11 @@ public: static void operator delete(void *ptr_arg, size_t size) { TRASH(ptr_arg, size); } uchar *ptr; // Position to field in record - uchar *null_ptr; // Byte where null_bit is + /** + Byte where the @c NULL bit is stored inside a record. If this Field is a + @c NOT @c NULL field, this member is @c NULL. + */ + uchar *null_ptr; /* Note that you can use table->in_use as replacement for current_thd member only inside of val_*() and store() members (e.g. you can't use it in cons) @@ -165,7 +169,7 @@ public: */ virtual uint32 pack_length_in_rec() const { return pack_length(); } virtual int compatible_field_size(uint field_metadata, - const Relay_log_info *); + const Relay_log_info *, uint16 mflags); virtual uint pack_length_from_metadata(uint field_metadata) { return field_metadata; } /* @@ -261,6 +265,9 @@ public: inline void set_notnull(my_ptrdiff_t row_offset= 0) { if (null_ptr) null_ptr[row_offset]&= (uchar) ~null_bit; } inline bool maybe_null(void) { return null_ptr != 0 || table->maybe_null; } + /** + Signals that this field is NULL-able. + */ inline bool real_maybe_null(void) { return null_ptr != 0; } enum { @@ -803,7 +810,7 @@ public: uint pack_length_from_metadata(uint field_metadata); uint row_pack_length() { return pack_length(); } int compatible_field_size(uint field_metadata, - const Relay_log_info *rli); + const Relay_log_info *rli, uint16 mflags); uint is_equal(Create_field *new_field); virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data, bool low_byte_first); @@ -1499,7 +1506,7 @@ public: return (((field_metadata >> 4) & 0x300) ^ 0x300) + (field_metadata & 0x00ff); } int compatible_field_size(uint field_metadata, - const Relay_log_info *rli); + const Relay_log_info *rli, uint16 mflags); uint row_pack_length() { return (field_length + 1); } int pack_cmp(const uchar *a,const uchar *b,uint key_length, my_bool insert_or_update); @@ -1968,7 +1975,7 @@ public: uint row_pack_length() { return (bytes_in_rec + ((bit_len > 0) ? 1 : 0)); } int compatible_field_size(uint field_metadata, - const Relay_log_info *rli); + const Relay_log_info *rli, uint16 mflags); void sql_type(String &str) const; virtual uchar *pack(uchar *to, const uchar *from, uint max_length, bool low_byte_first); diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 3574534722e..0bffde9671a 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -122,13 +122,18 @@ set_field_to_null(Field *field) return 0; } field->reset(); - if (field->table->in_use->count_cuted_fields == CHECK_FIELD_WARN) - { + switch (field->table->in_use->count_cuted_fields) { + case CHECK_FIELD_WARN: field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); + /* fall through */ + case CHECK_FIELD_IGNORE: return 0; + case CHECK_FIELD_ERROR_FOR_NULL: + if (!field->table->in_use->no_errors) + my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name); + return -1; } - if (!field->table->in_use->no_errors) - my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name); + DBUG_ASSERT(0); // impossible return -1; } @@ -178,13 +183,18 @@ set_field_to_null_with_conversions(Field *field, bool no_conversions) field->table->auto_increment_field_not_null= FALSE; return 0; // field is set in fill_record() } - if (field->table->in_use->count_cuted_fields == CHECK_FIELD_WARN) - { + switch (field->table->in_use->count_cuted_fields) { + case CHECK_FIELD_WARN: field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_BAD_NULL_ERROR, 1); + /* fall through */ + case CHECK_FIELD_IGNORE: return 0; + case CHECK_FIELD_ERROR_FOR_NULL: + if (!field->table->in_use->no_errors) + my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name); + return -1; } - if (!field->table->in_use->no_errors) - my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name); + DBUG_ASSERT(0); // impossible return -1; } diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 1d4290c6ab0..4523d620821 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -5090,6 +5090,7 @@ int ha_partition::info(uint flag) file= m_file[handler_instance]; file->info(HA_STATUS_CONST); + stats.block_size= file->stats.block_size; stats.create_time= file->stats.create_time; ref_length= m_ref_length; } @@ -6454,9 +6455,22 @@ void ha_partition::release_auto_increment() ulonglong next_auto_inc_val; lock_auto_increment(); next_auto_inc_val= ha_data->next_auto_inc_val; + /* + If the current auto_increment values is lower than the reserved + value, and the reserved value was reserved by this thread, + we can lower the reserved value. + */ if (next_insert_id < next_auto_inc_val && auto_inc_interval_for_cur_row.maximum() >= next_auto_inc_val) - ha_data->next_auto_inc_val= next_insert_id; + { + THD *thd= ha_thd(); + /* + Check that we do not lower the value because of a failed insert + with SET INSERT_ID, i.e. forced/non generated values. + */ + if (thd->auto_inc_intervals_forced.maximum() < next_insert_id) + ha_data->next_auto_inc_val= next_insert_id; + } DBUG_PRINT("info", ("ha_data->next_auto_inc_val: %lu", (ulong) ha_data->next_auto_inc_val)); diff --git a/sql/handler.cc b/sql/handler.cc index 216228ed509..19f397ef09f 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -159,7 +159,7 @@ redo: } -plugin_ref ha_lock_engine(THD *thd, handlerton *hton) +plugin_ref ha_lock_engine(THD *thd, const handlerton *hton) { if (hton) { @@ -601,9 +601,13 @@ static my_bool closecon_handlerton(THD *thd, plugin_ref plugin, there's no need to rollback here as all transactions must be rolled back already */ - if (hton->state == SHOW_OPTION_YES && hton->close_connection && - thd_get_ha_data(thd, hton)) - hton->close_connection(hton, thd); + if (hton->state == SHOW_OPTION_YES && thd_get_ha_data(thd, hton)) + { + if (hton->close_connection) + hton->close_connection(hton, thd); + /* make sure ha_data is reset and ha_data_lock is released */ + thd_set_ha_data(thd, hton, NULL); + } return FALSE; } diff --git a/sql/handler.h b/sql/handler.h index 7fc2bf2fece..d9dfd4f0707 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1956,7 +1956,7 @@ extern ulong total_ha, total_ha_2pc; /* lookups */ handlerton *ha_default_handlerton(THD *thd); plugin_ref ha_resolve_by_name(THD *thd, const LEX_STRING *name); -plugin_ref ha_lock_engine(THD *thd, handlerton *hton); +plugin_ref ha_lock_engine(THD *thd, const handlerton *hton); handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type); handler *get_new_handler(TABLE_SHARE *share, MEM_ROOT *alloc, handlerton *db_type); diff --git a/sql/item.cc b/sql/item.cc index f8cca3a0667..3407d2fecd4 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -556,6 +556,18 @@ Item_ident::Item_ident(Name_resolution_context *context_arg, } +Item_ident::Item_ident(TABLE_LIST *view_arg, const char *field_name_arg) + :orig_db_name(NullS), orig_table_name(view_arg->table_name), + 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), + alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX), + cached_table(NULL), depended_from(NULL) +{ + name = (char*) field_name_arg; +} + + /** Constructor used by Item_field & Item_*_ref (see Item comment) */ @@ -1701,7 +1713,16 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname, if (!(conv= (*arg)->safe_charset_converter(coll.collation)) && ((*arg)->collation.repertoire == MY_REPERTOIRE_ASCII)) - conv= new Item_func_conv_charset(*arg, coll.collation, 1); + { + /* + We should disable const subselect item evaluation because + subselect transformation does not happen in view_prepare_mode + and thus val_...() methods can not be called for const items. + */ + bool resolve_const= ((*arg)->type() == Item::SUBSELECT_ITEM && + thd->lex->view_prepare_mode) ? FALSE : TRUE; + conv= new Item_func_conv_charset(*arg, coll.collation, resolve_const); + } if (!conv) { @@ -2209,14 +2230,14 @@ String *Item_int::val_str(String *str) { // following assert is redundant, because fixed=1 assigned in constructor DBUG_ASSERT(fixed == 1); - str->set(value, &my_charset_bin); + str->set_int(value, unsigned_flag, &my_charset_bin); return str; } void Item_int::print(String *str, enum_query_type query_type) { // my_charset_bin is good enough for numbers - str_value.set(value, &my_charset_bin); + str_value.set_int(value, unsigned_flag, &my_charset_bin); str->append(str_value); } @@ -3503,7 +3524,7 @@ void Item_copy_decimal::copy() { my_decimal *nr= item->val_decimal(&cached_value); if (nr && nr != &cached_value) - memcpy (&cached_value, nr, sizeof (my_decimal)); + my_decimal2decimal (nr, &cached_value); null_value= item->null_value; } @@ -4475,6 +4496,7 @@ void Item_field::cleanup() I.e. we can drop 'field'. */ field= result_field= 0; + item_equal= NULL; null_value= FALSE; DBUG_VOID_RETURN; } @@ -5050,14 +5072,22 @@ int Item_field::save_in_field(Field *to, bool no_conversions) if (result_field->is_null()) { null_value=1; - res= set_field_to_null_with_conversions(to, no_conversions); + return set_field_to_null_with_conversions(to, no_conversions); } - else + to->set_notnull(); + + /* + If we're setting the same field as the one we're reading from there's + nothing to do. This can happen in 'SET x = x' type of scenarios. + */ + if (to == result_field) { - to->set_notnull(); - res= field_conv(to,result_field); null_value=0; + return 0; } + + res= field_conv(to,result_field); + null_value=0; return res; } @@ -5690,9 +5720,14 @@ void Item_field::print(String *str, enum_query_type query_type) char buff[MAX_FIELD_WIDTH]; String tmp(buff,sizeof(buff),str->charset()); field->val_str(&tmp); - str->append('\''); - str->append(tmp); - str->append('\''); + if (field->is_null()) + str->append("NULL"); + else + { + str->append('\''); + str->append(tmp); + str->append('\''); + } return; } Item_ident::print(str, query_type); @@ -5715,6 +5750,20 @@ Item_ref::Item_ref(Name_resolution_context *context_arg, } +Item_ref::Item_ref(TABLE_LIST *view_arg, Item **item, + const char *field_name_arg, bool alias_name_used_arg) + :Item_ident(view_arg, field_name_arg), + result_field(NULL), ref(item) +{ + alias_name_used= alias_name_used_arg; + /* + This constructor is used to create some internal references over fixed items + */ + if (ref && *ref && (*ref)->fixed) + set_properties(); +} + + /** Resolve the name of a reference to a column reference. @@ -7127,7 +7176,7 @@ double Item_cache_decimal::val_real() DBUG_ASSERT(fixed); double res; if (!value_cached && !cache_value()) - return NULL; + return 0.0; my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &res); return res; } diff --git a/sql/item.h b/sql/item.h index d2e8382023b..d2303853743 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1402,6 +1402,7 @@ public: const char *db_name_arg, const char *table_name_arg, const char *field_name_arg); Item_ident(THD *thd, Item_ident *item); + Item_ident(TABLE_LIST *view_arg, const char *field_name_arg); const char *full_name() const; void cleanup(); bool remove_dependence_processor(uchar * arg); @@ -2222,6 +2223,8 @@ public: Item_ref(Name_resolution_context *context_arg, Item **item, const char *table_name_arg, const char *field_name_arg, bool alias_name_used_arg= FALSE); + Item_ref(TABLE_LIST *view_arg, Item **item, + const char *field_name_arg, bool alias_name_used_arg= FALSE); /* Constructor need to process subselect with temporary tables (see Item) */ Item_ref(THD *thd, Item_ref *item) @@ -2317,6 +2320,11 @@ public: if (ref && result_type() == ROW_RESULT) (*ref)->bring_value(); } + bool get_time(MYSQL_TIME *ltime) + { + DBUG_ASSERT(fixed); + return (*ref)->get_time(ltime); + } }; @@ -2337,6 +2345,12 @@ public: {} /* Constructor need to process subselect with temporary tables (see Item) */ Item_direct_ref(THD *thd, Item_direct_ref *item) : Item_ref(thd, item) {} + Item_direct_ref(TABLE_LIST *view_arg, Item **item, + const char *field_name_arg, + bool alias_name_used_arg= FALSE) + :Item_ref(view_arg, item, field_name_arg, + alias_name_used_arg) + {} double val_real(); longlong val_int(); @@ -2362,6 +2376,10 @@ public: /* Constructor need to process subselect with temporary tables (see Item) */ Item_direct_view_ref(THD *thd, Item_direct_ref *item) :Item_direct_ref(thd, item) {} + Item_direct_view_ref(TABLE_LIST *view_arg, Item **item, + const char *field_name_arg) + :Item_direct_ref(view_arg, item, field_name_arg) + {} bool fix_fields(THD *, Item **); bool eq(const Item *item, bool binary_cmp) const; @@ -3015,6 +3033,7 @@ public: Item_cache_int(enum_field_types field_type_arg): Item_cache(field_type_arg), value(0) {} + virtual void store(Item *item){ Item_cache::store(item); } void store(Item *item, longlong val_arg); double val_real(); longlong val_int(); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 1d33e369af0..6e38220abd1 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2006 MySQL AB +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1022,12 +1022,12 @@ bool Arg_comparator::try_year_cmp_func(Item_result type) @return cache item or original value. */ -Item** Arg_comparator::cache_converted_constant(THD *thd, Item **value, +Item** Arg_comparator::cache_converted_constant(THD *thd_arg, Item **value, Item **cache_item, Item_result type) { /* Don't need cache if doing context analysis only. */ - if (!thd->is_context_analysis_only() && + if (!thd_arg->is_context_analysis_only() && (*value)->const_item() && type != (*value)->result_type()) { Item_cache *cache= Item_cache::get_cache(*value, type); @@ -1190,12 +1190,21 @@ get_year_value(THD *thd, Item ***item_arg, Item **cache_arg, /* Coerce value to the 19XX form in order to correctly compare YEAR(2) & YEAR(4) types. + Here we are converting all item values but YEAR(4) fields since + 1) YEAR(4) already has a regular YYYY form and + 2) we don't want to convert zero/bad YEAR(4) values to the + value of 2000. */ - if (value < 70) - value+= 100; - if (value <= 1900) - value+= 1900; - + Item *real_item= item->real_item(); + if (!(real_item->type() == Item::FIELD_ITEM && + ((Item_field *)real_item)->field->type() == MYSQL_TYPE_YEAR && + ((Item_field *)real_item)->field->field_length == 4)) + { + if (value < 70) + value+= 100; + if (value <= 1900) + value+= 1900; + } /* Convert year to DATETIME of form YYYY-00-00 00:00:00 (YYYY0000000000). */ value*= 10000000000LL; @@ -1368,12 +1377,12 @@ int Arg_comparator::compare_real() int Arg_comparator::compare_decimal() { - my_decimal value1; - my_decimal *val1= (*a)->val_decimal(&value1); + my_decimal decimal1; + my_decimal *val1= (*a)->val_decimal(&decimal1); if (!(*a)->null_value) { - my_decimal value2; - my_decimal *val2= (*b)->val_decimal(&value2); + my_decimal decimal2; + my_decimal *val2= (*b)->val_decimal(&decimal2); if (!(*b)->null_value) { if (set_null) @@ -1397,9 +1406,9 @@ int Arg_comparator::compare_e_real() int Arg_comparator::compare_e_decimal() { - my_decimal value1, value2; - my_decimal *val1= (*a)->val_decimal(&value1); - my_decimal *val2= (*b)->val_decimal(&value2); + my_decimal decimal1, decimal2; + my_decimal *val1= (*a)->val_decimal(&decimal1); + my_decimal *val2= (*b)->val_decimal(&decimal2); if ((*a)->null_value || (*b)->null_value) return test((*a)->null_value && (*b)->null_value); return test(my_decimal_cmp(val1, val2) == 0); @@ -5402,11 +5411,11 @@ void Item_equal::merge(Item_equal *item) members follow in a wrong order they are swapped. This is performed again and again until we get all members in a right order. - @param cmp function to compare field item + @param compare function to compare field item @param arg context extra parameter for the cmp function */ -void Item_equal::sort(Item_field_cmpfunc cmp, void *arg) +void Item_equal::sort(Item_field_cmpfunc compare, void *arg) { bool swap; List_iterator<Item_field> it(fields); @@ -5420,7 +5429,7 @@ void Item_equal::sort(Item_field_cmpfunc cmp, void *arg) while ((item2= it++)) { Item_field **ref2= it.ref(); - if (cmp(item1, item2, arg) < 0) + if (compare(item1, item2, arg) < 0) { Item_field *item= *ref1; *ref1= *ref2; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 38025ff0af5..4eb27988984 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2003 MySQL AB +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -54,9 +54,9 @@ public: /* Allow owner function to use string buffers. */ String value1, value2; - Arg_comparator(): thd(0), a_cache(0), b_cache(0), set_null(TRUE), + Arg_comparator(): comparators(0), thd(0), a_cache(0), b_cache(0), set_null(TRUE), get_value_a_func(0), get_value_b_func(0) {}; - Arg_comparator(Item **a1, Item **a2): a(a1), b(a2), thd(0), + Arg_comparator(Item **a1, Item **a2): a(a1), b(a2), comparators(0), thd(0), a_cache(0), b_cache(0), set_null(TRUE), get_value_a_func(0), get_value_b_func(0) {}; @@ -112,6 +112,11 @@ public: return (owner->type() == Item::FUNC_ITEM && ((Item_func*)owner)->functype() == Item_func::EQUAL_FUNC); } + void cleanup() + { + delete [] comparators; + comparators= 0; + } friend class Item_func; }; @@ -365,6 +370,11 @@ public: CHARSET_INFO *compare_collation() { return cmp.cmp_collation.collation; } uint decimal_precision() const { return 1; } void top_level_item() { abort_on_null= TRUE; } + void cleanup() + { + Item_int_func::cleanup(); + cmp.cleanup(); + } friend class Arg_comparator; }; @@ -1474,9 +1484,21 @@ public: Item_cond(THD *thd, Item_cond *item); Item_cond(List<Item> &nlist) :Item_bool_func(), list(nlist), abort_on_null(0) {} - bool add(Item *item) { return list.push_back(item); } - bool add_at_head(Item *item) { return list.push_front(item); } - void add_at_head(List<Item> *nlist) { list.prepand(nlist); } + bool add(Item *item) + { + DBUG_ASSERT(item); + return list.push_back(item); + } + bool add_at_head(Item *item) + { + DBUG_ASSERT(item); + return list.push_front(item); + } + void add_at_head(List<Item> *nlist) + { + DBUG_ASSERT(nlist->elements); + list.prepand(nlist); + } bool fix_fields(THD *, Item **ref); enum Type type() const { return COND_ITEM; } @@ -1604,7 +1626,7 @@ public: longlong val_int(); const char *func_name() const { return "multiple equal"; } optimize_type select_optimize() const { return OPTIMIZE_EQUAL; } - void sort(Item_field_cmpfunc cmp, void *arg); + void sort(Item_field_cmpfunc compare, void *arg); friend class Item_equal_iterator; void fix_length_and_dec(); bool fix_fields(THD *thd, Item **ref); diff --git a/sql/item_create.cc b/sql/item_create.cc index c309ccc06ca..fd8f13d6dc5 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2003 MySQL AB +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -42,7 +42,7 @@ class Create_native_func : public Create_func { public: - virtual Item *create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item *create_func(THD *thd, LEX_STRING name, List<Item> *item_list); /** Builder method, with no arguments. @@ -69,7 +69,7 @@ protected: class Create_func_arg0 : public Create_func { public: - virtual Item *create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item *create_func(THD *thd, LEX_STRING name, List<Item> *item_list); /** Builder method, with no arguments. @@ -93,7 +93,7 @@ protected: class Create_func_arg1 : public Create_func { public: - virtual Item *create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item *create_func(THD *thd, LEX_STRING name, List<Item> *item_list); /** Builder method, with one argument. @@ -118,7 +118,7 @@ protected: class Create_func_arg2 : public Create_func { public: - virtual Item *create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item *create_func(THD *thd, LEX_STRING name, List<Item> *item_list); /** Builder method, with two arguments. @@ -144,7 +144,7 @@ protected: class Create_func_arg3 : public Create_func { public: - virtual Item *create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item *create_func(THD *thd, LEX_STRING name, List<Item> *item_list); /** Builder method, with three arguments. @@ -194,7 +194,7 @@ protected: class Create_func_no_geom : public Create_func { public: - virtual Item *create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item *create_func(THD *thd, LEX_STRING name, List<Item> *item_list); /** Singleton. */ static Create_func_no_geom s_singleton; @@ -2315,7 +2315,7 @@ static bool has_named_parameters(List<Item> *params) Create_func_no_geom Create_func_no_geom::s_singleton; Item* -Create_func_no_geom::create(THD * /* unused */, +Create_func_no_geom::create_func(THD * /* unused */, LEX_STRING /* unused */, List<Item> * /* unused */) { @@ -2328,7 +2328,7 @@ Create_func_no_geom::create(THD * /* unused */, Item* -Create_qfunc::create(THD *thd, LEX_STRING name, List<Item> *item_list) +Create_qfunc::create_func(THD *thd, LEX_STRING name, List<Item> *item_list) { LEX_STRING db; @@ -2361,7 +2361,7 @@ Create_qfunc::create(THD *thd, LEX_STRING name, List<Item> *item_list) Create_udf_func Create_udf_func::s_singleton; Item* -Create_udf_func::create(THD *thd, LEX_STRING name, List<Item> *item_list) +Create_udf_func::create_func(THD *thd, LEX_STRING name, List<Item> *item_list) { udf_func *udf= find_udf(name.str, name.length); DBUG_ASSERT(udf); @@ -2512,7 +2512,7 @@ Create_sp_func::create(THD *thd, LEX_STRING db, LEX_STRING name, Item* -Create_native_func::create(THD *thd, LEX_STRING name, List<Item> *item_list) +Create_native_func::create_func(THD *thd, LEX_STRING name, List<Item> *item_list) { if (has_named_parameters(item_list)) { @@ -2525,7 +2525,7 @@ Create_native_func::create(THD *thd, LEX_STRING name, List<Item> *item_list) Item* -Create_func_arg0::create(THD *thd, LEX_STRING name, List<Item> *item_list) +Create_func_arg0::create_func(THD *thd, LEX_STRING name, List<Item> *item_list) { int arg_count= 0; @@ -2543,7 +2543,7 @@ Create_func_arg0::create(THD *thd, LEX_STRING name, List<Item> *item_list) Item* -Create_func_arg1::create(THD *thd, LEX_STRING name, List<Item> *item_list) +Create_func_arg1::create_func(THD *thd, LEX_STRING name, List<Item> *item_list) { int arg_count= 0; @@ -2569,7 +2569,7 @@ Create_func_arg1::create(THD *thd, LEX_STRING name, List<Item> *item_list) Item* -Create_func_arg2::create(THD *thd, LEX_STRING name, List<Item> *item_list) +Create_func_arg2::create_func(THD *thd, LEX_STRING name, List<Item> *item_list) { int arg_count= 0; @@ -2597,7 +2597,7 @@ Create_func_arg2::create(THD *thd, LEX_STRING name, List<Item> *item_list) Item* -Create_func_arg3::create(THD *thd, LEX_STRING name, List<Item> *item_list) +Create_func_arg3::create_func(THD *thd, LEX_STRING name, List<Item> *item_list) { int arg_count= 0; diff --git a/sql/item_create.h b/sql/item_create.h index a3ba6bd26a6..d84c764a3d9 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2006 MySQL AB +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -53,7 +53,7 @@ public: @param item_list The list of arguments to the function, can be NULL @return An item representing the parsed function call, or NULL */ - virtual Item *create(THD *thd, LEX_STRING name, List<Item> *item_list) = 0; + virtual Item *create_func(THD *thd, LEX_STRING name, List<Item> *item_list) = 0; protected: /** Constructor */ @@ -80,7 +80,7 @@ public: @param item_list The list of arguments to the function, can be NULL @return An item representing the parsed function call */ - virtual Item *create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item *create_func(THD *thd, LEX_STRING name, List<Item> *item_list); /** The builder create method, for qualified functions. @@ -127,7 +127,7 @@ extern Create_qfunc * find_qualified_function_builder(THD *thd); class Create_udf_func : public Create_func { public: - virtual Item *create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item *create_func(THD *thd, LEX_STRING name, List<Item> *item_list); /** The builder create method, for User Defined Functions. diff --git a/sql/item_func.cc b/sql/item_func.cc index 845654c1881..1e31755179b 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3362,80 +3362,6 @@ longlong Item_master_pos_wait::val_int() return event_count; } -#ifdef EXTRA_DEBUG -void debug_sync_point(const char* lock_name, uint lock_timeout) -{ - THD* thd=current_thd; - User_level_lock* ull; - struct timespec abstime; - size_t lock_name_len; - lock_name_len= strlen(lock_name); - pthread_mutex_lock(&LOCK_user_locks); - - if (thd->ull) - { - item_user_lock_release(thd->ull); - thd->ull=0; - } - - /* - If the lock has not been aquired by some client, we do not want to - create an entry for it, since we immediately release the lock. In - this case, we will not be waiting, but rather, just waste CPU and - memory on the whole deal - */ - if (!(ull= ((User_level_lock*) hash_search(&hash_user_locks, - (uchar*) lock_name, - lock_name_len)))) - { - pthread_mutex_unlock(&LOCK_user_locks); - return; - } - ull->count++; - - /* - Structure is now initialized. Try to get the lock. - Set up control struct to allow others to abort locks - */ - thd_proc_info(thd, "User lock"); - thd->mysys_var->current_mutex= &LOCK_user_locks; - thd->mysys_var->current_cond= &ull->cond; - - set_timespec(abstime,lock_timeout); - while (ull->locked && !thd->killed) - { - int error= pthread_cond_timedwait(&ull->cond, &LOCK_user_locks, &abstime); - if (error == ETIMEDOUT || error == ETIME) - break; - } - - if (ull->locked) - { - if (!--ull->count) - delete ull; // Should never happen - } - else - { - ull->locked=1; - ull->set_thread(thd); - thd->ull=ull; - } - pthread_mutex_unlock(&LOCK_user_locks); - pthread_mutex_lock(&thd->mysys_var->mutex); - thd_proc_info(thd, 0); - thd->mysys_var->current_mutex= 0; - thd->mysys_var->current_cond= 0; - pthread_mutex_unlock(&thd->mysys_var->mutex); - pthread_mutex_lock(&LOCK_user_locks); - if (thd->ull) - { - item_user_lock_release(thd->ull); - thd->ull=0; - } - pthread_mutex_unlock(&LOCK_user_locks); -} - -#endif /** Get a user level lock. If the thread has an old lock this is first released. diff --git a/sql/item_row.cc b/sql/item_row.cc index 29b37eb2bc0..7535c1fa80b 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -30,7 +30,8 @@ */ Item_row::Item_row(List<Item> &arg): - Item(), used_tables_cache(0), const_item_cache(1), with_null(0) + Item(), used_tables_cache(0), not_null_tables_cache(0), + const_item_cache(1), with_null(0) { //TODO: think placing 2-3 component items in item (as it done for function) @@ -71,6 +72,7 @@ bool Item_row::fix_fields(THD *thd, Item **ref) Item *item= *arg; used_tables_cache |= item->used_tables(); const_item_cache&= item->const_item() && !with_null; + not_null_tables_cache|= item->not_null_tables(); /* Some subqueries transformations aren't done in the view_prepare_mode thus is_null() will fail. So we skip is_null() calculation for CREATE VIEW as diff --git a/sql/item_row.h b/sql/item_row.h index 67441f49603..76d1c875e7d 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -16,7 +16,7 @@ class Item_row: public Item { Item **items; - table_map used_tables_cache; + table_map used_tables_cache, not_null_tables_cache; uint arg_count; bool const_item_cache; bool with_null; @@ -26,6 +26,7 @@ public: Item(), items(item->items), used_tables_cache(item->used_tables_cache), + not_null_tables_cache(0), arg_count(item->arg_count), const_item_cache(item->const_item_cache), with_null(0) @@ -65,6 +66,7 @@ public: bool const_item() const { return const_item_cache; }; enum Item_result result_type() const { return ROW_RESULT; } void update_used_tables(); + table_map not_null_tables() const { return not_null_tables_cache; } virtual void print(String *str, enum_query_type query_type); bool walk(Item_processor processor, bool walk_subquery, uchar *arg); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 66308215d0b..b53172d631a 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -324,7 +324,7 @@ String *Item_func_concat::val_str(String *str) } else if (str->alloced_length() >= res->length()+res2->length()) { - if (str == res2) + if (str->ptr() == res2->ptr()) str->replace(0,0,*res); else { diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 5799c768162..ab2bf006032 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -694,8 +694,9 @@ public: String *val_str(String *); void fix_length_and_dec() { + ulonglong max_result_length= (ulonglong) args[0]->max_length * 2 + 2; + max_length= (uint32) min(max_result_length, MAX_BLOB_WIDTH); collation.set(args[0]->collation); - max_length= args[0]->max_length * 2 + 2; } }; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 26d3833f72c..f3fcbc4db68 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -122,6 +122,21 @@ void Item_subselect::cleanup() DBUG_VOID_RETURN; } + +/* + We cannot use generic Item::safe_charset_converter() because + Subselect transformation does not happen in view_prepare_mode + and thus we can not evaluate val_...() for const items. +*/ + +Item *Item_subselect::safe_charset_converter(CHARSET_INFO *tocs) +{ + Item_func_conv_charset *conv= + new Item_func_conv_charset(this, tocs, thd->lex->view_prepare_mode ? 0 : 1); + return conv->safe ? conv : NULL; +} + + void Item_singlerow_subselect::cleanup() { DBUG_ENTER("Item_singlerow_subselect::cleanup"); @@ -249,9 +264,13 @@ bool Item_subselect::exec() { int res; - if (thd->is_error()) - /* Do not execute subselect in case of a fatal error */ + /* + Do not execute subselect in case of a fatal error + or if the query has been killed. + */ + if (thd->is_error() || thd->killed) return 1; + /* Simulate a failure in sub-query execution. Used to test e.g. out of memory or query being killed conditions. diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 467e9b22637..3806e68e377 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -126,6 +126,7 @@ public: virtual void reset_value_registration() {} enum_parsing_place place() { return parsing_place; } bool walk(Item_processor processor, bool walk_subquery, uchar *arg); + Item *safe_charset_converter(CHARSET_INFO *tocs); /** Get the SELECT_LEX structure associated with this Item. diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 142e90639e8..8c1e5501a1b 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2003 MySQL AB +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -647,7 +647,7 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) default: DBUG_ASSERT(0); }; - setup(args[0], NULL); + setup_hybrid(args[0], NULL); /* MIN/MAX can return NULL for empty set indepedent of the used column */ maybe_null= 1; unsigned_flag=item->unsigned_flag; @@ -681,7 +681,7 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) of the original MIN/MAX object and it is saved in this object's cache. */ -void Item_sum_hybrid::setup(Item *item, Item *value_arg) +void Item_sum_hybrid::setup_hybrid(Item *item, Item *value_arg) { value= Item_cache::get_cache(item); value->setup(item); @@ -1651,7 +1651,7 @@ void Item_sum_hybrid::no_rows_in_result() Item *Item_sum_min::copy_or_same(THD* thd) { Item_sum_min *item= new (thd->mem_root) Item_sum_min(thd, this); - item->setup(args[0], value); + item->setup_hybrid(args[0], value); return item; } @@ -1674,7 +1674,7 @@ bool Item_sum_min::add() Item *Item_sum_max::copy_or_same(THD* thd) { Item_sum_max *item= new (thd->mem_root) Item_sum_max(thd, this); - item->setup(args[0], value); + item->setup_hybrid(args[0], value); return item; } @@ -3420,7 +3420,7 @@ void Item_func_group_concat::print(String *str, enum_query_type query_type) { if (i) str->append(','); - (*order[i]->item)->print(str, query_type); + pargs[i + arg_count_field]->print(str, query_type); if (order[i]->asc) str->append(STRING_WITH_LEN(" ASC")); else diff --git a/sql/item_sum.h b/sql/item_sum.h index f70da52bcd1..5e3972698e9 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2006 MySQL AB +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -353,7 +353,7 @@ public: */ void no_rows_in_result() { clear(); } - virtual bool setup(THD *thd) {return 0;} + virtual bool setup(THD* thd) {return 0;} virtual void make_unique() {} Item *get_tmp_table_item(THD *thd); virtual Field *create_tmp_field(bool group, TABLE *table, @@ -843,7 +843,7 @@ protected: was_values(item->was_values) { } bool fix_fields(THD *, Item **); - void setup(Item *item, Item *value_arg); + void setup_hybrid(Item *item, Item *value_arg); void clear(); double val_real(); longlong val_int(); diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index ded4d28ca29..4248c2e6b4f 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -876,7 +876,7 @@ static bool get_interval_info(const char *str,uint length,CHARSET_INFO *cs, value= value*LL(10) + (longlong) (*str - '0'); if (transform_msec && i == count - 1) // microseconds always last { - int msec_length= 6 - (int)(str - start); + int msec_length= 6 - (int) (str - start); if (msec_length > 0) value*= (long)log_10_int[msec_length]; } diff --git a/sql/log.cc b/sql/log.cc index b7313a988c4..e7090a98fd9 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1714,11 +1714,14 @@ static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv) binlog_trans_log_savepos(thd, (my_off_t*) sv); /* Write it to the binary log */ + String log_query; + if (log_query.append(STRING_WITH_LEN("SAVEPOINT ")) || + log_query.append(thd->lex->ident.str, thd->lex->ident.length)) + DBUG_RETURN(1); int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); - int const error= - thd->binlog_query(THD::STMT_QUERY_TYPE, - thd->query(), thd->query_length(), TRUE, FALSE, errcode); - DBUG_RETURN(error); + Query_log_event qinfo(thd, log_query.c_ptr_safe(), log_query.length(), + TRUE, TRUE, errcode); + DBUG_RETURN(mysql_bin_log.write(&qinfo)); } static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) @@ -1733,11 +1736,14 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) if (unlikely(thd->transaction.all.modified_non_trans_table || (thd->options & OPTION_KEEP_LOG))) { + String log_query; + if (log_query.append(STRING_WITH_LEN("ROLLBACK TO ")) || + log_query.append(thd->lex->ident.str, thd->lex->ident.length)) + DBUG_RETURN(1); int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); - int error= - thd->binlog_query(THD::STMT_QUERY_TYPE, - thd->query(), thd->query_length(), TRUE, FALSE, errcode); - DBUG_RETURN(error); + Query_log_event qinfo(thd, log_query.c_ptr_safe(), log_query.length(), + TRUE, TRUE, errcode); + DBUG_RETURN(mysql_bin_log.write(&qinfo)); } binlog_trans_log_truncate(thd, *(my_off_t*)sv); DBUG_RETURN(0); @@ -4062,11 +4068,8 @@ int THD::binlog_write_table_map(TABLE *table, bool is_trans) DBUG_ASSERT(current_stmt_binlog_row_based && mysql_bin_log.is_open()); DBUG_ASSERT(table->s->table_map_id != ULONG_MAX); - Table_map_log_event::flag_set const - flags= Table_map_log_event::TM_NO_FLAGS; - Table_map_log_event - the_event(this, table, table->s->table_map_id, is_trans, flags); + the_event(this, table, table->s->table_map_id, is_trans); if (is_trans && binlog_table_maps == 0) binlog_start_trans_and_stmt(); @@ -4275,7 +4278,9 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) */ const char *local_db= event_info->get_db(); if ((thd && !(thd->options & OPTION_BIN_LOG)) || - (!binlog_filter->db_ok(local_db))) + (thd->lex->sql_command != SQLCOM_ROLLBACK_TO_SAVEPOINT && + thd->lex->sql_command != SQLCOM_SAVEPOINT && + !binlog_filter->db_ok(local_db))) { VOID(pthread_mutex_unlock(&LOCK_log)); DBUG_RETURN(0); @@ -4679,7 +4684,7 @@ int query_error_code(THD *thd, bool not_killed) { int error; - if (not_killed) + if (not_killed || (thd->killed == THD::KILL_BAD_DATA)) { error= thd->is_error() ? thd->main_da.sql_errno() : 0; diff --git a/sql/log_event.cc b/sql/log_event.cc index 7de986b325b..a8e227fa99b 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3063,10 +3063,7 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, ::do_apply_event(), then the companion SET also have so we don't need to reset_one_shot_variables(). */ - if (!strncmp(query_arg, "BEGIN", q_len_arg) || - !strncmp(query_arg, "COMMIT", q_len_arg) || - !strncmp(query_arg, "ROLLBACK", q_len_arg) || - rpl_filter->db_ok(thd->db)) + if (is_trans_keyword() || rpl_filter->db_ok(thd->db)) { thd->set_time((time_t)when); thd->set_query((char*)query_arg, q_len_arg); @@ -7896,7 +7893,7 @@ int Table_map_log_event::save_field_metadata() */ #if !defined(MYSQL_CLIENT) Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid, - bool is_transactional, uint16 flags) + bool is_transactional) : Log_event(thd, 0, true), m_table(tbl), m_dbnam(tbl->s->db.str), @@ -7906,7 +7903,7 @@ Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid, m_colcnt(tbl->s->fields), m_memory(NULL), m_table_id(tid), - m_flags(flags), + m_flags(TM_BIT_LEN_EXACT_F), m_data_size(0), m_field_metadata(0), m_field_metadata_size(0), @@ -8164,8 +8161,10 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli) inside Relay_log_info::clear_tables_to_lock() by calling the table_def destructor explicitly. */ - new (&table_list->m_tabledef) table_def(m_coltype, m_colcnt, - m_field_metadata, m_field_metadata_size, m_null_bits); + new (&table_list->m_tabledef) + table_def(m_coltype, m_colcnt, + m_field_metadata, m_field_metadata_size, + m_null_bits, m_flags); table_list->m_tabledef_valid= TRUE; /* @@ -9478,7 +9477,7 @@ Incident_log_event::write_data_body(IO_CACHE *file) they will always be printed for the first event. */ st_print_event_info::st_print_event_info() - :flags2_inited(0), sql_mode_inited(0), + :flags2_inited(0), sql_mode_inited(0), sql_mode(0), auto_increment_increment(0),auto_increment_offset(0), charset_inited(0), lc_time_names_number(~0), charset_database_number(ILLEGAL_CHARSET_INFO_NUMBER), diff --git a/sql/log_event.h b/sql/log_event.h index a0ba824dd99..9b7f000648d 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -1682,6 +1682,28 @@ public: /* !!! Public in this patch to allow old usage */ const char *query_arg, uint32 q_len_arg); #endif /* HAVE_REPLICATION */ + /* + If true, the event always be applied by slave SQL thread or be printed by + mysqlbinlog + */ + bool is_trans_keyword() + { + /* + Before the patch for bug#50407, The 'SAVEPOINT and ROLLBACK TO' + queries input by user was written into log events directly. + So the keywords can be written in both upper case and lower case + together, strncasecmp is used to check both cases. they also could be + binlogged with comments in the front of these keywords. for examples: + / * bla bla * / SAVEPOINT a; + / * bla bla * / ROLLBACK TO a; + but we don't handle these cases and after the patch, both quiries are + binlogged in upper case with no comments. + */ + return !strncmp(query, "BEGIN", q_len) || + !strncmp(query, "COMMIT", q_len) || + !strncasecmp(query, "SAVEPOINT", 9) || + !strncasecmp(query, "ROLLBACK", 8); + } }; @@ -3298,16 +3320,14 @@ public: /* Special constants representing sets of flags */ enum { - TM_NO_FLAGS = 0U + TM_NO_FLAGS = 0U, + TM_BIT_LEN_EXACT_F = (1U << 0) }; - void set_flags(flag_set flag) { m_flags |= flag; } - void clear_flags(flag_set flag) { m_flags &= ~flag; } flag_set get_flags(flag_set flag) const { return m_flags & flag; } #ifndef MYSQL_CLIENT - Table_map_log_event(THD *thd, TABLE *tbl, ulong tid, - bool is_transactional, uint16 flags); + Table_map_log_event(THD *thd, TABLE *tbl, ulong tid, bool is_transactional); #endif #ifdef HAVE_REPLICATION Table_map_log_event(const char *buf, uint event_len, @@ -3320,7 +3340,7 @@ public: table_def *create_table_def() { return new table_def(m_coltype, m_colcnt, m_field_metadata, - m_field_metadata_size, m_null_bits); + m_field_metadata_size, m_null_bits, m_flags); } ulong get_table_id() const { return m_table_id; } const char *get_table_name() const { return m_tblnam; } diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index 0f501fd1514..df162761b35 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -15,7 +15,7 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info { DBUG_ENTER("Old_rows_log_event::do_apply_event(st_relay_log_info*)"); int error= 0; - THD *thd= ev->thd; + THD *ev_thd= ev->thd; uchar const *row_start= ev->m_rows_buf; /* @@ -33,17 +33,17 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info DBUG_ASSERT(ev->get_flags(Old_rows_log_event::STMT_END_F)); const_cast<Relay_log_info*>(rli)->clear_tables_to_lock(); - close_thread_tables(thd); - thd->clear_error(); + close_thread_tables(ev_thd); + ev_thd->clear_error(); DBUG_RETURN(0); } /* - 'thd' has been set by exec_relay_log_event(), just before calling + 'ev_thd' has been set by exec_relay_log_event(), just before calling do_apply_event(). We still check here to prevent future coding errors. */ - DBUG_ASSERT(rli->sql_thd == thd); + DBUG_ASSERT(rli->sql_thd == ev_thd); /* If there is no locks taken, this is the first binrow event seen @@ -51,10 +51,10 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info used in the transaction and proceed with execution of the actual event. */ - if (!thd->lock) + if (!ev_thd->lock) { /* - Lock_tables() reads the contents of thd->lex, so they must be + Lock_tables() reads the contents of ev_thd->lex, so they must be initialized. We also call the mysql_reset_thd_for_next_command(), since this @@ -62,24 +62,24 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info call might reset the value of current_stmt_binlog_row_based, so we need to do any changes to that value after this function. */ - lex_start(thd); - mysql_reset_thd_for_next_command(thd); + lex_start(ev_thd); + mysql_reset_thd_for_next_command(ev_thd); /* Check if the slave is set to use SBR. If so, it should switch to using RBR until the end of the "statement", i.e., next STMT_END_F or next error. */ - if (!thd->current_stmt_binlog_row_based && - mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG)) + if (!ev_thd->current_stmt_binlog_row_based && + mysql_bin_log.is_open() && (ev_thd->options & OPTION_BIN_LOG)) { - thd->set_current_stmt_binlog_row_based(); + ev_thd->set_current_stmt_binlog_row_based(); } - if (simple_open_n_lock_tables(thd, rli->tables_to_lock)) + if (simple_open_n_lock_tables(ev_thd, rli->tables_to_lock)) { - uint actual_error= thd->main_da.sql_errno(); - if (thd->is_slave_error || thd->is_fatal_error) + uint actual_error= ev_thd->main_da.sql_errno(); + if (ev_thd->is_slave_error || ev_thd->is_fatal_error) { /* Error reporting borrowed from Query_log_event with many excessive @@ -87,9 +87,9 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info */ rli->report(ERROR_LEVEL, actual_error, "Error '%s' on opening tables", - (actual_error ? thd->main_da.message() : + (actual_error ? ev_thd->main_da.message() : "unexpected success or fatal error")); - thd->is_slave_error= 1; + ev_thd->is_slave_error= 1; } const_cast<Relay_log_info*>(rli)->clear_tables_to_lock(); DBUG_RETURN(actual_error); @@ -109,9 +109,9 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info { if (ptr->m_tabledef.compatible_with(rli, ptr->table)) { - mysql_unlock_tables(thd, thd->lock); - thd->lock= 0; - thd->is_slave_error= 1; + mysql_unlock_tables(ev_thd, ev_thd->lock); + ev_thd->lock= 0; + ev_thd->is_slave_error= 1; const_cast<Relay_log_info*>(rli)->clear_tables_to_lock(); DBUG_RETURN(Old_rows_log_event::ERR_BAD_TABLE_DEF); } @@ -159,23 +159,23 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info TIMESTAMP column to a table with one. So we call set_time(), like in SBR. Presently it changes nothing. */ - thd->set_time((time_t)ev->when); + ev_thd->set_time((time_t)ev->when); /* There are a few flags that are replicated with each row event. Make sure to set/clear them before executing the main body of the event. */ if (ev->get_flags(Old_rows_log_event::NO_FOREIGN_KEY_CHECKS_F)) - thd->options|= OPTION_NO_FOREIGN_KEY_CHECKS; + ev_thd->options|= OPTION_NO_FOREIGN_KEY_CHECKS; else - thd->options&= ~OPTION_NO_FOREIGN_KEY_CHECKS; + ev_thd->options&= ~OPTION_NO_FOREIGN_KEY_CHECKS; if (ev->get_flags(Old_rows_log_event::RELAXED_UNIQUE_CHECKS_F)) - thd->options|= OPTION_RELAXED_UNIQUE_CHECKS; + ev_thd->options|= OPTION_RELAXED_UNIQUE_CHECKS; else - thd->options&= ~OPTION_RELAXED_UNIQUE_CHECKS; + ev_thd->options&= ~OPTION_RELAXED_UNIQUE_CHECKS; /* A small test to verify that objects have consistent types */ - DBUG_ASSERT(sizeof(thd->options) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS)); + DBUG_ASSERT(sizeof(ev_thd->options) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS)); /* Now we are in a statement and will stay in a statement until we @@ -192,7 +192,7 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info while (error == 0 && row_start < ev->m_rows_end) { uchar const *row_end= NULL; - if ((error= do_prepare_row(thd, rli, table, row_start, &row_end))) + if ((error= do_prepare_row(ev_thd, rli, table, row_start, &row_end))) break; // We should perform the after-row operation even in // the case of error @@ -202,7 +202,7 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info /* in_use can have been set to NULL in close_tables_for_reopen */ THD* old_thd= table->in_use; if (!table->in_use) - table->in_use= thd; + table->in_use= ev_thd; error= do_exec_row(table); table->in_use = old_thd; switch (error) @@ -216,11 +216,11 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info break; default: - rli->report(ERROR_LEVEL, thd->main_da.sql_errno(), + rli->report(ERROR_LEVEL, ev_thd->main_da.sql_errno(), "Error in %s event: row application failed. %s", ev->get_type_str(), - thd->is_error() ? thd->main_da.message() : ""); - thd->is_slave_error= 1; + ev_thd->is_error() ? ev_thd->main_da.message() : ""); + ev_thd->is_slave_error= 1; break; } @@ -232,7 +232,7 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info if (!ev->cache_stmt) { DBUG_PRINT("info", ("Marked that we need to keep log")); - thd->options|= OPTION_KEEP_LOG; + ev_thd->options|= OPTION_KEEP_LOG; } } @@ -245,12 +245,12 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info if (error) { /* error has occured during the transaction */ - rli->report(ERROR_LEVEL, thd->main_da.sql_errno(), + rli->report(ERROR_LEVEL, ev_thd->main_da.sql_errno(), "Error in %s event: error during transaction execution " "on table %s.%s. %s", ev->get_type_str(), table->s->db.str, table->s->table_name.str, - thd->is_error() ? thd->main_da.message() : ""); + ev_thd->is_error() ? ev_thd->main_da.message() : ""); /* If one day we honour --skip-slave-errors in row-based replication, and @@ -263,9 +263,9 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info thread is certainly going to stop. rollback at the caller along with sbr. */ - thd->reset_current_stmt_binlog_row_based(); - const_cast<Relay_log_info*>(rli)->cleanup_context(thd, error); - thd->is_slave_error= 1; + ev_thd->reset_current_stmt_binlog_row_based(); + const_cast<Relay_log_info*>(rli)->cleanup_context(ev_thd, error); + ev_thd->is_slave_error= 1; DBUG_RETURN(error); } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 90b02f5337a..56175d069c5 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -580,20 +580,6 @@ protected: /* Used to check GROUP BY list in the MODE_ONLY_FULL_GROUP_BY mode */ #define UNDEF_POS (-1) -#ifdef EXTRA_DEBUG -/** - Sync points allow us to force the server to reach a certain line of code - and block there until the client tells the server it is ok to go on. - The client tells the server to block with SELECT GET_LOCK() - and unblocks it with SELECT RELEASE_LOCK(). Used for debugging difficult - concurrency problems -*/ -#define DBUG_SYNC_POINT(lock_name,lock_timeout) \ - debug_sync_point(lock_name,lock_timeout) -void debug_sync_point(const char* lock_name, uint lock_timeout); -#else -#define DBUG_SYNC_POINT(lock_name,lock_timeout) -#endif /* EXTRA_DEBUG */ /* BINLOG_DUMP options */ @@ -2004,6 +1990,7 @@ extern my_bool opt_log, opt_slow_log; extern ulong log_output_options; extern my_bool opt_log_queries_not_using_indexes; extern bool opt_disable_networking, opt_skip_show_db; +extern bool opt_skip_name_resolve; extern bool opt_ignore_builtin_innodb; extern my_bool opt_character_set_client_handshake; extern bool volatile abort_loop, shutdown_in_progress; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 9b66bdbcdf5..26dcc1753da 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -410,6 +410,7 @@ ulong log_output_options; my_bool opt_log_queries_not_using_indexes= 0; bool opt_error_log= IF_WIN(1,0); bool opt_disable_networking=0, opt_skip_show_db=0; +bool opt_skip_name_resolve=0; my_bool opt_character_set_client_handshake= 1; bool server_id_supplied = 0; bool opt_endinfo, using_udf_functions; @@ -1287,6 +1288,7 @@ void clean_up(bool print_message) lex_free(); /* Free some memory */ item_create_cleanup(); set_var_free(); + free_charsets(); if (!opt_noacl) { #ifdef HAVE_DLOPEN @@ -6076,8 +6078,8 @@ each time the SQL thread starts.", TC_LOG_PAGE_SIZE, 0}, #endif {"log-update", OPT_UPDATE_LOG, - "The update log is deprecated since version 5.0, is replaced by the binary \ -log and this option justs turns on --log-bin instead.", + "The update log is deprecated since version 5.0, is replaced by the binary " + "log and this option just turns on --log-bin instead.", (uchar**) &opt_update_logname, (uchar**) &opt_update_logname, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"log-warnings", 'W', "Log some not critical warnings to the log file.", @@ -6337,7 +6339,10 @@ thread is in the relay logs.", "Tells the slave thread to not replicate to the specified database. To specify more than one database to ignore, use the directive multiple times, once for each database. This option will not work if you use cross database updates. If you need cross database updates to work, make sure you have 3.23.28 or later, and use replicate-wild-ignore-table=db_name.%. ", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"replicate-ignore-table", OPT_REPLICATE_IGNORE_TABLE, - "Tells the slave thread to not replicate to the specified table. To specify more than one table to ignore, use the directive multiple times, once for each table. This will work for cross-datbase updates, in contrast to replicate-ignore-db.", + "Tells the slave thread to not replicate to the specified table. To specify " + "more than one table to ignore, use the directive multiple times, once for " + "each table. This will work for cross-database updates, in contrast to " + "replicate-ignore-db.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"replicate-rewrite-db", OPT_REPLICATE_REWRITE_DB, "Updates to a database with a different name than the original. Example: replicate-rewrite-db=master_db_name->slave_db_name.", @@ -6359,7 +6364,13 @@ Can't be set to 1 if --log-slave-updates is used.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, // In replication, we may need to tell the other servers how to connect {"report-host", OPT_REPORT_HOST, - "Hostname or IP of the slave to be reported to to the master during slave registration. Will appear in the output of SHOW SLAVE HOSTS. Leave unset if you do not want the slave to register itself with the master. Note that it is not sufficient for the master to simply read the IP of the slave off the socket once the slave connects. Due to NAT and other routing issues, that IP may not be valid for connecting to the slave from the master or other hosts.", + "Hostname or IP of the slave to be reported to the master during slave " + "registration. Will appear in the output of SHOW SLAVE HOSTS. Leave unset " + "if you do not want the slave to register itself with the master. Note that " + "it is not sufficient for the master to simply read the IP of the slave " + "from the socket once the slave connects. Due to NAT and other routing " + "issues, that IP may not be valid for connecting to the slave from the " + "master or other hosts.", (uchar**) &report_host, (uchar**) &report_host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"report-password", OPT_REPORT_PASSWORD, "Undocumented.", @@ -6664,7 +6675,10 @@ log and this option does nothing anymore.", (uchar**) &max_system_variables.keep_files_on_create, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"key_buffer_size", OPT_KEY_BUFFER_SIZE, - "The size of the buffer used for index blocks for MyISAM tables. Increase this to get better index handling (for all reads and multiple writes) to as much as you can afford; 64M on a 256M machine that mainly runs MySQL is quite common.", + "The size of the buffer used for index blocks for MyISAM tables. Increase " + "this to get better index handling (for all reads and multiple writes) to " + "as much as you can afford; 1GB on a 4GB machine that mainly runs MySQL is " + "quite common.", (uchar**) &dflt_key_cache_var.param_buff_size, (uchar**) 0, 0, (GET_ULL | GET_ASK_ADDR), @@ -6835,7 +6849,9 @@ The minimum value for this variable is 4096.", (uchar**) &myisam_mmap_size, (uchar**) &myisam_mmap_size, 0, GET_ULL, REQUIRED_ARG, SIZE_T_MAX, MEMMAP_EXTRA_MARGIN, SIZE_T_MAX, 0, 1, 0}, {"myisam_repair_threads", OPT_MYISAM_REPAIR_THREADS, - "Number of threads to use when repairing MyISAM tables. The value of 1 disables parallel repair.", + "Specifies whether several threads should be used when repairing MyISAM " + "tables. For values > 1, one thread is used per index. The value of 1 " + "disables parallel repair.", (uchar**) &global_system_variables.myisam_repair_threads, (uchar**) &max_system_variables.myisam_repair_threads, 0, GET_ULONG, REQUIRED_ARG, 1, 1, ULONG_MAX, 0, 1, 0}, @@ -6843,7 +6859,7 @@ The minimum value for this variable is 4096.", "The buffer that is allocated when sorting the index when doing a REPAIR or when creating indexes with CREATE INDEX or ALTER TABLE.", (uchar**) &global_system_variables.myisam_sort_buff_size, (uchar**) &max_system_variables.myisam_sort_buff_size, 0, - GET_ULONG, REQUIRED_ARG, 8192*1024, 4, ~0L, 0, 1, 0}, + GET_ULONG, REQUIRED_ARG, 8192 * 1024, 4096, ~0L, 0, 1, 0}, {"myisam_use_mmap", OPT_MYISAM_USE_MMAP, "Use memory mapping for reading and writing MyISAM tables.", (uchar**) &opt_myisam_use_mmap, @@ -7162,7 +7178,8 @@ static int show_slave_running(THD *thd, SHOW_VAR *var, char *buff) var->type= SHOW_MY_BOOL; pthread_mutex_lock(&LOCK_active_mi); var->value= buff; - *((my_bool *)buff)= (my_bool) (active_mi && active_mi->slave_running && + *((my_bool *)buff)= (my_bool) (active_mi && + active_mi->slave_running == MYSQL_SLAVE_RUN_CONNECT && active_mi->rli.slave_running); pthread_mutex_unlock(&LOCK_active_mi); return 0; @@ -7699,6 +7716,7 @@ static int mysql_init_variables(void) log_output_options= find_bit_type(log_output_str, &log_output_typelib); opt_bin_log= 0; opt_disable_networking= opt_skip_show_db=0; + opt_skip_name_resolve= 0; opt_ignore_builtin_innodb= 0; opt_logname= opt_update_logname= opt_binlog_index_name= opt_slow_logname= 0; opt_tc_log_file= (char *)"tc.log"; // no hostname in tc_log file name ! @@ -8225,6 +8243,7 @@ mysqld_get_one_option(int optid, opt_specialflag|= SPECIAL_NO_HOST_CACHE; break; case (int) OPT_SKIP_RESOLVE: + opt_skip_name_resolve= 1; opt_specialflag|=SPECIAL_NO_RESOLVE; break; case (int) OPT_SKIP_NETWORKING: diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 70d6d0a5b17..8a3fe6c3ae8 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2003 MySQL AB +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -11,7 +11,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /** @@ -96,7 +96,7 @@ static ulonglong get_exact_record_count(TABLE_LIST *tables) @param conds WHERE clause @note - This function is only called for queries with sum functions and no + This function is only called for queries with aggregate functions and no GROUP BY part. This means that the result set shall contain a single row only @@ -559,31 +559,57 @@ bool simple_pred(Item_func *func_item, Item **args, bool *inv_order) /** Check whether a condition matches a key to get {MAX|MIN}(field):. - For the index specified by the keyinfo parameter, index that - contains field as its component (field_part), the function - checks whether the condition cond is a conjunction and all its - conjuncts referring to the columns of the same table as column - field are one of the following forms: - - f_i= const_i or const_i= f_i or f_i is null, - where f_i is part of the index - - field {<|<=|>=|>|=} const or const {<|<=|>=|>|=} field - - field between const1 and const2 - - @param[in] max_fl Set to 1 if we are optimising MAX() - @param[in,out] ref Reference to the structure we store the key - value - @param[in] keyinfo Reference to the key info - @param[in] field_part Pointer to the key part for the field - @param[in] cond WHERE condition - @param[in,out] key_part_used Map of matchings parts - @param[in,out] range_fl Says whether including key will be used - @param[out] prefix_len Length of common key part for the range - where MAX/MIN is searched for + For the index specified by the keyinfo parameter and an index that + contains the field as its component (field_part), the function + checks whether + + - the condition cond is a conjunction, + - all of its conjuncts refer to columns of the same table, and + - each conjunct is on one of the following forms: + - f_i = const_i or const_i = f_i or f_i IS NULL, + where f_i is part of the index + - field {<|<=|>=|>|=} const + - const {<|<=|>=|>|=} field + - field BETWEEN const_1 AND const_2 + + As a side-effect, the key value to be used for looking up the MIN/MAX value + is actually stored inside the Field object. An interesting feature is that + the function will find the most restrictive endpoint by over-eager + evaluation of the @c WHERE condition. It continually stores the current + endpoint inside the Field object. For a query such as + + @code + SELECT MIN(a) FROM t1 WHERE a > 3 AND a > 5; + @endcode + + the algorithm will recurse over the conjuction, storing first a 3 in the + field. In the next recursive invocation the expression a > 5 is evaluated + as 3 > 5 (Due to the dual nature of Field objects as value carriers and + field identifiers), which will obviously fail, leading to 5 being stored in + the Field object. + + @param[in] max_fl Set to true if we are optimizing MAX(), + false means we are optimizing %MIN() + @param[in, out] ref Reference to the structure where the function + stores the key value + @param[in] keyinfo Reference to the key info + @param[in] field_part Pointer to the key part for the field + @param[in] cond WHERE condition + @param[in,out] key_part_used Map of matchings parts. The function will output + the set of key parts actually being matched in + this set, yet it relies on the caller to + initialize the value to zero. This is due + to the fact that this value is passed + recursively. + @param[in,out] range_fl Says whether endpoints use strict greater/less + than. + @param[out] prefix_len Length of common key part for the range + where MAX/MIN is searched for @retval - 0 Index can't be used. + false Index can't be used. @retval - 1 We can use index to get MIN/MAX value + true We can use the index to get MIN/MAX value */ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, @@ -620,17 +646,20 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, return 0; // Not operator, can't optimize bool eq_type= 0; // =, <=> or IS NULL + bool is_null_safe_eq= FALSE; // The operator is NULL safe, e.g. <=> bool noeq_type= 0; // < or > bool less_fl= 0; // < or <= - bool is_null= 0; - bool between= 0; + bool is_null= 0; // IS NULL + bool between= 0; // BETWEEN ... AND ... switch (((Item_func*) cond)->functype()) { case Item_func::ISNULL_FUNC: is_null= 1; /* fall through */ case Item_func::EQ_FUNC: + eq_type= TRUE; + break; case Item_func::EQUAL_FUNC: - eq_type= 1; + eq_type= is_null_safe_eq= TRUE; break; case Item_func::LT_FUNC: noeq_type= 1; /* fall through */ @@ -658,6 +687,10 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, if (!simple_pred((Item_func*) cond, args, &inv)) return 0; + if (!is_null_safe_eq && !is_null && + (args[1]->is_null() || (between && args[2]->is_null()))) + return FALSE; + if (inv && !eq_type) less_fl= 1-less_fl; // Convert '<' -> '>' (etc) @@ -708,15 +741,16 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, - field {>|>=} const, when searching for MIN */ - if (is_null) + if (is_null || (is_null_safe_eq && args[1]->is_null())) { part->field->set_null(); *key_ptr= (uchar) 1; } else { - store_val_in_field(part->field, args[between && max_fl ? 2 : 1], - CHECK_FIELD_IGNORE); + /* Update endpoints for MAX/MIN, see function comment. */ + Item *value= args[between && max_fl ? 2 : 1]; + store_val_in_field(part->field, value, CHECK_FIELD_IGNORE); if (part->null_bit) *key_ptr++= (uchar) test(part->field->is_null()); part->field->get_key_image(key_ptr, part->length, Field::itRAW); diff --git a/sql/protocol.cc b/sql/protocol.cc index 4f69a0fdb52..dc53e029647 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2003 MySQL AB +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -525,9 +525,9 @@ void Protocol::init(THD *thd_arg) for the error. */ -void Protocol::end_partial_result_set(THD *thd) +void Protocol::end_partial_result_set(THD *thd_arg) { - net_send_eof(thd, thd->server_status, 0 /* no warnings, we're inside SP */); + net_send_eof(thd_arg, thd_arg->server_status, 0 /* no warnings, we're inside SP */); } @@ -850,7 +850,7 @@ bool Protocol_text::store(const char *from, size_t length, CHARSET_INFO *tocs= this->thd->variables.character_set_results; #ifndef DBUG_OFF DBUG_PRINT("info", ("Protocol_text::store field %u (%u): %s", field_pos, - field_count, from)); + field_count, (length == 0? "" : from))); DBUG_ASSERT(field_pos < field_count); DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_DECIMAL || diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index e34f8561051..6058c473e9f 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -206,7 +206,7 @@ table_def::compatible_with(Relay_log_info const *rli_arg, TABLE *table) Check the slave's field size against that of the master. */ if (!error && - !field->compatible_field_size(field_metadata(col), rli_arg)) + !field->compatible_field_size(field_metadata(col), rli_arg, m_flags)) { error= 1; char buf[256]; diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h index d011e9aade8..b209c9140d1 100644 --- a/sql/rpl_utility.h +++ b/sql/rpl_utility.h @@ -32,12 +32,6 @@ class Relay_log_info; - Extract and decode table definition data from the table map event - Check if table definition in table map is compatible with table definition on slave - - Currently, the only field type data available is an array of the - type operators that are present in the table map event. - - @todo Add type operands to this structure to allow detection of - difference between, e.g., BIT(5) and BIT(10). */ class table_def @@ -59,9 +53,9 @@ public: @param null_bitmap The bitmap of fields that can be null */ table_def(field_type *types, ulong size, uchar *field_metadata, - int metadata_size, uchar *null_bitmap) + int metadata_size, uchar *null_bitmap, uint16 flags) : m_size(size), m_type(0), m_field_metadata_size(metadata_size), - m_field_metadata(0), m_null_bits(0), m_memory(NULL) + m_field_metadata(0), m_null_bits(0), m_flags(flags), m_memory(NULL) { m_memory= (uchar *)my_multi_malloc(MYF(MY_WME), &m_type, size, @@ -247,6 +241,7 @@ private: uint m_field_metadata_size; uint16 *m_field_metadata; uchar *m_null_bits; + uint16 m_flags; // Table flags uchar *m_memory; }; diff --git a/sql/set_var.cc b/sql/set_var.cc index 2c00d76b0f1..f7d9d9df42e 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -533,6 +533,10 @@ static sys_var_const sys_skip_show_database(&vars, "skip_show_database", OPT_GLOBAL, SHOW_BOOL, (uchar*) &opt_skip_show_db); +static sys_var_const sys_skip_name_resolve(&vars, "skip_name_resolve", + OPT_GLOBAL, SHOW_BOOL, + (uchar*) &opt_skip_name_resolve); + static sys_var_const sys_socket(&vars, "socket", OPT_GLOBAL, SHOW_CHAR_PTR, (uchar*) &mysqld_unix_port); @@ -3078,6 +3082,13 @@ static bool set_option_autocommit(THD *thd, set_var *var) if ((org_options & OPTION_NOT_AUTOCOMMIT)) { /* We changed to auto_commit mode */ + if (thd->transaction.xid_state.xa_state != XA_NOTR) + { + thd->options= org_options; + my_error(ER_XAER_RMFAIL, MYF(0), + xa_state_names[thd->transaction.xid_state.xa_state]); + return 1; + } thd->options&= ~(ulonglong) (OPTION_BEGIN | OPTION_KEEP_LOG); thd->transaction.all.modified_non_trans_table= FALSE; thd->server_status|= SERVER_STATUS_AUTOCOMMIT; diff --git a/sql/slave.cc b/sql/slave.cc index 271b3635cf1..e8405ffcd37 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -44,6 +44,7 @@ #ifdef HAVE_REPLICATION #include "rpl_tblmap.h" +#include "debug_sync.h" #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") @@ -981,7 +982,16 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi) unavailable (very old master not supporting UNIX_TIMESTAMP()?). */ - DBUG_SYNC_POINT("debug_lock.before_get_UNIX_TIMESTAMP", 10); + DBUG_EXECUTE_IF("dbug.before_get_UNIX_TIMESTAMP", + { + const char act[]= + "now " + "wait_for signal.get_unix_timestamp"; + DBUG_ASSERT(opt_debug_sync_timeout > 0); + DBUG_ASSERT(!debug_sync_set_action(current_thd, + STRING_WITH_LEN(act))); + };); + master_res= NULL; if (!mysql_real_query(mysql, STRING_WITH_LEN("SELECT UNIX_TIMESTAMP()")) && (master_res= mysql_store_result(mysql)) && @@ -1020,7 +1030,15 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi) Note: we could have put a @@SERVER_ID in the previous SELECT UNIX_TIMESTAMP() instead, but this would not have worked on 3.23 masters. */ - DBUG_SYNC_POINT("debug_lock.before_get_SERVER_ID", 10); + DBUG_EXECUTE_IF("dbug.before_get_SERVER_ID", + { + const char act[]= + "now " + "wait_for signal.get_server_id"; + DBUG_ASSERT(opt_debug_sync_timeout > 0); + DBUG_ASSERT(!debug_sync_set_action(current_thd, + STRING_WITH_LEN(act))); + };); master_res= NULL; master_row= NULL; if (!mysql_real_query(mysql, @@ -2557,6 +2575,16 @@ pthread_handler_t handle_slave_io(void *arg) connected: + DBUG_EXECUTE_IF("dbug.before_get_running_status_yes", + { + const char act[]= + "now " + "wait_for signal.io_thread_let_running"; + DBUG_ASSERT(opt_debug_sync_timeout > 0); + DBUG_ASSERT(!debug_sync_set_action(thd, + STRING_WITH_LEN(act))); + };); + // TODO: the assignment below should be under mutex (5.0) mi->slave_running= MYSQL_SLAVE_RUN_CONNECT; thd->slave_net = &mysql->net; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 8a626cabd90..11d5e5f830b 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -3009,6 +3009,7 @@ int sp_instr_set_trigger_field::execute(THD *thd, uint *nextp) { DBUG_ENTER("sp_instr_set_trigger_field::execute"); + thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this)); } diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index a8828d15cae..dd256c70ecb 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -6117,19 +6117,19 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) VOID(pthread_mutex_unlock(&acl_cache->lock)); - int binlog_error= + if (result) + my_message(ER_REVOKE_GRANTS, ER(ER_REVOKE_GRANTS), MYF(0)); + + result= result | write_bin_log(thd, FALSE, thd->query(), thd->query_length()); rw_unlock(&LOCK_grant); close_thread_tables(thd); - /* error for writing binary log has already been reported */ - if (result && !binlog_error) - my_message(ER_REVOKE_GRANTS, ER(ER_REVOKE_GRANTS), MYF(0)); /* Restore the state of binlog format */ thd->current_stmt_binlog_row_based= save_binlog_row_based; - DBUG_RETURN(result || binlog_error); + DBUG_RETURN(result); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index f75a73c15a8..0e70eb93725 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1515,6 +1515,7 @@ void close_temporary_tables(THD *thd) { if (is_user_table(table)) { + bool save_thread_specific_used= thd->thread_specific_used; my_thread_id save_pseudo_thread_id= thd->variables.pseudo_thread_id; /* Set pseudo_thread_id to be that of the processed table */ thd->variables.pseudo_thread_id= tmpkeyval(thd, table); @@ -1544,6 +1545,7 @@ void close_temporary_tables(THD *thd) thd->clear_error(); CHARSET_INFO *cs_save= thd->variables.character_set_client; thd->variables.character_set_client= system_charset_info; + thd->thread_specific_used= TRUE; Query_log_event qinfo(thd, s_query.ptr(), s_query.length() - 1 /* to remove trailing ',' */, 0, FALSE, 0); @@ -1556,6 +1558,7 @@ void close_temporary_tables(THD *thd) "Failed to write the DROP statement for temporary tables to binary log"); } thd->variables.pseudo_thread_id= save_pseudo_thread_id; + thd->thread_specific_used= save_thread_specific_used; } else { diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 673fc9b78e6..bf5af7141c0 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -284,6 +284,37 @@ void **thd_ha_data(const THD *thd, const struct handlerton *hton) return (void **) &thd->ha_data[hton->slot].ha_ptr; } + +/** + Provide a handler data getter to simplify coding +*/ +extern "C" +void *thd_get_ha_data(const THD *thd, const struct handlerton *hton) +{ + return *thd_ha_data(thd, hton); +} + + +/** + Provide a handler data setter to simplify coding + @see thd_set_ha_data() definition in plugin.h +*/ +extern "C" +void thd_set_ha_data(THD *thd, const struct handlerton *hton, + const void *ha_data) +{ + plugin_ref *lock= &thd->ha_data[hton->slot].lock; + if (ha_data && !*lock) + *lock= ha_lock_engine(NULL, (handlerton*) hton); + else if (!ha_data && *lock) + { + plugin_unlock(NULL, *lock); + *lock= NULL; + } + *thd_ha_data(thd, hton)= (void*) ha_data; +} + + extern "C" long long thd_test_options(const THD *thd, long long test_options) { @@ -3100,6 +3131,7 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, } #endif + backup->count_cuted_fields= count_cuted_fields; backup->options= options; backup->in_sub_stmt= in_sub_stmt; backup->enable_slow_log= enable_slow_log; @@ -3137,6 +3169,7 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, void THD::restore_sub_statement_state(Sub_statement_state *backup) { + DBUG_ENTER("THD::restore_sub_statement_state"); #ifndef EMBEDDED_LIBRARY /* BUG#33029, if we are replicating from a buggy master, restore auto_inc_intervals_forced so that the top statement can use the @@ -3163,6 +3196,7 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup) /* ha_release_savepoint() never returns error. */ (void)ha_release_savepoint(this, sv); } + count_cuted_fields= backup->count_cuted_fields; transaction.savepoints= backup->savepoints; options= backup->options; in_sub_stmt= backup->in_sub_stmt; @@ -3192,6 +3226,7 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup) */ examined_row_count+= backup->examined_row_count; cuted_fields+= backup->cuted_fields; + DBUG_VOID_RETURN; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 032985dc44e..4d0552c5b9d 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -995,6 +995,7 @@ public: bool enable_slow_log; bool last_insert_id_used; SAVEPOINT *savepoints; + enum enum_check_fields count_cuted_fields; }; @@ -1263,7 +1264,11 @@ struct Ha_data @sa trans_register_ha() */ Ha_trx_info ha_info[2]; - + /** + NULL: engine is not bound to this thread + non-NULL: engine is bound to this thread, engine shutdown forbidden + */ + plugin_ref lock; Ha_data() :ha_ptr(NULL) {} }; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index af3fdf11696..7e91a37257b 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -50,6 +50,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SELECT_LEX *select_lex= &thd->lex->select_lex; THD::killed_state killed_status= THD::NOT_KILLED; DBUG_ENTER("mysql_delete"); + bool save_binlog_row_based; THD::enum_binlog_query_type query_type= thd->lex->sql_command == SQLCOM_TRUNCATE ? @@ -147,12 +148,14 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, query_type= THD::STMT_QUERY_TYPE; error= -1; // ok deleted= maybe_deleted; + save_binlog_row_based= thd->current_stmt_binlog_row_based; goto cleanup; } if (error != HA_ERR_WRONG_COMMAND) { table->file->print_error(error,MYF(0)); error=0; + save_binlog_row_based= thd->current_stmt_binlog_row_based; goto cleanup; } /* Handler didn't support fast delete; Delete rows one by one */ @@ -293,6 +296,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, table->mark_columns_needed_for_delete(); + save_binlog_row_based= thd->current_stmt_binlog_row_based; + if (thd->lex->sql_command == SQLCOM_TRUNCATE && + thd->current_stmt_binlog_row_based) + thd->clear_current_stmt_binlog_row_based(); + while (!(error=info.read_record(&info)) && !thd->killed && ! thd->is_error()) { @@ -390,7 +398,10 @@ cleanup: /* See similar binlogging code in sql_update.cc, for comments */ if ((error < 0) || thd->transaction.stmt.modified_non_trans_table) { - if (mysql_bin_log.is_open()) + if (mysql_bin_log.is_open() && + !(thd->lex->sql_command == SQLCOM_TRUNCATE && + thd->current_stmt_binlog_row_based && + find_temporary_table(thd, table_list))) { bool const is_trans= thd->lex->sql_command == SQLCOM_TRUNCATE ? @@ -424,6 +435,7 @@ cleanup: if (thd->transaction.stmt.modified_non_trans_table) thd->transaction.all.modified_non_trans_table= TRUE; } + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_ASSERT(transactional_table || !deleted || thd->transaction.stmt.modified_non_trans_table); free_underlaid_joins(thd, select_lex); if (error < 0 || @@ -1059,15 +1071,13 @@ bool multi_delete::send_eof() static bool mysql_truncate_by_delete(THD *thd, TABLE_LIST *table_list) { - bool error, save_binlog_row_based= thd->current_stmt_binlog_row_based; + bool error; DBUG_ENTER("mysql_truncate_by_delete"); table_list->lock_type= TL_WRITE; mysql_init_select(thd->lex); - thd->clear_current_stmt_binlog_row_based(); error= mysql_delete(thd, table_list, NULL, NULL, HA_POS_ERROR, LL(0), TRUE); ha_autocommit_or_rollback(thd, error); end_trans(thd, error ? ROLLBACK : COMMIT); - thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(error); } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 1f4ca90157f..35c24e7571e 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3158,7 +3158,7 @@ bool select_insert::send_data(List<Item> &values) thd->count_cuted_fields= CHECK_FIELD_WARN; // Calculate cuted fields store_values(values); - thd->count_cuted_fields= CHECK_FIELD_IGNORE; + thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; if (thd->is_error()) { table->auto_increment_field_not_null= FALSE; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 459878c03fc..54eefa22a59 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1729,6 +1729,7 @@ typedef struct st_lex : public Query_tables_list - CREATE TRIGGER (points to "TRIGGER"); - CREATE PROCEDURE (points to "PROCEDURE"); - CREATE FUNCTION (points to "FUNCTION" or "AGGREGATE"); + - CREATE EVENT (points to "EVENT") This pointer is required to add possibly omitted DEFINER-clause to the DDL-statement before dumping it to the binlog. diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 869a52325ea..71cf118f577 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -687,12 +687,10 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, strcpy(end, p); end += pl; - thd->set_query_inner(load_data_query, end - load_data_query); - Execute_load_query_log_event - e(thd, thd->query(), thd->query_length(), - (uint) ((char*) fname_start - (char*) thd->query() - 1), - (uint) ((char*) fname_end - (char*) thd->query()), + e(thd, load_data_query, end-load_data_query, + (uint) ((char*) fname_start - load_data_query - 1), + (uint) ((char*) fname_end - load_data_query), (duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE : (ignore ? LOAD_DUP_IGNORE : LOAD_DUP_ERROR), transactional_table, FALSE, errcode); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 168b16c61bf..5228a37f490 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3241,7 +3241,7 @@ end_with_restore_list: TODO: this is workaround. right way will be move invalidating in the unlock procedure. */ - if (first_table->lock_type == TL_WRITE_CONCURRENT_INSERT && + if (!res && first_table->lock_type == TL_WRITE_CONCURRENT_INSERT && thd->lock) { /* INSERT ... SELECT should invalidate only the very first table */ diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 275115e3cbd..395156dcd63 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -2876,6 +2876,7 @@ int get_partition_id_range(partition_info *part_info, *func_value= part_func_value; if (unsigned_flag) part_func_value-= 0x8000000000000000ULL; + /* Search for the partition containing part_func_value */ while (max_part_id > min_part_id) { loc_part_id= (max_part_id + min_part_id) / 2; @@ -3015,11 +3016,17 @@ uint32 get_partition_id_range_for_endpoint(partition_info *part_info, part_end_val= range_array[loc_part_id]; if (left_endpoint) { + DBUG_ASSERT(part_func_value > part_end_val ? + (loc_part_id == max_partition && + !part_info->defined_max_value) : + 1); /* In case of PARTITION p VALUES LESS THAN MAXVALUE - the maximum value is in the current partition. + the maximum value is in the current (last) partition. + If value is equal or greater than the endpoint, + the range starts from the next partition. */ - if (part_func_value == part_end_val && + if (part_func_value >= part_end_val && (loc_part_id < max_partition || !part_info->defined_max_value)) loc_part_id++; } @@ -4273,6 +4280,12 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, { DBUG_ENTER("prep_alter_part_table"); + /* Foreign keys on partitioned tables are not supported, waits for WL#148 */ + if (table->part_info && (alter_info->flags & ALTER_FOREIGN_KEY)) + { + my_error(ER_FOREIGN_KEY_ON_PARTITIONED, MYF(0)); + DBUG_RETURN(TRUE); + } /* We are going to manipulate the partition info on the table object so we need to ensure that the data structure of the table object diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 9e35e392d2a..87c0adc3133 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1006,9 +1006,14 @@ void plugin_unlock_list(THD *thd, plugin_ref *list, uint count) static int plugin_initialize(struct st_plugin_int *plugin) { + int ret= 1; DBUG_ENTER("plugin_initialize"); safe_mutex_assert_owner(&LOCK_plugin); + uint state= plugin->state; + DBUG_ASSERT(state == PLUGIN_IS_UNINITIALIZED); + + pthread_mutex_unlock(&LOCK_plugin); if (plugin_type_initialize[plugin->plugin->type]) { if ((*plugin_type_initialize[plugin->plugin->type])(plugin)) @@ -1027,8 +1032,7 @@ static int plugin_initialize(struct st_plugin_int *plugin) goto err; } } - - plugin->state= PLUGIN_IS_READY; + state= PLUGIN_IS_READY; // plugin->init() succeeded if (plugin->plugin->status_vars) { @@ -1047,7 +1051,8 @@ static int plugin_initialize(struct st_plugin_int *plugin) if (add_status_vars(array)) // add_status_vars makes a copy goto err; #else - add_status_vars(plugin->plugin->status_vars); // add_status_vars makes a copy + if (add_status_vars(plugin->plugin->status_vars)) + goto err; #endif /* FIX_LATER */ } @@ -1067,9 +1072,12 @@ static int plugin_initialize(struct st_plugin_int *plugin) } } - DBUG_RETURN(0); + ret= 0; + err: - DBUG_RETURN(1); + pthread_mutex_lock(&LOCK_plugin); + plugin->state= state; + DBUG_RETURN(ret); } @@ -1736,6 +1744,8 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name) bzero(&tables, sizeof(tables)); tables.db= (char *)"mysql"; tables.table_name= tables.alias= (char *)"plugin"; + if (check_table_access(thd, DELETE_ACL, &tables, 1, FALSE)) + DBUG_RETURN(TRUE); /* need to open before acquiring LOCK_plugin or it will deadlock */ if (! (table= open_ltable(thd, &tables, TL_WRITE, 0))) diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 8c9b147089f..c661f3744aa 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2007 MySQL AB +/* Copyright (c) 2007, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -485,7 +485,7 @@ void PROFILING::set_query_source(char *query_source_arg, uint query_length_arg) There are two ways to get to this function: Selecting from the information schema, and a SHOW command. */ -int PROFILING::fill_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond) +int PROFILING::fill_statistics_info(THD *thd_arg, TABLE_LIST *tables, Item *cond) { DBUG_ENTER("PROFILING::fill_statistics_info"); TABLE *table= tables->table; @@ -520,7 +520,7 @@ int PROFILING::fill_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond) /* Skip the first. We count spans of fence, not fence-posts. */ if (previous == NULL) continue; - if (thd->lex->sql_command == SQLCOM_SHOW_PROFILE) + if (thd_arg->lex->sql_command == SQLCOM_SHOW_PROFILE) { /* We got here via a SHOW command. That means that we stored @@ -533,14 +533,14 @@ int PROFILING::fill_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond) struct where and having conditions at the SQL layer, then this condition should be ripped out. */ - if (thd->lex->profile_query_id == 0) /* 0 == show final query */ + if (thd_arg->lex->profile_query_id == 0) /* 0 == show final query */ { if (query != last) continue; } else { - if (thd->lex->profile_query_id != query->profiling_query_id) + if (thd_arg->lex->profile_query_id != query->profiling_query_id) continue; } } @@ -661,7 +661,7 @@ int PROFILING::fill_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond) table->field[17]->set_notnull(); } - if (schema_table_store_record(thd, table)) + if (schema_table_store_record(thd_arg, table)) DBUG_RETURN(1); } diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index ae995ea5ed3..44215d90634 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1711,7 +1711,6 @@ int log_loaded_block(IO_CACHE* file) if (mysql_bin_log.write(&b)) DBUG_RETURN(1); lf_info->wrote_create_file= 1; - DBUG_SYNC_POINT("debug_lock.created_file_event",10); } } DBUG_RETURN(0); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 52f9aae7a0c..a426f4b68a1 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1106,12 +1106,37 @@ JOIN::optimize() } } - if (conds &&!outer_join && const_table_map != found_const_table_map && + if (conds && const_table_map != found_const_table_map && (select_options & SELECT_DESCRIBE) && select_lex->master_unit() == &thd->lex->unit) // upper level SELECT { conds=new Item_int((longlong) 0,1); // Always false } + + /* + It's necessary to check const part of HAVING cond as + there is a chance that some cond parts may become + const items after make_join_statisctics(for example + when Item is a reference to cost table field from + outer join). + This check is performed only for those conditions + which do not use aggregate functions. In such case + temporary table may not be used and const condition + elements may be lost during further having + condition transformation in JOIN::exec. + */ + if (having && const_table_map) + { + having->update_used_tables(); + having= remove_eq_conds(thd, having, &having_value); + if (having_value == Item::COND_FALSE) + { + having= new Item_int((longlong) 0,1); + zero_result_cause= "Impossible HAVING noticed after reading const tables"; + DBUG_RETURN(0); + } + } + if (make_join_select(this, select, conds)) { zero_result_cause= @@ -2943,7 +2968,8 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds, s->quick=select->quick; s->needed_reg=select->needed_reg; select->quick=0; - if (records == 0 && s->table->reginfo.impossible_range) + if (records == 0 && s->table->reginfo.impossible_range && + (s->table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT)) { /* Impossible WHERE or ON expression @@ -5017,6 +5043,11 @@ greedy_search(JOIN *join, if (best_extension_by_limited_search(join, remaining_tables, idx, record_count, read_time, search_depth, prune_level)) DBUG_RETURN(TRUE); + /* + 'best_read < DBL_MAX' means that optimizer managed to find + some plan and updated 'best_positions' array accordingly. + */ + DBUG_ASSERT(join->best_read < DBL_MAX); if (size_remain <= search_depth) { @@ -5845,7 +5876,7 @@ store_val_in_field(Field *field, Item *item, enum_check_fields check_flag) @retval TRUE error occurred */ bool -JOIN::make_simple_join(JOIN *parent, TABLE *tmp_table) +JOIN::make_simple_join(JOIN *parent, TABLE *temp_table) { DBUG_ENTER("JOIN::make_simple_join"); @@ -5858,7 +5889,7 @@ JOIN::make_simple_join(JOIN *parent, TABLE *tmp_table) DBUG_RETURN(TRUE); /* purecov: inspected */ join_tab= parent->join_tab_reexec; - table= &parent->table_reexec[0]; parent->table_reexec[0]= tmp_table; + table= &parent->table_reexec[0]; parent->table_reexec[0]= temp_table; tables= 1; const_tables= 0; const_table_map= 0; @@ -5878,7 +5909,7 @@ JOIN::make_simple_join(JOIN *parent, TABLE *tmp_table) do_send_rows= row_limit ? 1 : 0; join_tab->cache.buff=0; /* No caching */ - join_tab->table=tmp_table; + join_tab->table=temp_table; join_tab->select=0; join_tab->select_cond=0; join_tab->quick=0; @@ -5895,8 +5926,8 @@ JOIN::make_simple_join(JOIN *parent, TABLE *tmp_table) join_tab->join= this; join_tab->ref.key_parts= 0; bzero((char*) &join_tab->read_record,sizeof(join_tab->read_record)); - tmp_table->status=0; - tmp_table->null_row=0; + temp_table->status=0; + temp_table->null_row=0; DBUG_RETURN(FALSE); } @@ -7028,9 +7059,11 @@ eq_ref_table(JOIN *join, ORDER *start_order, JOIN_TAB *tab) } if (order) { - found++; - DBUG_ASSERT(!(order->used & map)); - order->used|=map; + if (!(order->used & map)) + { + found++; + order->used|= map; + } continue; // Used in ORDER BY } if (!only_eq_ref_tables(join,start_order, (*ref_item)->used_tables())) @@ -8198,7 +8231,8 @@ static Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels, else { DBUG_ASSERT(cond->type() == Item::COND_ITEM); - ((Item_cond *) cond)->add_at_head(&eq_list); + if (eq_list.elements) + ((Item_cond *) cond)->add_at_head(&eq_list); } cond->quick_fix_field(); @@ -8795,8 +8829,14 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top) we still make the inner tables dependent on the outer tables. It would be enough to set dependency only on one outer table for them. Yet this is really a rare case. + Note: + RAND_TABLE_BIT mask should not be counted as it + prevents update of inner table dependences. + For example it might happen if RAND() function + is used in JOIN ON clause. */ - if (!(prev_table->on_expr->used_tables() & ~prev_used_tables)) + if (!((prev_table->on_expr->used_tables() & ~RAND_TABLE_BIT) & + ~prev_used_tables)) prev_table->dep_tables|= used_tables; } } @@ -12909,12 +12949,35 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, uint find_shortest_key(TABLE *table, const key_map *usable_keys) { - uint min_length= (uint) ~0; uint best= MAX_KEY; + uint usable_clustered_pk= (table->file->primary_key_is_clustered() && + table->s->primary_key != MAX_KEY && + usable_keys->is_set(table->s->primary_key)) ? + table->s->primary_key : MAX_KEY; if (!usable_keys->is_clear_all()) { + uint min_length= (uint) ~0; for (uint nr=0; nr < table->s->keys ; nr++) { + /* + As far as + 1) clustered primary key entry data set is a set of all record + fields (key fields and not key fields) and + 2) secondary index entry data is a union of its key fields and + primary key fields (at least InnoDB and its derivatives don't + duplicate primary key fields there, even if the primary and + the secondary keys have a common subset of key fields), + then secondary index entry data is always a subset of primary key + entry, and the PK is always longer. + Unfortunately, key_info[nr].key_length doesn't show the length + of key/pointer pair but a sum of key field lengths only, thus + we can't estimate index IO volume comparing only this key_length + value of seconday keys and clustered PK. + So, try secondary keys first, and choose PK only if there are no + usable secondary covering keys: + */ + if (nr == usable_clustered_pk) + continue; if (usable_keys->is_set(nr)) { if (table->key_info[nr].key_length < min_length) @@ -12925,7 +12988,7 @@ uint find_shortest_key(TABLE *table, const key_map *usable_keys) } } } - return best; + return best != MAX_KEY ? best : usable_clustered_pk; } /** @@ -13304,12 +13367,6 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, */ if (select_limit >= table_records) { - /* - filesort() and join cache are usually faster than reading in - index order and not using join cache - */ - if (tab->type == JT_ALL && tab->join->tables > tab->join->const_tables + 1) - DBUG_RETURN(0); keys= *table->file->keys_to_use_for_scanning(); keys.merge(table->covering_keys); @@ -13459,6 +13516,19 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, } } } + + /* + filesort() and join cache are usually faster than reading in + index order and not using join cache, except in case that chosen + index is clustered primary key. + */ + if ((select_limit >= table_records) && + (tab->type == JT_ALL && + tab->join->tables > tab->join->const_tables + 1) && + ((unsigned) best_key != table->s->primary_key || + !table->file->primary_key_is_clustered())) + DBUG_RETURN(0); + if (best_key >= 0) { bool quick_created= FALSE; @@ -15655,7 +15725,7 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab) Item_cond_and *cond=new Item_cond_and(); TABLE *table=join_tab->table; - int error; + int error= 0; if (!cond) DBUG_RETURN(TRUE); @@ -15673,7 +15743,8 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab) cond->fix_fields(thd, (Item**)&cond); if (join_tab->select) { - error=(int) cond->add(join_tab->select->cond); + if (join_tab->select->cond) + error=(int) cond->add(join_tab->select->cond); join_tab->select_cond=join_tab->select->cond=cond; } else if ((join_tab->select= make_select(join_tab->table, 0, 0, cond, 0, @@ -16916,7 +16987,17 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) first= 0; else str->append(','); - item->print_item_w_name(str, query_type); + + if (master_unit()->item && item->is_autogenerated_name) + { + /* + Do not print auto-generated aliases in subqueries. It has no purpose + in a view definition or other contexts where the query is printed. + */ + item->print(str, query_type); + } + else + item->print_item_w_name(str, query_type); } /* diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 989606300d8..cb60027842d 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1991,6 +1991,8 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) pthread_mutex_unlock(&mysys_var->mutex); /* INFO */ + /* Lock THD mutex that protects its data when looking at it. */ + pthread_mutex_lock(&tmp->LOCK_thd_data); if (tmp->query()) { table->field[7]->store(tmp->query(), @@ -1998,6 +2000,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) tmp->query_length()), cs); table->field[7]->set_notnull(); } + pthread_mutex_unlock(&tmp->LOCK_thd_data); if (schema_table_store_record(thd, table)) { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 871b2f2d552..ad72cab664e 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5566,6 +5566,45 @@ err: DBUG_RETURN(-1); } +/** + @brief Check if both DROP and CREATE are present for an index in ALTER TABLE + + @details Checks if any index is being modified (present as both DROP INDEX + and ADD INDEX) in the current ALTER TABLE statement. Needed for disabling + online ALTER TABLE. + + @param table The table being altered + @param alter_info The ALTER TABLE structure + @return presence of index being altered + @retval FALSE No such index + @retval TRUE Have at least 1 index modified +*/ + +static bool +is_index_maintenance_unique (TABLE *table, Alter_info *alter_info) +{ + List_iterator<Key> key_it(alter_info->key_list); + List_iterator<Alter_drop> drop_it(alter_info->drop_list); + Key *key; + + while ((key= key_it++)) + { + if (key->name) + { + Alter_drop *drop; + + drop_it.rewind(); + while ((drop= drop_it++)) + { + if (drop->type == Alter_drop::KEY && + !my_strcasecmp(system_charset_info, key->name, drop->name)) + return TRUE; + } + } + } + return FALSE; +} + /* SYNOPSIS @@ -5654,6 +5693,7 @@ compare_tables(TABLE *table, */ Alter_info tmp_alter_info(*alter_info, thd->mem_root); uint db_options= 0; /* not used */ + /* Create the prepared information. */ if (mysql_prepare_create_table(thd, create_info, &tmp_alter_info, @@ -6851,10 +6891,14 @@ view_err: */ new_db_type= create_info->db_type; + if (is_index_maintenance_unique (table, alter_info)) + need_copy_table= ALTER_TABLE_DATA_CHANGED; + if (mysql_prepare_alter_table(thd, table, create_info, alter_info)) goto err; - need_copy_table= alter_info->change_level; + if (need_copy_table == ALTER_TABLE_METADATA_ONLY) + need_copy_table= alter_info->change_level; set_table_default_charset(thd, create_info, db); @@ -7934,22 +7978,28 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, for (uint i= 0; i < t->s->fields; i++ ) { Field *f= t->field[i]; - enum_field_types field_type= f->type(); - /* - BLOB and VARCHAR have pointers in their field, we must convert - to string; GEOMETRY is implemented on top of BLOB. - */ - if ((field_type == MYSQL_TYPE_BLOB) || - (field_type == MYSQL_TYPE_VARCHAR) || - (field_type == MYSQL_TYPE_GEOMETRY)) - { - String tmp; - f->val_str(&tmp); - row_crc= my_checksum(row_crc, (uchar*) tmp.ptr(), tmp.length()); + + /* + BLOB and VARCHAR have pointers in their field, we must convert + to string; GEOMETRY is implemented on top of BLOB. + BIT may store its data among NULL bits, convert as well. + */ + switch (f->type()) { + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_GEOMETRY: + case MYSQL_TYPE_BIT: + { + String tmp; + f->val_str(&tmp); + row_crc= my_checksum(row_crc, (uchar*) tmp.ptr(), + tmp.length()); + break; + } + default: + row_crc= my_checksum(row_crc, f->ptr, f->pack_length()); + break; } - else - row_crc= my_checksum(row_crc, f->ptr, - f->pack_length()); } crc+= row_crc; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index c66990c54c6..5ec80dfb621 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -155,6 +155,35 @@ err: DBUG_RETURN(TRUE); } + +/** + Check if auto generated column names are conforming and + possibly generate a conforming name for them if not. + + @param item_list List of Items which should be checked +*/ + +static void make_valid_column_names(List<Item> &item_list) +{ + Item *item; + uint name_len; + List_iterator_fast<Item> it(item_list); + char buff[NAME_LEN]; + DBUG_ENTER("make_valid_column_names"); + + for (uint column_no= 1; (item= it++); column_no++) + { + if (!item->is_autogenerated_name || !check_column_name(item->name)) + continue; + name_len= my_snprintf(buff, NAME_LEN, "Name_exp_%u", column_no); + item->orig_name= item->name; + item->set_name(buff, name_len, system_charset_info); + } + + DBUG_VOID_RETURN; +} + + /* Fill defined view parts @@ -548,6 +577,9 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, } } + /* Check if the auto generated column names are conforming. */ + make_valid_column_names(select_lex->item_list); + if (check_duplicate_names(select_lex->item_list, 1)) { res= TRUE; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 37150bf835d..4f43ab8bebd 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -4596,7 +4596,7 @@ create_table_option: | TYPE_SYM opt_equal storage_engines { Lex->create_info.db_type= $3; - WARN_DEPRECATED(yythd, "5.4.4", "TYPE=storage_engine", + WARN_DEPRECATED(yythd, "6.0", "TYPE=storage_engine", "'ENGINE=storage_engine'"); Lex->create_info.used_fields|= HA_CREATE_USED_ENGINE; } @@ -8013,7 +8013,7 @@ function_call_generic: builder= find_native_function_builder(thd, $1); if (builder) { - item= builder->create(thd, $1, $4); + item= builder->create_func(thd, $1, $4); } else { @@ -8035,7 +8035,7 @@ function_call_generic: { builder= find_qualified_function_builder(thd); DBUG_ASSERT(builder); - item= builder->create(thd, $1, $4); + item= builder->create_func(thd, $1, $4); } } diff --git a/sql/table.cc b/sql/table.cc index 8758596d408..a4e2c59fb87 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -4023,9 +4023,7 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref, { DBUG_RETURN(field); } - Item *item= new Item_direct_view_ref(&view->view->select_lex.context, - field_ref, view->alias, - name); + Item *item= new Item_direct_view_ref(view, field_ref, name); DBUG_RETURN(item); } |