mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
A fix and test case for Bug#5315 "mysql_change_user() doesn't free
prepared statements."
This commit is contained in:
@ -47,6 +47,7 @@ my_bool _hash_init(HASH *hash, CHARSET_INFO *charset,
|
|||||||
uint key_length, hash_get_key get_key,
|
uint key_length, hash_get_key get_key,
|
||||||
void (*free_element)(void*), uint flags CALLER_INFO_PROTO);
|
void (*free_element)(void*), uint flags CALLER_INFO_PROTO);
|
||||||
void hash_free(HASH *tree);
|
void hash_free(HASH *tree);
|
||||||
|
void hash_reset(HASH *hash);
|
||||||
byte *hash_element(HASH *hash,uint idx);
|
byte *hash_element(HASH *hash,uint idx);
|
||||||
gptr hash_search(HASH *info,const byte *key,uint length);
|
gptr hash_search(HASH *info,const byte *key,uint length);
|
||||||
gptr hash_next(HASH *info,const byte *key,uint length);
|
gptr hash_next(HASH *info,const byte *key,uint length);
|
||||||
@ -56,7 +57,6 @@ my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length);
|
|||||||
void hash_replace(HASH *hash, uint idx, byte *new_row);
|
void hash_replace(HASH *hash, uint idx, byte *new_row);
|
||||||
my_bool hash_check(HASH *hash); /* Only in debug library */
|
my_bool hash_check(HASH *hash); /* Only in debug library */
|
||||||
|
|
||||||
#define hash_clear(H) bzero((char*) (H),sizeof(*(H)))
|
|
||||||
#define hash_inited(H) ((H)->array.buffer != 0)
|
#define hash_inited(H) ((H)->array.buffer != 0)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -42,6 +42,7 @@ my_bool handle_local_infile(MYSQL *mysql, const char *net_filename);
|
|||||||
|
|
||||||
void mysql_read_default_options(struct st_mysql_options *options,
|
void mysql_read_default_options(struct st_mysql_options *options,
|
||||||
const char *filename,const char *group);
|
const char *filename,const char *group);
|
||||||
|
void mysql_detach_stmt_list(LIST **stmt_list);
|
||||||
MYSQL * STDCALL
|
MYSQL * STDCALL
|
||||||
cli_mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
|
cli_mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
|
||||||
const char *passwd, const char *db,
|
const char *passwd, const char *db,
|
||||||
|
@ -662,6 +662,7 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
|
|||||||
const char *passwd, const char *db)
|
const char *passwd, const char *db)
|
||||||
{
|
{
|
||||||
char buff[512],*end=buff;
|
char buff[512],*end=buff;
|
||||||
|
int rc;
|
||||||
DBUG_ENTER("mysql_change_user");
|
DBUG_ENTER("mysql_change_user");
|
||||||
|
|
||||||
if (!user)
|
if (!user)
|
||||||
@ -695,8 +696,15 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
|
|||||||
/* Write authentication package */
|
/* Write authentication package */
|
||||||
simple_command(mysql,COM_CHANGE_USER, buff,(ulong) (end-buff),1);
|
simple_command(mysql,COM_CHANGE_USER, buff,(ulong) (end-buff),1);
|
||||||
|
|
||||||
if ((*mysql->methods->read_change_user_result)(mysql, buff, passwd))
|
rc= (*mysql->methods->read_change_user_result)(mysql, buff, passwd);
|
||||||
DBUG_RETURN(1);
|
|
||||||
|
/*
|
||||||
|
The server will close all statements no matter was the attempt
|
||||||
|
to change user successful or not.
|
||||||
|
*/
|
||||||
|
mysql_detach_stmt_list(&mysql->stmts);
|
||||||
|
if (rc == 0)
|
||||||
|
{
|
||||||
/* Free old connect information */
|
/* Free old connect information */
|
||||||
my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR));
|
my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR));
|
||||||
my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR));
|
my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR));
|
||||||
@ -706,7 +714,8 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
|
|||||||
mysql->user= my_strdup(user,MYF(MY_WME));
|
mysql->user= my_strdup(user,MYF(MY_WME));
|
||||||
mysql->passwd=my_strdup(passwd,MYF(MY_WME));
|
mysql->passwd=my_strdup(passwd,MYF(MY_WME));
|
||||||
mysql->db= db ? my_strdup(db,MYF(MY_WME)) : 0;
|
mysql->db= db ? my_strdup(db,MYF(MY_WME)) : 0;
|
||||||
DBUG_RETURN(0);
|
}
|
||||||
|
DBUG_RETURN(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(HAVE_GETPWUID) && defined(NO_GETPWUID_DECL)
|
#if defined(HAVE_GETPWUID) && defined(NO_GETPWUID_DECL)
|
||||||
|
26
mysys/hash.c
26
mysys/hash.c
@ -88,6 +88,32 @@ void hash_free(HASH *hash)
|
|||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Delete all elements from the hash (the hash itself is to be reused).
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
hash_reset()
|
||||||
|
hash the hash to delete elements of
|
||||||
|
*/
|
||||||
|
|
||||||
|
void hash_reset(HASH *hash)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("hash_reset");
|
||||||
|
if (hash->free)
|
||||||
|
{
|
||||||
|
HASH_LINK *link= dynamic_element(&hash->array, 0, HASH_LINK*);
|
||||||
|
HASH_LINK *end= link + hash->records;
|
||||||
|
for (; link < end; ++link)
|
||||||
|
(*hash->free)(link->data);
|
||||||
|
}
|
||||||
|
reset_dynamic(&hash->array);
|
||||||
|
hash->records= 0;
|
||||||
|
hash->blength= 1;
|
||||||
|
hash->current_record= NO_RECORD;
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
/* some helper functions */
|
/* some helper functions */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2239,6 +2239,32 @@ static void mysql_close_free(MYSQL *mysql)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Clear connection pointer of every statement: this is necessary
|
||||||
|
to give error on attempt to use a prepared statement of closed
|
||||||
|
connection.
|
||||||
|
|
||||||
|
SYNOPSYS
|
||||||
|
mysql_detach_stmt_list()
|
||||||
|
stmt_list pointer to mysql->stmts
|
||||||
|
*/
|
||||||
|
|
||||||
|
void mysql_detach_stmt_list(LIST **stmt_list)
|
||||||
|
{
|
||||||
|
#ifdef MYSQL_CLIENT
|
||||||
|
/* Reset connection handle in all prepared statements. */
|
||||||
|
LIST *element= *stmt_list;
|
||||||
|
for (; element; element= element->next)
|
||||||
|
{
|
||||||
|
MYSQL_STMT *stmt= (MYSQL_STMT *) element->data;
|
||||||
|
stmt->mysql= 0;
|
||||||
|
/* No need to call list_delete for statement here */
|
||||||
|
}
|
||||||
|
*stmt_list= 0;
|
||||||
|
#endif /* MYSQL_CLIENT */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void STDCALL mysql_close(MYSQL *mysql)
|
void STDCALL mysql_close(MYSQL *mysql)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("mysql_close");
|
DBUG_ENTER("mysql_close");
|
||||||
@ -2255,20 +2281,7 @@ void STDCALL mysql_close(MYSQL *mysql)
|
|||||||
}
|
}
|
||||||
mysql_close_free_options(mysql);
|
mysql_close_free_options(mysql);
|
||||||
mysql_close_free(mysql);
|
mysql_close_free(mysql);
|
||||||
#ifdef MYSQL_CLIENT
|
mysql_detach_stmt_list(&mysql->stmts);
|
||||||
if (mysql->stmts)
|
|
||||||
{
|
|
||||||
/* Reset connection handle in all prepared statements. */
|
|
||||||
LIST *element;
|
|
||||||
for (element= mysql->stmts; element; element= element->next)
|
|
||||||
{
|
|
||||||
MYSQL_STMT *stmt= (MYSQL_STMT *) element->data;
|
|
||||||
stmt->mysql= 0;
|
|
||||||
/* No need to call list_delete for statement here */
|
|
||||||
}
|
|
||||||
mysql->stmts= 0;
|
|
||||||
}
|
|
||||||
#endif /*MYSQL_CLIENT*/
|
|
||||||
#ifndef TO_BE_DELETED
|
#ifndef TO_BE_DELETED
|
||||||
/* free/close slave list */
|
/* free/close slave list */
|
||||||
if (mysql->rpl_pivot)
|
if (mysql->rpl_pivot)
|
||||||
|
@ -328,6 +328,7 @@ void THD::change_user(void)
|
|||||||
cleanup();
|
cleanup();
|
||||||
cleanup_done= 0;
|
cleanup_done= 0;
|
||||||
init();
|
init();
|
||||||
|
stmt_map.reset();
|
||||||
hash_init(&user_vars, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0,
|
hash_init(&user_vars, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0,
|
||||||
(hash_get_key) get_var_key,
|
(hash_get_key) get_var_key,
|
||||||
(hash_free_key) free_user_var, 0);
|
(hash_free_key) free_user_var, 0);
|
||||||
|
@ -608,11 +608,18 @@ public:
|
|||||||
}
|
}
|
||||||
hash_delete(&st_hash, (byte *) statement);
|
hash_delete(&st_hash, (byte *) statement);
|
||||||
}
|
}
|
||||||
|
/* Erase all statements (calls Statement destructor) */
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
hash_reset(&names_hash);
|
||||||
|
hash_reset(&st_hash);
|
||||||
|
last_found_statement= 0;
|
||||||
|
}
|
||||||
|
|
||||||
~Statement_map()
|
~Statement_map()
|
||||||
{
|
{
|
||||||
hash_free(&st_hash);
|
|
||||||
hash_free(&names_hash);
|
hash_free(&names_hash);
|
||||||
|
hash_free(&st_hash);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
HASH st_hash;
|
HASH st_hash;
|
||||||
|
@ -10391,6 +10391,34 @@ static void test_bug5194()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void test_bug5315()
|
||||||
|
{
|
||||||
|
MYSQL_STMT *stmt;
|
||||||
|
const char *stmt_text;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
myheader("test_bug5315");
|
||||||
|
|
||||||
|
stmt_text= "SELECT 1";
|
||||||
|
stmt= mysql_stmt_init(mysql);
|
||||||
|
rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
|
||||||
|
DBUG_ASSERT(rc == 0);
|
||||||
|
mysql_change_user(mysql, opt_user, opt_password, current_db);
|
||||||
|
rc= mysql_stmt_execute(stmt);
|
||||||
|
DBUG_ASSERT(rc != 0);
|
||||||
|
if (rc)
|
||||||
|
printf("Got error (as expected):\n%s", mysql_stmt_error(stmt));
|
||||||
|
/* check that connection is OK */
|
||||||
|
mysql_stmt_close(stmt);
|
||||||
|
stmt= mysql_stmt_init(mysql);
|
||||||
|
rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
|
||||||
|
DBUG_ASSERT(rc == 0);
|
||||||
|
rc= mysql_stmt_execute(stmt);
|
||||||
|
DBUG_ASSERT(rc == 0);
|
||||||
|
mysql_stmt_close(stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Read and parse arguments and MySQL options from my.cnf
|
Read and parse arguments and MySQL options from my.cnf
|
||||||
*/
|
*/
|
||||||
@ -10694,6 +10722,8 @@ int main(int argc, char **argv)
|
|||||||
test_bug5399(); /* check that statement id uniquely identifies
|
test_bug5399(); /* check that statement id uniquely identifies
|
||||||
statement */
|
statement */
|
||||||
test_bug5194(); /* bulk inserts in prepared mode */
|
test_bug5194(); /* bulk inserts in prepared mode */
|
||||||
|
test_bug5315(); /* check that mysql_change_user closes all
|
||||||
|
prepared statements */
|
||||||
/*
|
/*
|
||||||
XXX: PLEASE RUN THIS PROGRAM UNDER VALGRIND AND VERIFY THAT YOUR TEST
|
XXX: PLEASE RUN THIS PROGRAM UNDER VALGRIND AND VERIFY THAT YOUR TEST
|
||||||
DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH.
|
DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH.
|
||||||
|
Reference in New Issue
Block a user