diff options
author | Igor Babaev <igor@askmonty.org> | 2012-08-29 18:50:38 -0700 |
---|---|---|
committer | Igor Babaev <igor@askmonty.org> | 2012-08-29 18:50:38 -0700 |
commit | 98f239a8494104743b4a7f2df5b8d7f310975689 (patch) | |
tree | 4beee747e184ab6b7d873d936e244397e4f8b49d /sql | |
parent | d0ad93fbc7eca575364e46f67c4613efb0807047 (diff) | |
parent | b45c551ee32d0d5260f4958abf93efab1a4614a2 (diff) | |
download | mariadb-git-98f239a8494104743b4a7f2df5b8d7f310975689.tar.gz |
Merge 5.5->5.5-mwl248.
Diffstat (limited to 'sql')
51 files changed, 664 insertions, 481 deletions
diff --git a/sql/create_options.cc b/sql/create_options.cc index 9a6f6b5cf7c..e4881388688 100644 --- a/sql/create_options.cc +++ b/sql/create_options.cc @@ -137,7 +137,10 @@ static bool set_one_value(ha_create_table_option *opt, my_option optp= { opt->name, 1, 0, (uchar **)val, 0, 0, GET_ULL, - REQUIRED_ARG, opt->def_value, opt->min_value, opt->max_value, + REQUIRED_ARG, + (longlong) opt->def_value, + (longlong) opt->min_value, + opt->max_value, 0, (long) opt->block_size, 0}; ulonglong orig_val= strtoull(value->str, NULL, 10); diff --git a/sql/filesort.cc b/sql/filesort.cc index 03379f2738a..04b223b7db0 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -103,6 +103,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, int error; ulong memory_available= thd->variables.sortbuff_size; ulong min_sort_memory; + ulong sort_buff_sz; uint maxbuffer; BUFFPEK *buffpek; ha_rows num_rows= HA_POS_ERROR; @@ -193,19 +194,21 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, goto err; min_sort_memory= max(MIN_SORT_MEMORY, param.sort_length * MERGEBUFF2); + set_if_bigger(min_sort_memory, sizeof(BUFFPEK*)*MERGEBUFF2); if (!table_sort.sort_keys) { while (memory_available >= min_sort_memory) { ulong keys= memory_available / (param.rec_length + sizeof(char*)); table_sort.keys= (uint) min(num_rows, keys); + sort_buff_sz= table_sort.keys*(param.rec_length+sizeof(char*)); + set_if_bigger(sort_buff_sz, param.rec_length * MERGEBUFF2); DBUG_EXECUTE_IF("make_sort_keys_alloc_fail", DBUG_SET("+d,simulate_out_of_memory");); if ((table_sort.sort_keys= - (uchar**) my_malloc(table_sort.keys*(param.rec_length+sizeof(char*)), - MYF(0)))) + (uchar**) my_malloc(sort_buff_sz, MYF(0)))) break; ulong old_memory_available= memory_available; memory_available= memory_available/4*3; @@ -1259,9 +1262,8 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file, to_start_filepos= my_b_tell(to_file); strpos= sort_buffer; org_max_rows=max_rows= param->max_rows; - - /* The following will fire if there is not enough space in sort_buffer */ - DBUG_ASSERT(maxcount!=0); + + set_if_bigger(maxcount, 1); if (unique_buff) { diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index f91e19df08e..59b9d6eab6b 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -1295,7 +1295,9 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share, DBUG_RETURN(0); } - char tmp_buf2[FN_REFLEN]; + char tmp_buf2_mem[FN_REFLEN]; + String tmp_buf2(tmp_buf2_mem, sizeof(tmp_buf2_mem), system_charset_info); + tmp_buf2.length(0); const char *type_str; switch (type) { @@ -1304,17 +1306,24 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share, if (thd->lex->sql_command == SQLCOM_DROP_DB) DBUG_RETURN(0); /* redo the drop table query as is may contain several tables */ - query= tmp_buf2; - query_length= (uint) (strxmov(tmp_buf2, "drop table `", - table_name, "`", NullS) - tmp_buf2); + tmp_buf2.append(STRING_WITH_LEN("drop table ")); + append_identifier(thd, &tmp_buf2, table_name, strlen(table_name)); + query= tmp_buf2.c_ptr_safe(); + query_length= tmp_buf2.length(); type_str= "drop table"; break; case SOT_RENAME_TABLE: /* redo the rename table query as is may contain several tables */ - query= tmp_buf2; - query_length= (uint) (strxmov(tmp_buf2, "rename table `", - db, ".", table_name, "` to `", - new_db, ".", new_table_name, "`", NullS) - tmp_buf2); + tmp_buf2.append(STRING_WITH_LEN("rename table ")); + append_identifier(thd, &tmp_buf2, db, strlen(db)); + tmp_buf2.append(STRING_WITH_LEN(".")); + append_identifier(thd, &tmp_buf2, table_name, strlen(table_name)); + tmp_buf2.append(STRING_WITH_LEN(" to ")); + append_identifier(thd, &tmp_buf2, new_db, strlen(new_db)); + tmp_buf2.append(STRING_WITH_LEN(".")); + append_identifier(thd, &tmp_buf2, new_table_name, strlen(new_table_name)); + query= tmp_buf2.c_ptr_safe(); + query_length= tmp_buf2.length(); type_str= "rename table"; break; case SOT_CREATE_TABLE: diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 0d2b4387327..b3f97d35033 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -3837,7 +3837,7 @@ int ha_partition::truncate_partition(Alter_info *alter_info, bool *binlog_stmt) { List_iterator<partition_element> subpart_it(part_elem->subpartitions); - partition_element *sub_elem; + partition_element *sub_elem __attribute__((unused)); uint j= 0, part; do { diff --git a/sql/handler.cc b/sql/handler.cc index b5c9716bbbf..58d37532796 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3009,7 +3009,7 @@ void handler::print_error(int error, myf errflag) textno=ER_TABLE_DEF_CHANGED; break; case HA_ERR_NO_SUCH_TABLE: - my_error(ER_NO_SUCH_TABLE, errflag, table_share->db.str, + my_error(ER_NO_SUCH_TABLE_IN_ENGINE, errflag, table_share->db.str, table_share->table_name.str); DBUG_VOID_RETURN; case HA_ERR_RBR_LOGGING_FAILED: @@ -4800,10 +4800,14 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat) db_type->show_status(db_type, thd, stat_print, stat) ? 1 : 0; } - if (!result) + /* + We also check thd->is_error() as Innodb may return 0 even if + there was an error. + */ + if (!result && !thd->is_error()) my_eof(thd); else if (!thd->is_error()) - my_error(ER_GET_ERRNO, MYF(0), 0); + my_error(ER_GET_ERRNO, MYF(0), errno); return result; } diff --git a/sql/item.cc b/sql/item.cc index eac33041797..ac54e1925b7 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -992,15 +992,31 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs) if (!my_charset_same(cs, system_charset_info)) { size_t res_length; - name= sql_strmake_with_convert(str, name_length= length, cs, + name= sql_strmake_with_convert(str, length, cs, MAX_ALIAS_NAME, system_charset_info, &res_length); + name_length= res_length; } else name= sql_strmake(str, (name_length= min(length,MAX_ALIAS_NAME))); } +void Item::set_name_no_truncate(const char *str, uint length, CHARSET_INFO *cs) +{ + if (!my_charset_same(cs, system_charset_info)) + { + size_t res_length; + name= sql_strmake_with_convert(str, length, cs, + UINT_MAX, system_charset_info, + &res_length); + name_length= res_length; + } + else + name= sql_strmake(str, (name_length= length)); +} + + void Item::set_name_for_rollback(THD *thd, const char *str, uint length, CHARSET_INFO *cs) { diff --git a/sql/item.h b/sql/item.h index f7f3edda384..8855996b76c 100644 --- a/sql/item.h +++ b/sql/item.h @@ -656,6 +656,7 @@ public: #endif } /*lint -e1509 */ void set_name(const char *str, uint length, CHARSET_INFO *cs); + void set_name_no_truncate(const char *str, uint length, CHARSET_INFO *cs); void set_name_for_rollback(THD *thd, const char *str, uint length, CHARSET_INFO *cs); void rename(char *new_name); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 8cfbcb97144..d950c0c1443 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -3089,6 +3089,15 @@ void Item_func_case::fix_length_and_dec() return; } } + /* + Set cmp_context of all WHEN arguments. This prevents + Item_field::equal_fields_propagator() from transforming a + zerofill argument into a string constant. Such a change would + require rebuilding cmp_items. + */ + for (i= 0; i < ncases; i+= 2) + args[i]->cmp_context= item_cmp_type(left_result_type, + args[i]->result_type()); } if (else_expr_num == -1 || args[else_expr_num]->maybe_null) @@ -4069,6 +4078,16 @@ void Item_func_in::fix_length_and_dec() } } } + /* + Set cmp_context of all arguments. This prevents + Item_field::equal_fields_propagator() from transforming a zerofill integer + argument into a string constant. Such a change would require rebuilding + cmp_itmes. + */ + for (arg= args + 1, arg_end= args + arg_count; arg != arg_end ; arg++) + { + arg[0]->cmp_context= item_cmp_type(left_result_type, arg[0]->result_type()); + } max_length= 1; } diff --git a/sql/item_func.cc b/sql/item_func.cc index d65f13931e2..7a7cdd4ba02 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -5443,10 +5443,10 @@ my_decimal* Item_user_var_as_out_param::val_decimal(my_decimal *decimal_buffer) } -void Item_user_var_as_out_param::print(String *str, enum_query_type query_type) +void Item_user_var_as_out_param::print_for_load(THD *thd, String *str) { str->append('@'); - str->append(name.str,name.length); + append_identifier(thd, str, name.str, name.length); } diff --git a/sql/item_func.h b/sql/item_func.h index cb9c1929d7d..111479c8e52 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1670,7 +1670,7 @@ public: my_decimal *val_decimal(my_decimal *decimal_buffer); /* fix_fields() binds variable name with its entry structure */ bool fix_fields(THD *thd, Item **ref); - virtual void print(String *str, enum_query_type query_type); + void print_for_load(THD *thd, String *str); void set_null_value(CHARSET_INFO* cs); void set_value(const char *str, uint length, CHARSET_INFO* cs); }; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 49d232d31be..8bb4e7af00f 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -819,7 +819,9 @@ table_map Item_subselect::used_tables() const bool Item_subselect::const_item() const { - return thd->lex->context_analysis_only ? FALSE : const_item_cache; + return (thd->lex->context_analysis_only ? + FALSE : + forced_const || const_item_cache); } Item *Item_subselect::get_tmp_table_item(THD *thd_arg) @@ -1272,7 +1274,7 @@ bool Item_singlerow_subselect::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate) else { reset(); - return 0; + return 1; } } @@ -1538,6 +1540,10 @@ double Item_in_subselect::val_real() */ DBUG_ASSERT(0); DBUG_ASSERT(fixed == 1); + if (forced_const) + return value; + DBUG_ASSERT((engine->uncacheable() & ~UNCACHEABLE_EXPLAIN) || + ! engine->is_executed()); null_value= was_null= FALSE; if (exec()) { @@ -1558,6 +1564,10 @@ longlong Item_in_subselect::val_int() */ DBUG_ASSERT(0); DBUG_ASSERT(fixed == 1); + if (forced_const) + return value; + DBUG_ASSERT((engine->uncacheable() & ~UNCACHEABLE_EXPLAIN) || + ! engine->is_executed()); null_value= was_null= FALSE; if (exec()) { @@ -1578,6 +1588,10 @@ String *Item_in_subselect::val_str(String *str) */ DBUG_ASSERT(0); DBUG_ASSERT(fixed == 1); + if (forced_const) + goto value_is_ready; + DBUG_ASSERT((engine->uncacheable() & ~UNCACHEABLE_EXPLAIN) || + ! engine->is_executed()); null_value= was_null= FALSE; if (exec()) { @@ -1589,6 +1603,7 @@ String *Item_in_subselect::val_str(String *str) null_value= TRUE; return 0; } +value_is_ready: str->set((ulonglong)value, &my_charset_bin); return str; } @@ -1599,6 +1614,8 @@ bool Item_in_subselect::val_bool() DBUG_ASSERT(fixed == 1); if (forced_const) return value; + DBUG_ASSERT((engine->uncacheable() & ~UNCACHEABLE_EXPLAIN) || + ! engine->is_executed()); null_value= was_null= FALSE; if (exec()) { @@ -1617,6 +1634,10 @@ my_decimal *Item_in_subselect::val_decimal(my_decimal *decimal_value) method should not be used */ DBUG_ASSERT(0); + if (forced_const) + goto value_is_ready; + DBUG_ASSERT((engine->uncacheable() & ~UNCACHEABLE_EXPLAIN) || + ! engine->is_executed()); null_value= was_null= FALSE; DBUG_ASSERT(fixed == 1); if (exec()) @@ -1626,6 +1647,7 @@ my_decimal *Item_in_subselect::val_decimal(my_decimal *decimal_value) } if (was_null && !value) null_value= TRUE; +value_is_ready: int2my_decimal(E_DEC_FATAL_ERROR, value, 0, decimal_value); return decimal_value; } @@ -3176,6 +3198,8 @@ int subselect_single_select_engine::exec() tab->read_record.read_record= tab->save_read_record; } executed= 1; + if (!(uncacheable() & ~UNCACHEABLE_EXPLAIN)) + item->make_const(); thd->where= save_where; thd->lex->current_select= save_select; DBUG_RETURN(join->error || thd->is_fatal_error || thd->is_error()); @@ -5167,10 +5191,20 @@ Ordered_key::cmp_keys_by_row_data(ha_rows a, ha_rows b) rowid_a= row_num_to_rowid + a * rowid_length; rowid_b= row_num_to_rowid + b * rowid_length; /* Fetch the rows for comparison. */ - error= tbl->file->ha_rnd_pos(tbl->record[0], rowid_a); - DBUG_ASSERT(!error); - error= tbl->file->ha_rnd_pos(tbl->record[1], rowid_b); - DBUG_ASSERT(!error); + if ((error= tbl->file->ha_rnd_pos(tbl->record[0], rowid_a))) + { + /* purecov: begin inspected */ + tbl->file->print_error(error, MYF(ME_FATALERROR)); // Sets fatal_error + return 0; + /* purecov: end */ + } + if ((error= tbl->file->ha_rnd_pos(tbl->record[1], rowid_b))) + { + /* purecov: begin inspected */ + tbl->file->print_error(error, MYF(ME_FATALERROR)); // Sets fatal_error + return 0; + /* purecov: end */ + } /* Compare the two rows by the corresponding values of the indexed columns. @@ -5245,8 +5279,13 @@ int Ordered_key::cmp_key_with_search_key(rownum_t row_num) uchar *cur_rowid= row_num_to_rowid + row_num * rowid_length; int error, cmp_res; - error= tbl->file->ha_rnd_pos(tbl->record[0], cur_rowid); - DBUG_ASSERT(!error); + if ((error= tbl->file->ha_rnd_pos(tbl->record[0], cur_rowid))) + { + /* purecov: begin inspected */ + tbl->file->print_error(error, MYF(ME_FATALERROR)); // Sets fatal_error + return 0; + /* purecov: end */ + } for (uint i= 0; i < key_column_count; i++) { diff --git a/sql/log.cc b/sql/log.cc index 9cb85ab4b2b..56c07f81c9e 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -52,6 +52,7 @@ #include "sql_plugin.h" #include "rpl_handler.h" #include "debug_sync.h" +#include "sql_show.h" /* max size of the log message */ #define MAX_LOG_BUFFER_SIZE 1024 @@ -2073,9 +2074,8 @@ static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv) String log_query; if (log_query.append(STRING_WITH_LEN("SAVEPOINT ")) || - log_query.append("`") || - log_query.append(thd->lex->ident.str, thd->lex->ident.length) || - log_query.append("`")) + append_identifier(thd, &log_query, + thd->lex->ident.str, thd->lex->ident.length)) DBUG_RETURN(1); int errcode= query_error_code(thd, thd->killed == NOT_KILLED); Query_log_event qinfo(thd, log_query.ptr(), log_query.length(), @@ -2097,9 +2097,8 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) { String log_query; if (log_query.append(STRING_WITH_LEN("ROLLBACK TO ")) || - log_query.append("`") || - log_query.append(thd->lex->ident.str, thd->lex->ident.length) || - log_query.append("`")) + append_identifier(thd, &log_query, + thd->lex->ident.str, thd->lex->ident.length)) DBUG_RETURN(1); int errcode= query_error_code(thd, thd->killed == NOT_KILLED); Query_log_event qinfo(thd, log_query.ptr(), log_query.length(), diff --git a/sql/log.h b/sql/log.h index 88352de5418..9b9bed1262a 100644 --- a/sql/log.h +++ b/sql/log.h @@ -863,7 +863,7 @@ int query_error_code(THD *thd, bool not_killed); uint purge_log_get_error_code(int res); int vprint_msg_to_log(enum loglevel level, const char *format, va_list args); -void sql_print_error(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2); +void sql_print_error(const char *format, ...); void sql_print_warning(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2); void sql_print_information(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2); diff --git a/sql/log_event.cc b/sql/log_event.cc index 6ef5a68e768..dca9091e03d 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -46,6 +46,7 @@ #include "rpl_record.h" #include "transaction.h" #include <my_dir.h> +#include "sql_show.h" #endif /* MYSQL_CLIENT */ @@ -471,29 +472,28 @@ inline bool unexpected_error_code(int unexpected_error) pretty_print_str() */ -static char *pretty_print_str(char *packet, const char *str, int len) +static void +pretty_print_str(String *packet, const char *str, int len) { const char *end= str + len; - char *pos= packet; - *pos++= '\''; + packet->append(STRING_WITH_LEN("'")); while (str < end) { char c; switch ((c=*str++)) { - case '\n': *pos++= '\\'; *pos++= 'n'; break; - case '\r': *pos++= '\\'; *pos++= 'r'; break; - case '\\': *pos++= '\\'; *pos++= '\\'; break; - case '\b': *pos++= '\\'; *pos++= 'b'; break; - case '\t': *pos++= '\\'; *pos++= 't'; break; - case '\'': *pos++= '\\'; *pos++= '\''; break; - case 0 : *pos++= '\\'; *pos++= '0'; break; + case '\n': packet->append(STRING_WITH_LEN("\\n")); break; + case '\r': packet->append(STRING_WITH_LEN("\\r")); break; + case '\\': packet->append(STRING_WITH_LEN("\\\\")); break; + case '\b': packet->append(STRING_WITH_LEN("\\b")); break; + case '\t': packet->append(STRING_WITH_LEN("\\t")); break; + case '\'': packet->append(STRING_WITH_LEN("\\'")); break; + case 0 : packet->append(STRING_WITH_LEN("\\0")); break; default: - *pos++= c; + packet->append(&c, 1); break; } } - *pos++= '\''; - return pos; + packet->append(STRING_WITH_LEN("'")); } #endif /* !MYSQL_CLIENT */ @@ -926,7 +926,7 @@ Log_event::do_shall_skip(Relay_log_info *rli) Log_event::pack_info() */ -void Log_event::pack_info(Protocol *protocol) +void Log_event::pack_info(THD *thd, Protocol *protocol) { protocol->store("", &my_charset_bin); } @@ -935,7 +935,8 @@ void Log_event::pack_info(Protocol *protocol) /** Only called by SHOW BINLOG EVENTS */ -int Log_event::net_send(Protocol *protocol, const char* log_name, my_off_t pos) +int Log_event::net_send(THD *thd, Protocol *protocol, const char* log_name, + my_off_t pos) { const char *p= strrchr(log_name, FN_LIBCHAR); const char *event_type; @@ -949,7 +950,7 @@ int Log_event::net_send(Protocol *protocol, const char* log_name, my_off_t pos) protocol->store(event_type, strlen(event_type), &my_charset_bin); protocol->store((uint32) server_id); protocol->store((ulonglong) log_pos); - pack_info(protocol); + pack_info(thd, protocol); return protocol->write(); } #endif /* HAVE_REPLICATION */ @@ -2448,27 +2449,22 @@ Log_event::continue_group(Relay_log_info *rli) show the catalog ?? */ -void Query_log_event::pack_info(Protocol *protocol) +void Query_log_event::pack_info(THD *thd, Protocol *protocol) { // TODO: show the catalog ?? - char *buf, *pos; - if (!(buf= (char*) my_malloc(9 + db_len + q_len, MYF(MY_WME)))) - return; - pos= buf; + char buf_mem[1024]; + String buf(buf_mem, sizeof(buf_mem), system_charset_info); + buf.real_alloc(9 + db_len + q_len); if (!(flags & LOG_EVENT_SUPPRESS_USE_F) && db && db_len) { - pos= strmov(buf, "use `"); - memcpy(pos, db, db_len); - pos= strmov(pos+db_len, "`; "); + buf.append(STRING_WITH_LEN("use ")); + append_identifier(thd, &buf, db, db_len); + buf.append("; "); } if (query && q_len) - { - memcpy(pos, query, q_len); - pos+= q_len; - } - protocol->store(buf, pos-buf, &my_charset_bin); - my_free(buf); + buf.append(query, q_len); + protocol->store(&buf); } #endif @@ -3334,11 +3330,17 @@ void Query_log_event::print_query_header(IO_CACHE* file, } else if (db) { + /* Room for expand ` to `` + initial/final ` + \0 */ + char buf[FN_REFLEN*2+3]; + different_db= memcmp(print_event_info->db, db, db_len + 1); if (different_db) memcpy(print_event_info->db, db, db_len + 1); if (db[0] && different_db) - my_b_printf(file, "use %s%s\n", db, print_event_info->delimiter); + { + my_snprintf(buf, sizeof(buf), "%`s", db); + my_b_printf(file, "use %s%s\n", buf, print_event_info->delimiter); + } } end=int10_to_str((long) when, strmov(buff,"SET TIMESTAMP="),10); @@ -3534,6 +3536,7 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, LEX_STRING new_db; int expected_error,actual_error= 0; HA_CREATE_INFO db_options; + DBUG_ENTER("Query_log_event::do_apply_event"); /* Colleagues: please never free(thd->catalog) in MySQL. This would @@ -3929,7 +3932,7 @@ end: thd->first_successful_insert_id_in_prev_stmt= 0; thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0; free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC)); - return thd->is_slave_error; + DBUG_RETURN(thd->is_slave_error); } int Query_log_event::do_update_pos(Relay_log_info *rli) @@ -4002,7 +4005,7 @@ Start_log_event_v3::Start_log_event_v3() */ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -void Start_log_event_v3::pack_info(Protocol *protocol) +void Start_log_event_v3::pack_info(THD *thd, Protocol *protocol) { char buf[12 + ST_SERVER_VER_LEN + 14 + 22], *pos; pos= strmov(buf, "Server ver: "); @@ -4778,131 +4781,113 @@ uint8 get_checksum_alg(const char* buf, ulong len) */ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -uint Load_log_event::get_query_buffer_length() -{ - return - 5 + db_len + 3 + // "use DB; " - 18 + fname_len + 2 + // "LOAD DATA INFILE 'file''" - 11 + // "CONCURRENT " - 7 + // LOCAL - 9 + // " REPLACE or IGNORE " - 13 + table_name_len*2 + // "INTO TABLE `table`" - 21 + sql_ex.field_term_len*4 + 2 + // " FIELDS TERMINATED BY 'str'" - 23 + sql_ex.enclosed_len*4 + 2 + // " OPTIONALLY ENCLOSED BY 'str'" - 12 + sql_ex.escaped_len*4 + 2 + // " ESCAPED BY 'str'" - 21 + sql_ex.line_term_len*4 + 2 + // " LINES TERMINATED BY 'str'" - 19 + sql_ex.line_start_len*4 + 2 + // " LINES STARTING BY 'str'" - 15 + 22 + // " IGNORE xxx LINES" - 3 + (num_fields-1)*2 + field_block_len; // " (field1, field2, ...)" -} - - -void Load_log_event::print_query(bool need_db, const char *cs, char *buf, - char **end, char **fn_start, char **fn_end) +void Load_log_event::print_query(THD *thd, bool need_db, const char *cs, + String *buf, my_off_t *fn_start, + my_off_t *fn_end, const char *qualify_db) { - char *pos= buf; - if (need_db && db && db_len) { - pos= strmov(pos, "use `"); - memcpy(pos, db, db_len); - pos= strmov(pos+db_len, "`; "); + buf->append(STRING_WITH_LEN("use ")); + append_identifier(thd, buf, db, db_len); + buf->append(STRING_WITH_LEN("; ")); } - pos= strmov(pos, "LOAD DATA "); + buf->append(STRING_WITH_LEN("LOAD DATA ")); if (is_concurrent) - pos= strmov(pos, "CONCURRENT "); + buf->append(STRING_WITH_LEN("CONCURRENT ")); if (fn_start) - *fn_start= pos; + *fn_start= buf->length(); if (check_fname_outside_temp_buf()) - pos= strmov(pos, "LOCAL "); - pos= strmov(pos, "INFILE '"); - memcpy(pos, fname, fname_len); - pos= strmov(pos+fname_len, "' "); + buf->append(STRING_WITH_LEN("LOCAL ")); + buf->append(STRING_WITH_LEN("INFILE '")); + buf->append_for_single_quote(fname, fname_len); + buf->append(STRING_WITH_LEN("' ")); if (sql_ex.opt_flags & REPLACE_FLAG) - pos= strmov(pos, "REPLACE "); + buf->append(STRING_WITH_LEN("REPLACE ")); else if (sql_ex.opt_flags & IGNORE_FLAG) - pos= strmov(pos, "IGNORE "); + buf->append(STRING_WITH_LEN("IGNORE ")); - pos= strmov(pos ,"INTO"); + buf->append(STRING_WITH_LEN("INTO")); if (fn_end) - *fn_end= pos; + *fn_end= buf->length(); - pos= strmov(pos ," TABLE `"); - memcpy(pos, table_name, table_name_len); - pos+= table_name_len; + buf->append(STRING_WITH_LEN(" TABLE ")); + if (qualify_db) + { + append_identifier(thd, buf, qualify_db, strlen(qualify_db)); + buf->append(STRING_WITH_LEN(".")); + } + append_identifier(thd, buf, table_name, table_name_len); if (cs != NULL) { - pos= strmov(pos ,"` CHARACTER SET "); - pos= strmov(pos , cs); + buf->append(STRING_WITH_LEN(" CHARACTER SET ")); + buf->append(cs, strlen(cs)); } - else - pos= strmov(pos, "`"); /* We have to create all optional fields as the default is not empty */ - pos= strmov(pos, " FIELDS TERMINATED BY "); - pos= pretty_print_str(pos, sql_ex.field_term, sql_ex.field_term_len); + buf->append(STRING_WITH_LEN(" FIELDS TERMINATED BY ")); + pretty_print_str(buf, sql_ex.field_term, sql_ex.field_term_len); if (sql_ex.opt_flags & OPT_ENCLOSED_FLAG) - pos= strmov(pos, " OPTIONALLY "); - pos= strmov(pos, " ENCLOSED BY "); - pos= pretty_print_str(pos, sql_ex.enclosed, sql_ex.enclosed_len); + buf->append(STRING_WITH_LEN(" OPTIONALLY ")); + buf->append(STRING_WITH_LEN(" ENCLOSED BY ")); + pretty_print_str(buf, sql_ex.enclosed, sql_ex.enclosed_len); - pos= strmov(pos, " ESCAPED BY "); - pos= pretty_print_str(pos, sql_ex.escaped, sql_ex.escaped_len); + buf->append(STRING_WITH_LEN(" ESCAPED BY ")); + pretty_print_str(buf, sql_ex.escaped, sql_ex.escaped_len); - pos= strmov(pos, " LINES TERMINATED BY "); - pos= pretty_print_str(pos, sql_ex.line_term, sql_ex.line_term_len); + buf->append(STRING_WITH_LEN(" LINES TERMINATED BY ")); + pretty_print_str(buf, sql_ex.line_term, sql_ex.line_term_len); if (sql_ex.line_start_len) { - pos= strmov(pos, " STARTING BY "); - pos= pretty_print_str(pos, sql_ex.line_start, sql_ex.line_start_len); + buf->append(STRING_WITH_LEN(" STARTING BY ")); + pretty_print_str(buf, sql_ex.line_start, sql_ex.line_start_len); } if ((long) skip_lines > 0) { - pos= strmov(pos, " IGNORE "); - pos= longlong10_to_str((longlong) skip_lines, pos, 10); - pos= strmov(pos," LINES "); + buf->append(STRING_WITH_LEN(" IGNORE ")); + buf->append_ulonglong(skip_lines); + buf->append(STRING_WITH_LEN(" LINES ")); } if (num_fields) { uint i; const char *field= fields; - pos= strmov(pos, " ("); + buf->append(STRING_WITH_LEN(" (")); for (i = 0; i < num_fields; i++) { if (i) { - *pos++= ' '; - *pos++= ','; + /* + Yes, the space and comma is reversed here. But this is mostly dead + code, at most used when reading really old binlogs from old servers, + so better just leave it as is... + */ + buf->append(STRING_WITH_LEN(" ,")); } - memcpy(pos, field, field_lens[i]); - pos+= field_lens[i]; + append_identifier(thd, buf, field, field_lens[i]); field+= field_lens[i] + 1; } - *pos++= ')'; + buf->append(STRING_WITH_LEN(")")); } - - *end= pos; } -void Load_log_event::pack_info(Protocol *protocol) +void Load_log_event::pack_info(THD *thd, Protocol *protocol) { - char *buf, *end; + char query_buffer[1024]; + String query_str(query_buffer, sizeof(query_buffer), system_charset_info); - if (!(buf= (char*) my_malloc(get_query_buffer_length(), MYF(MY_WME)))) - return; - print_query(TRUE, NULL, buf, &end, 0, 0); - protocol->store(buf, end-buf, &my_charset_bin); - my_free(buf); + query_str.length(0); + print_query(thd, TRUE, NULL, &query_str, 0, 0, NULL); + protocol->store(query_str.ptr(), query_str.length(), &my_charset_bin); } #endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ @@ -5284,6 +5269,8 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli, bool use_rli_only_for_errors) { LEX_STRING new_db; + DBUG_ENTER("Load_log_event::do_apply_event"); + new_db.length= db_len; new_db.str= (char *) rpl_filter->get_rewrite_db(db, &new_db.length); thd->set_db(new_db.str, new_db.length); @@ -5358,16 +5345,20 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli, else { char llbuff[22]; - char *end; enum enum_duplicates handle_dup; bool ignore= 0; + char query_buffer[1024]; + String query_str(query_buffer, sizeof(query_buffer), system_charset_info); char *load_data_query; + query_str.length(0); /* Forge LOAD DATA INFILE query which will be used in SHOW PROCESS LIST and written to slave's binlog if binlogging is on. */ - if (!(load_data_query= (char *)thd->alloc(get_query_buffer_length() + 1))) + print_query(thd, FALSE, NULL, &query_str, NULL, NULL, NULL); + if (!(load_data_query= (char *)thd->strmake(query_str.ptr(), + query_str.length()))) { /* This will set thd->fatal_error in case of OOM. So we surely will notice @@ -5376,9 +5367,7 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli, goto error; } - print_query(FALSE, NULL, load_data_query, &end, NULL, NULL); - *end= 0; - thd->set_query(load_data_query, (uint) (end - load_data_query)); + thd->set_query(load_data_query, (uint) (query_str.length())); if (sql_ex.opt_flags & REPLACE_FLAG) handle_dup= DUP_REPLACE; @@ -5524,7 +5513,7 @@ error: Error '%s' running LOAD DATA INFILE on table '%s'. Default database: '%s'", err, (char*)table_name, print_slave_db_safe(remember_db)); free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC)); - return 1; + DBUG_RETURN(1); } free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC)); @@ -5539,10 +5528,10 @@ Error '%s' running LOAD DATA INFILE on table '%s'. Default database: '%s'", rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, ER(ER_SLAVE_FATAL_ERROR), buf); - return 1; + DBUG_RETURN(1); } - return ( use_rli_only_for_errors ? 0 : Log_event::do_apply_event(rli) ); + DBUG_RETURN( use_rli_only_for_errors ? 0 : Log_event::do_apply_event(rli) ); } #endif @@ -5556,7 +5545,7 @@ Error '%s' running LOAD DATA INFILE on table '%s'. Default database: '%s'", */ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -void Rotate_log_event::pack_info(Protocol *protocol) +void Rotate_log_event::pack_info(THD *thd, Protocol *protocol) { char buf1[256], buf[22]; String tmp(buf1, sizeof(buf1), log_cs); @@ -5774,7 +5763,7 @@ Rotate_log_event::do_shall_skip(Relay_log_info *rli) */ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -void Intvar_log_event::pack_info(Protocol *protocol) +void Intvar_log_event::pack_info(THD *thd, Protocol *protocol) { char buf[256], *pos; pos= strmake(buf, get_var_type_name(), sizeof(buf)-23); @@ -5928,7 +5917,7 @@ Intvar_log_event::do_shall_skip(Relay_log_info *rli) **************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -void Rand_log_event::pack_info(Protocol *protocol) +void Rand_log_event::pack_info(THD *thd, Protocol *protocol) { char buf1[256], *pos; pos= strmov(buf1,"rand_seed1="); @@ -6053,7 +6042,7 @@ bool slave_execute_deferred_events(THD *thd) **************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -void Xid_log_event::pack_info(Protocol *protocol) +void Xid_log_event::pack_info(THD *thd, Protocol *protocol) { char buf[128], *pos; pos= strmov(buf, "COMMIT /* xid="); @@ -6150,84 +6139,117 @@ Xid_log_event::do_shall_skip(Relay_log_info *rli) **************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -void User_var_log_event::pack_info(Protocol* protocol) +static bool +user_var_append_name_part(THD *thd, String *buf, + const char *name, size_t name_len) { - char *buf= 0; - uint val_offset= 4 + name_len; - uint event_len= val_offset; + return buf->append("@") || + append_identifier(thd, buf, name, name_len) || + buf->append("="); +} +void User_var_log_event::pack_info(THD *thd, Protocol* protocol) +{ if (is_null) { - if (!(buf= (char*) my_malloc(val_offset + 5, MYF(MY_WME)))) + char buf_mem[FN_REFLEN+7]; + String buf(buf_mem, sizeof(buf_mem), system_charset_info); + buf.length(0); + if (user_var_append_name_part(thd, &buf, name, name_len) || + buf.append("NULL")) return; - strmov(buf + val_offset, "NULL"); - event_len= val_offset + 4; + protocol->store(buf.ptr(), buf.length(), &my_charset_bin); } else { switch (type) { case REAL_RESULT: + { double real_val; + char buf2[MY_GCVT_MAX_FIELD_WIDTH+1]; + char buf_mem[FN_REFLEN + MY_GCVT_MAX_FIELD_WIDTH + 1]; + String buf(buf_mem, sizeof(buf_mem), system_charset_info); float8get(real_val, val); - if (!(buf= (char*) my_malloc(val_offset + MY_GCVT_MAX_FIELD_WIDTH + 1, - MYF(MY_WME)))) + buf.length(0); + if (user_var_append_name_part(thd, &buf, name, name_len) || + buf.append(buf2, my_gcvt(real_val, MY_GCVT_ARG_DOUBLE, + MY_GCVT_MAX_FIELD_WIDTH, buf2, NULL))) return; - event_len+= my_gcvt(real_val, MY_GCVT_ARG_DOUBLE, MY_GCVT_MAX_FIELD_WIDTH, - buf + val_offset, NULL); + protocol->store(buf.ptr(), buf.length(), &my_charset_bin); break; + } case INT_RESULT: - if (!(buf= (char*) my_malloc(val_offset + 22, MYF(MY_WME)))) + { + char buf2[22]; + char buf_mem[FN_REFLEN + 22]; + String buf(buf_mem, sizeof(buf_mem), system_charset_info); + buf.length(0); + if (user_var_append_name_part(thd, &buf, name, name_len) || + buf.append(buf2, + longlong10_to_str(uint8korr(val), buf2, + ((flags & User_var_log_event::UNSIGNED_F) ? 10 : -10))-buf2)) return; - event_len= longlong10_to_str(uint8korr(val), buf + val_offset, - ((flags & User_var_log_event::UNSIGNED_F) ? - 10 : -10))-buf; + protocol->store(buf.ptr(), buf.length(), &my_charset_bin); break; + } case DECIMAL_RESULT: { - if (!(buf= (char*) my_malloc(val_offset + DECIMAL_MAX_STR_LENGTH, - MYF(MY_WME)))) - return; - String str(buf+val_offset, DECIMAL_MAX_STR_LENGTH, &my_charset_bin); + char buf_mem[FN_REFLEN + DECIMAL_MAX_STR_LENGTH]; + String buf(buf_mem, sizeof(buf_mem), system_charset_info); + char buf2[DECIMAL_MAX_STR_LENGTH+1]; + String str(buf2, sizeof(buf2), &my_charset_bin); my_decimal dec; + buf.length(0); binary2my_decimal(E_DEC_FATAL_ERROR, (uchar*) (val+2), &dec, val[0], val[1]); my_decimal2string(E_DEC_FATAL_ERROR, &dec, 0, 0, 0, &str); - event_len= str.length() + val_offset; + if (user_var_append_name_part(thd, &buf, name, name_len) || + buf.append(buf2)) + return; + protocol->store(buf.ptr(), buf.length(), &my_charset_bin); break; - } + } case STRING_RESULT: + { /* 15 is for 'COLLATE' and other chars */ - buf= (char*) my_malloc(event_len+val_len*2+1+2*MY_CS_NAME_SIZE+15, - MYF(MY_WME)); + char buf_mem[FN_REFLEN + 512 + 1 + 2*MY_CS_NAME_SIZE+15]; + String buf(buf_mem, sizeof(buf_mem), system_charset_info); CHARSET_INFO *cs; - if (!buf) - return; + buf.length(0); if (!(cs= get_charset(charset_number, MYF(0)))) { - strmov(buf+val_offset, "???"); - event_len+= 3; + if (buf.append("???")) + return; } else { - char *p= strxmov(buf + val_offset, "_", cs->csname, " ", NullS); - p= str_to_hex(p, val, val_len); - p= strxmov(p, " COLLATE ", cs->name, NullS); - event_len= p-buf; + size_t old_len; + char *beg, *end; + if (user_var_append_name_part(thd, &buf, name, name_len) || + buf.append("_") || + buf.append(cs->csname) || + buf.append(" ")) + return; + old_len= buf.length(); + if (buf.reserve(old_len + val_len*2 + 2 + sizeof(" COLLATE ") + + MY_CS_NAME_SIZE)) + return; + beg= const_cast<char *>(buf.ptr()) + old_len; + end= str_to_hex(beg, val, val_len); + buf.length(old_len + (end - beg)); + if (buf.append(" COLLATE ") || + buf.append(cs->name)) + return; } + protocol->store(buf.ptr(), buf.length(), &my_charset_bin); break; + } case ROW_RESULT: default: DBUG_ASSERT(0); return; } } - buf[0]= '@'; - buf[1]= '`'; - memcpy(buf+2, name, name_len); - buf[2+name_len]= '`'; - buf[3+name_len]= '='; - protocol->store(buf, event_len, &my_charset_bin); - my_free(buf); } #endif /* !MYSQL_CLIENT */ @@ -6385,9 +6407,8 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) my_b_printf(&cache, "\tUser_var\n"); } - my_b_printf(&cache, "SET @`"); - my_b_write(&cache, (uchar*) name, (uint) (name_len)); - my_b_printf(&cache, "`"); + my_b_printf(&cache, "SET @"); + my_b_write_backtick_quote(&cache, name, name_len); if (is_null) { @@ -6486,15 +6507,16 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli) { Item *it= 0; CHARSET_INFO *charset; + DBUG_ENTER("User_var_log_event::do_apply_event"); if (rli->deferred_events_collecting) { set_deferred(); - return rli->deferred_events->add(this); + DBUG_RETURN(rli->deferred_events->add(this)); } if (!(charset= get_charset(charset_number, MYF(MY_WME)))) - return 1; + DBUG_RETURN(1); LEX_STRING user_var_name; user_var_name.str= name; user_var_name.length= name_len; @@ -6540,7 +6562,7 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli) case ROW_RESULT: default: DBUG_ASSERT(0); - return 0; + DBUG_RETURN(0); } } @@ -6554,7 +6576,7 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli) error. */ if (e->fix_fields(thd, 0)) - return 1; + DBUG_RETURN(1); /* A variable can just be considered as a table with @@ -6566,7 +6588,7 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli) if (!is_deferred()) free_root(thd->mem_root, 0); - return 0; + DBUG_RETURN(0); } int User_var_log_event::do_update_pos(Relay_log_info *rli) @@ -6609,7 +6631,7 @@ void Unknown_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info #endif #ifndef MYSQL_CLIENT -void Slave_log_event::pack_info(Protocol *protocol) +void Slave_log_event::pack_info(THD *thd, Protocol *protocol) { char buf[256+HOSTNAME_LENGTH], *pos; pos= strmov(buf, "host="); @@ -6991,7 +7013,7 @@ void Create_file_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info */ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -void Create_file_log_event::pack_info(Protocol *protocol) +void Create_file_log_event::pack_info(THD *thd, Protocol *protocol) { char buf[SAFE_NAME_LEN*2 + 30 + 21*2], *pos; pos= strmov(buf, "db="); @@ -7177,7 +7199,7 @@ void Append_block_log_event::print(FILE* file, */ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -void Append_block_log_event::pack_info(Protocol *protocol) +void Append_block_log_event::pack_info(THD *thd, Protocol *protocol) { char buf[256]; uint length; @@ -7334,7 +7356,7 @@ void Delete_file_log_event::print(FILE* file, */ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -void Delete_file_log_event::pack_info(Protocol *protocol) +void Delete_file_log_event::pack_info(THD *thd, Protocol *protocol) { char buf[64]; uint length; @@ -7433,7 +7455,7 @@ void Execute_load_log_event::print(FILE* file, */ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -void Execute_load_log_event::pack_info(Protocol *protocol) +void Execute_load_log_event::pack_info(THD *thd, Protocol *protocol) { char buf[64]; uint length; @@ -7695,27 +7717,24 @@ void Execute_load_query_log_event::print(FILE* file, #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -void Execute_load_query_log_event::pack_info(Protocol *protocol) +void Execute_load_query_log_event::pack_info(THD *thd, Protocol *protocol) { - char *buf, *pos; - if (!(buf= (char*) my_malloc(9 + db_len + q_len + 10 + 21, MYF(MY_WME)))) - return; - pos= buf; + char buf_mem[1024]; + String buf(buf_mem, sizeof(buf_mem), system_charset_info); + buf.real_alloc(9 + db_len + q_len + 10 + 21); if (db && db_len) { - pos= strmov(buf, "use `"); - memcpy(pos, db, db_len); - pos= strmov(pos+db_len, "`; "); - } - if (query && q_len) - { - memcpy(pos, query, q_len); - pos+= q_len; + if (buf.append("use ") || + append_identifier(thd, &buf, db, db_len) || + buf.append("; ")) + return; } - pos= strmov(pos, " ;file_id="); - pos= int10_to_str((long) file_id, pos, 10); - protocol->store(buf, pos-buf, &my_charset_bin); - my_free(buf); + if (query && q_len && buf.append(query, q_len)) + return; + if (buf.append(" ;file_id=") || + buf.append_ulonglong(file_id)) + return; + protocol->store(buf.ptr(), buf.length(), &my_charset_bin); } @@ -8678,7 +8697,7 @@ bool Rows_log_event::write_data_body(IO_CACHE*file) #endif #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -void Rows_log_event::pack_info(Protocol *protocol) +void Rows_log_event::pack_info(THD *thd, Protocol *protocol) { char buf[256]; char const *const flagstr= @@ -8782,7 +8801,7 @@ bool Annotate_rows_log_event::write_data_body(IO_CACHE *file) #endif #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) -void Annotate_rows_log_event::pack_info(Protocol* protocol) +void Annotate_rows_log_event::pack_info(THD *thd, Protocol* protocol) { if (m_query_txt && m_query_len) protocol->store(m_query_txt, m_query_len, &my_charset_bin); @@ -9526,7 +9545,7 @@ bool Table_map_log_event::write_data_body(IO_CACHE *file) */ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -void Table_map_log_event::pack_info(Protocol *protocol) +void Table_map_log_event::pack_info(THD *thd, Protocol *protocol) { char buf[256]; size_t bytes= my_snprintf(buf, sizeof(buf), @@ -9547,7 +9566,7 @@ void Table_map_log_event::print(FILE *, PRINT_EVENT_INFO *print_event_info) { print_header(&print_event_info->head_cache, print_event_info, TRUE); my_b_printf(&print_event_info->head_cache, - "\tTable_map: `%s`.`%s` mapped to number %lu\n", + "\tTable_map: %`s.%`s mapped to number %lu\n", m_dbnam, m_tblnam, m_table_id); print_base64(&print_event_info->body_cache, print_event_info, TRUE); } @@ -10880,7 +10899,7 @@ Incident_log_event::description() const #ifndef MYSQL_CLIENT -void Incident_log_event::pack_info(Protocol *protocol) +void Incident_log_event::pack_info(THD *thd, Protocol *protocol) { char buf[256]; size_t bytes; diff --git a/sql/log_event.h b/sql/log_event.h index 19a77f03b84..bf45dd0cc93 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -1065,14 +1065,15 @@ public: */ static void init_show_field_list(List<Item>* field_list); #ifdef HAVE_REPLICATION - int net_send(Protocol *protocol, const char* log_name, my_off_t pos); + int net_send(THD *thd, Protocol *protocol, const char* log_name, + my_off_t pos); /* pack_info() is used by SHOW BINLOG EVENTS; as print() it prepares and sends a string to display to the user, so it resembles print(). */ - virtual void pack_info(Protocol *protocol); + virtual void pack_info(THD *thd, Protocol *protocol); #endif /* HAVE_REPLICATION */ virtual const char* get_db() @@ -1809,7 +1810,7 @@ public: bool using_trans, bool direct, bool suppress_use, int error); const char* get_db() { return db; } #ifdef HAVE_REPLICATION - void pack_info(Protocol* protocol); + void pack_info(THD *thd, Protocol* protocol); #endif /* HAVE_REPLICATION */ #else void print_query_header(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info); @@ -1939,7 +1940,7 @@ public: #ifdef MYSQL_SERVER Slave_log_event(THD* thd_arg, Relay_log_info* rli); - void pack_info(Protocol* protocol); + void pack_info(THD *thd, Protocol* protocol); #else void print(FILE* file, PRINT_EVENT_INFO* print_event_info); #endif @@ -2172,9 +2173,9 @@ protected: const Format_description_log_event* description_event); public: - uint get_query_buffer_length(); - void print_query(bool need_db, const char *cs, char *buf, char **end, - char **fn_start, char **fn_end); + void print_query(THD *thd, bool need_db, const char *cs, String *buf, + my_off_t *fn_start, my_off_t *fn_end, + const char *qualify_db); ulong thread_id; ulong slave_proxy_id; uint32 table_name_len; @@ -2235,7 +2236,7 @@ public: Name_resolution_context *context); const char* get_db() { return db; } #ifdef HAVE_REPLICATION - void pack_info(Protocol* protocol); + void pack_info(THD *thd, Protocol* protocol); #endif /* HAVE_REPLICATION */ #else void print(FILE* file, PRINT_EVENT_INFO* print_event_info); @@ -2332,7 +2333,7 @@ public: #ifdef MYSQL_SERVER Start_log_event_v3(); #ifdef HAVE_REPLICATION - void pack_info(Protocol* protocol); + void pack_info(THD *thd, Protocol* protocol); #endif /* HAVE_REPLICATION */ #else Start_log_event_v3() {} @@ -2496,7 +2497,7 @@ Intvar_log_event(THD* thd_arg,uchar type_arg, ulonglong val_arg, cache_type= Log_event::EVENT_NO_CACHE; } #ifdef HAVE_REPLICATION - void pack_info(Protocol* protocol); + void pack_info(THD *thd, Protocol* protocol); #endif /* HAVE_REPLICATION */ #else void print(FILE* file, PRINT_EVENT_INFO* print_event_info); @@ -2576,7 +2577,7 @@ class Rand_log_event: public Log_event cache_type= Log_event::EVENT_NO_CACHE; } #ifdef HAVE_REPLICATION - void pack_info(Protocol* protocol); + void pack_info(THD *thd, Protocol* protocol); #endif /* HAVE_REPLICATION */ #else void print(FILE* file, PRINT_EVENT_INFO* print_event_info); @@ -2625,7 +2626,7 @@ class Xid_log_event: public Log_event cache_type= Log_event::EVENT_NO_CACHE; } #ifdef HAVE_REPLICATION - void pack_info(Protocol* protocol); + void pack_info(THD *thd, Protocol* protocol); #endif /* HAVE_REPLICATION */ #else void print(FILE* file, PRINT_EVENT_INFO* print_event_info); @@ -2687,7 +2688,7 @@ public: if (direct) cache_type= Log_event::EVENT_NO_CACHE; } - void pack_info(Protocol* protocol); + void pack_info(THD *thd, Protocol* protocol); #else void print(FILE* file, PRINT_EVENT_INFO* print_event_info); #endif @@ -2825,7 +2826,7 @@ public: uint ident_len_arg, ulonglong pos_arg, uint flags); #ifdef HAVE_REPLICATION - void pack_info(Protocol* protocol); + void pack_info(THD *thd, Protocol* protocol); #endif /* HAVE_REPLICATION */ #else void print(FILE* file, PRINT_EVENT_INFO* print_event_info); @@ -2886,7 +2887,7 @@ public: uchar* block_arg, uint block_len_arg, bool using_trans); #ifdef HAVE_REPLICATION - void pack_info(Protocol* protocol); + void pack_info(THD *thd, Protocol* protocol); #endif /* HAVE_REPLICATION */ #else void print(FILE* file, PRINT_EVENT_INFO* print_event_info); @@ -2958,7 +2959,7 @@ public: Append_block_log_event(THD* thd, const char* db_arg, uchar* block_arg, uint block_len_arg, bool using_trans); #ifdef HAVE_REPLICATION - void pack_info(Protocol* protocol); + void pack_info(THD *thd, Protocol* protocol); virtual int get_create_or_append() const; #endif /* HAVE_REPLICATION */ #else @@ -2999,7 +3000,7 @@ public: #ifdef MYSQL_SERVER Delete_file_log_event(THD* thd, const char* db_arg, bool using_trans); #ifdef HAVE_REPLICATION - void pack_info(Protocol* protocol); + void pack_info(THD *thd, Protocol* protocol); #endif /* HAVE_REPLICATION */ #else void print(FILE* file, PRINT_EVENT_INFO* print_event_info); @@ -3040,7 +3041,7 @@ public: #ifdef MYSQL_SERVER Execute_load_log_event(THD* thd, const char* db_arg, bool using_trans); #ifdef HAVE_REPLICATION - void pack_info(Protocol* protocol); + void pack_info(THD *thd, Protocol* protocol); #endif /* HAVE_REPLICATION */ #else void print(FILE* file, PRINT_EVENT_INFO* print_event_info); @@ -3136,7 +3137,7 @@ public: bool using_trans, bool direct, bool suppress_use, int errcode); #ifdef HAVE_REPLICATION - void pack_info(Protocol* protocol); + void pack_info(THD *thd, Protocol* protocol); #endif /* HAVE_REPLICATION */ #else void print(FILE* file, PRINT_EVENT_INFO* print_event_info); @@ -3222,7 +3223,7 @@ public: #endif #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) - virtual void pack_info(Protocol*); + virtual void pack_info(THD *thd, Protocol*); #endif #ifdef MYSQL_CLIENT @@ -3636,7 +3637,7 @@ public: #endif #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) - virtual void pack_info(Protocol *protocol); + virtual void pack_info(THD *thd, Protocol *protocol); #endif #ifdef MYSQL_CLIENT @@ -3748,7 +3749,7 @@ public: flag_set get_flags(flag_set flags_arg) const { return m_flags & flags_arg; } #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) - virtual void pack_info(Protocol *protocol); + virtual void pack_info(THD *thd, Protocol *protocol); #endif #ifdef MYSQL_CLIENT @@ -4195,7 +4196,7 @@ public: #endif #ifdef MYSQL_SERVER - void pack_info(Protocol*); + void pack_info(THD *thd, Protocol*); #endif Incident_log_event(const char *buf, uint event_len, @@ -4294,6 +4295,16 @@ bool event_checksum_test(uchar *buf, ulong event_len, uint8 alg); uint8 get_checksum_alg(const char* buf, ulong len); extern TYPELIB binlog_checksum_typelib; +#ifndef MYSQL_CLIENT +/** + The function is called by slave applier in case there are + active table filtering rules to force gathering events associated + with Query-log-event into an array to execute + them once the fate of the Query is determined for execution. +*/ +bool slave_execute_deferred_events(THD *thd); +#endif + /** @} (end of group Replication) */ diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index 8f2c515e11c..d7c66af769a 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -1935,7 +1935,7 @@ bool Old_rows_log_event::write_data_body(IO_CACHE*file) #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -void Old_rows_log_event::pack_info(Protocol *protocol) +void Old_rows_log_event::pack_info(THD *thd, Protocol *protocol) { char buf[256]; char const *const flagstr= diff --git a/sql/log_event_old.h b/sql/log_event_old.h index 8fe2e9e0a75..3e1efd8e2c0 100644 --- a/sql/log_event_old.h +++ b/sql/log_event_old.h @@ -108,7 +108,7 @@ public: flag_set get_flags(flag_set flags_arg) const { return m_flags & flags_arg; } #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) - virtual void pack_info(Protocol *protocol); + virtual void pack_info(THD *thd, Protocol *protocol); #endif #ifdef MYSQL_CLIENT diff --git a/sql/multi_range_read.cc b/sql/multi_range_read.cc index 036775cdf3e..1361d5822c9 100644 --- a/sql/multi_range_read.cc +++ b/sql/multi_range_read.cc @@ -1404,7 +1404,7 @@ ha_rows DsMrr_impl::dsmrr_info(uint keyno, uint n_ranges, uint rows, uint key_parts, uint *bufsz, uint *flags, COST_VECT *cost) { - ha_rows res; + ha_rows res __attribute__((unused)); uint def_flags= *flags; uint def_bufsz= *bufsz; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 11b397e3e0c..faac606a96b 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2001,7 +2001,7 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler) { handler *save_file= file, *org_file; my_bool org_key_read; - THD *thd; + THD *thd= head->in_use; DBUG_ENTER("QUICK_RANGE_SELECT::init_ror_merged_scan"); in_ror_merged_scan= 1; @@ -2023,7 +2023,6 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler) DBUG_RETURN(0); } - thd= head->in_use; if (!(file= head->file->clone(head->s->normalized_path.str, thd->mem_root))) { /* diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 8d1cbeba5f4..e70e5a784ba 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -160,18 +160,18 @@ 3.2.1 Non-merged semi-joins and join optimization ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ For join optimization purposes, non-merged semi-join nests are similar to - base tables - they've got one JOIN_TAB, which can be accessed with one of - two methods: + base tables. Each such nest is represented by one one JOIN_TAB, which has + two possible access strategies: - full table scan (representing SJ-Materialization-Scan strategy) - eq_ref-like table lookup (representing SJ-Materialization-Lookup) Unlike regular base tables, non-merged semi-joins have: - non-zero JOIN_TAB::startup_cost, and - join_tab->table->is_filled_at_execution()==TRUE, which means one - cannot do const table detection or range analysis or other table data- - dependent inferences - // instead, get_delayed_table_estimates() runs optimization on the nest so that - // we get an idea about temptable size + cannot do const table detection, range analysis or other dataset-dependent + optimizations. + Instead, get_delayed_table_estimates() will run optimization for the + subquery and produce an E(materialized table size). 3.2.2 Merged semi-joins and join optimization ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index abc22a00695..89fb1bb27de 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -35,7 +35,6 @@ #include "rpl_mi.h" #include "rpl_filter.h" #include "log_event.h" -#include "sql_db.h" // mysql_create_db #include <mysql.h> #define SLAVE_LIST_CHUNK 128 diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index a49f10db440..99bf8a82004 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -314,7 +314,7 @@ unpack_row(Relay_log_info const *rli, if (!pack_ptr) { rli->report(ERROR_LEVEL, ER_SLAVE_CORRUPT_EVENT, - "Could not read field `%s` of table `%s`.`%s`", + "Could not read field '%s' of table '%s.%s'", f->field_name, table->s->db.str, table->s->table_name.str); DBUG_RETURN(ER_SLAVE_CORRUPT_EVENT); diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index 388a6c9f9bb..069fac1c3ec 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -15,11 +15,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "rpl_utility.h" +#include "log_event.h" -#ifndef MYSQL_CLIENT -#include "unireg.h" // REQUIRED by later includes +#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) #include "rpl_rli.h" -#include "log_event.h" #include "sql_select.h" /** @@ -954,7 +953,6 @@ TABLE *table_def::create_conversion_table(THD *thd, Relay_log_info *rli, TABLE * target_table->s->table_name.str); DBUG_RETURN(conv_table); } - #endif /* MYSQL_CLIENT */ table_def::table_def(unsigned char *types, ulong size, @@ -1115,7 +1113,6 @@ bool event_checksum_test(uchar *event_buf, ulong event_len, uint8 alg) return DBUG_EVALUATE_IF("simulate_checksum_test_failure", TRUE, res); } - #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) Deferred_log_events::Deferred_log_events(Relay_log_info *rli) : last_added(NULL) diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 923e8e73bc7..31a6f13e52f 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6585,3 +6585,6 @@ ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION eng "Cannot modify @@session.skip_replication inside a stored function or trigger" ER_QUERY_EXCEEDED_ROWS_EXAMINED_LIMIT eng "Query execution was interrupted. The query examined at least %llu rows, which exceeds LIMIT ROWS EXAMINED (%llu). The query result may be incomplete." +ER_NO_SUCH_TABLE_IN_ENGINE 42S02 + eng "Table '%-.192s.%-.192s' doesn't exist in engine" + swe "Det finns ingen tabell som heter '%-.192s.%-.192s' i handlern" diff --git a/sql/slave.cc b/sql/slave.cc index 9149cd82d5e..7b7fd12e267 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3005,6 +3005,8 @@ pthread_handler_t handle_slave_io(void *arg) mysql= NULL ; retry_count= 0; + thd= new THD; // note that contructor of THD uses DBUG_ ! + mysql_mutex_lock(&mi->run_lock); /* Inform waiting threads that slave has started */ mi->slave_run_id++; @@ -3013,7 +3015,6 @@ pthread_handler_t handle_slave_io(void *arg) mi->events_till_disconnect = disconnect_slave_event_count; #endif - thd= new THD; // note that contructor of THD uses DBUG_ ! THD_CHECK_SENTRY(thd); mi->io_thd = thd; diff --git a/sql/sp.cc b/sql/sp.cc index 29195234a5a..93cd64b4104 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -1429,6 +1429,7 @@ public: MYSQL_ERROR ** cond_hdl) { if (sql_errno == ER_NO_SUCH_TABLE || + sql_errno == ER_NO_SUCH_TABLE_IN_ENGINE || sql_errno == ER_CANNOT_LOAD_FROM_TABLE || sql_errno == ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE || sql_errno == ER_COL_COUNT_DOESNT_MATCH_CORRUPTED) diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 9a356cb3321..f3ba0073c69 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -3032,6 +3032,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, if (!res || !thd->is_error() || (thd->stmt_da->sql_errno() != ER_CANT_REOPEN_TABLE && thd->stmt_da->sql_errno() != ER_NO_SUCH_TABLE && + thd->stmt_da->sql_errno() != ER_NO_SUCH_TABLE_IN_ENGINE && thd->stmt_da->sql_errno() != ER_UPDATE_TABLE_USED)) thd->stmt_arena->state= Query_arena::STMT_EXECUTED; diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index e00b35a19db..1305e882ede 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -286,6 +286,7 @@ end: static inline bool table_not_corrupt_error(uint sql_errno) { return (sql_errno == ER_NO_SUCH_TABLE || + sql_errno == ER_NO_SUCH_TABLE_IN_ENGINE || sql_errno == ER_FILE_NOT_FOUND || sql_errno == ER_LOCK_WAIT_TIMEOUT || sql_errno == ER_LOCK_DEADLOCK || diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 911f2560d85..0dfc98864b1 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -70,7 +70,7 @@ No_such_table_error_handler::handle_condition(THD *, MYSQL_ERROR ** cond_hdl) { *cond_hdl= NULL; - if (sql_errno == ER_NO_SUCH_TABLE) + if (sql_errno == ER_NO_SUCH_TABLE || sql_errno == ER_NO_SUCH_TABLE_IN_ENGINE) { m_handled_errors++; return TRUE; @@ -144,7 +144,9 @@ Repair_mrg_table_error_handler::handle_condition(THD *, MYSQL_ERROR ** cond_hdl) { *cond_hdl= NULL; - if (sql_errno == ER_NO_SUCH_TABLE || sql_errno == ER_WRONG_MRG_TABLE) + if (sql_errno == ER_NO_SUCH_TABLE || + sql_errno == ER_NO_SUCH_TABLE_IN_ENGINE || + sql_errno == ER_WRONG_MRG_TABLE) { m_handled_errors= true; return TRUE; @@ -717,7 +719,9 @@ get_table_share_with_discover(THD *thd, TABLE_LIST *table_list, @todo Rework alternative ways to deal with ER_NO_SUCH TABLE. */ - if (share || (thd->is_error() && thd->stmt_da->sql_errno() != ER_NO_SUCH_TABLE)) + if (share || + (thd->is_error() && thd->stmt_da->sql_errno() != ER_NO_SUCH_TABLE && + thd->stmt_da->sql_errno() != ER_NO_SUCH_TABLE_IN_ENGINE)) DBUG_RETURN(share); *error= 0; @@ -3897,22 +3901,22 @@ static bool open_table_entry_fini(THD *thd, TABLE_SHARE *share, TABLE *entry) entry->file->implicit_emptied= 0; if (mysql_bin_log.is_open()) { - char *query, *end; - uint query_buf_size= 20 + share->db.length + share->table_name.length +1; - if ((query= (char*) my_malloc(query_buf_size,MYF(MY_WME)))) + char query_buf[2*FN_REFLEN + 21]; + String query(query_buf, sizeof(query_buf), system_charset_info); + query.length(0); + if (query.ptr()) { /* this DELETE FROM is needed even with row-based binlogging */ - end = strxmov(strmov(query, "DELETE FROM `"), - share->db.str,"`.`",share->table_name.str,"`", NullS); + query.append("DELETE FROM "); + append_identifier(thd, &query, share->db.str, share->db.length); + query.append("."); + append_identifier(thd, &query, share->table_name.str, + share->table_name.length); int errcode= query_error_code(thd, TRUE); if (thd->binlog_query(THD::STMT_QUERY_TYPE, - query, (ulong)(end-query), + query.ptr(), query.length(), FALSE, FALSE, FALSE, errcode)) - { - my_free(query); return TRUE; - } - my_free(query); } else { @@ -3922,7 +3926,7 @@ static bool open_table_entry_fini(THD *thd, TABLE_SHARE *share, TABLE *entry) because of MYF(MY_WME) in my_malloc() above). */ sql_print_error("When opening HEAP table, could not allocate memory " - "to write 'DELETE FROM `%s`.`%s`' to the binary log", + "to write 'DELETE FROM %`s.%`s' to the binary log", share->db.str, share->table_name.str); delete entry->triggers; return TRUE; diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 7edd28446a2..191cc4e01c8 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1813,7 +1813,10 @@ Query_cache::send_result_to_client(THD *thd, char *org_sql, uint query_length) goto err; if (query_cache_size == 0) + { + thd->query_cache_is_applicable= 0; // Query can't be cached goto err_unlock; + } Query_cache_block *query_block; if (thd->variables.query_cache_strip_comments) diff --git a/sql/sql_class.h b/sql/sql_class.h index b2fe8c21aae..b1e9b095be2 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1845,6 +1845,7 @@ public: MEM_ROOT mem_root; // Transaction-life memory allocation pool void cleanup() { + DBUG_ENTER("thd::cleanup"); changed_tables= 0; savepoints= 0; /* @@ -1856,6 +1857,7 @@ public: if (!xid_state.rm_error) xid_state.xid.null(); free_root(&mem_root,MYF(MY_KEEP_PREALLOC)); + DBUG_VOID_RETURN; } my_bool is_active() { diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index c50cded7470..b8b979a282b 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -115,6 +115,8 @@ int mysql_open_cursor(THD *thd, select_result *result, &thd->security_ctx->priv_user[0], (char *) thd->security_ctx->host_or_ip, 2); + /* Mark that we can't use query cache with cursors */ + thd->query_cache_is_applicable= 0; rc= mysql_execute_command(thd); MYSQL_QUERY_EXEC_DONE(rc); diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 28565b02c1f..086445948bd 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -544,7 +544,6 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, bool silent) { char path[FN_REFLEN+16]; - char tmp_query[FN_REFLEN+16]; long result= 1; int error= 0; MY_STAT stat_info; @@ -622,17 +621,9 @@ not_silent: char *query; uint query_length; - if (!thd->query()) // Only in replication - { - query= tmp_query; - query_length= (uint) (strxmov(tmp_query,"create database `", - db, "`", NullS) - tmp_query); - } - else - { - query= thd->query(); - query_length= thd->query_length(); - } + query= thd->query(); + query_length= thd->query_length(); + DBUG_ASSERT(query); ha_binlog_log_query(thd, 0, LOGCOM_CREATE_DB, query, query_length, @@ -896,18 +887,11 @@ update_binlog: { const char *query; ulong query_length; - if (!thd->query()) - { - /* The client used the old obsolete mysql_drop_db() call */ - query= path; - query_length= (uint) (strxmov(path, "drop database `", db, "`", - NullS) - path); - } - else - { - query= thd->query(); - query_length= thd->query_length(); - } + + query= thd->query(); + query_length= thd->query_length(); + DBUG_ASSERT(query); + if (mysql_bin_log.is_open()) { int errcode= query_error_code(thd, TRUE); @@ -951,6 +935,7 @@ update_binlog: { uint tbl_name_len; bool exists; + char quoted_name[FN_REFLEN+3]; // Only write drop table to the binlog for tables that no longer exist. if (check_if_table_exists(thd, tbl, &exists)) @@ -961,8 +946,8 @@ update_binlog: if (exists) continue; - /* 3 for the quotes and the comma*/ - tbl_name_len= strlen(tbl->table_name) + 3; + my_snprintf(quoted_name, sizeof(quoted_name), "%`s", tbl->table_name); + tbl_name_len= strlen(quoted_name) + 1; /* +1 for the comma */ if (query_pos + tbl_name_len + 1 >= query_end) { /* @@ -977,9 +962,7 @@ update_binlog: query_pos= query_data_start; } - *query_pos++ = '`'; - query_pos= strmov(query_pos,tbl->table_name); - *query_pos++ = '`'; + query_pos= strmov(query_pos, quoted_name); *query_pos++ = ','; } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index d9d2f9fa649..f6e2ca09ec9 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -4161,7 +4161,6 @@ bool LEX::is_partition_management() const alter_info.flags == ALTER_REORGANIZE_PARTITION)); } - #ifdef MYSQL_SERVER uint binlog_unsafe_map[256]; diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 33d1741b5ec..98031c96225 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -39,6 +39,7 @@ #include "sp_head.h" #include "sql_trigger.h" #include "sql_derived.h" +#include "sql_show.h" class XML_TAG { public: @@ -675,24 +676,28 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, bool transactional_table, int errcode) { - char *load_data_query, - *end, - *fname_start, - *fname_end, - *p= NULL; - size_t pl= 0; + char *load_data_query; + my_off_t fname_start, + fname_end; List<Item> fv; Item *item, *val; int n; - const char *tbl= table_name_arg; const char *tdb= (thd->db != NULL ? thd->db : db_arg); - char name_buffer[SAFE_NAME_LEN*2]; + const char *qualify_db= NULL; char command_buffer[1024]; - String string_buf(name_buffer, sizeof(name_buffer), - system_charset_info); - String pfields(command_buffer, sizeof(command_buffer), + String query_str(command_buffer, sizeof(command_buffer), system_charset_info); + Load_log_event lle(thd, ex, tdb, table_name_arg, fv, is_concurrent, + duplicates, ignore, transactional_table); + + /* + force in a LOCAL if there was one in the original. + */ + if (thd->lex->local_file) + lle.set_fname_outside_temp_buf(ex->file_name, strlen(ex->file_name)); + + query_str.length(0); if (!thd->db || strcmp(db_arg, thd->db)) { /* @@ -700,49 +705,35 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, prefix table name with database name so that it becomes a FQ name. */ - string_buf.length(0); - string_buf.append(db_arg); - string_buf.append("`"); - string_buf.append("."); - string_buf.append("`"); - string_buf.append(table_name_arg); - tbl= string_buf.c_ptr_safe(); + qualify_db= db_arg; } - - Load_log_event lle(thd, ex, tdb, tbl, fv, is_concurrent, - duplicates, ignore, transactional_table); - - /* - force in a LOCAL if there was one in the original. - */ - if (thd->lex->local_file) - lle.set_fname_outside_temp_buf(ex->file_name, strlen(ex->file_name)); + lle.print_query(thd, FALSE, (const char *) ex->cs?ex->cs->csname:NULL, + &query_str, &fname_start, &fname_end, qualify_db); /* prepare fields-list and SET if needed; print_query won't do that for us. */ - pfields.length(0); if (!thd->lex->field_list.is_empty()) { List_iterator<Item> li(thd->lex->field_list); - pfields.append(" ("); + query_str.append(" ("); n= 0; while ((item= li++)) { if (n++) - pfields.append(", "); + query_str.append(", "); if (item->type() == Item::FIELD_ITEM) + append_identifier(thd, &query_str, item->name, strlen(item->name)); + else { - pfields.append("`"); - pfields.append(item->name); - pfields.append("`"); + /* Actually Item_user_var_as_out_param despite claiming STRING_ITEM. */ + DBUG_ASSERT(item->type() == Item::STRING_ITEM); + ((Item_user_var_as_out_param *)item)->print_for_load(thd, &query_str); } - else - item->print(&pfields, QT_ORDINARY); } - pfields.append(")"); + query_str.append(")"); } if (!thd->lex->update_list.is_empty()) @@ -750,38 +741,25 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, List_iterator<Item> lu(thd->lex->update_list); List_iterator<Item> lv(thd->lex->value_list); - pfields.append(" SET "); + query_str.append(" SET "); n= 0; while ((item= lu++)) { val= lv++; if (n++) - pfields.append(", "); - pfields.append("`"); - pfields.append(item->name); - pfields.append("`"); - pfields.append(val->name); + query_str.append(", "); + append_identifier(thd, &query_str, item->name, strlen(item->name)); + query_str.append(val->name); } } - p= pfields.c_ptr_safe(); - pl= pfields.length(); - - if (!(load_data_query= (char *)thd->alloc(lle.get_query_buffer_length() + 1 + pl))) + if (!(load_data_query= (char *)thd->strmake(query_str.ptr(), query_str.length()))) return TRUE; - lle.print_query(FALSE, (const char *) ex->cs?ex->cs->csname:NULL, - load_data_query, &end, - (char **)&fname_start, (char **)&fname_end); - - strcpy(end, p); - end += pl; - Execute_load_query_log_event - e(thd, load_data_query, end-load_data_query, - (uint) ((char*) fname_start - load_data_query - 1), - (uint) ((char*) fname_end - load_data_query), + e(thd, load_data_query, query_str.length(), + (uint) (fname_start - 1), (uint) fname_end, (duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE : (ignore ? LOAD_DUP_IGNORE : LOAD_DUP_ERROR), transactional_table, FALSE, FALSE, errcode); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 49014db9505..6f157c89ee2 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1325,7 +1325,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, { STATUS_VAR *current_global_status_var; // Big; Don't allocate on stack ulong uptime; - uint length; + uint length __attribute__((unused)); ulonglong queries_per_second1000; char buff[250]; uint buff_len= sizeof(buff); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index a9c79589faa..2bec12e4f66 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5500,10 +5500,12 @@ static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) build_table_filename(path, sizeof(path) - 1, lpt->db, lpt->table_name, "", 0); - if(mysql_trans_prepare_alter_copy_data(thd)) + /* First lock the original tables */ + if (file->ha_external_lock(thd, F_WRLCK)) DBUG_RETURN(TRUE); - if (file->ha_external_lock(thd, F_WRLCK)) + /* Disable transactions for all new tables */ + if (mysql_trans_prepare_alter_copy_data(thd)) DBUG_RETURN(TRUE); /* TODO: test if bulk_insert would increase the performance */ diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 751c0d6ada5..53ac103dda1 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2012, Oracle and/or its affiliates. - Copyright (c) 2008, 2011, Monty Program Ab + Copyright (c) 2008, 2012, Monty Program Ab 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 @@ -2000,7 +2000,7 @@ bool mysql_show_binlog_events(THD* thd) description_event->checksum_alg= ev->checksum_alg; if (event_count >= limit_start && - ev->net_send(protocol, linfo.log_file_name, pos)) + ev->net_send(thd, protocol, linfo.log_file_name, pos)) { errmsg = "Net error"; delete ev; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 51ba2d1c4e4..33991851218 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -272,8 +272,11 @@ Item_equal *find_item_equal(COND_EQUAL *cond_equal, Field *field, bool *inherited_fl); JOIN_TAB *first_depth_first_tab(JOIN* join); JOIN_TAB *next_depth_first_tab(JOIN* join, JOIN_TAB* tab); -JOIN_TAB *first_breadth_first_tab(JOIN *join); -JOIN_TAB *next_breadth_first_tab(JOIN *join, JOIN_TAB *tab); + +enum enum_exec_or_opt {WALK_OPTIMIZATION_TABS , WALK_EXECUTION_TABS}; +JOIN_TAB *first_breadth_first_tab(JOIN *join, enum enum_exec_or_opt tabs_kind); +JOIN_TAB *next_breadth_first_tab(JOIN *join, enum enum_exec_or_opt tabs_kind, + JOIN_TAB *tab); /** This handles SELECT with and without UNION. @@ -6410,7 +6413,8 @@ greedy_search(JOIN *join, uint size_remain; // cardinality of remaining_tables POSITION best_pos; JOIN_TAB *best_table; // the next plan node to be added to the curr QEP - uint n_tables; // ==join->tables or # tables in the sj-mat nest we're optimizing + // ==join->tables or # tables in the sj-mat nest we're optimizing + uint n_tables __attribute__((unused)); DBUG_ENTER("greedy_search"); @@ -6650,15 +6654,15 @@ double JOIN::get_examined_rows() { ha_rows examined_rows; double prev_fanout= 1; - JOIN_TAB *tab= first_breadth_first_tab(this); + JOIN_TAB *tab= first_breadth_first_tab(this, WALK_OPTIMIZATION_TABS); JOIN_TAB *prev_tab= tab; examined_rows= tab->get_examined_rows(); - while ((tab= next_breadth_first_tab(this, tab))) + while ((tab= next_breadth_first_tab(this, WALK_OPTIMIZATION_TABS, tab))) { prev_fanout *= prev_tab->records_read; - examined_rows+= tab->get_examined_rows() * prev_fanout; + examined_rows+= (ha_rows) (tab->get_examined_rows() * prev_fanout); prev_tab= tab; } return examined_rows; @@ -7270,23 +7274,30 @@ prev_record_reads(POSITION *positions, uint idx, table_map found_ref) Enumerate join tabs in breadth-first fashion, including const tables. */ -JOIN_TAB *first_breadth_first_tab(JOIN *join) +JOIN_TAB *first_breadth_first_tab(JOIN *join, enum enum_exec_or_opt tabs_kind) { - return join->join_tab; /* There's always one (i.e. first) table */ + /* There's always one (i.e. first) table */ + return (tabs_kind == WALK_EXECUTION_TABS)? join->join_tab: + join->table_access_tabs; } -JOIN_TAB *next_breadth_first_tab(JOIN *join, JOIN_TAB *tab) +JOIN_TAB *next_breadth_first_tab(JOIN *join, enum enum_exec_or_opt tabs_kind, + JOIN_TAB *tab) { + JOIN_TAB* const first_top_tab= first_breadth_first_tab(join, tabs_kind); + const uint n_top_tabs_count= (tabs_kind == WALK_EXECUTION_TABS)? + join->top_join_tab_count: + join->top_table_access_tabs_count; if (!tab->bush_root_tab) { /* We're at top level. Get the next top-level tab */ tab++; - if (tab < join->join_tab + join->top_join_tab_count) + if (tab < first_top_tab + n_top_tabs_count) return tab; /* No more top-level tabs. Switch to enumerating SJM nest children */ - tab= join->join_tab; + tab= first_top_tab; } else { @@ -7310,7 +7321,7 @@ JOIN_TAB *next_breadth_first_tab(JOIN *join, JOIN_TAB *tab) Ok, "tab" points to a top-level table, and we need to find the next SJM nest and enter it. */ - for (; tab < join->join_tab + join->top_join_tab_count; tab++) + for (; tab < first_top_tab + n_top_tabs_count; tab++) { if (tab->bush_children) return tab->bush_children->start; @@ -7334,7 +7345,7 @@ JOIN_TAB *first_top_level_tab(JOIN *join, enum enum_with_const_tables with_const JOIN_TAB *next_top_level_tab(JOIN *join, JOIN_TAB *tab) { - tab= next_breadth_first_tab(join, tab); + tab= next_breadth_first_tab(join, WALK_EXECUTION_TABS, tab); if (tab && tab->bush_root_tab) tab= NULL; return tab; @@ -7634,6 +7645,12 @@ get_best_combination(JOIN *join) join->top_join_tab_count= join->join_tab_ranges.head()->end - join->join_tab_ranges.head()->start; + /* + Save pointers to select join tabs for SHOW EXPLAIN + */ + join->table_access_tabs= join->join_tab; + join->top_table_access_tabs_count= join->top_join_tab_count; + update_depend_map(join); DBUG_RETURN(0); } @@ -10529,7 +10546,7 @@ void JOIN::join_free() Optimization: if not EXPLAIN and we are done with the JOIN, free all tables. */ - bool full= !(select_lex->uncacheable); + bool full= !(select_lex->uncacheable) && !(thd->lex->describe); bool can_unlock= full; DBUG_ENTER("JOIN::join_free"); @@ -11890,9 +11907,9 @@ static int compare_fields_by_table_order(Item *field1, bool outer_ref= 0; Item_field *f1= (Item_field *) (field1->real_item()); Item_field *f2= (Item_field *) (field2->real_item()); - if (f1->const_item()) + if (field1->const_item() || f1->const_item()) return 1; - if (f2->const_item()) + if (field2->const_item() || f2->const_item()) return -1; if (f2->used_tables() & OUTER_REF_TABLE_BIT) { @@ -16473,7 +16490,7 @@ int report_error(TABLE *table, int error) && !table->in_use->killed) { push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN, error, - "Got error %d when reading table `%s`.`%s`", + "Got error %d when reading table %`s.%`s", error, table->s->db.str, table->s->table_name.str); sql_print_error("Got error %d when reading table '%s'", error, table->s->path.str); @@ -21397,8 +21414,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, bool printing_materialize_nest= FALSE; uint select_id= join->select_lex->select_number; - for (JOIN_TAB *tab= first_breadth_first_tab(join); tab; - tab= next_breadth_first_tab(join, tab)) + for (JOIN_TAB *tab= first_breadth_first_tab(join, WALK_OPTIMIZATION_TABS); tab; + tab= next_breadth_first_tab(join, WALK_OPTIMIZATION_TABS, tab)) { if (tab->bush_root_tab) { @@ -21481,16 +21498,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, else { TABLE_LIST *real_table= table->pos_in_table_list; - /* - Internal temporary tables have no corresponding table reference - object. Such a table may appear in EXPLAIN when a subquery that needs - a temporary table has been executed, and JOIN::exec replaced the - original JOIN with a plan to access the data in the temp table - (made by JOIN::make_simple_join). - */ - const char *tab_name= real_table ? real_table->alias : - "internal_tmp_table"; - item_list.push_back(new Item_string(tab_name, strlen(tab_name), cs)); + item_list.push_back(new Item_string(real_table->alias, + strlen(real_table->alias), cs)); } /* "partitions" column */ if (join->thd->lex->describe & DESCRIBE_PARTITIONS) diff --git a/sql/sql_select.h b/sql/sql_select.h index 0ed976ac36a..be5f523a7e2 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -897,6 +897,19 @@ protected: public: JOIN_TAB *join_tab, **best_ref; + + /* + For "Using temporary+Using filesort" queries, JOIN::join_tab can point to + either: + 1. array of join tabs describing how to run the select, or + 2. array of single join tab describing read from the temporary table. + + SHOW EXPLAIN code needs to read/show #1. This is why two next members are + there for saving it. + */ + JOIN_TAB *table_access_tabs; + uint top_table_access_tabs_count; + JOIN_TAB **map2table; ///< mapping between table indexes and JOIN_TABs JOIN_TAB *join_tab_save; ///< saved join_tab for subquery reexecution diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 38ff07e0204..6d56bc8520b 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -660,6 +660,7 @@ public: break; case ER_NO_SUCH_TABLE: + case ER_NO_SUCH_TABLE_IN_ENGINE: /* Established behavior: warn if underlying tables are missing. */ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_VIEW_INVALID, @@ -992,9 +993,13 @@ static const char *require_quotes(const char *name, uint name_length) packet target string name the identifier to be appended name_length length of the appending identifier + + RETURN VALUES + true Error + false Ok */ -void +bool append_identifier(THD *thd, String *packet, const char *name, uint length) { const char *name_end; @@ -1002,10 +1007,7 @@ append_identifier(THD *thd, String *packet, const char *name, uint length) int q= get_quote_char_for_identifier(thd, name, length); if (q == EOF) - { - packet->append(name, length, packet->charset()); - return; - } + return packet->append(name, length, packet->charset()); /* The identifier must be quoted as it includes a quote character or @@ -1014,7 +1016,8 @@ append_identifier(THD *thd, String *packet, const char *name, uint length) (void) packet->reserve(length*2 + 2); quote_char= (char) q; - packet->append("e_char, 1, system_charset_info); + if (packet->append("e_char, 1, system_charset_info)) + return true; for (name_end= name+length ; name < name_end ; name+= length) { @@ -1029,11 +1032,13 @@ append_identifier(THD *thd, String *packet, const char *name, uint length) */ if (!length) length= 1; - if (length == 1 && chr == (uchar) quote_char) - packet->append("e_char, 1, system_charset_info); - packet->append(name, length, system_charset_info); + if (length == 1 && chr == (uchar) quote_char && + packet->append("e_char, 1, system_charset_info)) + return true; + if (packet->append(name, length, system_charset_info)) + return true; } - packet->append("e_char, 1, system_charset_info); + return packet->append("e_char, 1, system_charset_info); } diff --git a/sql/sql_show.h b/sql/sql_show.h index 8ad9327c08c..611e3a64c73 100644 --- a/sql/sql_show.h +++ b/sql/sql_show.h @@ -90,7 +90,7 @@ int view_store_create_info(THD *thd, TABLE_LIST *table, String *buff); int copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table); -void append_identifier(THD *thd, String *packet, const char *name, +bool append_identifier(THD *thd, String *packet, const char *name, uint length); void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild); int mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd); diff --git a/sql/sql_string.cc b/sql/sql_string.cc index c4f5f315b08..75029a03790 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -1121,39 +1121,47 @@ outp: - -void String::print(String *str) +/* + Append characters to a single-quoted string '...', escaping special + characters as necessary. + Does not add the enclosing quotes, this is left up to caller. +*/ +void String::append_for_single_quote(const char *st, uint len) { - char *st= (char*)Ptr, *end= st+str_length; + const char *end= st+len; for (; st < end; st++) { uchar c= *st; switch (c) { case '\\': - str->append(STRING_WITH_LEN("\\\\")); + append(STRING_WITH_LEN("\\\\")); break; case '\0': - str->append(STRING_WITH_LEN("\\0")); + append(STRING_WITH_LEN("\\0")); break; case '\'': - str->append(STRING_WITH_LEN("\\'")); + append(STRING_WITH_LEN("\\'")); break; case '\n': - str->append(STRING_WITH_LEN("\\n")); + append(STRING_WITH_LEN("\\n")); break; case '\r': - str->append(STRING_WITH_LEN("\\r")); + append(STRING_WITH_LEN("\\r")); break; case '\032': // Ctrl-Z - str->append(STRING_WITH_LEN("\\Z")); + append(STRING_WITH_LEN("\\Z")); break; default: - str->append(c); + append(c); } } } +void String::print(String *str) +{ + str->append_for_single_quote(Ptr, str_length); +} /* Exchange state of this object and argument. diff --git a/sql/sql_string.h b/sql/sql_string.h index 86af507918c..2f0cd9103dc 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -459,6 +459,7 @@ public: return FALSE; } void print(String *print); + void append_for_single_quote(const char *st, uint len); /* Swap two string objects. Efficient way to exchange data without memcpy. */ void swap(String &s); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 5cdfb62a047..9bbbf814422 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -163,6 +163,13 @@ static char* add_identifier(THD* thd, char *to_p, const char * end_p, diagnostic, error etc. when it would be useful to know what a particular file [and directory] means. Such as SHOW ENGINE STATUS, error messages etc. + Examples: + + t1#P#p1 table t1 partition p1 + t1#P#p1#SP#sp1 table t1 partition p1 subpartition sp1 + t1#P#p1#SP#sp1#TMP# table t1 partition p1 subpartition sp1 temporary + t1#P#p1#SP#sp1#REN# table t1 partition p1 subpartition sp1 renamed + @param thd Thread handle @param from Path name in my_charset_filename Null terminated in my_charset_filename, normalized @@ -201,7 +208,7 @@ uint explain_filename(THD* thd, int part_name_len= 0; const char *subpart_name= NULL; int subpart_name_len= 0; - enum enum_file_name_type {NORMAL, TEMP, RENAMED} name_type= NORMAL; + uint name_variant= NORMAL_PART_NAME; const char *tmp_p; DBUG_ENTER("explain_filename"); DBUG_PRINT("enter", ("from '%s'", from)); @@ -244,7 +251,6 @@ uint explain_filename(THD* thd, (tmp_p[2] == 'L' || tmp_p[2] == 'l') && tmp_p[3] == '-') { - name_type= TEMP; tmp_p+= 4; /* sql- prefix found */ } else @@ -255,7 +261,7 @@ uint explain_filename(THD* thd, if ((tmp_p[1] == 'M' || tmp_p[1] == 'm') && (tmp_p[2] == 'P' || tmp_p[2] == 'p') && tmp_p[3] == '#' && !tmp_p[4]) - name_type= TEMP; + name_variant= TEMP_PART_NAME; else res= 3; tmp_p+= 4; @@ -265,7 +271,7 @@ uint explain_filename(THD* thd, if ((tmp_p[1] == 'E' || tmp_p[1] == 'e') && (tmp_p[2] == 'N' || tmp_p[2] == 'n') && tmp_p[3] == '#' && !tmp_p[4]) - name_type= RENAMED; + name_variant= RENAMED_PART_NAME; else res= 4; tmp_p+= 4; @@ -290,7 +296,7 @@ uint explain_filename(THD* thd, subpart_name_len= strlen(subpart_name); else part_name_len= strlen(part_name); - if (name_type != NORMAL) + if (name_variant != NORMAL_PART_NAME) { if (subpart_name) subpart_name_len-= 5; @@ -332,9 +338,9 @@ uint explain_filename(THD* thd, to_p= strnmov(to_p, " ", end_p - to_p); else to_p= strnmov(to_p, ", ", end_p - to_p); - if (name_type != NORMAL) + if (name_variant != NORMAL_PART_NAME) { - if (name_type == TEMP) + if (name_variant == TEMP_PART_NAME) to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_TEMPORARY_NAME), end_p - to_p); else @@ -1972,27 +1978,28 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists, static uint32 comment_length(THD *thd, uint32 comment_pos, const char **comment_start) { - const char *query= thd->query(); - const char *query_end= query + thd->query_length(); + /* We use uchar * here to make array indexing portable */ + const uchar *query= (uchar*) thd->query(); + const uchar *query_end= (uchar*) query + thd->query_length(); const uchar *const state_map= thd->charset()->state_map; for (; query < query_end; query++) { - if (state_map[*query] == MY_LEX_SKIP) + if (state_map[static_cast<uchar>(*query)] == MY_LEX_SKIP) continue; if (comment_pos-- == 0) break; } if (query > query_end - 3 /* comment can't be shorter than 4 */ || - state_map[*query] != MY_LEX_LONG_COMMENT || query[1] != '*') + state_map[static_cast<uchar>(*query)] != MY_LEX_LONG_COMMENT || query[1] != '*') return 0; - *comment_start= query; + *comment_start= (char*) query; for (query+= 3; query < query_end; query++) { if (query[-1] == '*' && query[0] == '/') - return query - *comment_start + 1; + return (char*) query - *comment_start + 1; } return 0; } @@ -2109,6 +2116,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, { bool is_trans; char *db=table->db; + size_t db_length= table->db_length; handlerton *table_type; enum legacy_db_type frm_db_type= DB_TYPE_UNKNOWN; @@ -2170,14 +2178,14 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, Don't write the database name if it is the current one (or if thd->db is NULL). */ - built_ptr_query->append("`"); if (thd->db == NULL || strcmp(db,thd->db) != 0) { - built_ptr_query->append(db); - built_ptr_query->append("`.`"); + append_identifier(thd, built_ptr_query, db, db_length); + built_ptr_query->append("."); } - built_ptr_query->append(table->table_name); - built_ptr_query->append("`,"); + append_identifier(thd, built_ptr_query, table->table_name, + table->table_name_length); + built_ptr_query->append(","); } /* This means that a temporary table was droped and as such there @@ -2192,7 +2200,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, if (thd->locked_tables_mode) { - if (wait_while_table_is_used(thd, table->table, HA_EXTRA_FORCE_REOPEN)) + if (wait_while_table_is_used(thd, table->table, HA_EXTRA_NOT_USED)) { error= -1; goto err; @@ -2233,15 +2241,15 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, Don't write the database name if it is the current one (or if thd->db is NULL). */ - built_query.append("`"); if (thd->db == NULL || strcmp(db,thd->db) != 0) { - built_query.append(db); - built_query.append("`.`"); + append_identifier(thd, &built_query, db, db_length); + built_query.append("."); } - built_query.append(table->table_name); - built_query.append("`,"); + append_identifier(thd, &built_query, table->table_name, + table->table_name_length); + built_query.append(","); } } DEBUG_SYNC(thd, "rm_table_no_locks_before_delete_table"); @@ -7302,7 +7310,7 @@ err_with_mdl: bool mysql_trans_prepare_alter_copy_data(THD *thd) { - DBUG_ENTER("mysql_prepare_alter_copy_data"); + DBUG_ENTER("mysql_trans_prepare_alter_copy_data"); /* Turn off recovery logging since rollback of an alter table is to delete the new table so there is no need to log the changes to it. @@ -7322,7 +7330,7 @@ bool mysql_trans_prepare_alter_copy_data(THD *thd) bool mysql_trans_commit_alter_copy_data(THD *thd) { bool error= FALSE; - DBUG_ENTER("mysql_commit_alter_copy_data"); + DBUG_ENTER("mysql_trans_commit_alter_copy_data"); if (ha_enable_transaction(thd, TRUE)) DBUG_RETURN(TRUE); diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index 3c1b231d3f2..9d4ca5e1373 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -24,6 +24,7 @@ #include "sql_acl.h" // DROP_ACL #include "sql_parse.h" // check_one_table_access() #include "sql_truncate.h" +#include "sql_show.h" /** @@ -35,7 +36,8 @@ @return TRUE on failure, FALSE otherwise. */ -static bool fk_info_append_fields(String *str, List<LEX_STRING> *fields) +static bool fk_info_append_fields(THD *thd, String *str, + List<LEX_STRING> *fields) { bool res= FALSE; LEX_STRING *field; @@ -43,9 +45,8 @@ static bool fk_info_append_fields(String *str, List<LEX_STRING> *fields) while ((field= it++)) { - res|= str->append("`"); - res|= str->append(field); - res|= str->append("`, "); + res|= append_identifier(thd, str, field->str, field->length); + res|= str->append(", "); } str->chop(); @@ -76,20 +77,24 @@ static const char *fk_info_str(THD *thd, FOREIGN_KEY_INFO *fk_info) `db`.`tbl`, CONSTRAINT `id` FOREIGN KEY (`fk`) REFERENCES `db`.`tbl` (`fk`) */ - res|= str.append('`'); - res|= str.append(fk_info->foreign_db); - res|= str.append("`.`"); - res|= str.append(fk_info->foreign_table); - res|= str.append("`, CONSTRAINT `"); - res|= str.append(fk_info->foreign_id); - res|= str.append("` FOREIGN KEY ("); - res|= fk_info_append_fields(&str, &fk_info->foreign_fields); - res|= str.append(") REFERENCES `"); - res|= str.append(fk_info->referenced_db); - res|= str.append("`.`"); - res|= str.append(fk_info->referenced_table); - res|= str.append("` ("); - res|= fk_info_append_fields(&str, &fk_info->referenced_fields); + res|= append_identifier(thd, &str, fk_info->foreign_db->str, + fk_info->foreign_db->length); + res|= str.append("."); + res|= append_identifier(thd, &str, fk_info->foreign_table->str, + fk_info->foreign_table->length); + res|= str.append(", CONSTRAINT "); + res|= append_identifier(thd, &str, fk_info->foreign_id->str, + fk_info->foreign_id->length); + res|= str.append(" FOREIGN KEY ("); + res|= fk_info_append_fields(thd, &str, &fk_info->foreign_fields); + res|= str.append(") REFERENCES "); + res|= append_identifier(thd, &str, fk_info->referenced_db->str, + fk_info->referenced_db->length); + res|= str.append("."); + res|= append_identifier(thd, &str, fk_info->referenced_table->str, + fk_info->referenced_table->length); + res|= str.append(" ("); + res|= fk_info_append_fields(thd, &str, &fk_info->referenced_fields); res|= str.append(')'); return res ? NULL : thd->strmake(str.ptr(), str.length()); diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 021267b53bd..8dcae907926 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -621,6 +621,8 @@ bool st_select_lex_unit::exec() if (executed && !uncacheable && !describe) DBUG_RETURN(FALSE); executed= 1; + if (!(uncacheable & ~UNCACHEABLE_EXPLAIN) && item) + item->make_const(); saved_error= optimize(); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 13c6cd3aded..48d2406c559 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -12236,7 +12236,7 @@ load_data_set_elem: if (lex->update_list.push_back($1) || lex->value_list.push_back($4)) MYSQL_YYABORT; - $4->set_name($3, (uint) ($5 - $3), YYTHD->charset()); + $4->set_name_no_truncate($3, (uint) ($5 - $3), YYTHD->charset()); } ; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 47dc8b3addf..01505525d7e 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -47,6 +47,7 @@ #include "sql_base.h" // close_cached_tables #include <myisam.h> #include "log_slow.h" +#include "debug_sync.h" // DEBUG_SYNC #include "log_event.h" #ifdef WITH_PERFSCHEMA_STORAGE_ENGINE @@ -3256,6 +3257,13 @@ bool Sys_var_rpl_filter::do_check(THD *thd, set_var *var) { bool status; + /* + We must not be holding LOCK_global_system_variables here, otherwise we can + deadlock with THD::init() which is invoked from within the slave threads + with opposite locking order. + */ + mysql_mutex_assert_not_owner(&LOCK_global_system_variables); + mysql_mutex_lock(&LOCK_active_mi); mysql_mutex_lock(&active_mi->rli.run_lock); @@ -3272,22 +3280,43 @@ bool Sys_var_rpl_filter::do_check(THD *thd, set_var *var) return status; } -bool Sys_var_rpl_filter::global_update(THD *thd, set_var *var) +void Sys_var_rpl_filter::lock(void) { - bool slave_running, status= false; + /* + Starting a slave thread causes the new thread to attempt to + acquire LOCK_global_system_variables (in THD::init) while + LOCK_active_mi is being held by the thread that initiated + the process. In order to not violate the lock order, unlock + LOCK_global_system_variables before grabbing LOCK_active_mi. + */ + mysql_mutex_unlock(&LOCK_global_system_variables); mysql_mutex_lock(&LOCK_active_mi); mysql_mutex_lock(&active_mi->rli.run_lock); +} - if (! (slave_running= active_mi->rli.slave_running)) - status= set_filter_value(var->save_result.string_value.str); - +void Sys_var_rpl_filter::unlock(void) +{ mysql_mutex_unlock(&active_mi->rli.run_lock); mysql_mutex_unlock(&LOCK_active_mi); + mysql_mutex_lock(&LOCK_global_system_variables); +} + +bool Sys_var_rpl_filter::global_update(THD *thd, set_var *var) +{ + bool slave_running, status= false; + + lock(); + + if (! (slave_running= active_mi->rli.slave_running)) + status= set_filter_value(var->save_result.string_value.str); + if (slave_running) my_error(ER_SLAVE_MUST_STOP, MYF(0)); + unlock(); + return slave_running || status; } @@ -3326,8 +3355,7 @@ uchar *Sys_var_rpl_filter::global_value_ptr(THD *thd, LEX_STRING *base) tmp.length(0); - mysql_mutex_lock(&LOCK_active_mi); - mysql_mutex_lock(&active_mi->rli.run_lock); + lock(); switch (opt_id) { case OPT_REPLICATE_DO_DB: @@ -3350,8 +3378,7 @@ uchar *Sys_var_rpl_filter::global_value_ptr(THD *thd, LEX_STRING *base) break; } - mysql_mutex_unlock(&active_mi->rli.run_lock); - mysql_mutex_unlock(&LOCK_active_mi); + unlock(); return (uchar *) thd->strmake(tmp.ptr(), tmp.length()); } @@ -3404,6 +3431,9 @@ static Sys_var_charptr Sys_slave_load_tmpdir( static bool fix_slave_net_timeout(sys_var *self, THD *thd, enum_var_type type) { + DEBUG_SYNC(thd, "fix_slave_net_timeout"); + + mysql_mutex_unlock(&LOCK_global_system_variables); mysql_mutex_lock(&LOCK_active_mi); DBUG_PRINT("info", ("slave_net_timeout=%u mi->heartbeat_period=%.3f", slave_net_timeout, @@ -3413,6 +3443,7 @@ static bool fix_slave_net_timeout(sys_var *self, THD *thd, enum_var_type type) ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX, ER(ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX)); mysql_mutex_unlock(&LOCK_active_mi); + mysql_mutex_lock(&LOCK_global_system_variables); return false; } static Sys_var_uint Sys_slave_net_timeout( @@ -3439,6 +3470,7 @@ static bool check_slave_skip_counter(sys_var *self, THD *thd, set_var *var) } static bool fix_slave_skip_counter(sys_var *self, THD *thd, enum_var_type type) { + mysql_mutex_unlock(&LOCK_global_system_variables); mysql_mutex_lock(&LOCK_active_mi); mysql_mutex_lock(&active_mi->rli.run_lock); /* @@ -3454,6 +3486,7 @@ static bool fix_slave_skip_counter(sys_var *self, THD *thd, enum_var_type type) } mysql_mutex_unlock(&active_mi->rli.run_lock); mysql_mutex_unlock(&LOCK_active_mi); + mysql_mutex_lock(&LOCK_global_system_variables); return 0; } static Sys_var_uint Sys_slave_skip_counter( diff --git a/sql/sys_vars.h b/sql/sys_vars.h index 4ea6b1f036e..21bebcd762c 100644 --- a/sql/sys_vars.h +++ b/sql/sys_vars.h @@ -588,6 +588,8 @@ public: protected: uchar *global_value_ptr(THD *thd, LEX_STRING *base); bool set_filter_value(const char *value); + void lock(void); + void unlock(void); }; /** @@ -957,7 +959,7 @@ public: Sys_var_max_user_conn(const char *name_arg, const char *comment, int flag_args, ptrdiff_t off, size_t size, CMD_LINE getopt, - uint min_val, uint max_val, uint def_val, + int min_val, int max_val, int def_val, uint block_size, PolyLock *lock=0, enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG, on_check_function on_check_func=0, diff --git a/sql/table.cc b/sql/table.cc index daccb0d1ca6..1fa5069a07e 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -4400,7 +4400,7 @@ bool TABLE_LIST::prep_check_option(THD *thd, uint8 check_opt_type) There are currently two mechanisms at work that handle errors for views, this one and a more general mechanism based on an Internal_error_handler, see Show_create_error_handler. The latter handles errors encountered during - execution of SHOW CREATE VIEW, while the machanism using this method is + execution of SHOW CREATE VIEW, while the mechanism using this method is handles SELECT from views. The two methods should not clash. @param[in,out] thd thread handler |