Commit 8d0c4696 authored by Michael Widenius's avatar Michael Widenius

Added new options to KILL. New syntax is KILL [HARD|SOFT] [CONNECTION|QUERY] [ID | USER user_name]

- If USER is given, all threads for that user is signaled
- If SOFT is used then the KILL will not be sent to the handler. This can be used to not interrupt critical things in the handler like 'REPAIR'.

Internally added more kill signals. This gives us more information of why a query/connection was killed.
- KILL_SERVER is used when server is going down. In this case the users gets ER_SHUTDOWN as the reason connection was killed.
- Changed signals to number in correct order, which makes it easier to test how the signal should affect the code.
- New error message ER_CONNECTION_KILLED if connection was killed by 'KILL CONNECTION'. Before we got error ER_SHUTDOWN.

Changed names of not used parameters KILL_QUERY & KILL_CONNCTION to mysql_kill() to not conflict with defines in the server


include/mysql.h.pp:
  Updated file
include/mysql_com.h:
  Changed names of not used parameters KILL_QUERY & KILL_CONNCTION to mysql_kill() to not conflict with defines in the server
mysql-test/r/kill.result:
  Added test of KILL USER
mysql-test/suite/rpl/r/rpl_stm_000001.result:
  Updated error code
mysql-test/suite/rpl/t/rpl_stm_000001.test:
  Updated error codes
mysql-test/t/flush_read_lock_kill.test:
  Updated error codes
mysql-test/t/kill.test:
  Added test of KILL USER
plugin/handler_socket/handlersocket/database.cpp:
  Removed THD:: from KILL
sql/debug_sync.cc:
  Removed THD:: from KILL
sql/event_scheduler.cc:
  Removed THD:: from KILL
sql/filesort.cc:
  Removed THD:: from KILL
sql/ha_ndbcluster_binlog.cc:
  Removed THD:: from KILL
sql/handler.cc:
  Removed THD:: from KILL
  Simplify code.
sql/lex.h:
  Added new keywords HARD | SOFT
sql/log.cc:
  Removed THD:: from KILL
  Added testing of new error ER_CONNECTION_KILLED
sql/log_event.cc:
  Removed THD:: from KILL
  Added testing of new error ER_CONNECTION_KILLED
sql/mysql_priv.h:
  Added new prototypes
sql/mysqld.cc:
  Removed THD:: from KILL
  Use KILL_SERVER_HARD signal on shutdown.
sql/scheduler.cc:
  Removed THD:: from KILL
  Simplify test if connection should be killed
sql/share/errmsg.txt:
  New error message ER_CONNECTION_KILLED
sql/slave.cc:
  Removed THD:: from KILL
sql/sp_head.cc:
  Removed THD:: from KILL
sql/sql_base.cc:
  Removed THD:: from KILL
sql/sql_cache.cc:
  Removed THD:: from KILL
sql/sql_class.cc:
  Removed THD:: from KILL
  Added killed_errno()
  Only signal kill to storage engine if HARD bit is set.
sql/sql_class.h:
  Move KILL options out from THD to make them easier to use in sql_yacc.yy
sql/sql_connect.cc:
  Removed THD:: from KILL
sql/sql_delete.cc:
  Removed THD:: from KILL
sql/sql_error.cc:
  Removed THD:: from KILL
sql/sql_insert.cc:
  Removed THD:: from KILL
  Simplifed testing if thread is killed.
sql/sql_lex.h:
  Added kill options to st_lex
sql/sql_load.cc:
  Removed THD:: from KILL
sql/sql_parse.cc:
  Added kill options to st_lex
  Simplifed and optimzed testing of thd->killed at end of query
  Added support for KILL USER
  Extended sql_kill() to allow use of more kill signals.
sql/sql_repl.cc:
  Removed THD:: from KILL
sql/sql_show.cc:
  Removed THD:: from KILL
  Simplied testing if query/connection was killed
sql/sql_table.cc:
  Removed THD:: from KILL
sql/sql_update.cc:
  Removed THD:: from KILL
sql/sql_yacc.yy:
  Added support for new KILL syntax: KILL [HARD|SOFT] [CONNECTION|QUERY] [ID | USER user_name]
storage/archive/ha_archive.cc:
  Simplify compilation
storage/maria/ha_maria.cc:
  Removed THD:: from KILL
parent 2b0a5824
......@@ -67,8 +67,8 @@ enum mysql_enum_shutdown_level {
SHUTDOWN_WAIT_UPDATES= (unsigned char)(1 << 3),
SHUTDOWN_WAIT_ALL_BUFFERS= ((unsigned char)(1 << 3) << 1),
SHUTDOWN_WAIT_CRITICAL_BUFFERS= ((unsigned char)(1 << 3) << 1) + 1,
KILL_QUERY= 254,
KILL_CONNECTION= 255
SHUTDOWN_KILL_QUERY= 254,
SHUTDOWN_KILL_CONNECTION= 255
};
enum enum_cursor_type
{
......
......@@ -385,12 +385,15 @@ enum mysql_enum_shutdown_level {
/* don't flush InnoDB buffers, flush other storage engines' buffers*/
SHUTDOWN_WAIT_CRITICAL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1) + 1,
/* Now the 2 levels of the KILL command */
#if MYSQL_VERSION_ID >= 50000
KILL_QUERY= 254,
#endif
KILL_CONNECTION= 255
SHUTDOWN_KILL_QUERY= 254,
SHUTDOWN_KILL_CONNECTION= 255
};
/* Compatibility */
#if !defined(MYSQL_SERVER) && defined(USE_OLD_FUNCTIONS)
#define KILL_QUERY SHUTDOWN_KILL_QUERY
#define KILL_CONNECTION SHUTDOWN_KILL_CONNECTION
#endif
enum enum_cursor_type
{
......
......@@ -125,6 +125,7 @@ release_lock("lock27563")
drop table t1, t2;
drop function bug27563;
drop procedure proc27563;
set session optimizer_search_depth=0;
PREPARE stmt FROM 'EXPLAIN SELECT * FROM t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24,t25,t26,t27,t28,t29,t30,t31,t32,t33,t34,t35,t36,t37,t38,t39,t40 WHERE a1=a2 AND a2=a3 AND a3=a4 AND a4=a5 AND a5=a6 AND a6=a7 AND a7=a8 AND a8=a9 AND a9=a10 AND a10=a11 AND a11=a12 AND a12=a13 AND a13=a14 AND a14=a15 AND a15=a16 AND a16=a17 AND a17=a18 AND a18=a19 AND a19=a20 AND a20=a21 AND a21=a22 AND a22=a23 AND a23=a24 AND a24=a25 AND a25=a26 AND a26=a27 AND a27=a28 AND a28=a29 AND a29=a30 AND a30=a31 AND a31=a32 AND a32=a33 AND a33=a34 AND a34=a35 AND a35=a36 AND a36=a37 AND a37=a38 AND a38=a39 AND a39=a40 ';
EXECUTE stmt;
#
......@@ -138,4 +139,27 @@ KILL CONNECTION_ID();
# of close of the connection socket
SELECT 1;
Got one of the listed errors
#
# Test kill USER
#
grant ALL on test.* to test@localhost;
grant ALL on test.* to test2@localhost;
kill hard query user test2@nohost;
affected rows: 0
kill soft query user test@localhost;
affected rows: 1
kill hard query user test@localhost;
affected rows: 1
kill soft connection user test2;
affected rows: 1
kill hard connection user test@localhost;
affected rows: 1
revoke all privileges on test.* from test@localhost;
revoke all privileges on test.* from test2@localhost;
drop user test@localhost;
drop user test2@localhost;
select 1;
Got one of the listed errors
select 1;
Got one of the listed errors
set @@global.concurrent_insert= @old_concurrent_insert;
......@@ -48,7 +48,7 @@ select (@id := id) - id from t2;
kill @id;
drop table t2;
Got one of the listed errors
include/wait_for_slave_sql_error_and_skip.inc [errno=1053]
include/wait_for_slave_sql_error_and_skip.inc [errno=1927]
select count(*) from t1;
count(*)
5000
......
......@@ -96,14 +96,14 @@ drop table t2;
connection master;
# The get_lock function causes warning for unsafe statement.
--disable_warnings
--error 1317,2013
--error ER_QUERY_INTERRUPTED,ER_CONNECTION_KILLED
reap;
--enable_warnings
connection slave;
# The SQL slave thread should now have stopped because the query was killed on
# the master (so it has a non-zero error code in the binlog).
# 1053 = ER_SERVER_SHUTDOWN
--let $slave_sql_errno= 1053
# 1927 = ER_CONNECTION_KILLED
--let $slave_sql_errno= 1927
--source include/wait_for_slave_sql_error_and_skip.inc
select count(*) from t1;
......
......@@ -57,7 +57,7 @@ connection con1;
# debug build running without our --debug=make_global..., will be
# error 0 (no error). The only important thing to test is that on
# debug builds with our --debug=make_global... we don't hang forever.
--error 0,1317,2013
--error 0,ER_CONNECTION_KILLED,2013
reap;
connection con2;
......
......@@ -99,7 +99,7 @@ select ((@id := kill_id) - kill_id) from t3;
kill @id;
connection conn1;
-- error 1317,2013
-- error ER_QUERY_INTERRUPTED,ER_CONNECTION_KILLED,2013
reap;
connection default;
......@@ -337,5 +337,35 @@ SELECT 1;
###########################################################################
--echo #
--echo # Test kill USER
--echo #
grant ALL on test.* to test@localhost;
grant ALL on test.* to test2@localhost;
connect (con3, localhost, test,,);
connect (con4, localhost, test2,,);
connection default;
--enable_info
kill hard query user test2@nohost;
kill soft query user test@localhost;
kill hard query user test@localhost;
kill soft connection user test2;
kill hard connection user test@localhost;
--disable_info
revoke all privileges on test.* from test@localhost;
revoke all privileges on test.* from test2@localhost;
drop user test@localhost;
drop user test2@localhost;
connection con3;
--error 2013,2006
select 1;
connection con4;
--error 2013,2006
select 1;
connection default;
# Restore global concurrent_insert value. Keep in the end of the test file.
set @@global.concurrent_insert= @old_concurrent_insert;
......@@ -246,11 +246,11 @@ wait_server_to_start(THD *thd, volatile int& shutdown_flag)
&abstime);
pthread_mutex_unlock(&LOCK_server_started);
pthread_mutex_lock(&thd->mysys_var->mutex);
THD::killed_state st = thd->killed;
killed_state st = thd->killed;
pthread_mutex_unlock(&thd->mysys_var->mutex);
DBG_SHUT(fprintf(stderr, "HNDSOCK wsts kst %d\n", (int)st));
pthread_mutex_lock(&LOCK_server_started);
if (st != THD::NOT_KILLED) {
if (st != NOT_KILLED) {
DBG_SHUT(fprintf(stderr, "HNDSOCK wsts kst %d break\n", (int)st));
r = -1;
break;
......@@ -357,11 +357,11 @@ bool
dbcontext::check_alive()
{
pthread_mutex_lock(&thd->mysys_var->mutex);
THD::killed_state st = thd->killed;
killed_state st = thd->killed;
pthread_mutex_unlock(&thd->mysys_var->mutex);
DBG_SHUT(fprintf(stderr, "chk HNDSOCK kst %p %p %d %zu\n", thd, &thd->killed,
(int)st, sizeof(*thd)));
if (st != THD::NOT_KILLED) {
if (st != NOT_KILLED) {
DBG_SHUT(fprintf(stderr, "chk HNDSOCK kst %d break\n", (int)st));
return false;
}
......
......@@ -1078,7 +1078,7 @@ static bool debug_sync_set_action(THD *thd, st_debug_sync_action *action)
point decremented it to 0. In this case the following happened:
- an error message was reported with my_error() and
- the statement was killed with thd->killed= THD::KILL_QUERY.
- the statement was killed with thd->killed= KILL_QUERY.
If a statement reports an error, it must not call send_ok().
The calling functions will not call send_ok(), if we return TRUE
......@@ -1852,7 +1852,7 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
{
if (!--action->hit_limit)
{
thd->killed= THD::KILL_QUERY;
thd->killed= KILL_QUERY;
my_error(ER_DEBUG_SYNC_HIT_LIMIT, MYF(0));
}
DBUG_PRINT("debug_sync_exec", ("hit_limit: %lu at: '%s'",
......
......@@ -642,7 +642,7 @@ Event_scheduler::stop()
sql_print_information("Event Scheduler: Killing the scheduler thread, "
"thread id %lu",
scheduler_thd->thread_id);
scheduler_thd->awake(THD::KILL_CONNECTION);
scheduler_thd->awake(KILL_CONNECTION);
pthread_mutex_unlock(&scheduler_thd->LOCK_thd_data);
/* thd could be 0x0, when shutting down */
......
......@@ -506,7 +506,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
my_off_t record;
TABLE *sort_form;
THD *thd= current_thd;
volatile THD::killed_state *killed= &thd->killed;
volatile killed_state *killed= &thd->killed;
handler *file;
MY_BITMAP *save_read_set, *save_write_set, *save_vcol_set;
DBUG_ENTER("find_all_keys");
......@@ -1239,9 +1239,9 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
void *first_cmp_arg;
element_count dupl_count= 0;
uchar *src;
THD::killed_state not_killable;
killed_state not_killable;
uchar *unique_buff= param->unique_buff;
volatile THD::killed_state *killed= &current_thd->killed;
volatile killed_state *killed= &current_thd->killed;
DBUG_ENTER("merge_buffers");
status_var_increment(current_thd->status_var.filesort_merge_passes);
......@@ -1249,7 +1249,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
if (param->not_killable)
{
killed= &not_killable;
not_killable= THD::NOT_KILLED;
not_killable= NOT_KILLED;
}
error=0;
......
......@@ -1855,7 +1855,7 @@ static void ndb_binlog_query(THD *thd, Cluster_schema *schema)
else
thd->server_id= schema->any_value;
thd->db= schema->db;
int errcode = query_error_code(thd, thd->killed == THD::NOT_KILLED);
int errcode = query_error_code(thd, thd->killed == NOT_KILLED);
thd->binlog_query(THD::STMT_QUERY_TYPE, schema->query,
schema->query_length, FALSE,
schema->name[0] == 0 || thd->db[0] == 0,
......
......@@ -1404,13 +1404,12 @@ int ha_rollback_trans(THD *thd, bool all)
the error log; but we don't want users to wonder why they have this
message in the error log, so we don't send it.
We don't have to test for thd->killed == THD::KILL_SYSTEM_THREAD as
We don't have to test for thd->killed == KILL_SYSTEM_THREAD as
it doesn't matter if a warning is pushed to a system thread or not:
No one will see it...
*/
if (is_real_trans && thd->transaction.all.modified_non_trans_table &&
!thd->slave_thread && thd->killed != THD::KILL_CONNECTION &&
thd->killed != THD::KILL_SERVER)
!thd->slave_thread && thd->killed < KILL_CONNECTION)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARNING_NOT_COMPLETE_ROLLBACK,
ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
......@@ -2564,7 +2563,7 @@ int handler::update_auto_increment()
/*
first test if the query was aborted due to strict mode constraints
*/
if (thd->killed == THD::KILL_BAD_DATA)
if (killed_mask_hard(thd->killed) == KILL_BAD_DATA)
DBUG_RETURN(HA_ERR_AUTOINC_ERANGE);
/*
......
......@@ -238,6 +238,7 @@ static SYMBOL symbols[] = {
{ "GRANTS", SYM(GRANTS)},
{ "GROUP", SYM(GROUP_SYM)},
{ "HANDLER", SYM(HANDLER_SYM)},
{ "HARD", SYM(HARD_SYM)},
{ "HASH", SYM(HASH_SYM)},
{ "HAVING", SYM(HAVING)},
{ "HELP", SYM(HELP_SYM)},
......@@ -496,6 +497,7 @@ static SYMBOL symbols[] = {
{ "SNAPSHOT", SYM(SNAPSHOT_SYM)},
{ "SMALLINT", SYM(SMALLINT)},
{ "SOCKET", SYM(SOCKET_SYM)},
{ "SOFT", SYM(SOFT_SYM)},
{ "SOME", SYM(ANY_SYM)},
{ "SONAME", SYM(SONAME_SYM)},
{ "SOUNDS", SYM(SOUNDS_SYM)},
......
......@@ -1809,7 +1809,7 @@ static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv)
log_query.append(thd->lex->ident.str, thd->lex->ident.length) ||
log_query.append("`"))
DBUG_RETURN(1);
int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
int errcode= query_error_code(thd, thd->killed == NOT_KILLED);
Query_log_event qinfo(thd, log_query.ptr(), log_query.length(),
TRUE, TRUE, errcode);
DBUG_RETURN(mysql_bin_log.write(&qinfo));
......@@ -1833,7 +1833,7 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
log_query.append(thd->lex->ident.str, thd->lex->ident.length) ||
log_query.append("`"))
DBUG_RETURN(1);
int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
int errcode= query_error_code(thd, thd->killed == NOT_KILLED);
Query_log_event qinfo(thd, log_query.ptr(), log_query.length(),
TRUE, TRUE, errcode);
DBUG_RETURN(mysql_bin_log.write(&qinfo));
......@@ -5166,7 +5166,7 @@ int query_error_code(THD *thd, bool not_killed)
{
int error;
if (not_killed || (thd->killed == THD::KILL_BAD_DATA))
if (not_killed || (killed_mask_hard(thd->killed) == KILL_BAD_DATA))
{
error= thd->is_error() ? thd->main_da.sql_errno() : 0;
......@@ -5176,7 +5176,7 @@ int query_error_code(THD *thd, bool not_killed)
caller.
*/
if (error == ER_SERVER_SHUTDOWN || error == ER_QUERY_INTERRUPTED ||
error == ER_NEW_ABORTING_CONNECTION)
error == ER_NEW_ABORTING_CONNECTION || error == ER_CONNECTION_KILLED)
error= 0;
}
else
......
......@@ -437,6 +437,7 @@ inline bool unexpected_error_code(int unexpected_error)
case ER_NET_READ_ERROR:
case ER_NET_ERROR_ON_WRITE:
case ER_QUERY_INTERRUPTED:
case ER_CONNECTION_KILLED:
case ER_SERVER_SHUTDOWN:
case ER_NEW_ABORTING_CONNECTION:
return(TRUE);
......@@ -3686,7 +3687,7 @@ Default database: '%s'. Query: '%s'",
{
DBUG_PRINT("info",("error ignored"));
clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
thd->killed= THD::NOT_KILLED;
thd->killed= NOT_KILLED;
/*
When an error is expected and matches the actual error the
slave does not report any error and by consequence changes
......
......@@ -118,8 +118,6 @@ char *sql_strmake_with_convert(const char *str, size_t arg_length,
CHARSET_INFO *from_cs,
size_t max_res_length,
CHARSET_INFO *to_cs, size_t *result_length);
uint kill_one_thread(THD *thd, ulong id, bool only_kill_query);
void sql_kill(THD *thd, ulong id, bool only_kill_query);
bool net_request_file(NET* net, const char* fname);
char* query_table_status(THD *thd,const char *db,const char *table_name);
......@@ -1074,6 +1072,10 @@ struct Query_cache_query_flags
#define query_cache_is_cacheable_query(L) 0
#endif /*HAVE_QUERY_CACHE*/
uint kill_one_thread(THD *thd, ulong id, killed_state kill_signal);
void sql_kill(THD *thd, ulong id, killed_state kill_signal);
void sql_kill_user(THD *thd, LEX_USER *str, killed_state kill_signal);
/*
Error injector Macros to enable easy testing of recovery after failures
in various error cases.
......
......@@ -1082,7 +1082,7 @@ static void close_connections(void)
if (tmp->slave_thread)
continue;
tmp->killed= THD::KILL_CONNECTION;
tmp->killed= KILL_SERVER_HARD;
thread_scheduler.post_kill_notification(tmp);
pthread_mutex_lock(&tmp->LOCK_thd_data);
if (tmp->mysys_var)
......@@ -2033,7 +2033,7 @@ void close_connection(THD *thd, uint errcode, bool lock)
errcode ? ER(errcode) : ""));
if (lock)
(void) pthread_mutex_lock(&LOCK_thread_count);
thd->killed= THD::KILL_CONNECTION;
thd->killed= KILL_CONNECTION;
if (global_system_variables.log_warnings > 3)
{
......@@ -2728,27 +2728,30 @@ the thread stack. Please read http://dev.mysql.com/doc/mysql/en/linux.html\n\n",
{
const char *kreason= "UNKNOWN";
switch (thd->killed) {
case THD::NOT_KILLED:
case NOT_KILLED:
case KILL_HARD_BIT:
kreason= "NOT_KILLED";
break;
case THD::KILL_BAD_DATA:
case KILL_BAD_DATA:
case KILL_BAD_DATA_HARD:
kreason= "KILL_BAD_DATA";
break;
case THD::KILL_CONNECTION:
case KILL_CONNECTION:
case KILL_CONNECTION_HARD:
kreason= "KILL_CONNECTION";
break;
case THD::KILL_QUERY:
case KILL_QUERY:
case KILL_QUERY_HARD:
kreason= "KILL_QUERY";
break;
case THD::KILL_SYSTEM_THREAD:
case KILL_SYSTEM_THREAD:
case KILL_SYSTEM_THREAD_HARD:
kreason= "KILL_SYSTEM_THREAD";
break;
case THD::KILL_SERVER:
case KILL_SERVER:
case KILL_SERVER_HARD:
kreason= "KILL_SERVER";
break;
case THD::KILLED_NO_VALUE:
kreason= "KILLED_NO_VALUE";
break;
}
fprintf(stderr, "\nTrying to get some variables.\n"
"Some pointers may be invalid and cause the dump to abort.\n");
......@@ -5270,7 +5273,7 @@ void create_thread_to_handle_connection(THD *thd)
("Can't create thread to handle request (error %d)",
error));
thread_count--;
thd->killed= THD::KILL_CONNECTION; // Safety
thd->killed= KILL_CONNECTION; // Safety
(void) pthread_mutex_unlock(&LOCK_thread_count);
pthread_mutex_lock(&LOCK_connection_count);
......
......@@ -376,9 +376,7 @@ void libevent_kill_thd_callback(int Fd, short, void*)
{
THD *thd= (THD*)list->data;
list= list_rest(list);
if (thd->killed == THD::KILL_CONNECTION ||
thd->killed == THD::KILL_SYSTEM_THREAD ||
thd->killed == THD::KILL_SERVER)
if ((int) thd->killed >= (int) KILL_CONNECTION)
{
/*
Delete from libevent and add to the processing queue.
......@@ -512,7 +510,7 @@ static void libevent_connection_close(THD *thd)
DBUG_ENTER("libevent_connection_close");
DBUG_PRINT("enter", ("thd: %p", thd));
thd->killed= THD::KILL_CONNECTION; // Avoid error messages
thd->killed= KILL_CONNECTION; // Avoid error messages
if (thd->net.vio->sd >= 0) // not already closed
{
......@@ -535,8 +533,7 @@ static bool libevent_should_close_connection(THD* thd)
{
return (thd->net.error ||
thd->net.vio == 0 ||
thd->killed == THD::KILL_CONNECTION ||
thd->killed == THD::KILL_SERVER);
(int) thd->killed >= (int) KILL_CONNECTION);
}
......
......@@ -6290,3 +6290,5 @@ ER_QUERY_CACHE_IS_GLOBALY_DISABLED
eng "Query cache is globally disabled and you can't enable it only for this session"
ER_VIEW_ORDERBY_IGNORED
eng "View '%-.192s'.'%-.192s' ORDER BY clause ignored because there is other ORDER BY clause already."
ER_CONNECTION_KILLED 70100
eng "Connection was killed"
......@@ -524,7 +524,7 @@ terminate_slave_thread(THD *thd,
IF_DBUG(int err= ) pthread_kill(thd->real_id, thr_client_alarm);
DBUG_ASSERT(err != EINVAL);
#endif
thd->awake(THD::NOT_KILLED);
thd->awake(KILL_CONNECTION);
pthread_mutex_unlock(&thd->LOCK_thd_data);
/*
......
......@@ -1312,7 +1312,7 @@ sp_head::execute(THD *thd)
ctx->enter_handler(hip);
thd->clear_error();
thd->is_fatal_error= 0;
thd->killed= THD::NOT_KILLED;
thd->killed= NOT_KILLED;
thd->mysys_var->abort= 0;
continue;
}
......@@ -1362,10 +1362,7 @@ sp_head::execute(THD *thd)
If the DB has changed, the pointer has changed too, but the
original thd->db will then have been freed
*/
if (cur_db_changed &&
thd->killed != THD::KILL_CONNECTION &&
thd->killed != THD::KILL_SERVER &&
thd->killed != THD::KILL_SYSTEM_THREAD)
if (cur_db_changed && thd->killed < KILL_CONNECTION)
{
/*
Force switching back to the saved current database, because it may be
......@@ -1799,7 +1796,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
thd->options= binlog_save_options;
if (thd->binlog_evt_union.unioned_events)
{
int errcode = query_error_code(thd, thd->killed == THD::NOT_KILLED);
int errcode = query_error_code(thd, thd->killed == NOT_KILLED);
Query_log_event qinfo(thd, binlog_buf.ptr(), binlog_buf.length(),
thd->binlog_evt_union.unioned_events_trans, FALSE, errcode);
if (mysql_bin_log.write(&qinfo) &&
......
......@@ -8910,7 +8910,7 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
{
if (!in_use->killed)
{
in_use->killed= THD::KILL_SYSTEM_THREAD;
in_use->killed= KILL_SYSTEM_THREAD;
pthread_mutex_lock(&in_use->mysys_var->mutex);
if (in_use->mysys_var->current_cond)
{
......@@ -9244,7 +9244,7 @@ void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table
if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
! in_use->killed)
{
in_use->killed= THD::KILL_SYSTEM_THREAD;
in_use->killed= KILL_SYSTEM_THREAD;
pthread_mutex_lock(&in_use->mysys_var->mutex);
if (in_use->mysys_var->current_cond)
{
......
......@@ -391,7 +391,7 @@ static void debug_wait_for_kill(const char *info)
sql_print_information("%s", info);
while(!thd->killed)
my_sleep(1000);
thd->killed= THD::NOT_KILLED;
thd->killed= NOT_KILLED;
/*
Remove the set debug variable, to ensure we don't get stuck on it again
This is needed as for MyISAM, invalidate_table() may be called twice
......@@ -4439,7 +4439,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= THD::KILL_CONNECTION;
thd->killed= KILL_CONNECTION;
cache_dump();
/* check_integrity(0); */ /* Can't call it here because of locks */
bins_dump();
......
......@@ -1266,7 +1266,7 @@ void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
#endif
void THD::awake(THD::killed_state state_to_set)
void THD::awake(killed_state state_to_set)
{
DBUG_ENTER("THD::awake");
DBUG_PRINT("enter", ("this: 0x%lx", (long) this));
......@@ -1283,7 +1283,7 @@ void THD::awake(THD::killed_state state_to_set)
"KILLED");
}
killed= state_to_set;
if (state_to_set != THD::KILL_QUERY)
if (state_to_set >= KILL_CONNECTION)
{
thr_alarm_kill(thread_id);
if (!slave_thread)
......@@ -1363,6 +1363,38 @@ void THD::awake(THD::killed_state state_to_set)
DBUG_VOID_RETURN;
}
/*
Get error number for killed state
Note that the error message can't have any parameters.
See thd::kill_message()
*/
int killed_errno(killed_state killed)
{
switch (killed) {
case NOT_KILLED:
case KILL_HARD_BIT:
return 0; // Probably wrong usage
case KILL_BAD_DATA:
case KILL_BAD_DATA_HARD:
return 0; // Not a real error
case KILL_CONNECTION:
case KILL_CONNECTION_HARD:
case KILL_SYSTEM_THREAD:
case KILL_SYSTEM_THREAD_HARD:
return ER_CONNECTION_KILLED;
case KILL_QUERY:
case KILL_QUERY_HARD:
return ER_QUERY_INTERRUPTED;
case KILL_SERVER:
case KILL_SERVER_HARD:
return ER_SERVER_SHUTDOWN;
}
return 0; // Keep compiler happy
}
/*
Remember the location of thread info, the structure needed for
sql_alloc() and the structure for the net buffer
......@@ -3397,12 +3429,13 @@ void THD::restore_backup_open_tables_state(Open_tables_state *backup)
@param thd user thread
@retval 0 the user thread is active
@retval 1 the user thread has been killed
This is used to signal a storage engine if it should be killed.
*/
extern "C" int thd_killed(const MYSQL_THD thd)
{
if (thd->killed == THD::NOT_KILLED || thd->killed == THD::KILL_BAD_DATA ||
thd->killed == THD::KILL_SYSTEM_THREAD)
if (!(thd->killed & KILL_HARD_BIT))
return 0;
return thd->killed;
}
......
......@@ -362,6 +362,38 @@ class LEX_COLUMN : public Sql_alloc
LEX_COLUMN (const String& x,const uint& y ): column (x),rights (y) {}
};
/* Note: these states are actually bit coded with HARD */
enum killed_state
{
NOT_KILLED= 0,
KILL_HARD_BIT= 1, /* Bit for HARD KILL */
KILL_BAD_DATA= 2,
KILL_BAD_DATA_HARD= 3,
KILL_QUERY= 4,
KILL_QUERY_HARD= 5,
/*
All of the following killed states will kill the connection
KILL_CONNECTION must be the first of these!
*/
KILL_CONNECTION= 6,
KILL_CONNECTION_HARD= 7,
KILL_SYSTEM_THREAD= 8,
KILL_SYSTEM_THREAD_HARD= 9,
KILL_SERVER= 10,
KILL_SERVER_HARD= 11
};
extern int killed_errno(killed_state killed);
#define killed_mask_hard(killed) ((killed_state) ((killed) & ~KILL_HARD_BIT))
enum killed_type
{
KILL_TYPE_ID,
KILL_TYPE_USER
};
#include "sql_lex.h" /* Must be here */
class Delayed_insert;
......@@ -1973,16 +2005,6 @@ class THD :public Statement,
DYNAMIC_ARRAY user_var_events; /* For user variables replication */
MEM_ROOT *user_var_events_alloc; /* Allocate above array elements here */
enum killed_state
{
NOT_KILLED=0,
KILL_BAD_DATA=1,
KILL_CONNECTION=ER_SERVER_SHUTDOWN,
KILL_SYSTEM_THREAD=ER_NEW_ABORTING_CONNECTION, /* Kill connection nicely */
KILL_QUERY=ER_QUERY_INTERRUPTED,
KILL_SERVER, /* Placeholder for shortdown */
KILLED_NO_VALUE /* means neither of the states */
};
killed_state volatile killed;
/* scramble - random string sent to client on handshake */
......@@ -2165,7 +2187,7 @@ class THD :public Statement,
}
void close_active_vio();
#endif
void awake(THD::killed_state state_to_set);
void awake(killed_state state_to_set);
#ifndef MYSQL_CLIENT
enum enum_binlog_query_type {
......@@ -2399,18 +2421,13 @@ class THD :public Statement,
void end_statement();
inline int killed_errno() const
{
killed_state killed_val; /* to cache the volatile 'killed' */
return (killed_val= killed) != KILL_BAD_DATA ? killed_val : 0;
return ::killed_errno(killed);
}
inline void send_kill_message() const
{
int err= killed_errno();
if (err)
{
if ((err == KILL_CONNECTION) && !shutdown_in_progress)
err = KILL_QUERY;
my_message(err, ER(err), MYF(0));
}
}
/* return TRUE if we will abort query if we make a warning now */
inline bool really_abort_on_warning()
......
......@@ -1095,7 +1095,7 @@ void prepare_new_connection_state(THD* thd)
execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
if (thd->is_error())
{
thd->killed= THD::KILL_CONNECTION;
thd->killed= KILL_CONNECTION;
sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
thd->thread_id,(thd->db ? thd->db : "unconnected"),
sctx->user ? sctx->user : "unauthenticated",
......@@ -1181,8 +1181,7 @@ pthread_handler_t handle_one_connection(void *arg)
prepare_new_connection_state(thd);
while (!net->error && net->vio != 0 &&
thd->killed != THD::KILL_CONNECTION &&
thd->killed != THD::KILL_SERVER)
thd->killed < KILL_CONNECTION)
{
if (do_command(thd))
break;
......
......@@ -49,7 +49,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
bool triggers_applicable;
uint usable_index= MAX_KEY;
SELECT_LEX *select_lex= &thd->lex->select_lex;
THD::killed_state killed_status= THD::NOT_KILLED;
killed_state killed_status= NOT_KILLED;
DBUG_ENTER("mysql_delete");
bool save_binlog_row_based;
......@@ -383,7 +383,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
table->file->unlock_row(); // Row failed selection, release lock on it
}
killed_status= thd->killed;
if (killed_status != THD::NOT_KILLED || thd->is_error())
if (killed_status != NOT_KILLED || thd->is_error())
error= 1; // Aborted
if (will_batch && (loc_error= table->file->end_bulk_delete()))
{
......@@ -450,7 +450,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (error < 0)
thd->clear_error();
else
errcode= query_error_code(thd, killed_status == THD::NOT_KILLED);
errcode= query_error_code(thd, killed_status == NOT_KILLED);
/*
[binlog]: If 'handler::delete_all_rows()' was called and the
......@@ -916,7 +916,7 @@ void multi_delete::abort()
*/
if (mysql_bin_log.is_open())
{
int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
int errcode= query_error_code(thd, thd->killed == NOT_KILLED);
/* possible error of writing binary log is ignored deliberately */
(void) thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query(), thd->query_length(),
......@@ -1066,7 +1066,7 @@ int multi_delete::do_table_deletes(TABLE *table, bool ignore)
bool multi_delete::send_eof()
{
THD::killed_state killed_status= THD::NOT_KILLED;
killed_state killed_status= NOT_KILLED;
thd_proc_info(thd, "deleting from reference tables");
/* Does deletes for the last n - 1 tables, returns 0 if ok */
......@@ -1074,7 +1074,7 @@ bool multi_delete::send_eof()
/* compute a total error to know if something failed */
local_error= local_error || error;
killed_status= (local_error == 0)? THD::NOT_KILLED : thd->killed;
killed_status= (local_error == 0)? NOT_KILLED : thd->killed;
/* reset used flags */
thd_proc_info(thd, "end");
......@@ -1094,7 +1094,7 @@ bool multi_delete::send_eof()
if (local_error == 0)
thd->clear_error();
else
errcode= query_error_code(thd, killed_status == THD::NOT_KILLED);
errcode= query_error_code(thd, killed_status == NOT_KILLED);
if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query(), thd->query_length(),
transactional_tables, FALSE, errcode) &&
......
......@@ -131,7 +131,7 @@ MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
thd->no_warnings_for_error= 1;
thd->spcont= NULL;
thd->killed= THD::KILL_BAD_DATA;
thd->killed= KILL_BAD_DATA;
my_message(code, msg, MYF(0));
thd->spcont= spcont;
......
......@@ -943,7 +943,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
thd->clear_error();
}
else
errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
errcode= query_error_code(thd, thd->killed == NOT_KILLED);
/* bug#22725:
......@@ -957,7 +957,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
routines did not result in any error due to the KILLED. In
such case the flag is ignored for constructing binlog event.
*/
DBUG_ASSERT(thd->killed != THD::KILL_BAD_DATA || error > 0);
DBUG_ASSERT(thd->killed != KILL_BAD_DATA || error > 0);
if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query(), thd->query_length(),
transactional_table, FALSE,
......@@ -2362,7 +2362,7 @@ void kill_delayed_threads(void)
Delayed_insert *di;
while ((di= it++))
{
di->thd.killed= THD::KILL_SYSTEM_THREAD;
di->thd.killed= KILL_SYSTEM_THREAD;
pthread_mutex_lock(&di->thd.LOCK_thd_data);
if (di->thd.mysys_var)
{
......@@ -2447,8 +2447,7 @@ static void handle_delayed_insert_impl(THD *thd, Delayed_insert *di)
for (;;)
{
if (thd->killed == THD::KILL_CONNECTION ||
thd->killed == THD::KILL_SYSTEM_THREAD || thd->killed == THD::KILL_SERVER)
if (thd->killed >= KILL_CONNECTION)
{
uint lock_count;
/*
......@@ -2496,7 +2495,7 @@ static void handle_delayed_insert_impl(THD *thd, Delayed_insert *di)
break;
if (error == ETIMEDOUT || error == ETIME)
{
thd->killed= THD::KILL_SYSTEM_THREAD;
thd->killed= KILL_SYSTEM_THREAD;
break;
}
}
......@@ -2529,7 +2528,7 @@ static void handle_delayed_insert_impl(THD *thd, Delayed_insert *di)
{
/* Fatal error */
di->dead= 1;
thd->killed= THD::KILL_SYSTEM_THREAD;
thd->killed= KILL_SYSTEM_THREAD;
}
pthread_cond_broadcast(&di->cond_client);
}
......@@ -2539,7 +2538,7 @@ static void handle_delayed_insert_impl(THD *thd, Delayed_insert *di)
{
/* Some fatal error */
di->dead= 1;
thd->killed= THD::KILL_SYSTEM_THREAD;
thd->killed= KILL_SYSTEM_THREAD;
}
}
di->status=0;
......@@ -2599,7 +2598,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
thd->set_current_time();
threads.append(thd);
thd->killed=abort_loop ? THD::KILL_SYSTEM_THREAD : THD::NOT_KILLED;
thd->killed=abort_loop ? KILL_SYSTEM_THREAD : NOT_KILLED;
pthread_mutex_unlock(&LOCK_thread_count);
/*
......@@ -2633,7 +2632,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
di->table=0;
di->dead= 1; // If error
thd->killed= THD::KILL_SYSTEM_THREAD; // If error
thd->killed= KILL_SYSTEM_THREAD; // If error
pthread_mutex_unlock(&di->mutex);
close_thread_tables(thd); // Free the table
......@@ -2712,7 +2711,7 @@ bool Delayed_insert::handle_inserts(void)
max_rows= delayed_insert_limit;
if (thd.killed || table->needs_reopen_or_name_lock())
{
thd.killed= THD::KILL_SYSTEM_THREAD;
thd.killed= KILL_SYSTEM_THREAD;
max_rows= ULONG_MAX; // Do as much as possible
}
......@@ -2825,7 +2824,7 @@ bool Delayed_insert::handle_inserts(void)
/* if the delayed insert was killed, the killed status is
ignored while binlogging */
int errcode= 0;
if (thd.killed == THD::NOT_KILLED)
if (thd.killed == NOT_KILLED)
errcode= query_error_code(&thd, TRUE);
/*
......@@ -3354,7 +3353,7 @@ bool select_insert::send_eof()
bool const trans_table= table->file->has_transactions();
ulonglong id;
bool changed;
THD::killed_state killed_status= thd->killed;
killed_state killed_status= thd->killed;
DBUG_ENTER("select_insert::send_eof");
DBUG_PRINT("enter", ("trans_table=%d, table_type='%s'",
trans_table, table->file->table_type()));
......@@ -3389,7 +3388,7 @@ bool select_insert::send_eof()
if (!error)
thd->clear_error();
else
errcode= query_error_code(thd, killed_status == THD::NOT_KILLED);
errcode= query_error_code(thd, killed_status == NOT_KILLED);
if (write_to_binlog(trans_table, errcode))
{
......@@ -3463,7 +3462,7 @@ void select_insert::abort() {
{
if (mysql_bin_log.is_open())
{
int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
int errcode= query_error_code(thd, thd->killed == NOT_KILLED);
/* error of writing binary log is ignored */
write_to_binlog(transactional_table, errcode);
}
......@@ -3824,7 +3823,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
!table->s->tmp_table &&
!ptr->get_create_info()->table_existed)
{
int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
int errcode= query_error_code(thd, thd->killed == NOT_KILLED);
if (int error= ptr->binlog_show_create_table(tables, count, errcode))
return error;
}
......@@ -3867,7 +3866,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
create_table->table_name);
if (thd->current_stmt_binlog_row_based)
{
int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
int errcode= query_error_code(thd, thd->killed == NOT_KILLED);
binlog_show_create_table(&(create_table->table), 1, errcode);
}
table= create_table->table;
......
......@@ -1735,6 +1735,9 @@ typedef struct st_lex : public Query_tables_list
LEX_SERVER_OPTIONS server_options;
USER_RESOURCES mqh;
ulong type;
/* The following is used by KILL */
killed_state kill_signal;
killed_type kill_type;
/*
This variable is used in post-parse stage to declare that sum-functions,
or functions which have sense only if GROUP BY is present, are allowed.
......
......@@ -130,7 +130,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
bool is_fifo=0;
#ifndef EMBEDDED_LIBRARY
LOAD_FILE_INFO lf_info;
THD::killed_state killed_status;
killed_state killed_status;
#endif
char *db = table_list->db; // This is never null
/*
......@@ -471,11 +471,11 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
DBUG_EXECUTE_IF("simulate_kill_bug27571",
{
error=1;
thd->killed= THD::KILL_QUERY;
thd->killed= KILL_QUERY;
};);
#ifndef EMBEDDED_LIBRARY
killed_status= (error == 0) ? THD::NOT_KILLED : thd->killed;
killed_status= (error == 0) ? NOT_KILLED : thd->killed;
#endif
/*
......@@ -519,7 +519,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
/* If the file was not empty, wrote_create_file is true */
if (lf_info.wrote_create_file)
{
int errcode= query_error_code(thd, killed_status == THD::NOT_KILLED);
int errcode= query_error_code(thd, killed_status == NOT_KILLED);
/* since there is already an error, the possible error of
writing binary log will be ignored */
......@@ -570,7 +570,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
read_info.end_io_cache();
if (lf_info.wrote_create_file)
{
int errcode= query_error_code(thd, killed_status == THD::NOT_KILLED);
int errcode= query_error_code(thd, killed_status == NOT_KILLED);
error= write_execute_load_query_log_event(thd, ex,
table_list->db, table_list->table_name,
handle_duplicates, ignore,
......
......@@ -793,7 +793,7 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion)
my_error(thd->killed_errno(), MYF(0));
else if ((res == 0) && do_release)
{
thd->killed= THD::KILL_CONNECTION;
thd->killed= KILL_CONNECTION;
if (global_system_variables.log_warnings > 3)
{
Security_context *sctx= &thd->main_security_ctx;
......@@ -1530,7 +1530,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
{
status_var_increment(thd->status_var.com_stat[SQLCOM_KILL]);
ulong id=(ulong) uint4korr(packet);
sql_kill(thd,id,false);
sql_kill(thd,id, KILL_CONNECTION_HARD);
break;
}
case COM_SET_OPTION:
......@@ -1572,15 +1572,18 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
/* report error issued during command execution */
if (thd->killed_errno())
if (thd->killed)
{
if (! thd->main_da.is_set())
thd->send_kill_message();
}
if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA)
{
thd->killed= THD::NOT_KILLED;
thd->mysys_var->abort= 0;
if (thd->killed_errno())
{
if (! thd->main_da.is_set())
thd->send_kill_message();
}
if (thd->killed < KILL_CONNECTION)
{
thd->killed= NOT_KILLED;
thd->mysys_var->abort= 0;
}
}
/* If commit fails, we should be able to reset the OK status. */
......@@ -4038,8 +4041,6 @@ mysql_execute_command(THD *thd)
}
case SQLCOM_KILL:
{
Item *it= (Item *)lex->value_list.head();
if (lex->table_or_sp_used())
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "Usage of subqueries or stored "
......@@ -4047,13 +4048,20 @@ mysql_execute_command(THD *thd)
break;
}
if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1))
if (lex->kill_type == KILL_TYPE_ID)
{
my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY),
MYF(0));
goto error;
Item *it= (Item *)lex->value_list.head();
if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1))
{
my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY),
MYF(0));
goto error;
}
sql_kill(thd, (ulong) it->val_int(), lex->kill_signal);
}
sql_kill(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY);
else
sql_kill_user(thd, get_current_user(thd, lex->users_list.head()),
lex->kill_signal);
break;
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
......@@ -7174,12 +7182,13 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
This is written such that we have a short lock on LOCK_thread_count
*/
uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
uint kill_one_thread(THD *thd, ulong id, killed_state kill_signal)
{
THD *tmp;
uint error=ER_NO_SUCH_THREAD;
DBUG_ENTER("kill_one_thread");
DBUG_PRINT("enter", ("id=%lu only_kill=%d", id, only_kill_query));
DBUG_PRINT("enter", ("id: %lu signal: %u", id, (uint) kill_signal));
VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
I_List_iterator<THD> it(threads);
while ((tmp=it++))
......@@ -7219,7 +7228,7 @@ uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
if ((thd->security_ctx->master_access & SUPER_ACL) ||
thd->security_ctx->user_matches(tmp->security_ctx))
{
tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION);
tmp->awake(kill_signal);
error=0;
}
else
......@@ -7231,6 +7240,76 @@ uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
}
/**
kill all threads from one user
@param thd Thread class
@param user_name User name for threads we should kill
@param only_kill_query Should it kill the query or the connection
@note
This is written such that we have a short lock on LOCK_thread_count
If we can't kill all threads because of security issues, no threads
are killed.
*/
static uint kill_threads_for_user(THD *thd, LEX_USER *user,
killed_state kill_signal, ha_rows *rows)
{
THD *tmp;
List<THD> threads_to_kill;
DBUG_ENTER("kill_threads_for_user");
*rows= 0;
if (thd->is_fatal_error) // If we run out of memory
DBUG_RETURN(ER_OUT_OF_RESOURCES);
DBUG_PRINT("enter", ("user: %s signal: %u", user->user.str,
(uint) kill_signal));
VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
I_List_iterator<THD> it(threads);
while ((tmp=it++))
{
if (tmp->command == COM_DAEMON)
continue;
/*
Check that hostname (if given) and user name matches.
host.str[0] == '%' means that host name was not given. See sql_yacc.yy
*/
if (((user->host.str[0] == '%' && !user->host.str[1]) ||
!strcmp(tmp->security_ctx->host, user->host.str)) &&
!strcmp(tmp->security_ctx->user, user->user.str))
{
if (!(thd->security_ctx->master_access & SUPER_ACL) &&
!thd->security_ctx->user_matches(tmp->security_ctx))
{
VOID(pthread_mutex_unlock(&LOCK_thread_count));
DBUG_RETURN(ER_KILL_DENIED_ERROR);
}
if (!threads_to_kill.push_back(tmp, tmp->mem_root))
pthread_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete
}
}
VOID(pthread_mutex_unlock(&LOCK_thread_count));
if (!threads_to_kill.is_empty())
{
List_iterator_fast<THD> it(threads_to_kill);
THD *ptr;
while ((ptr= it++))
{
ptr->awake(kill_signal);
pthread_mutex_unlock(&ptr->LOCK_thd_data);
(*rows)++;
}
}
DBUG_RETURN(0);
}
/*
kills a thread and sends response
......@@ -7241,16 +7320,33 @@ uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
only_kill_query Should it kill the query or the connection
*/
void sql_kill(THD *thd, ulong id, bool only_kill_query)
void sql_kill(THD *thd, ulong id, killed_state state)
{
uint error;
if (!(error= kill_one_thread(thd, id, only_kill_query)))
if (!(error= kill_one_thread(thd, id, state)))
my_ok(thd);
else
my_error(error, MYF(0), id);
}
void sql_kill_user(THD *thd, LEX_USER *user, killed_state state)
{
uint error;
ha_rows rows;
if (!(error= kill_threads_for_user(thd, user, state, &rows)))
my_ok(thd, rows);
else
{
/*
This is probably ER_OUT_OF_RESOURCES, but in the future we may
want to write the name of the user we tried to kill
*/
my_error(error, MYF(0), user->host.str, user->user.str);
}
}
/** If pointer is not a null pointer, append filename to it. */
bool append_file_to_dir(THD *thd, const char **filename_ptr,
......
......@@ -1277,9 +1277,9 @@ int reset_slave(THD *thd, Master_info* mi)
idle, then this could last long, and if the slave reconnects, we could have 2
Binlog_dump threads in SHOW PROCESSLIST, until a query is written to the
binlog. To avoid this, when the slave reconnects and sends COM_BINLOG_DUMP,
the master kills any existing thread with the slave's server id (if this id is
not zero; it will be true for real slaves, but false for mysqlbinlog when it
sends COM_BINLOG_DUMP to get a remote binlog dump).
the master kills any existing thread with the slave's server id (if this id
is not zero; it will be true for real slaves, but false for mysqlbinlog when
it sends COM_BINLOG_DUMP to get a remote binlog dump).
SYNOPSIS
kill_zombie_dump_threads()
......@@ -1311,7 +1311,7 @@ void kill_zombie_dump_threads(uint32 slave_server_id)
it will be slow because it will iterate through the list
again. We just to do kill the thread ourselves.
*/
tmp->awake(THD::KILL_QUERY);
tmp->awake(KILL_QUERY);
pthread_mutex_unlock(&tmp->LOCK_thd_data);
}
}
......
......@@ -1943,8 +1943,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
pthread_mutex_lock(&tmp->LOCK_thd_data);
if ((mysys_var= tmp->mysys_var))
pthread_mutex_lock(&mysys_var->mutex);
thd_info->proc_info= (char*) (tmp->killed != THD::NOT_KILLED &&
tmp->killed != THD::KILL_BAD_DATA ?
thd_info->proc_info= (char*) (tmp->killed >= KILL_QUERY ?
"Killed" : 0);
#ifndef EMBEDDED_LIBRARY
thd_info->state_info= (char*) (tmp->net.reading_or_writing ?
......@@ -2084,8 +2083,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
if ((mysys_var= tmp->mysys_var))
pthread_mutex_lock(&mysys_var->mutex);
/* COMMAND */
if ((val= (char *) ((tmp->killed != THD::NOT_KILLED &&
tmp->killed != THD::KILL_BAD_DATA ?
if ((val= (char *) ((tmp->killed >= KILL_QUERY ?
"Killed" : 0))))
table->field[4]->store(val, strlen(val), cs);
else
......
......@@ -59,7 +59,7 @@ static void wait_for_kill_signal(THD *thd)
while (thd->killed == 0)
sleep(1);
// Reset signal and continue as if nothing happend
thd->killed= THD::NOT_KILLED;
thd->killed= NOT_KILLED;
}
#endif
......
......@@ -221,7 +221,7 @@ int mysql_update(THD *thd,
bool need_reopen;
ulonglong id;
List<Item> all_fields;
THD::killed_state killed_status= THD::NOT_KILLED;
killed_state killed_status= NOT_KILLED;
DBUG_ENTER("mysql_update");
for ( ; ; )
......@@ -788,9 +788,9 @@ int mysql_update(THD *thd,
// simulated killing after the loop must be ineffective for binlogging
DBUG_EXECUTE_IF("simulate_kill_bug27571",
{
thd->killed= THD::KILL_QUERY;
thd->killed= KILL_QUERY;
};);
error= (killed_status == THD::NOT_KILLED)? error : 1;
error= (killed_status == NOT_KILLED)? error : 1;
if (error &&
will_batch &&
......@@ -851,7 +851,7 @@ int mysql_update(THD *thd,
if (error < 0)
thd->clear_error();
else
errcode= query_error_code(thd, killed_status == THD::NOT_KILLED);
errcode= query_error_code(thd, killed_status == NOT_KILLED);
if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query(), thd->query_length(),
......@@ -1937,7 +1937,7 @@ void multi_update::abort()
got caught and if happens later the killed error is written
into repl event.
*/
int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
int errcode= query_error_code(thd, thd->killed == NOT_KILLED);
/* the error of binary logging is ignored */
(void)thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query(), thd->query_length(),
......@@ -2151,7 +2151,7 @@ bool multi_update::send_eof()
{
char buff[STRING_BUFFER_USUAL_SIZE];
ulonglong id;
THD::killed_state killed_status= THD::NOT_KILLED;
killed_state killed_status= NOT_KILLED;
DBUG_ENTER("multi_update::send_eof");
thd_proc_info(thd, "updating reference tables");
......@@ -2164,7 +2164,7 @@ bool multi_update::send_eof()
if local_error is not set ON until after do_updates() then
later carried out killing should not affect binlogging.
*/
killed_status= (local_error == 0)? THD::NOT_KILLED : thd->killed;
killed_status= (local_error == 0) ? NOT_KILLED : thd->killed;
thd_proc_info(thd, "end");
/* We must invalidate the query cache before binlog writing and
......@@ -2193,7 +2193,7 @@ bool multi_update::send_eof()
if (local_error == 0)
thd->clear_error();
else
errcode= query_error_code(thd, killed_status == THD::NOT_KILLED);
errcode= query_error_code(thd, killed_status == NOT_KILLED);
if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query(), thd->query_length(),
transactional_tables, FALSE, errcode))
......
......@@ -682,10 +682,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%pure_parser /* We have threads */
/*
Currently there are 171 shift/reduce conflicts.
Currently there are 174 shift/reduce conflicts.
We should not introduce new conflicts any more.
*/
%expect 171
%expect 174
/*
Comments for TOKENS.
......@@ -901,6 +901,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token GROUP_CONCAT_SYM
%token GT_SYM /* OPERATOR */
%token HANDLER_SYM
%token HARD_SYM
%token HASH_SYM
%token HAVING /* SQL-2003-R */
%token HELP_SYM
......@@ -1169,6 +1170,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token SMALLINT /* SQL-2003-R */
%token SNAPSHOT_SYM
%token SOCKET_SYM
%token SOFT_SYM
%token SONAME_SYM
%token SOUNDS_SYM
%token SOURCE_SYM
......@@ -1348,7 +1350,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
opt_ev_status opt_ev_on_completion ev_on_completion opt_ev_comment
ev_alter_on_schedule_completion opt_ev_rename_to opt_ev_sql_stmt
optional_flush_tables_arguments opt_dyncol_type dyncol_type
opt_time_precision
opt_time_precision kill_type kill_option
%type <ulong_num>
ulong_num real_ulong_num merge_insert_types
......@@ -1380,7 +1382,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
function_call_keyword
function_call_nonkeyword
function_call_generic
function_call_conflict
function_call_conflict kill_expr
%type <item_num>
NUM_literal
......@@ -11081,19 +11083,41 @@ purge_option:
/* kill threads */
kill:
KILL_SYM kill_option expr
KILL_SYM
{
LEX *lex=Lex;
lex->value_list.empty();
lex->value_list.push_front($3);
lex->users_list.empty();
lex->sql_command= SQLCOM_KILL;
}
kill_type kill_option kill_expr
{
Lex->kill_signal= (killed_state) ($3 | $4);
}
;
kill_type:
/* Empty */ { $$= (int) KILL_HARD_BIT; }
| HARD_SYM { $$= (int) KILL_HARD_BIT; }
| SOFT_SYM { $$= 0; }
kill_option:
/* empty */ { Lex->type= 0; }
| CONNECTION_SYM { Lex->type= 0; }
| QUERY_SYM { Lex->type= ONLY_KILL_QUERY; }
/* empty */ { $$= (int) KILL_CONNECTION; }
| CONNECTION_SYM { $$= (int) KILL_CONNECTION; }
| QUERY_SYM { $$= (int) KILL_QUERY; }
;
kill_expr:
expr
{
Lex->value_list.push_front($$);
Lex->kill_type= KILL_TYPE_ID;
}
| USER user
{
Lex->users_list.push_back($2);
Lex->kill_type= KILL_TYPE_USER;
}
;
/* change database */
......@@ -12208,6 +12232,7 @@ keyword_sp:
| GRANTS {}
| GLOBAL_SYM {}
| HASH_SYM {}
| HARD_SYM {}
| HOSTS_SYM {}
| HOUR_SYM {}
| IDENTIFIED_SYM {}
......@@ -12339,6 +12364,7 @@ keyword_sp:
| SHUTDOWN {}
| SLOW_SYM {}
| SNAPSHOT_SYM {}
| SOFT_SYM {}
| SOUNDS_SYM {}
| SOURCE_SYM {}
| SQL_CACHE_SYM {}
......
......@@ -17,6 +17,7 @@
#pragma implementation // gcc: Class implementation
#endif
#define MYSQL_SERVER 1
#include "mysql_priv.h"
#include <myisam.h>
......
......@@ -2701,7 +2701,7 @@ int ha_maria::external_lock(THD *thd, int lock_type)
changes to commit (rollback shouldn't be tested).
*/
DBUG_ASSERT(!thd->main_da.is_sent ||
thd->killed == THD::KILL_CONNECTION);
thd->killed == KILL_CONNECTION);
/* autocommit ? rollback a transaction */
#ifdef MARIA_CANNOT_ROLLBACK
if (ma_commit(trn))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment