diff --git a/sql/mysqld.cc b/sql/mysqld.cc index ff81198..449a8d7 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -429,7 +429,7 @@ uint opt_large_page_size= 0; uint opt_debug_sync_timeout= 0; #endif /* defined(ENABLED_DEBUG_SYNC) */ my_bool opt_old_style_user_limits= 0, trust_function_creators= 0; -my_bool opt_userstat= 0, opt_thread_statistics= 0; +my_bool opt_userstat= 1, opt_thread_statistics= 0; /* True if there is at least one per-hour limit for some user, so we should check them before each query (and possibly reset counters when hour is @@ -7469,6 +7469,7 @@ static void set_server_version(void) #endif if (opt_log || opt_slow_log || opt_bin_log) strmov(end, "-log"); // This may slow down system + end= strmov(end, "-cll"); } diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 1875813..63240d5 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -906,7 +906,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) { /* Starting from 5.0.3 we have max_user_connections field */ ptr= get_field(thd->mem_root, table->field[next_field++]); - user.user_resource.user_conn= ptr ? atoi(ptr) : 0; + user.user_resource.user_conn= ptr ? atoll(ptr) : 0; } if (table->s->fields >= 41) @@ -9311,10 +9311,7 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len) } /* Don't allow the user to connect if he has done too many queries */ - if ((acl_user->user_resource.questions || acl_user->user_resource.updates || - acl_user->user_resource.conn_per_hour || - acl_user->user_resource.user_conn || - global_system_variables.max_user_connections) && + if ( get_or_create_user_conn(thd, (opt_old_style_user_limits ? sctx->user : sctx->priv_user), (opt_old_style_user_limits ? sctx->host_or_ip : sctx->priv_host), diff --git a/sql/sql_class.h b/sql/sql_class.h index 6ee2821..ba8b9ac 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3718,6 +3718,7 @@ inline bool add_group_to_list(THD *thd, Item *item, bool asc) #endif /* MYSQL_SERVER */ + /** The meat of thd_proc_info(THD*, char*), a macro that packs the last three calling-info parameters. diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 3499e0f..7eb4898 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -630,6 +630,10 @@ static void update_global_thread_stats_with_thread(THD* thd, thread_stats->empty_queries+= thd->diff_empty_queries; } +int is_root_access(char *user_name){ + return !strcmp(user_name,"root")||!strcmp(user_name,"mysql"); +} + // Updates the global stats of a user or client void update_global_user_stats(THD* thd, bool create_user, time_t now) { @@ -734,6 +738,15 @@ int check_for_max_user_connections(THD *thd, USER_CONN *uc) DBUG_ENTER("check_for_max_user_connections"); mysql_mutex_lock(&LOCK_user_conn); + + + if (((uc->user_resources.user_conn==(uint)~0) || (global_system_variables.max_user_connections == (uint)~0)) && !is_root_access(uc->user)) + { + my_error(ER_TOO_MANY_USER_CONNECTIONS, MYF(0), uc->user); + error=1; + goto end; + } + if (global_system_variables.max_user_connections && !uc->user_resources.user_conn && global_system_variables.max_user_connections < (uint) uc->connections) diff --git a/sql/sql_list.cc b/sql/sql_list.cc index 31f0ba2..20707de 100644 --- a/sql/sql_list.cc +++ b/sql/sql_list.cc @@ -39,6 +39,14 @@ void free_list(I_List *list) } +void free_list(I_List *list) +{ + i_thd *tmp; + while ((tmp= list->get())) + delete tmp; +} + + base_list::base_list(const base_list &rhs, MEM_ROOT *mem_root) { if (rhs.elements) diff --git a/sql/sql_list.h b/sql/sql_list.h index 5cd2423..a10f4b4 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -562,6 +562,15 @@ public: i_string(const char* s) : ptr(s) {} }; +/* DB_GOVERNOR ADDITIONS */ +class i_thd: public ilink +{ + public: + THD* ptr; + i_thd():ptr(0) { } + i_thd(THD* s) : ptr(s) {} +}; + /* needed for linked list of two strings for replicate-rewrite-db */ class i_string_pair: public ilink { @@ -711,5 +720,6 @@ list_copy_and_replace_each_value(List &list, MEM_ROOT *mem_root) void free_list(I_List *list); void free_list(I_List *list); +void free_list(I_List *list); #endif // INCLUDES_MYSQL_SQL_LIST_H diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 9ee6c42..ea6c42e 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -114,6 +114,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables); static void sql_kill(THD *thd, ulong id, bool only_kill_query); +static void sql_kill_user(THD *thd, char *user, bool only_kill_query); // Uses the THD to update the global stats by user name and client IP void update_global_user_stats(THD* thd, bool create_user, time_t now); @@ -3593,7 +3594,13 @@ end_with_restore_list: MYF(0)); goto error; } - sql_kill(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY); + + if(it->type()==Item::STRING_ITEM){ + sql_kill_user(thd, it->val_str(0)->c_ptr(), lex->type & ONLY_KILL_QUERY); + } else { + sql_kill(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY); + } + break; } #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -6477,6 +6484,15 @@ void sql_kill(THD *thd, ulong id, bool only_kill_query) my_error(error, MYF(0), id); } +static void sql_kill_user(THD *thd, char *user, bool only_kill_query) +{ + uint error; + if (!(error= kill_user_thread(thd, user, only_kill_query))) + if (! thd->killed) my_ok(thd); + else + my_error(error, MYF(0), user); +} + /** If pointer is not a null pointer, append filename to it. */ @@ -7382,3 +7398,58 @@ merge_charset_and_collation(CHARSET_INFO *cs, CHARSET_INFO *cl) } return cs; } + +uint kill_user_thread(THD *thd, char *user, bool only_kill_query) +{ + THD *tmp; + uint error=0; + DBUG_ENTER("kill_user_thread"); + DBUG_PRINT("enter", ("id=%s only_kill=%d", !user?"nop":user, only_kill_query)); + i_thd *thd_tmp; + I_List threads_tmp; + threads_tmp.empty(); + mysql_mutex_lock(&LOCK_thread_count); // For unlink from list + I_List_iterator it(threads); + while ((tmp=it++)) + { + if (tmp->command == COM_DAEMON) + continue; + if((tmp)&&(user)&&(tmp->user_connect)&&(tmp->user_connect->user)){ + if (!strncmp(tmp->user_connect->user,user,16)) + { + mysql_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete + thd_tmp = new i_thd(tmp); + if (thd_tmp) threads_tmp.append(thd_tmp); + else mysql_mutex_unlock(&tmp->LOCK_thd_data); + } + } + } + mysql_mutex_unlock(&LOCK_thread_count); + + if(!threads_tmp.is_empty()) + { + I_List_iterator it_tmp(threads_tmp); + while ((thd_tmp=it_tmp++)){ + tmp=thd_tmp->ptr; + + if ((tmp)&&(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); + error=0; + } + else + error=ER_KILL_DENIED_ERROR; + mysql_mutex_unlock(&tmp->LOCK_thd_data); + } + free_list(&threads_tmp); + threads_tmp.empty(); + } + DBUG_PRINT("exit", ("%d", error)); + DBUG_RETURN(error); +} + + + + + diff --git a/sql/sql_parse.h b/sql/sql_parse.h index 9eea074..7262d4c 100644 --- a/sql/sql_parse.h +++ b/sql/sql_parse.h @@ -50,6 +50,7 @@ bool parse_sql(THD *thd, Parser_state *parser_state, Object_creation_ctx *creation_ctx); +uint kill_user_thread(THD *thd, char *user, bool only_kill_query); uint kill_one_thread(THD *thd, ulong id, bool only_kill_query); void free_items(Item *item); diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 5ff927d..692ceff 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1603,7 +1603,7 @@ static Sys_var_mybool Sys_userstat( "userstat", "Control USER_STATISTICS, CLIENT_STATISTICS, THREAD_STATISTICS, " "INDEX_STATISTICS and TABLE_STATISTICS running", - GLOBAL_VAR(opt_userstat), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); + GLOBAL_VAR(opt_userstat), CMD_LINE(OPT_ARG), DEFAULT(TRUE)); static Sys_var_mybool Sys_thread_statistics( "thread_statistics",