diff options
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= ¤t_thd->killed; + volatile killed_state *killed= ¤t_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= ¬_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)) |