mirror of
https://github.com/MariaDB/server.git
synced 2025-07-27 18:02:13 +03:00
Added max_user_connections
This commit is contained in:
@ -11,7 +11,8 @@ extra_configs="$pentium_configs $debug_configs"
|
|||||||
# Use the debug version if it exists
|
# Use the debug version if it exists
|
||||||
if test -d /usr/local/BerkeleyDB-dbug/
|
if test -d /usr/local/BerkeleyDB-dbug/
|
||||||
then
|
then
|
||||||
extra_configs="$extra_configs --with-berkeley-db=/usr/local/BerkeleyDB-dbug/ --with-innobase"
|
extra_configs="$extra_configs --with-berkeley-db=/usr/local/BerkeleyDB-dbug/"
|
||||||
fi
|
fi
|
||||||
|
extra_configs="$extra_configs --with-innobase"
|
||||||
|
|
||||||
. "$path/FINISH.sh"
|
. "$path/FINISH.sh"
|
||||||
|
@ -9579,6 +9579,7 @@ uses:
|
|||||||
|
|
||||||
@findex command-line options
|
@findex command-line options
|
||||||
@cindex options, command-line
|
@cindex options, command-line
|
||||||
|
@cindex mysqld options
|
||||||
@node Command-line options, Option files, Automatic start, Post-installation
|
@node Command-line options, Option files, Automatic start, Post-installation
|
||||||
@subsection Command-line Options
|
@subsection Command-line Options
|
||||||
|
|
||||||
@ -11522,6 +11523,11 @@ in the grant tables. In principle, the @code{--secure} option to
|
|||||||
@code{mysqld} should make hostnames safe. In any case, you should be very
|
@code{mysqld} should make hostnames safe. In any case, you should be very
|
||||||
careful about creating grant table entries using hostname values that
|
careful about creating grant table entries using hostname values that
|
||||||
contain wild cards!
|
contain wild cards!
|
||||||
|
|
||||||
|
@item
|
||||||
|
If you want to restrict the number of connections for a single user, you
|
||||||
|
can do this by setting the @code{max_user_connections} variable in
|
||||||
|
@code{mysqld}.
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
@node Privileges options, What Privileges, Security, Privilege system
|
@node Privileges options, What Privileges, Security, Privilege system
|
||||||
@ -21048,6 +21054,9 @@ The number of bytes to use when sorting @code{BLOB} or @code{TEXT}
|
|||||||
values (only the first @code{max_sort_length} bytes of each value
|
values (only the first @code{max_sort_length} bytes of each value
|
||||||
are used; the rest are ignored).
|
are used; the rest are ignored).
|
||||||
|
|
||||||
|
@item @code{max_user_connections}
|
||||||
|
The maximum number of active connections for a single user (0 = no limit).
|
||||||
|
|
||||||
@item @code{max_tmp_tables}
|
@item @code{max_tmp_tables}
|
||||||
(This option doesn't yet do anything.)
|
(This option doesn't yet do anything.)
|
||||||
Maximum number of temporary tables a client can keep open at the same time.
|
Maximum number of temporary tables a client can keep open at the same time.
|
||||||
@ -41585,6 +41594,8 @@ not yet 100 % confident in this code.
|
|||||||
@appendixsubsec Changes in release 3.23.34
|
@appendixsubsec Changes in release 3.23.34
|
||||||
@itemize @bullet
|
@itemize @bullet
|
||||||
@item
|
@item
|
||||||
|
Added option @code{max_user_connections} to @code{mysqld}.
|
||||||
|
@item
|
||||||
Limit query length for replication by max_allowed_packet, not the arbitrary
|
Limit query length for replication by max_allowed_packet, not the arbitrary
|
||||||
limit of 4 MB
|
limit of 4 MB
|
||||||
@item
|
@item
|
||||||
|
@ -19,14 +19,14 @@ Created 9/6/1995 Heikki Tuuri
|
|||||||
#include "ut0mem.h"
|
#include "ut0mem.h"
|
||||||
|
|
||||||
/* Type definition for an operating system mutex struct */
|
/* Type definition for an operating system mutex struct */
|
||||||
struct os_mutex_struct{
|
struct os_mutex_struct{
|
||||||
void* handle; /* OS handle to mutex */
|
void* handle; /* OS handle to mutex */
|
||||||
ulint count; /* we use this counter to check
|
ulint count; /* we use this counter to check
|
||||||
that the same thread does not
|
that the same thread does not
|
||||||
recursively lock the mutex: we
|
recursively lock the mutex: we
|
||||||
do not assume that the OS mutex
|
do not assume that the OS mutex
|
||||||
supports recursive locking, though
|
supports recursive locking, though
|
||||||
NT seems to do that */
|
NT seems to do that */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
@ -44,7 +44,7 @@ os_event_create(
|
|||||||
{
|
{
|
||||||
#ifdef __WIN__
|
#ifdef __WIN__
|
||||||
HANDLE event;
|
HANDLE event;
|
||||||
|
|
||||||
event = CreateEvent(NULL, /* No security attributes */
|
event = CreateEvent(NULL, /* No security attributes */
|
||||||
TRUE, /* Manual reset */
|
TRUE, /* Manual reset */
|
||||||
FALSE, /* Initial state nonsignaled */
|
FALSE, /* Initial state nonsignaled */
|
||||||
@ -60,9 +60,9 @@ os_event_create(
|
|||||||
event = ut_malloc(sizeof(struct os_event_struct));
|
event = ut_malloc(sizeof(struct os_event_struct));
|
||||||
|
|
||||||
os_fast_mutex_init(&(event->os_mutex));
|
os_fast_mutex_init(&(event->os_mutex));
|
||||||
os_fast_mutex_init(&(event->wait_mutex));
|
pthread_cond_init(&(event->cond_var), NULL);
|
||||||
|
|
||||||
event->is_set = TRUE;
|
event->is_set = FALSE;
|
||||||
|
|
||||||
return(event);
|
return(event);
|
||||||
#endif
|
#endif
|
||||||
@ -108,7 +108,7 @@ os_event_set(
|
|||||||
/*=========*/
|
/*=========*/
|
||||||
os_event_t event) /* in: event to set */
|
os_event_t event) /* in: event to set */
|
||||||
{
|
{
|
||||||
#ifdef __WIN__
|
#ifdef __WIN__
|
||||||
ut_a(event);
|
ut_a(event);
|
||||||
ut_a(SetEvent(event));
|
ut_a(SetEvent(event));
|
||||||
#else
|
#else
|
||||||
@ -119,12 +119,12 @@ os_event_set(
|
|||||||
if (event->is_set) {
|
if (event->is_set) {
|
||||||
/* Do nothing */
|
/* Do nothing */
|
||||||
} else {
|
} else {
|
||||||
os_fast_mutex_unlock(&(event->wait_mutex));
|
|
||||||
event->is_set = TRUE;
|
event->is_set = TRUE;
|
||||||
|
pthread_cond_broadcast(&(event->cond_var));
|
||||||
}
|
}
|
||||||
|
|
||||||
os_fast_mutex_unlock(&(event->os_mutex));
|
os_fast_mutex_unlock(&(event->os_mutex));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************
|
/**************************************************************
|
||||||
@ -148,7 +148,6 @@ os_event_reset(
|
|||||||
if (!event->is_set) {
|
if (!event->is_set) {
|
||||||
/* Do nothing */
|
/* Do nothing */
|
||||||
} else {
|
} else {
|
||||||
os_fast_mutex_lock(&(event->wait_mutex));
|
|
||||||
event->is_set = FALSE;
|
event->is_set = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +162,7 @@ void
|
|||||||
os_event_free(
|
os_event_free(
|
||||||
/*==========*/
|
/*==========*/
|
||||||
os_event_t event) /* in: event to free */
|
os_event_t event) /* in: event to free */
|
||||||
|
|
||||||
{
|
{
|
||||||
#ifdef __WIN__
|
#ifdef __WIN__
|
||||||
ut_a(event);
|
ut_a(event);
|
||||||
@ -173,7 +172,7 @@ os_event_free(
|
|||||||
ut_a(event);
|
ut_a(event);
|
||||||
|
|
||||||
os_fast_mutex_free(&(event->os_mutex));
|
os_fast_mutex_free(&(event->os_mutex));
|
||||||
os_fast_mutex_free(&(event->wait_mutex));
|
pthread_cond_destroy(&(event->cond_var));
|
||||||
|
|
||||||
ut_free(event);
|
ut_free(event);
|
||||||
#endif
|
#endif
|
||||||
@ -197,8 +196,22 @@ os_event_wait(
|
|||||||
|
|
||||||
ut_a(err == WAIT_OBJECT_0);
|
ut_a(err == WAIT_OBJECT_0);
|
||||||
#else
|
#else
|
||||||
os_fast_mutex_lock(&(event->wait_mutex));
|
os_fast_mutex_lock(&(event->os_mutex));
|
||||||
os_fast_mutex_unlock(&(event->wait_mutex));
|
loop:
|
||||||
|
if (event->is_set == TRUE) {
|
||||||
|
os_fast_mutex_unlock(&(event->os_mutex));
|
||||||
|
|
||||||
|
/* Ok, we may return */
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_cond_wait(&(event->cond_var), &(event->os_mutex));
|
||||||
|
|
||||||
|
/* Solaris manual said that spurious wakeups may occur: we have
|
||||||
|
to check the 'is_set' variable again */
|
||||||
|
|
||||||
|
goto loop;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,7 +238,7 @@ os_event_wait_time(
|
|||||||
} else {
|
} else {
|
||||||
err = WaitForSingleObject(event, INFINITE);
|
err = WaitForSingleObject(event, INFINITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err == WAIT_OBJECT_0) {
|
if (err == WAIT_OBJECT_0) {
|
||||||
|
|
||||||
return(0);
|
return(0);
|
||||||
@ -237,7 +250,7 @@ os_event_wait_time(
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
UT_NOT_USED(time);
|
UT_NOT_USED(time);
|
||||||
|
|
||||||
/* In Posix this is just an ordinary, infinite wait */
|
/* In Posix this is just an ordinary, infinite wait */
|
||||||
|
|
||||||
os_event_wait(event);
|
os_event_wait(event);
|
||||||
@ -277,7 +290,7 @@ os_event_wait_multiple(
|
|||||||
return(index - WAIT_OBJECT_0);
|
return(index - WAIT_OBJECT_0);
|
||||||
#else
|
#else
|
||||||
ut_a(n == 0);
|
ut_a(n == 0);
|
||||||
|
|
||||||
/* In Posix we can only wait for a single event */
|
/* In Posix we can only wait for a single event */
|
||||||
|
|
||||||
os_event_wait(*event_array);
|
os_event_wait(*event_array);
|
||||||
@ -318,7 +331,7 @@ os_mutex_create(
|
|||||||
os_mutex_t mutex_str;
|
os_mutex_t mutex_str;
|
||||||
|
|
||||||
UT_NOT_USED(name);
|
UT_NOT_USED(name);
|
||||||
|
|
||||||
os_mutex = ut_malloc(sizeof(os_fast_mutex_t));
|
os_mutex = ut_malloc(sizeof(os_fast_mutex_t));
|
||||||
|
|
||||||
os_fast_mutex_init(os_mutex);
|
os_fast_mutex_init(os_mutex);
|
||||||
@ -329,7 +342,7 @@ os_mutex_create(
|
|||||||
mutex_str->count = 0;
|
mutex_str->count = 0;
|
||||||
|
|
||||||
return(mutex_str);
|
return(mutex_str);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************
|
/**************************************************************
|
||||||
@ -385,7 +398,7 @@ os_mutex_exit(
|
|||||||
(mutex->count)--;
|
(mutex->count)--;
|
||||||
|
|
||||||
os_fast_mutex_unlock(mutex->handle);
|
os_fast_mutex_unlock(mutex->handle);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************
|
/**************************************************************
|
||||||
@ -419,7 +432,7 @@ os_fast_mutex_init(
|
|||||||
{
|
{
|
||||||
#ifdef __WIN__
|
#ifdef __WIN__
|
||||||
ut_a(fast_mutex);
|
ut_a(fast_mutex);
|
||||||
|
|
||||||
InitializeCriticalSection((LPCRITICAL_SECTION) fast_mutex);
|
InitializeCriticalSection((LPCRITICAL_SECTION) fast_mutex);
|
||||||
#else
|
#else
|
||||||
pthread_mutex_init(fast_mutex, NULL);
|
pthread_mutex_init(fast_mutex, NULL);
|
||||||
|
@ -521,7 +521,7 @@ extern uint protocol_version,dropping_tables;
|
|||||||
extern ulong keybuff_size,sortbuff_size,max_item_sort_length,table_cache_size,
|
extern ulong keybuff_size,sortbuff_size,max_item_sort_length,table_cache_size,
|
||||||
max_join_size,join_buff_size,tmp_table_size,
|
max_join_size,join_buff_size,tmp_table_size,
|
||||||
max_connections,max_connect_errors,long_query_time,
|
max_connections,max_connect_errors,long_query_time,
|
||||||
max_insert_delayed_threads,
|
max_insert_delayed_threads, max_user_connections,
|
||||||
long_query_count,net_wait_timeout,net_interactive_timeout,
|
long_query_count,net_wait_timeout,net_interactive_timeout,
|
||||||
net_read_timeout,net_write_timeout,
|
net_read_timeout,net_write_timeout,
|
||||||
what_to_log,flush_time,
|
what_to_log,flush_time,
|
||||||
|
134
sql/sql_parse.cc
134
sql/sql_parse.cc
@ -22,6 +22,7 @@
|
|||||||
#include <thr_alarm.h>
|
#include <thr_alarm.h>
|
||||||
#include <myisam.h>
|
#include <myisam.h>
|
||||||
#include <my_dir.h>
|
#include <my_dir.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#define SCRAMBLE_LENGTH 8
|
#define SCRAMBLE_LENGTH 8
|
||||||
|
|
||||||
@ -32,6 +33,9 @@ extern "C" pthread_mutex_t THR_LOCK_keycache;
|
|||||||
extern "C" int gethostname(char *name, int namelen);
|
extern "C" int gethostname(char *name, int namelen);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int check_for_max_user_connections(const char *user, int u_length,
|
||||||
|
const char *host);
|
||||||
|
static void decrease_user_connections(const char *user, const char *host);
|
||||||
static bool check_table_access(THD *thd,uint want_access, TABLE_LIST *tables);
|
static bool check_table_access(THD *thd,uint want_access, TABLE_LIST *tables);
|
||||||
static bool check_db_used(THD *thd,TABLE_LIST *tables);
|
static bool check_db_used(THD *thd,TABLE_LIST *tables);
|
||||||
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
|
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
|
||||||
@ -145,13 +149,134 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
|
|||||||
thd->host ? thd->host : thd->ip ? thd->ip : "unknown ip",
|
thd->host ? thd->host : thd->ip ? thd->ip : "unknown ip",
|
||||||
db ? db : (char*) "");
|
db ? db : (char*) "");
|
||||||
thd->db_access=0;
|
thd->db_access=0;
|
||||||
|
if (max_user_connections &&
|
||||||
|
check_for_max_user_connections(user, strlen(user), thd->host))
|
||||||
|
return -1;
|
||||||
if (db && db[0])
|
if (db && db[0])
|
||||||
return test(mysql_change_db(thd,db));
|
{
|
||||||
|
bool error=test(mysql_change_db(thd,db));
|
||||||
|
if (error)
|
||||||
|
decrease_user_connections(user,thd->host);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
send_ok(net); // Ready to handle questions
|
send_ok(net); // Ready to handle questions
|
||||||
return 0; // ok
|
return 0; // ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** check for maximum allowable user connections
|
||||||
|
** if mysql server is started with corresponding
|
||||||
|
** variable that is greater then 0
|
||||||
|
*/
|
||||||
|
|
||||||
|
static HASH hash_user_connections;
|
||||||
|
static DYNAMIC_ARRAY user_conn_array;
|
||||||
|
extern pthread_mutex_t LOCK_user_conn;
|
||||||
|
|
||||||
|
struct user_conn {
|
||||||
|
char user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
|
||||||
|
int connections, len;
|
||||||
|
};
|
||||||
|
|
||||||
|
static byte* get_key_conn(user_conn *buff, uint *length,
|
||||||
|
my_bool not_used __attribute__((unused)))
|
||||||
|
{
|
||||||
|
*length=buff->len;
|
||||||
|
return (byte*) buff->user;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEF_USER_COUNT 50
|
||||||
|
|
||||||
|
void init_max_user_conn(void)
|
||||||
|
{
|
||||||
|
(void) hash_init(&hash_user_connections,DEF_USER_COUNT,0,0,
|
||||||
|
(hash_get_key) get_key_conn,0, 0);
|
||||||
|
(void) init_dynamic_array(&user_conn_array,sizeof(user_conn),
|
||||||
|
DEF_USER_COUNT, DEF_USER_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int check_for_max_user_connections(const char *user, int u_length,
|
||||||
|
const char *host)
|
||||||
|
{
|
||||||
|
uint temp_len;
|
||||||
|
char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
|
||||||
|
struct user_conn *uc;
|
||||||
|
if (!user)
|
||||||
|
user="";
|
||||||
|
if (!host)
|
||||||
|
host="";
|
||||||
|
temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user), user, "@", host,
|
||||||
|
NullS) - temp_user);
|
||||||
|
(void) pthread_mutex_lock(&LOCK_user_conn);
|
||||||
|
uc = (struct user_conn *) hash_search(&hash_user_connections,
|
||||||
|
(byte*) temp_user, temp_len);
|
||||||
|
if (uc) /* user found ; check for no. of connections */
|
||||||
|
{
|
||||||
|
if (max_user_connections == uc->connections)
|
||||||
|
{
|
||||||
|
net_printf(&(current_thd->net),ER_TOO_MANY_USER_CONNECTIONS, temp_user);
|
||||||
|
pthread_mutex_unlock(&LOCK_user_conn);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
uc->connections++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* the user is not found in the cache; Insert it */
|
||||||
|
struct user_conn uc;
|
||||||
|
memcpy(uc.user,temp_user,temp_len+1);
|
||||||
|
uc.len = temp_len;
|
||||||
|
uc.connections = 1;
|
||||||
|
if (!insert_dynamic(&user_conn_array, (char *) &uc))
|
||||||
|
{
|
||||||
|
hash_insert(&hash_user_connections,
|
||||||
|
(byte *) dynamic_array_ptr(&user_conn_array,
|
||||||
|
user_conn_array.elements - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(void) pthread_mutex_unlock(&LOCK_user_conn);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void decrease_user_connections(const char *user, const char *host)
|
||||||
|
{
|
||||||
|
char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
|
||||||
|
int temp_len;
|
||||||
|
struct user_conn uucc, *uc;
|
||||||
|
if (!user)
|
||||||
|
user="";
|
||||||
|
if (!host)
|
||||||
|
host="";
|
||||||
|
temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user), user, "@", host,
|
||||||
|
NullS) - temp_user);
|
||||||
|
(void) pthread_mutex_lock(&LOCK_user_conn);
|
||||||
|
|
||||||
|
uc = (struct user_conn *) hash_search(&hash_user_connections,
|
||||||
|
(byte*) temp_user, temp_len);
|
||||||
|
dbug_assert(uc != 0); // We should always find the user
|
||||||
|
if (!uc)
|
||||||
|
goto end; // Safety; Something went wrong
|
||||||
|
if (! --uc->connections)
|
||||||
|
{
|
||||||
|
/* Last connection for user; Delete it */
|
||||||
|
(void) hash_delete(&hash_user_connections,(char *) uc);
|
||||||
|
uint element= ((uint) ((byte*) uc - (byte*) user_conn_array.buffer) /
|
||||||
|
user_conn_array.size_of_element);
|
||||||
|
delete_dynamic_element(&user_conn_array,element);
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
(void) pthread_mutex_unlock(&LOCK_user_conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_max_user_conn(void)
|
||||||
|
{
|
||||||
|
delete_dynamic(&user_conn_array);
|
||||||
|
hash_free(&hash_user_connections);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** check connnetion and get priviliges
|
** check connnetion and get priviliges
|
||||||
@ -417,6 +542,8 @@ pthread_handler_decl(handle_one_connection,arg)
|
|||||||
thread_safe_increment(aborted_threads,&LOCK_thread_count);
|
thread_safe_increment(aborted_threads,&LOCK_thread_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (max_user_connections)
|
||||||
|
decrease_user_connections(thd->user,thd->host);
|
||||||
end_thread:
|
end_thread:
|
||||||
close_connection(net);
|
close_connection(net);
|
||||||
end_thread(thd,1);
|
end_thread(thd,1);
|
||||||
@ -512,7 +639,7 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
|
|||||||
DBUG_ENTER("mysql_table_dump");
|
DBUG_ENTER("mysql_table_dump");
|
||||||
db = (db && db[0]) ? db : thd->db;
|
db = (db && db[0]) ? db : thd->db;
|
||||||
if (!(table_list = (TABLE_LIST*) sql_calloc(sizeof(TABLE_LIST))))
|
if (!(table_list = (TABLE_LIST*) sql_calloc(sizeof(TABLE_LIST))))
|
||||||
DBUG_RETURN(1); // out of memory
|
DBUG_RETURN(1); // out of memory
|
||||||
table_list->db = db;
|
table_list->db = db;
|
||||||
table_list->real_name = table_list->name = tbl_name;
|
table_list->real_name = table_list->name = tbl_name;
|
||||||
table_list->lock_type = TL_READ_NO_INSERT;
|
table_list->lock_type = TL_READ_NO_INSERT;
|
||||||
@ -641,7 +768,7 @@ bool do_command(THD *thd)
|
|||||||
send_error(net, ER_UNKNOWN_COM_ERROR);
|
send_error(net, ER_UNKNOWN_COM_ERROR);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (check_user(thd, COM_CHANGE_USER, user, passwd, db,0))
|
if (check_user(thd, COM_CHANGE_USER, user, passwd, db, 0))
|
||||||
{ // Restore old user
|
{ // Restore old user
|
||||||
x_free(thd->user);
|
x_free(thd->user);
|
||||||
x_free(thd->db);
|
x_free(thd->db);
|
||||||
@ -652,6 +779,7 @@ bool do_command(THD *thd)
|
|||||||
thd->priv_user=save_priv_user;
|
thd->priv_user=save_priv_user;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
decrease_user_connections (save_user, thd->host);
|
||||||
x_free((gptr) save_db);
|
x_free((gptr) save_db);
|
||||||
x_free((gptr) save_user);
|
x_free((gptr) save_user);
|
||||||
thd->password=test(passwd[0]);
|
thd->password=test(passwd[0]);
|
||||||
|
Reference in New Issue
Block a user