Bug#29363867: LOST CONNECTION TO MYSQL SERVER DURING QUERY
plugin variables in SET only locked the plugin till the end of the statement. If SET with a plugin variable was prepared, it was possible to uninstall the plugin before EXECUTE. Then EXECUTE would crash, trying to resolve a now-invalid pointer to a disappeared variable. Fix: keep plugins locked until the prepared statement is closed.
This commit is contained in:
parent
4f63b6cf53
commit
91599701d0
@ -30,3 +30,38 @@ disconnect con2;
|
|||||||
USE test;
|
USE test;
|
||||||
DROP PROCEDURE p_install;
|
DROP PROCEDURE p_install;
|
||||||
DROP PROCEDURE p_show_vars;
|
DROP PROCEDURE p_show_vars;
|
||||||
|
#
|
||||||
|
# Bug#29363867: LOST CONNECTION TO MYSQL SERVER DURING QUERY
|
||||||
|
#
|
||||||
|
## prepared SET with a plugin variable prevents uninstall
|
||||||
|
install plugin query_response_time soname 'query_response_time';
|
||||||
|
prepare s from 'set global query_response_time_range_base=16';
|
||||||
|
select plugin_status from information_schema.plugins where plugin_name='query_response_time';
|
||||||
|
plugin_status
|
||||||
|
ACTIVE
|
||||||
|
uninstall plugin query_response_time;
|
||||||
|
Warnings:
|
||||||
|
Warning 1620 Plugin is busy and will be uninstalled on shutdown
|
||||||
|
execute s;
|
||||||
|
execute s;
|
||||||
|
select plugin_status from information_schema.plugins where plugin_name='query_response_time';
|
||||||
|
plugin_status
|
||||||
|
DELETED
|
||||||
|
deallocate prepare s;
|
||||||
|
select plugin_status from information_schema.plugins where plugin_name='query_response_time';
|
||||||
|
plugin_status
|
||||||
|
## prepared SET mentioning a plugin otherwise does not prevent uninstall
|
||||||
|
install plugin archive soname 'ha_archive';
|
||||||
|
create table t1 (a int) engine=archive;
|
||||||
|
insert t1 values (1),(2),(3);
|
||||||
|
prepare s from 'set session auto_increment_increment=(select count(*) from t1)';
|
||||||
|
flush tables;
|
||||||
|
select plugin_status from information_schema.plugins where plugin_name='archive';
|
||||||
|
plugin_status
|
||||||
|
ACTIVE
|
||||||
|
uninstall plugin archive;
|
||||||
|
select plugin_status from information_schema.plugins where plugin_name='archive';
|
||||||
|
plugin_status
|
||||||
|
execute s;
|
||||||
|
ERROR 42000: Unknown storage engine 'ARCHIVE'
|
||||||
|
drop table t1;
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
|
if (!$QUERY_RESPONSE_TIME_SO) {
|
||||||
|
skip Needs query_response_time loadable plugin;
|
||||||
|
}
|
||||||
|
if (!$HA_ARCHIVE_SO) {
|
||||||
|
skip Needs Archive loadable plugin;
|
||||||
|
}
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # MDEV-5345 - Deadlock between mysql_change_user(), SHOW VARIABLES and
|
--echo # MDEV-5345 - Deadlock between mysql_change_user(), SHOW VARIABLES and
|
||||||
--echo # INSTALL PLUGIN
|
--echo # INSTALL PLUGIN
|
||||||
@ -54,3 +61,31 @@ disconnect con2;
|
|||||||
USE test;
|
USE test;
|
||||||
DROP PROCEDURE p_install;
|
DROP PROCEDURE p_install;
|
||||||
DROP PROCEDURE p_show_vars;
|
DROP PROCEDURE p_show_vars;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Bug#29363867: LOST CONNECTION TO MYSQL SERVER DURING QUERY
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo ## prepared SET with a plugin variable prevents uninstall
|
||||||
|
install plugin query_response_time soname 'query_response_time';
|
||||||
|
prepare s from 'set global query_response_time_range_base=16';
|
||||||
|
select plugin_status from information_schema.plugins where plugin_name='query_response_time';
|
||||||
|
uninstall plugin query_response_time;
|
||||||
|
execute s;
|
||||||
|
execute s;
|
||||||
|
select plugin_status from information_schema.plugins where plugin_name='query_response_time';
|
||||||
|
deallocate prepare s;
|
||||||
|
select plugin_status from information_schema.plugins where plugin_name='query_response_time';
|
||||||
|
|
||||||
|
--echo ## prepared SET mentioning a plugin otherwise does not prevent uninstall
|
||||||
|
install plugin archive soname 'ha_archive';
|
||||||
|
create table t1 (a int) engine=archive;
|
||||||
|
insert t1 values (1),(2),(3);
|
||||||
|
prepare s from 'set session auto_increment_increment=(select count(*) from t1)';
|
||||||
|
flush tables;
|
||||||
|
select plugin_status from information_schema.plugins where plugin_name='archive';
|
||||||
|
uninstall plugin archive;
|
||||||
|
select plugin_status from information_schema.plugins where plugin_name='archive';
|
||||||
|
--error ER_UNKNOWN_STORAGE_ENGINE
|
||||||
|
execute s;
|
||||||
|
drop table t1;
|
||||||
|
@ -765,15 +765,15 @@ void lex_end(LEX *lex)
|
|||||||
DBUG_ENTER("lex_end");
|
DBUG_ENTER("lex_end");
|
||||||
DBUG_PRINT("enter", ("lex: %p", lex));
|
DBUG_PRINT("enter", ("lex: %p", lex));
|
||||||
|
|
||||||
lex_end_stage1(lex);
|
lex_unlock_plugins(lex);
|
||||||
lex_end_stage2(lex);
|
lex_end_nops(lex);
|
||||||
|
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lex_end_stage1(LEX *lex)
|
void lex_unlock_plugins(LEX *lex)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("lex_end_stage1");
|
DBUG_ENTER("lex_unlock_plugins");
|
||||||
|
|
||||||
/* release used plugins */
|
/* release used plugins */
|
||||||
if (lex->plugins.elements) /* No function call and no mutex if no plugins. */
|
if (lex->plugins.elements) /* No function call and no mutex if no plugins. */
|
||||||
@ -782,33 +782,23 @@ void lex_end_stage1(LEX *lex)
|
|||||||
lex->plugins.elements);
|
lex->plugins.elements);
|
||||||
}
|
}
|
||||||
reset_dynamic(&lex->plugins);
|
reset_dynamic(&lex->plugins);
|
||||||
|
|
||||||
if (lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_PREPARE)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
Don't delete lex->sphead, it'll be needed for EXECUTE.
|
|
||||||
Note that of all statements that populate lex->sphead
|
|
||||||
only SQLCOM_COMPOUND can be PREPAREd
|
|
||||||
*/
|
|
||||||
DBUG_ASSERT(lex->sphead == 0 || lex->sql_command == SQLCOM_COMPOUND);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sp_head::destroy(lex->sphead);
|
|
||||||
lex->sphead= NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Don't delete lex->sphead, it'll be needed for EXECUTE.
|
||||||
|
Note that of all statements that populate lex->sphead
|
||||||
|
only SQLCOM_COMPOUND can be PREPAREd
|
||||||
|
|
||||||
MASTER INFO parameters (or state) is normally cleared towards the end
|
MASTER INFO parameters (or state) is normally cleared towards the end
|
||||||
of a statement. But in case of PS, the state needs to be preserved during
|
of a statement. But in case of PS, the state needs to be preserved during
|
||||||
its lifetime and should only be cleared on PS close or deallocation.
|
its lifetime and should only be cleared on PS close or deallocation.
|
||||||
*/
|
*/
|
||||||
void lex_end_stage2(LEX *lex)
|
void lex_end_nops(LEX *lex)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("lex_end_stage2");
|
DBUG_ENTER("lex_end_nops");
|
||||||
|
sp_head::destroy(lex->sphead);
|
||||||
|
lex->sphead= NULL;
|
||||||
|
|
||||||
/* Reset LEX_MASTER_INFO */
|
/* Reset LEX_MASTER_INFO */
|
||||||
lex->mi.reset(lex->sql_command == SQLCOM_CHANGE_MASTER);
|
lex->mi.reset(lex->sql_command == SQLCOM_CHANGE_MASTER);
|
||||||
|
@ -3412,8 +3412,8 @@ extern void lex_init(void);
|
|||||||
extern void lex_free(void);
|
extern void lex_free(void);
|
||||||
extern void lex_start(THD *thd);
|
extern void lex_start(THD *thd);
|
||||||
extern void lex_end(LEX *lex);
|
extern void lex_end(LEX *lex);
|
||||||
extern void lex_end_stage1(LEX *lex);
|
extern void lex_end_nops(LEX *lex);
|
||||||
extern void lex_end_stage2(LEX *lex);
|
extern void lex_unlock_plugins(LEX *lex);
|
||||||
void end_lex_with_single_table(THD *thd, TABLE *table, LEX *old_lex);
|
void end_lex_with_single_table(THD *thd, TABLE *table, LEX *old_lex);
|
||||||
int init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex);
|
int init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex);
|
||||||
extern int MYSQLlex(union YYSTYPE *yylval, THD *thd);
|
extern int MYSQLlex(union YYSTYPE *yylval, THD *thd);
|
||||||
|
@ -4307,8 +4307,10 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
|
|||||||
thd->release_transactional_locks();
|
thd->release_transactional_locks();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Preserve CHANGE MASTER attributes */
|
/* Preserve locked plugins for SET */
|
||||||
lex_end_stage1(lex);
|
if (lex->sql_command != SQLCOM_SET_OPTION)
|
||||||
|
lex_unlock_plugins(lex);
|
||||||
|
|
||||||
cleanup_stmt();
|
cleanup_stmt();
|
||||||
thd->restore_backup_statement(this, &stmt_backup);
|
thd->restore_backup_statement(this, &stmt_backup);
|
||||||
thd->stmt_arena= old_stmt_arena;
|
thd->stmt_arena= old_stmt_arena;
|
||||||
@ -5189,7 +5191,7 @@ void Prepared_statement::deallocate_immediate()
|
|||||||
status_var_increment(thd->status_var.com_stmt_close);
|
status_var_increment(thd->status_var.com_stmt_close);
|
||||||
|
|
||||||
/* It should now be safe to reset CHANGE MASTER parameters */
|
/* It should now be safe to reset CHANGE MASTER parameters */
|
||||||
lex_end_stage2(lex);
|
lex_end(lex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user