MDEV-13179 main.errors fails with wrong errno

The problem was that the introduction of max-thread-mem-used can cause
an allocation error very early, even before mysql_parse() is called.
As mysql_parse() calls thd->reset_for_next_command(), which called
clear_error(), the error number was lost.

Fixed by adding an option to have unique messages for each KILL
signal and change max-thread-mem-used to use this new feature.
This removes a lot of problems with the original approach, where
one could get errors signaled silenty almost any time.

ixed by moving clear_error() from reset_for_next_command() to
do_command(), before any memory allocation for the thread.

Related changes:
- reset_for_next_command() now have an optional parameter if we should
  call clear_error() or not. By default it's called, but not anymore from
  dispatch_command() which was the original problem.
- Added optional paramater to clear_error() to force calling of
  reset_diagnostics_area(). Before clear_error() only called
  reset_diagnostics_area() if there was no error, so we normally
  called reset_diagnostics_area() twice.
- This change removed several duplicated calls to clear_error()
  when starting a query.
- Reset max_mem_used on COM_QUIT, to protect against kill during
  quit.
- Use fatal_error() instead of setting is_fatal_error (cleanup)
- Set fatal_error if max_thead_mem_used is signaled.
  (Same logic we use for other places where we are out of resources)
This commit is contained in:
Monty 2017-08-05 19:26:10 +03:00
parent 008786aedb
commit 74543698a7
24 changed files with 177 additions and 101 deletions

View File

@ -140,8 +140,7 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command,
}
/* Clear result variables */
thd->clear_error();
thd->get_stmt_da()->reset_diagnostics_area();
thd->clear_error(1);
mysql->affected_rows= ~(my_ulonglong) 0;
mysql->field_count= 0;
net_clear_error(net);

View File

@ -168,7 +168,7 @@ UPDATE t1 SET a = 'new'
WHERE COLUMN_CREATE( 1, 'v', 1, 'w' ) IS NULL;
ERROR 22007: Illegal value used as argument of dynamic column function
drop table t1;
set max_session_mem_used = 50000;
select * from seq_1_to_1000;
set max_session_mem_used = 8192;
select * from seq_1_to_1000;
Got one of the listed errors
set global max_session_mem_used = default;

View File

@ -203,7 +203,13 @@ drop table t1;
#
# errors caused by max_session_mem_used
#
set max_session_mem_used = 8192;
--error ER_SQL_DISCOVER_ERROR,ER_OPTION_PREVENTS_STATEMENT
--disable_result_log
set max_session_mem_used = 50000;
--error 0,ER_OPTION_PREVENTS_STATEMENT
select * from seq_1_to_1000;
set global max_session_mem_used = default;
set max_session_mem_used = 8192;
--error 0,ER_OPTION_PREVENTS_STATEMENT
select * from seq_1_to_1000;
--enable_result_log
# We may not be able to execute any more queries with this connection
# because of too little memory#

View File

@ -1502,7 +1502,7 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
{
if (!--action->hit_limit)
{
thd->killed= KILL_QUERY;
thd->set_killed(KILL_QUERY);
my_error(ER_DEBUG_SYNC_HIT_LIMIT, MYF(0));
}
DBUG_PRINT("debug_sync_exec", ("hit_limit: %lu at: '%s'",

View File

@ -371,12 +371,6 @@ static void pretty_print_str(IO_CACHE* cache, const char* str, int len)
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
static void clear_all_errors(THD *thd, Relay_log_info *rli)
{
thd->is_slave_error = 0;
thd->clear_error();
}
inline int idempotent_error_code(int err_code)
{
int ret= 0;
@ -4255,7 +4249,7 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi,
DBUG_PRINT("info", ("log_pos: %lu", (ulong) log_pos));
clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
thd->clear_error(1);
current_stmt_is_commit= is_commit();
DBUG_ASSERT(!current_stmt_is_commit || !rgi->tables_to_lock);
@ -4475,7 +4469,7 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi,
to check/fix it.
*/
if (mysql_test_parse_for_slave(thd, thd->query(), thd->query_length()))
clear_all_errors(thd, const_cast<Relay_log_info*>(rli)); /* Can ignore query */
thd->clear_error(1);
else
{
rli->report(ERROR_LEVEL, expected_error, rgi->gtid_info(),
@ -4556,7 +4550,7 @@ compare_errors:
ignored_error_code(actual_error))
{
DBUG_PRINT("info",("error ignored"));
clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
thd->clear_error(1);
if (actual_error == ER_QUERY_INTERRUPTED ||
actual_error == ER_CONNECTION_KILLED)
thd->reset_killed();
@ -6025,8 +6019,7 @@ int Load_log_event::do_apply_event(NET* net, rpl_group_info *rgi,
new_db.str= (char *) rpl_filter->get_rewrite_db(db, &new_db.length);
thd->set_db(new_db.str, new_db.length);
DBUG_ASSERT(thd->query() == 0);
thd->is_slave_error= 0;
clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
thd->clear_error(1);
/* see Query_log_event::do_apply_event() and BUG#13360 */
DBUG_ASSERT(!rgi->m_table_map.count());
@ -6036,7 +6029,7 @@ int Load_log_event::do_apply_event(NET* net, rpl_group_info *rgi,
*/
lex_start(thd);
thd->lex->local_file= local_fname;
thd->reset_for_next_command();
thd->reset_for_next_command(0); // Errors are cleared above
/*
We test replicate_*_db rules. Note that we have already prepared
@ -10091,7 +10084,7 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
slave_rows_error_report(WARNING_LEVEL, error, rgi, thd, table,
get_type_str(),
RPL_LOG_NAME, (ulong) log_pos);
clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
thd->clear_error(1);
error= 0;
if (idempotent_error == 0)
break;
@ -10143,7 +10136,7 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
slave_rows_error_report(WARNING_LEVEL, error, rgi, thd, table,
get_type_str(),
RPL_LOG_NAME, (ulong) log_pos);
clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
thd->clear_error(1);
error= 0;
}
} // if (table)

View File

@ -878,7 +878,7 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
key_LOCK_prepared_stmt_count,
key_LOCK_rpl_status, key_LOCK_server_started,
key_LOCK_status, key_LOCK_show_status,
key_LOCK_system_variables_hash, key_LOCK_thd_data,
key_LOCK_system_variables_hash, key_LOCK_thd_data, key_LOCK_thd_kill,
key_LOCK_user_conn, key_LOCK_uuid_short_generator, key_LOG_LOCK_log,
key_master_info_data_lock, key_master_info_run_lock,
key_master_info_sleep_lock, key_master_info_start_stop_lock,
@ -949,6 +949,7 @@ static PSI_mutex_info all_server_mutexes[]=
{ &key_LOCK_wait_commit, "wait_for_commit::LOCK_wait_commit", 0},
{ &key_LOCK_gtid_waiting, "gtid_waiting::LOCK_gtid_waiting", 0},
{ &key_LOCK_thd_data, "THD::LOCK_thd_data", 0},
{ &key_LOCK_thd_kill, "THD::LOCK_thd_kill", 0},
{ &key_LOCK_user_conn, "LOCK_user_conn", PSI_FLAG_GLOBAL},
{ &key_LOCK_uuid_short_generator, "LOCK_uuid_short_generator", PSI_FLAG_GLOBAL},
{ &key_LOG_LOCK_log, "LOG::LOCK_log", 0},
@ -1650,7 +1651,7 @@ static void close_connections(void)
if (WSREP(tmp) && (tmp->wsrep_exec_mode==REPL_RECV || tmp->wsrep_applier))
continue;
#endif
tmp->killed= KILL_SERVER_HARD;
tmp->set_killed(KILL_SERVER_HARD);
MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (tmp));
mysql_mutex_lock(&tmp->LOCK_thd_data);
if (tmp->mysys_var)
@ -1738,7 +1739,7 @@ static void close_connections(void)
if (WSREP(tmp) && tmp->wsrep_exec_mode==REPL_RECV)
{
sql_print_information("closing wsrep system thread");
tmp->killed= KILL_CONNECTION;
tmp->set_killed(KILL_CONNECTION);
MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (tmp));
if (tmp->mysys_var)
{
@ -3943,11 +3944,16 @@ static void my_malloc_size_cb_func(long long size, my_bool is_thread_specific)
thd->status_var.local_memory_used > (int64)thd->variables.max_mem_used &&
!thd->killed && !thd->get_stmt_da()->is_set())
{
char buf[1024];
thd->killed= KILL_QUERY;
/* Ensure we don't get called here again */
char buf[50], *buf2;
thd->set_killed(KILL_QUERY);
my_snprintf(buf, sizeof(buf), "--max-thread-mem-used=%llu",
thd->variables.max_mem_used);
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), buf);
if ((buf2= (char*) thd->alloc(256)))
{
my_snprintf(buf2, 256, ER_THD(thd, ER_OPTION_PREVENTS_STATEMENT), buf);
thd->set_killed(KILL_QUERY, ER_OPTION_PREVENTS_STATEMENT, buf2);
}
}
DBUG_ASSERT((longlong) thd->status_var.local_memory_used >= 0);
}
@ -6318,7 +6324,7 @@ void create_thread_to_handle_connection(THD *thd)
DBUG_PRINT("error",
("Can't create thread to handle request (error %d)",
error));
thd->killed= KILL_CONNECTION; // Safety
thd->set_killed(KILL_CONNECTION); // Safety
mysql_mutex_unlock(&LOCK_thread_count);
mysql_mutex_lock(&LOCK_connection_count);

View File

@ -290,7 +290,7 @@ extern PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
key_LOCK_prepared_stmt_count,
key_LOCK_rpl_status, key_LOCK_server_started,
key_LOCK_status, key_LOCK_show_status,
key_LOCK_thd_data,
key_LOCK_thd_data, key_LOCK_thd_kill,
key_LOCK_user_conn, key_LOG_LOCK_log,
key_master_info_data_lock, key_master_info_run_lock,
key_master_info_sleep_lock, key_master_info_start_stop_lock,

View File

@ -714,9 +714,7 @@ do_retry:
DBUG_EXECUTE_IF("inject_mdev8031", {
/* Simulate that we get deadlock killed at this exact point. */
rgi->killed_for_retry= rpl_group_info::RETRY_KILL_KILLED;
mysql_mutex_lock(&thd->LOCK_thd_data);
thd->killed= KILL_CONNECTION;
mysql_mutex_unlock(&thd->LOCK_thd_data);
thd->set_killed(KILL_CONNECTION);
});
rgi->cleanup_context(thd, 1);
wait_for_pending_deadlock_kill(thd, rgi);
@ -862,9 +860,7 @@ do_retry:
/* Simulate that we get deadlock killed during open_binlog(). */
thd->reset_for_next_command();
rgi->killed_for_retry= rpl_group_info::RETRY_KILL_KILLED;
mysql_mutex_lock(&thd->LOCK_thd_data);
thd->killed= KILL_CONNECTION;
mysql_mutex_unlock(&thd->LOCK_thd_data);
thd->set_killed(KILL_CONNECTION);
thd->send_kill_message();
fd= (File)-1;
err= 1;

View File

@ -331,8 +331,7 @@ bool sp_rcontext::handle_sql_condition(THD *thd,
/* Reset error state. */
thd->clear_error();
thd->killed= NOT_KILLED; // Some errors set thd->killed
// (e.g. "bad data").
thd->reset_killed(); // Some errors set thd->killed, (e.g. "bad data").
/* Add a frame to handler-call-stack. */
Sql_condition_info *cond_info=

View File

@ -400,7 +400,7 @@ void kill_delayed_threads_for_table(TDC_element *element)
if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
! in_use->killed)
{
in_use->killed= KILL_SYSTEM_THREAD;
in_use->set_killed(KILL_SYSTEM_THREAD);
mysql_mutex_lock(&in_use->mysys_var->mutex);
if (in_use->mysys_var->current_cond)
{
@ -9136,7 +9136,7 @@ bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use,
if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
!in_use->killed)
{
in_use->killed= KILL_SYSTEM_THREAD;
in_use->set_killed(KILL_SYSTEM_THREAD);
mysql_mutex_lock(&in_use->mysys_var->mutex);
if (in_use->mysys_var->current_cond)
{

View File

@ -2160,8 +2160,7 @@ lookup:
response, we can't handle it anyway.
*/
(void) trans_commit_stmt(thd);
if (!thd->get_stmt_da()->is_set())
thd->get_stmt_da()->disable_status();
thd->get_stmt_da()->disable_status();
BLOCK_UNLOCK_RD(query_block);
MYSQL_QUERY_CACHE_HIT(thd->query(), (ulong) thd->limit_found_rows);
@ -4615,7 +4614,7 @@ void Query_cache::wreck(uint line, const char *message)
DBUG_PRINT("warning", ("%5d QUERY CACHE WRECK => DISABLED",line));
DBUG_PRINT("warning", ("=================================="));
if (thd)
thd->killed= KILL_CONNECTION;
thd->set_killed(KILL_CONNECTION);
cache_dump();
/* check_integrity(0); */ /* Can't call it here because of locks */
bins_dump();

View File

@ -333,7 +333,7 @@ void thd_set_psi(THD *thd, PSI_thread *psi)
*/
void thd_set_killed(THD *thd)
{
thd->killed= KILL_CONNECTION;
thd->set_killed(KILL_CONNECTION);
}
/**
@ -935,6 +935,7 @@ THD::THD(bool is_wsrep_applier)
query_start_used= query_start_sec_part_used= 0;
count_cuted_fields= CHECK_FIELD_IGNORE;
killed= NOT_KILLED;
killed_err= 0;
col_access=0;
is_slave_error= thread_specific_used= FALSE;
my_hash_clear(&handler_tables_hash);
@ -992,6 +993,7 @@ THD::THD(bool is_wsrep_applier)
#endif
mysql_mutex_init(key_LOCK_thd_data, &LOCK_thd_data, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_wakeup_ready, &LOCK_wakeup_ready, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_thd_kill, &LOCK_thd_kill, MY_MUTEX_INIT_FAST);
mysql_cond_init(key_COND_wakeup_ready, &COND_wakeup_ready, 0);
/*
LOCK_thread_count goes before LOCK_thd_data - the former is called around
@ -1256,7 +1258,7 @@ Sql_condition* THD::raise_condition(uint sql_errno,
push_warning and strict SQL_MODE case.
*/
level= Sql_condition::WARN_LEVEL_ERROR;
killed= KILL_BAD_DATA;
set_killed(KILL_BAD_DATA);
}
switch (level)
@ -1564,7 +1566,7 @@ void THD::cleanup(void)
DBUG_ENTER("THD::cleanup");
DBUG_ASSERT(cleanup_done == 0);
killed= KILL_CONNECTION;
set_killed(KILL_CONNECTION);
#ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE
if (transaction.xid_state.xa_state == XA_PREPARED)
{
@ -1667,6 +1669,7 @@ THD::~THD()
mysql_cond_destroy(&COND_wakeup_ready);
mysql_mutex_destroy(&LOCK_wakeup_ready);
mysql_mutex_destroy(&LOCK_thd_data);
mysql_mutex_destroy(&LOCK_thd_kill);
#ifndef DBUG_OFF
dbug_sentry= THD_SENTRY_GONE;
#endif
@ -1839,7 +1842,8 @@ void THD::awake(killed_state state_to_set)
state_to_set= killed;
/* Set the 'killed' flag of 'this', which is the target THD object. */
killed= state_to_set;
mysql_mutex_lock(&LOCK_thd_kill);
set_killed_no_mutex(state_to_set);
if (state_to_set >= KILL_CONNECTION || state_to_set == NOT_KILLED)
{
@ -1925,6 +1929,7 @@ void THD::awake(killed_state state_to_set)
}
mysql_mutex_unlock(&mysys_var->mutex);
}
mysql_mutex_unlock(&LOCK_thd_kill);
DBUG_VOID_RETURN;
}
@ -1942,7 +1947,7 @@ void THD::disconnect()
mysql_mutex_lock(&LOCK_thd_data);
killed= KILL_CONNECTION;
set_killed(KILL_CONNECTION);
#ifdef SIGNAL_WITH_VIO_CLOSE
/*
@ -1978,7 +1983,7 @@ bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use,
DBUG_PRINT("info", ("kill delayed thread"));
mysql_mutex_lock(&in_use->LOCK_thd_data);
if (in_use->killed < KILL_CONNECTION)
in_use->killed= KILL_CONNECTION;
in_use->set_killed(KILL_CONNECTION);
if (in_use->mysys_var)
{
mysql_mutex_lock(&in_use->mysys_var->mutex);
@ -2031,13 +2036,21 @@ bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use,
/*
Get error number for killed state
Note that the error message can't have any parameters.
If one needs parameters, one should use THD::killed_err_msg
See thd::kill_message()
*/
int killed_errno(killed_state killed)
int THD::killed_errno()
{
DBUG_ENTER("killed_errno");
DBUG_PRINT("enter", ("killed: %d", killed));
DBUG_PRINT("enter", ("killed: %d killed_errno: %d",
killed, killed_err ? killed_err->no: 0));
/* Ensure that killed_err is not set if we are not killed */
DBUG_ASSERT(!killed_err || killed != NOT_KILLED);
if (killed_err)
DBUG_RETURN(killed_err->no);
switch (killed) {
case NOT_KILLED:
@ -2478,7 +2491,7 @@ CHANGED_TABLE_LIST* THD::changed_table_dup(const char *key, long key_length)
{
my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_FATALERROR),
ALIGN_SIZE(sizeof(TABLE_LIST)) + key_length + 1);
killed= KILL_CONNECTION;
set_killed(KILL_CONNECTION);
return 0;
}

View File

@ -482,7 +482,6 @@ enum killed_state
KILL_SERVER_HARD= 15
};
extern int killed_errno(killed_state killed);
#define killed_mask_hard(killed) ((killed_state) ((killed) & ~KILL_HARD_BIT))
enum killed_type
@ -1924,7 +1923,7 @@ public:
rpl_sql_thread_info *rpl_sql_info;
} system_thread_info;
void reset_for_next_command();
void reset_for_next_command(bool do_clear_errors= 1);
/*
Constant for THD::where initialization in the beginning of every query.
@ -1980,6 +1979,8 @@ public:
Is locked when THD is deleted.
*/
mysql_mutex_t LOCK_thd_data;
/* Protect kill information */
mysql_mutex_t LOCK_thd_kill;
/* all prepared statements and cursors of this connection */
Statement_map stmt_map;
@ -2615,7 +2616,7 @@ public:
void check_limit_rows_examined()
{
if (++accessed_rows_and_keys > lex->limit_rows_examined_cnt)
killed= ABORT_QUERY;
set_killed(ABORT_QUERY);
}
USER_CONN *user_connect;
@ -2716,6 +2717,16 @@ public:
*/
killed_state volatile killed;
/*
The following is used if one wants to have a specific error number and
text for the kill
*/
struct err_info
{
int no;
const char msg[256];
} *killed_err;
/* See also thd_killed() */
inline bool check_killed()
{
@ -3280,18 +3291,18 @@ public:
@todo: To silence an error, one should use Internal_error_handler
mechanism. Issuing an error that can be possibly later "cleared" is not
compatible with other installed error handlers and audit plugins.
In future this function will be removed.
*/
inline void clear_error()
inline void clear_error(bool clear_diagnostics= 0)
{
DBUG_ENTER("clear_error");
if (get_stmt_da()->is_error())
if (get_stmt_da()->is_error() || clear_diagnostics)
get_stmt_da()->reset_diagnostics_area();
is_slave_error= 0;
if (killed == KILL_BAD_DATA)
killed= NOT_KILLED; // KILL_BAD_DATA can be reset w/o a mutex
reset_killed();
DBUG_VOID_RETURN;
}
#ifndef EMBEDDED_LIBRARY
inline bool vio_ok() const { return net.vio != 0; }
/** Return FALSE if connection to client is broken. */
@ -3401,10 +3412,54 @@ public:
state after execution of a non-prepared SQL statement.
*/
void end_statement();
inline int killed_errno() const
/*
Mark thread to be killed, with optional error number and string.
string is not released, so it has to be allocted on thd mem_root
or be a global string
Ensure that we don't replace a kill with a lesser one. For example
if user has done 'kill_connection' we shouldn't replace it with
KILL_QUERY.
*/
inline void set_killed(killed_state killed_arg,
int killed_errno_arg= 0,
const char *killed_err_msg_arg= 0)
{
return ::killed_errno(killed);
mysql_mutex_lock(&LOCK_thd_kill);
set_killed_no_mutex(killed_arg, killed_errno_arg, killed_err_msg_arg);
mysql_mutex_unlock(&LOCK_thd_kill);
}
/*
This is only used by THD::awake where we need to keep the lock mutex
locked over some time.
It's ok to have this inline, as in most cases killed_errno_arg will
be a constant 0 and most of the function will disappear.
*/
inline void set_killed_no_mutex(killed_state killed_arg,
int killed_errno_arg= 0,
const char *killed_err_msg_arg= 0)
{
if (killed <= killed_arg)
{
killed= killed_arg;
if (killed_errno_arg)
{
/*
If alloc fails, we only remember the killed flag.
The worst things that can happen is that we get
a suboptimal error message.
*/
if ((killed_err= (err_info*) alloc(sizeof(*killed_err))))
{
killed_err->no= killed_errno_arg;
::strmake((char*) killed_err->msg, killed_err_msg_arg,
sizeof(killed_err->msg)-1);
}
}
}
}
int killed_errno();
inline void reset_killed()
{
/*
@ -3413,9 +3468,10 @@ public:
*/
if (killed != NOT_KILLED)
{
mysql_mutex_lock(&LOCK_thd_data);
mysql_mutex_lock(&LOCK_thd_kill);
killed= NOT_KILLED;
mysql_mutex_unlock(&LOCK_thd_data);
killed_err= 0;
mysql_mutex_unlock(&LOCK_thd_kill);
}
}
inline void reset_kill_query()
@ -3426,11 +3482,14 @@ public:
mysys_var->abort= 0;
}
}
inline void send_kill_message() const
inline void send_kill_message()
{
mysql_mutex_lock(&LOCK_thd_kill);
int err= killed_errno();
if (err)
my_message(err, ER_THD(this, err), MYF(0));
my_message(err, killed_err ? killed_err->msg : ER_THD(this, err),
MYF(0));
mysql_mutex_unlock(&LOCK_thd_kill);
}
/* return TRUE if we will abort query if we make a warning now */
inline bool really_abort_on_warning()

View File

@ -1196,7 +1196,7 @@ void prepare_new_connection_state(THD* thd)
if (thd->is_error())
{
Host_errors errors;
thd->killed= KILL_CONNECTION;
thd->set_killed(KILL_CONNECTION);
thd->print_aborted_warning(0, "init_connect command failed");
sql_print_warning("%s", thd->get_stmt_da()->message());

View File

@ -2681,7 +2681,7 @@ void kill_delayed_threads(void)
{
mysql_mutex_lock(&di->thd.LOCK_thd_data);
if (di->thd.killed < KILL_CONNECTION)
di->thd.killed= KILL_CONNECTION;
di->thd.set_killed(KILL_CONNECTION);
if (di->thd.mysys_var)
{
mysql_mutex_lock(&di->thd.mysys_var->mutex);
@ -2827,7 +2827,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
thd->set_current_time();
threads.append(thd);
if (abort_loop)
thd->killed= KILL_CONNECTION;
thd->set_killed(KILL_CONNECTION);
else
thd->reset_killed();
mysql_mutex_unlock(&LOCK_thread_count);
@ -2972,7 +2972,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
}
#endif
if (error == ETIMEDOUT || error == ETIME)
thd->killed= KILL_CONNECTION;
thd->set_killed(KILL_CONNECTION);
}
/* We can't lock di->mutex and mysys_var->mutex at the same time */
mysql_mutex_unlock(&di->mutex);
@ -3001,7 +3001,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
if (! (thd->lock= mysql_lock_tables(thd, &di->table, 1, 0)))
{
/* Fatal error */
thd->killed= KILL_CONNECTION;
thd->set_killed(KILL_CONNECTION);
}
mysql_cond_broadcast(&di->cond_client);
}
@ -3010,7 +3010,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
if (di->handle_inserts())
{
/* Some fatal error */
thd->killed= KILL_CONNECTION;
thd->set_killed(KILL_CONNECTION);
}
}
di->status=0;
@ -3054,7 +3054,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
this.
*/
mysql_mutex_lock(&thd->LOCK_thd_data);
thd->killed= KILL_CONNECTION_HARD; // If error
thd->set_killed(KILL_CONNECTION_HARD); // If error
thd->mdl_context.set_needs_thr_lock_abort(0);
mysql_mutex_unlock(&thd->LOCK_thd_data);
@ -3143,7 +3143,7 @@ bool Delayed_insert::handle_inserts(void)
max_rows= delayed_insert_limit;
if (thd.killed || table->s->tdc->flushed)
{
thd.killed= KILL_SYSTEM_THREAD;
thd.set_killed(KILL_SYSTEM_THREAD);
max_rows= ULONG_MAX; // Do as much as possible
}

View File

@ -613,7 +613,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
DBUG_EXECUTE_IF("simulate_kill_bug27571",
{
error=1;
thd->killed= KILL_QUERY;
thd->set_killed(KILL_QUERY);
};);
#ifndef EMBEDDED_LIBRARY

View File

@ -669,6 +669,7 @@ void execute_init_command(THD *thd, LEX_STRING *init_command,
*/
save_vio= thd->net.vio;
thd->net.vio= 0;
thd->clear_error(1);
dispatch_command(COM_QUERY, thd, buf, len);
thd->client_capabilities= save_client_capabilities;
thd->net.vio= save_vio;
@ -800,6 +801,7 @@ static void handle_bootstrap_impl(THD *thd)
if (bootstrap_error)
break;
thd->reset_kill_query(); /* Ensure that killed_errmsg is released */
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
thd->lex->restore_set_statement_var();
@ -954,13 +956,8 @@ bool do_command(THD *thd)
if(!thd->skip_wait_timeout)
my_net_set_read_timeout(net, thd->variables.net_wait_timeout);
/*
XXX: this code is here only to clear possible errors of init_connect.
Consider moving to init_connect() instead.
*/
thd->clear_error(); // Clear error message
thd->get_stmt_da()->reset_diagnostics_area();
/* Errors and diagnostics are cleared once here before query */
thd->clear_error(1);
net_new_transaction(net);
@ -1123,6 +1120,7 @@ bool do_command(THD *thd)
WSREP_WARN("For retry temporally setting character set to : %s",
my_charset_latin1.csname);
}
thd->clear_error();
return_value= dispatch_command(command, thd, thd->wsrep_retry_query,
thd->wsrep_retry_query_len);
thd->variables.character_set_client = current_charset;
@ -1272,7 +1270,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction");
WSREP_DEBUG("Deadlock error for: %s", thd->query());
mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
thd->killed = NOT_KILLED;
thd->reset_killed();
thd->mysys_var->abort = 0;
thd->wsrep_conflict_state = NO_CONFLICT;
thd->wsrep_retry_counter = 0;
@ -1625,7 +1623,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
}
packet= arg_end + 1;
thd->reset_for_next_command();
thd->reset_for_next_command(0); // Don't clear errors
lex_start(thd);
/* Must be before we init the table list. */
if (lower_case_table_names)
@ -1694,7 +1692,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
#endif
case COM_QUIT:
/* We don't calculate statistics for this command */
/* Note: We don't calculate statistics for this command */
/* Ensure that quit works even if max_mem_used is set */
thd->variables.max_mem_used= LONGLONG_MAX;
general_log_print(thd, command, NullS);
net->error=0; // Don't give 'abort' message
thd->get_stmt_da()->disable_status(); // Don't send anything back
@ -1974,6 +1975,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
dec_thread_running();
thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory
thd->reset_kill_query(); /* Ensure that killed_errmsg is released */
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
#if defined(ENABLED_PROFILING)
@ -5047,7 +5049,7 @@ end_with_restore_list:
/* Disconnect the current client connection. */
if (tx_release)
{
thd->killed= KILL_CONNECTION;
thd->set_killed(KILL_CONNECTION);
thd->print_aborted_warning(3, "RELEASE");
}
#ifdef WITH_WSREP
@ -5093,7 +5095,7 @@ end_with_restore_list:
}
/* Disconnect the current client connection. */
if (tx_release)
thd->killed= KILL_CONNECTION;
thd->set_killed(KILL_CONNECTION);
#ifdef WITH_WSREP
if (WSREP(thd) && thd->wsrep_conflict_state != NO_CONFLICT)
{
@ -6879,6 +6881,8 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
Reset the part of THD responsible for the state of command
processing.
@param do_clear_error Set if we should clear errors
This needs to be called before execution of every statement
(prepared or conventional). It is not called by substatements of
routines.
@ -6886,12 +6890,16 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
@todo Call it after we use THD for queries, not before.
*/
void THD::reset_for_next_command()
void THD::reset_for_next_command(bool do_clear_error)
{
THD *thd= this;
DBUG_ENTER("THD::reset_for_next_command");
DBUG_ASSERT(!thd->spcont); /* not for substatements of routines */
DBUG_ASSERT(! thd->in_sub_stmt);
if (do_clear_error)
clear_error(1);
thd->free_list= 0;
thd->select_number= 1;
/*
@ -6947,8 +6955,6 @@ void THD::reset_for_next_command()
reset_dynamic(&thd->user_var_events);
thd->user_var_events_alloc= thd->mem_root;
}
thd->clear_error();
thd->get_stmt_da()->reset_diagnostics_area();
thd->get_stmt_da()->reset_for_next_command();
thd->rand_used= 0;
thd->m_sent_row_count= thd->m_examined_row_count= 0;
@ -7180,7 +7186,7 @@ static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
thd->wsrep_conflict_state == CERT_FAILURE)
{
thd->reset_for_next_command();
thd->killed= NOT_KILLED;
thd->reset_killed();
if (is_autocommit &&
thd->lex->sql_command != SQLCOM_SELECT &&
(thd->wsrep_retry_counter < thd->variables.wsrep_retry_autocommit))
@ -7208,7 +7214,7 @@ static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
thd->thread_id, is_autocommit, thd->wsrep_retry_counter,
thd->variables.wsrep_retry_autocommit, thd->query());
my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction");
thd->killed= NOT_KILLED;
thd->reset_killed();
thd->wsrep_conflict_state= NO_CONFLICT;
if (thd->wsrep_conflict_state != REPLAYING)
thd->wsrep_retry_counter= 0; // reset
@ -8282,10 +8288,10 @@ void sql_kill(THD *thd, longlong id, killed_state state, killed_type type)
uint error;
if (!(error= kill_one_thread(thd, id, state, type)))
{
if ((!thd->killed))
if (!thd->killed)
my_ok(thd);
else
my_error(killed_errno(thd->killed), MYF(0), id);
thd->send_kill_message();
}
else
my_error(error, MYF(0), id);

View File

@ -3592,7 +3592,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
#endif
DBUG_EXECUTE_IF("bug11747970_raise_error",
{ join->thd->killed= KILL_QUERY_HARD; });
{ join->thd->set_killed(KILL_QUERY_HARD); });
if (error)
{
table->file->print_error(error, MYF(0));

View File

@ -4783,7 +4783,7 @@ int create_table_impl(THD *thd,
thd->variables.option_bits|= OPTION_KEEP_LOG;
thd->log_current_statement= 1;
create_info->table_was_deleted= 1;
DBUG_EXECUTE_IF("send_kill_after_delete", thd->killed= KILL_QUERY; );
DBUG_EXECUTE_IF("send_kill_after_delete", thd->set_killed(KILL_QUERY); );
/*
Restart statement transactions for the case of CREATE ... SELECT.

View File

@ -940,7 +940,7 @@ int mysql_update(THD *thd,
// simulated killing after the loop must be ineffective for binlogging
DBUG_EXECUTE_IF("simulate_kill_bug27571",
{
thd->killed= KILL_QUERY;
thd->set_killed(KILL_QUERY);
};);
error= (killed_status == NOT_KILLED)? error : 1;

View File

@ -463,7 +463,7 @@ static void timeout_check(pool_timer_t *timer)
{
/* Wait timeout exceeded, kill connection. */
mysql_mutex_lock(&thd->LOCK_thd_data);
thd->killed = KILL_CONNECTION;
thd->set_killed(KILL_CONNECTION);
post_kill_notification(thd);
mysql_mutex_unlock(&thd->LOCK_thd_data);
}

View File

@ -613,7 +613,7 @@ static VOID CALLBACK timer_callback(PTP_CALLBACK_INSTANCE instance,
if (timeout <= now())
{
con->thd->killed = KILL_CONNECTION;
con->thd->set_killed(KILL_CONNECTION);
if(con->thd->net.vio)
vio_shutdown(con->thd->net.vio, SD_BOTH);
}

View File

@ -1965,7 +1965,7 @@ static bool have_client_connections()
static void wsrep_close_thread(THD *thd)
{
thd->killed= KILL_CONNECTION;
thd->set_killed(KILL_CONNECTION);
MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (thd));
if (thd->mysys_var)
{
@ -2045,7 +2045,7 @@ void wsrep_close_client_connections(my_bool wait_to_end)
if (is_replaying_connection(tmp))
{
tmp->killed= KILL_CONNECTION;
tmp->set_killed(KILL_CONNECTION);
continue;
}

View File

@ -232,7 +232,7 @@ void wsrep_replay_transaction(THD *thd)
mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
thd->reset_for_next_command();
thd->killed= NOT_KILLED;
thd->reset_killed();
close_thread_tables(thd);
if (thd->locked_tables_mode && thd->lock)
{