mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
MDEV-7640: CHANGE MASTER TO doesn't work with prepared statements
When CHANGE MASTER was executed as a PS, its attributes were wrongly getting reset toward the end of PREPARE. As a result, the subsequent executions had no effect. Fixed by making sure that the CHANGE MASTER attributes are preserved during the lifetime of the PS.
This commit is contained in:
22
mysql-test/r/ps_change_master.result
Normal file
22
mysql-test/r/ps_change_master.result
Normal file
@ -0,0 +1,22 @@
|
||||
#
|
||||
# CHANGE MASTER TO doesn't work with prepared statements
|
||||
#
|
||||
CHANGE MASTER TO MASTER_HOST='host1', MASTER_USER='user1';
|
||||
# Master_Host : host1
|
||||
# Master_User : user1
|
||||
SET @s := "CHANGE MASTER TO MASTER_HOST='host2'";
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
# Master_Host : host2
|
||||
# Master_User : user1
|
||||
SET @s := "CHANGE MASTER TO MASTER_USER='user2'";
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
EXECUTE stmt;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
# Master_Host : host2
|
||||
# Master_User : user2
|
||||
CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_USER='root';
|
||||
# End of test
|
45
mysql-test/t/ps_change_master.test
Normal file
45
mysql-test/t/ps_change_master.test
Normal file
@ -0,0 +1,45 @@
|
||||
--source include/not_embedded.inc
|
||||
--source include/have_log_bin.inc
|
||||
|
||||
--echo #
|
||||
--echo # CHANGE MASTER TO doesn't work with prepared statements
|
||||
--echo #
|
||||
|
||||
CHANGE MASTER TO MASTER_HOST='host1', MASTER_USER='user1';
|
||||
|
||||
let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1);
|
||||
let $master_user= query_get_value(SHOW SLAVE STATUS, Master_User, 1);
|
||||
|
||||
--echo # Master_Host : $master_host
|
||||
--echo # Master_User : $master_user
|
||||
|
||||
SET @s := "CHANGE MASTER TO MASTER_HOST='host2'";
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1);
|
||||
let $master_user= query_get_value(SHOW SLAVE STATUS, Master_User, 1);
|
||||
|
||||
--echo # Master_Host : $master_host
|
||||
--echo # Master_User : $master_user
|
||||
|
||||
SET @s := "CHANGE MASTER TO MASTER_USER='user2'";
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
# Multiple executions should not hurt.
|
||||
EXECUTE stmt;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1);
|
||||
let $master_user= query_get_value(SHOW SLAVE STATUS, Master_User, 1);
|
||||
|
||||
--echo # Master_Host : $master_host
|
||||
--echo # Master_User : $master_user
|
||||
|
||||
|
||||
# Reset
|
||||
CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_USER='root';
|
||||
|
||||
--echo # End of test
|
@ -568,6 +568,16 @@ void lex_end(LEX *lex)
|
||||
DBUG_ENTER("lex_end");
|
||||
DBUG_PRINT("enter", ("lex: 0x%lx", (long) lex));
|
||||
|
||||
lex_end_stage1(lex);
|
||||
lex_end_stage2(lex);
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
void lex_end_stage1(LEX *lex)
|
||||
{
|
||||
DBUG_ENTER("lex_end_stage1");
|
||||
|
||||
/* release used plugins */
|
||||
if (lex->plugins.elements) /* No function call and no mutex if no plugins. */
|
||||
{
|
||||
@ -579,6 +589,19 @@ void lex_end(LEX *lex)
|
||||
delete lex->sphead;
|
||||
lex->sphead= NULL;
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
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)
|
||||
{
|
||||
DBUG_ENTER("lex_end_stage2");
|
||||
|
||||
/* Reset LEX_MASTER_INFO */
|
||||
lex->mi.reset();
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
|
@ -2947,6 +2947,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);
|
||||
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);
|
||||
|
@ -3456,7 +3456,8 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
|
||||
thd->mdl_context.release_transactional_locks();
|
||||
}
|
||||
|
||||
lex_end(lex);
|
||||
/* Preserve CHANGE MASTER attributes */
|
||||
lex_end_stage1(lex);
|
||||
cleanup_stmt();
|
||||
thd->restore_backup_statement(this, &stmt_backup);
|
||||
thd->stmt_arena= old_stmt_arena;
|
||||
@ -4056,6 +4057,10 @@ void Prepared_statement::deallocate()
|
||||
{
|
||||
/* We account deallocate in the same manner as mysqld_stmt_close */
|
||||
status_var_increment(thd->status_var.com_stmt_close);
|
||||
|
||||
/* It should now be safe to reset CHANGE MASTER parameters */
|
||||
lex_end_stage2(lex);
|
||||
|
||||
/* Statement map calls delete stmt on erase */
|
||||
thd->stmt_map.erase(this);
|
||||
}
|
||||
|
Reference in New Issue
Block a user