summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mysql.h.pp4
-rw-r--r--include/mysql_com.h11
-rw-r--r--mysql-test/r/kill.result24
-rw-r--r--mysql-test/suite/rpl/r/rpl_stm_000001.result2
-rw-r--r--mysql-test/suite/rpl/t/rpl_stm_000001.test6
-rw-r--r--mysql-test/t/flush_read_lock_kill.test2
-rw-r--r--mysql-test/t/kill.test32
-rw-r--r--plugin/handler_socket/handlersocket/database.cpp8
-rw-r--r--sql/debug_sync.cc4
-rw-r--r--sql/event_scheduler.cc2
-rw-r--r--sql/filesort.cc8
-rw-r--r--sql/ha_ndbcluster_binlog.cc2
-rw-r--r--sql/handler.cc7
-rw-r--r--sql/lex.h2
-rw-r--r--sql/log.cc8
-rw-r--r--sql/log_event.cc3
-rw-r--r--sql/mysql_priv.h6
-rw-r--r--sql/mysqld.cc27
-rw-r--r--sql/scheduler.cc9
-rw-r--r--sql/share/errmsg.txt2
-rw-r--r--sql/slave.cc2
-rw-r--r--sql/sp_head.cc9
-rw-r--r--sql/sql_base.cc4
-rw-r--r--sql/sql_cache.cc4
-rw-r--r--sql/sql_class.cc41
-rw-r--r--sql/sql_class.h51
-rw-r--r--sql/sql_connect.cc5
-rw-r--r--sql/sql_delete.cc14
-rw-r--r--sql/sql_error.cc2
-rw-r--r--sql/sql_insert.cc33
-rw-r--r--sql/sql_lex.h3
-rw-r--r--sql/sql_load.cc10
-rw-r--r--sql/sql_parse.cc140
-rw-r--r--sql/sql_repl.cc8
-rw-r--r--sql/sql_show.cc6
-rw-r--r--sql/sql_table.cc2
-rw-r--r--sql/sql_update.cc16
-rw-r--r--sql/sql_yacc.yy44
-rw-r--r--storage/archive/ha_archive.cc1
-rw-r--r--storage/maria/ha_maria.cc2
40 files changed, 399 insertions, 167 deletions
diff --git a/include/mysql.h.pp b/include/mysql.h.pp
index 659f30a2a67..780dbc9db3d 100644
--- a/include/mysql.h.pp
+++ b/include/mysql.h.pp
@@ -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
{
diff --git a/include/mysql_com.h b/include/mysql_com.h
index 119676df5ce..81e0f4abaf6 100644
--- a/include/mysql_com.h
+++ b/include/mysql_com.h
@@ -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
{
diff --git a/mysql-test/r/kill.result b/mysql-test/r/kill.result
index 8b6830d4798..fa6b90ea891 100644
--- a/mysql-test/r/kill.result
+++ b/mysql-test/r/kill.result
@@ -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;
diff --git a/mysql-test/suite/rpl/r/rpl_stm_000001.result b/mysql-test/suite/rpl/r/rpl_stm_000001.result
index 3a67772d11a..afe4096b84c 100644
--- a/mysql-test/suite/rpl/r/rpl_stm_000001.result
+++ b/mysql-test/suite/rpl/r/rpl_stm_000001.result
@@ -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
diff --git a/mysql-test/suite/rpl/t/rpl_stm_000001.test b/mysql-test/suite/rpl/t/rpl_stm_000001.test
index 9841ecb040a..4056b700b3b 100644
--- a/mysql-test/suite/rpl/t/rpl_stm_000001.test
+++ b/mysql-test/suite/rpl/t/rpl_stm_000001.test
@@ -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;
diff --git a/mysql-test/t/flush_read_lock_kill.test b/mysql-test/t/flush_read_lock_kill.test
index 2d359383949..ada73755067 100644
--- a/mysql-test/t/flush_read_lock_kill.test
+++ b/mysql-test/t/flush_read_lock_kill.test
@@ -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;
diff --git a/mysql-test/t/kill.test b/mysql-test/t/kill.test
index b199a1224c3..f51b9723142 100644
--- a/mysql-test/t/kill.test
+++ b/mysql-test/t/kill.test
@@ -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;
diff --git a/plugin/handler_socket/handlersocket/database.cpp b/plugin/handler_socket/handlersocket/database.cpp
index f63f011d9b1..311eec55fa8 100644
--- a/plugin/handler_socket/handlersocket/database.cpp
+++ b/plugin/handler_socket/handlersocket/database.cpp
@@ -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;
}
diff --git a/sql/debug_sync.cc b/sql/debug_sync.cc
index 322db38adf2..5e5e5a72850 100644
--- a/sql/debug_sync.cc
+++ b/sql/debug_sync.cc
@@ -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'",
diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc
index ecddcb7ca46..240d2df8e65 100644
--- a/sql/event_scheduler.cc
+++ b/sql/event_scheduler.cc
@@ -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 */
diff --git a/sql/filesort.cc b/sql/filesort.cc
index b3bb15bd7f0..da275c1c14f 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -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;
diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc
index 77851119e34..5a3365b29d2 100644
--- a/sql/ha_ndbcluster_binlog.cc
+++ b/sql/ha_ndbcluster_binlog.cc
@@ -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,
diff --git a/sql/handler.cc b/sql/handler.cc
index 905668114dd..08d778022dc 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -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);
/*
diff --git a/sql/lex.h b/sql/lex.h
index 6ab234f8d81..3041168e4fb 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -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)},
diff --git a/sql/log.cc b/sql/log.cc
index e53c8d12770..649db6a4c29 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -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
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 3dad0c87e00..ae7a37f2b3d 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -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
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index b38253c866a..62fdef5aec6 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -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.
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index aa394c4b7da..a54f845a762 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -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);
diff --git a/sql/scheduler.cc b/sql/scheduler.cc
index 6dd93640dc5..5b83bb4753e 100644
--- a/sql/scheduler.cc
+++ b/sql/scheduler.cc
@@ -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);
}
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index 928a28aba24..5f6931ab155 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -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"
diff --git a/sql/slave.cc b/sql/slave.cc
index 1ab1caecfb5..25ce31ab47c 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -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);
/*
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 6532e6c56f2..fda922f91ae 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -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) &&
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index e2142bc2734..cacec989518 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -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)
{
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 5378390ebb4..8631a13eae7 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -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();
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 16165cdedbb..39edcdca3de 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -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;
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 748c2a4a818..17111b9a8c6 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -362,6 +362,38 @@ public:
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 @@ public:
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 @@ public:
}
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 @@ public:
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()
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index 5b7d392d773..5e0ab339418 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -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;
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index becc1ada7ae..98d034a4d5c 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -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 @@ cleanup:
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) &&
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
index 835e60cd6ba..1db4a110d01 100644
--- a/sql/sql_error.cc
+++ b/sql/sql_error.cc
@@ -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;
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index b840eebf4cc..778805d0eb6 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -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 @@ end:
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;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 4ef24876474..32ad4f414c9 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -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.
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index cc0527591e1..3df6305f620 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -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,
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index f850dc9145f..acdd6b76df4 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -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 @@ end_with_restore_list:
}
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 @@ end_with_restore_list:
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,
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index fc472c17e57..80231c1a293 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1277,9 +1277,9 @@ err:
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);
}
}
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 2a717ba1572..57d6d585997 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -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
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 299e88107d7..e6ec80bbd8d 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -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
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index b516065eff7..80eb823c346 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -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))
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index c2fea985aa1..08738f14cca 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -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 {}
diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc
index f7efaf4566f..80292503904 100644
--- a/storage/archive/ha_archive.cc
+++ b/storage/archive/ha_archive.cc
@@ -17,6 +17,7 @@
#pragma implementation // gcc: Class implementation
#endif
+#define MYSQL_SERVER 1
#include "mysql_priv.h"
#include <myisam.h>
diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc
index abefe56095a..e65ac7e443c 100644
--- a/storage/maria/ha_maria.cc
+++ b/storage/maria/ha_maria.cc
@@ -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))