diff --git a/mysql-test/r/plugin_vars.result b/mysql-test/r/plugin_vars.result index 0e382427b1d..3fadd5e74fd 100644 --- a/mysql-test/r/plugin_vars.result +++ b/mysql-test/r/plugin_vars.result @@ -30,3 +30,38 @@ disconnect con2; USE test; DROP PROCEDURE p_install; 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; diff --git a/mysql-test/t/plugin_vars.test b/mysql-test/t/plugin_vars.test index 8ba8fe2ec0e..797dcbea727 100644 --- a/mysql-test/t/plugin_vars.test +++ b/mysql-test/t/plugin_vars.test @@ -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 # MDEV-5345 - Deadlock between mysql_change_user(), SHOW VARIABLES and --echo # INSTALL PLUGIN @@ -54,3 +61,31 @@ disconnect con2; USE test; DROP PROCEDURE p_install; 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; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 57c6dfad4e5..c534ba76670 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -765,15 +765,15 @@ void lex_end(LEX *lex) DBUG_ENTER("lex_end"); DBUG_PRINT("enter", ("lex: %p", lex)); - lex_end_stage1(lex); - lex_end_stage2(lex); + lex_unlock_plugins(lex); + lex_end_nops(lex); 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 */ 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); } 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; } /* + 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 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. */ -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 */ lex->mi.reset(lex->sql_command == SQLCOM_CHANGE_MASTER); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 0dab0f0666d..fbc2bf7f822 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3412,8 +3412,8 @@ extern void lex_init(void); extern void lex_free(void); extern void lex_start(THD *thd); extern void lex_end(LEX *lex); -extern void lex_end_stage1(LEX *lex); -extern void lex_end_stage2(LEX *lex); +extern void lex_end_nops(LEX *lex); +extern void lex_unlock_plugins(LEX *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); extern int MYSQLlex(union YYSTYPE *yylval, THD *thd); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index fa335465f02..56a38757f28 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -4307,8 +4307,10 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) thd->release_transactional_locks(); } - /* Preserve CHANGE MASTER attributes */ - lex_end_stage1(lex); + /* Preserve locked plugins for SET */ + if (lex->sql_command != SQLCOM_SET_OPTION) + lex_unlock_plugins(lex); + cleanup_stmt(); thd->restore_backup_statement(this, &stmt_backup); thd->stmt_arena= old_stmt_arena; @@ -5189,7 +5191,7 @@ void Prepared_statement::deallocate_immediate() status_var_increment(thd->status_var.com_stmt_close); /* It should now be safe to reset CHANGE MASTER parameters */ - lex_end_stage2(lex); + lex_end(lex); }