Skip to content
Permalink
Browse files

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.
  • Loading branch information...
Nirbhay Choubey
Nirbhay Choubey committed Oct 11, 2015
1 parent 16c4b3c commit 978c2a37c01a3adece280d7e9d560fcd67a48cb4
Showing with 98 additions and 1 deletion.
  1. +22 −0 mysql-test/r/ps_change_master.result
  2. +45 −0 mysql-test/t/ps_change_master.test
  3. +23 −0 sql/sql_lex.cc
  4. +2 −0 sql/sql_lex.h
  5. +6 −1 sql/sql_prepare.cc
@@ -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
@@ -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
@@ -545,6 +545,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. */
{
@@ -556,6 +566,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;
@@ -2940,6 +2940,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);
@@ -3416,7 +3416,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;
@@ -3997,6 +3998,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);
}

0 comments on commit 978c2a3

Please sign in to comment.
You can’t perform that action at this time.