diff --git a/mysql-test/suite/rpl/r/rpl_gtid_stop_start.result b/mysql-test/suite/rpl/r/rpl_gtid_stop_start.result index 6d607ff0277..61c2fc0a0e9 100644 --- a/mysql-test/suite/rpl/r/rpl_gtid_stop_start.result +++ b/mysql-test/suite/rpl/r/rpl_gtid_stop_start.result @@ -155,5 +155,31 @@ SELECT domain_id, COUNT(*) FROM mysql.gtid_slave_pos GROUP BY domain_id; domain_id COUNT(*) 0 2 1 2 +*** MDEV-4650: show variables; ERROR 1946 (HY000): Failed to load replication slave GTID position *** +SET sql_log_bin=0; +RENAME TABLE mysql.gtid_slave_pos TO mysql.gtid_slave_pos_old; +SET sql_log_bin=1; +SHOW VARIABLES; +SHOW VARIABLES LIKE 'gtid_slave_pos'; +Variable_name Value +gtid_slave_pos +SET GLOBAL gtid_slave_pos = '0-1-2'; +Got one of the listed errors +SHOW WARNINGS; +Level Code Message +Error 1146 Table 'mysql.gtid_slave_pos' doesn't exist +Error 1946 Failed to load replication slave GTID position from table mysql.gtid_slave_pos +SET sql_log_bin=0; +RENAME TABLE mysql.gtid_slave_pos_old TO mysql.gtid_slave_pos; +CALL mtr.add_suppression("Failed to load slave replication state from table mysql.gtid_slave_pos"); +SET sql_log_bin=1; +SHOW VARIABLES LIKE 'gtid_slave_pos'; +Variable_name Value +gtid_slave_pos +SET GLOBAL gtid_slave_pos = '0-1-2'; +SHOW VARIABLES LIKE 'gtid_slave_pos'; +Variable_name Value +gtid_slave_pos 0-1-2 +include/start_slave.inc DROP TABLE t1; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_basic.test b/mysql-test/suite/rpl/t/rpl_gtid_basic.test index 17d03ddc90c..37f7886118a 100644 --- a/mysql-test/suite/rpl/t/rpl_gtid_basic.test +++ b/mysql-test/suite/rpl/t/rpl_gtid_basic.test @@ -191,11 +191,15 @@ SET GLOBAL gtid_binlog_state = @old_state; CREATE TABLE t1 (a INT PRIMARY KEY); INSERT INTO t1 VALUES (1); ---save_master_pos +--let $master_pos= `SELECT @@GLOBAL.gtid_binlog_pos` --connection server_2 --source include/start_slave.inc ---sync_with_master +# We cannot just use sync_with_master as we've done RESET MASTER, so +# slave old-style position is wrong. +# So sync on gtid position instead. +--let $wait_condition= SELECT @@GLOBAL.gtid_binlog_pos = '$master_pos' +--source include/wait_condition.inc SELECT * FROM t1; diff --git a/mysql-test/suite/rpl/t/rpl_gtid_stop_start.test b/mysql-test/suite/rpl/t/rpl_gtid_stop_start.test index fda310db0da..925095c852b 100644 --- a/mysql-test/suite/rpl/t/rpl_gtid_stop_start.test +++ b/mysql-test/suite/rpl/t/rpl_gtid_stop_start.test @@ -273,6 +273,57 @@ INSERT INTO t1 VALUES (13); SELECT domain_id, COUNT(*) FROM mysql.gtid_slave_pos GROUP BY domain_id; +--echo *** MDEV-4650: show variables; ERROR 1946 (HY000): Failed to load replication slave GTID position *** + +--connection server_2 +SET sql_log_bin=0; +--let $old_pos= `SELECT @@GLOBAL.gtid_slave_pos` +RENAME TABLE mysql.gtid_slave_pos TO mysql.gtid_slave_pos_old; +SET sql_log_bin=1; + +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF +--shutdown_server 30 +--source include/wait_until_disconnected.inc + +# Let the slave mysqld server start again. +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +restart +EOF + +--enable_reconnect +--source include/wait_until_connected_again.inc + +--disable_result_log +SHOW VARIABLES; +--enable_result_log +SHOW VARIABLES LIKE 'gtid_slave_pos'; +--error ER_CANNOT_LOAD_SLAVE_GTID_STATE,ER_NO_SUCH_TABLE +SET GLOBAL gtid_slave_pos = '0-1-2'; +SHOW WARNINGS; + +# Restore things. + +SET sql_log_bin=0; +RENAME TABLE mysql.gtid_slave_pos_old TO mysql.gtid_slave_pos; +CALL mtr.add_suppression("Failed to load slave replication state from table mysql.gtid_slave_pos"); +SET sql_log_bin=1; + +SHOW VARIABLES LIKE 'gtid_slave_pos'; +SET GLOBAL gtid_slave_pos = '0-1-2'; +SHOW VARIABLES LIKE 'gtid_slave_pos'; + +# Don't let .result file depend on old state of gtid_slave_pos +--disable_query_log +--disable_result_log +eval SET GLOBAL gtid_slave_pos = '$old_pos'; +--enable_query_log +--enable_result_log + +--source include/start_slave.inc + + --connection server_1 DROP TABLE t1; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 3827e3f4b67..3dc6ba88293 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1282,12 +1282,6 @@ Sys_var_gtid_binlog_pos::global_value_ptr(THD *thd, LEX_STRING *base) String str(buf, sizeof(buf), system_charset_info); char *p; - if (!rpl_global_gtid_slave_state.loaded) - { - my_error(ER_CANNOT_LOAD_SLAVE_GTID_STATE, MYF(0), "mysql", - rpl_gtid_slave_state_table_name.str); - return NULL; - } str.length(0); if ((opt_bin_log && mysql_bin_log.append_state_pos(&str)) || !(p= thd->strmake(str.ptr(), str.length()))) @@ -1316,7 +1310,17 @@ Sys_var_gtid_current_pos::global_value_ptr(THD *thd, LEX_STRING *base) char *p; str.length(0); - if (rpl_append_gtid_state(&str, true) || + + /* + If the mysql.rpl_slave_pos table could not be loaded, then we cannot + easily automatically try to reload it here - we may be inside a statement + that already has tables locked and so opening more tables is problematic. + + But if the table is not loaded (eg. missing mysql_upgrade_db or some such), + then the slave state must be empty anyway. + */ + if ((rpl_global_gtid_slave_state.loaded && + rpl_append_gtid_state(&str, true)) || !(p= thd->strmake(str.ptr(), str.length()))) { my_error(ER_OUT_OF_RESOURCES, MYF(0)); @@ -1335,7 +1339,7 @@ Sys_var_gtid_slave_pos::do_check(THD *thd, set_var *var) DBUG_ASSERT(var->type == OPT_GLOBAL); - if (!rpl_global_gtid_slave_state.loaded) + if (rpl_load_gtid_slave_state(thd)) { my_error(ER_CANNOT_LOAD_SLAVE_GTID_STATE, MYF(0), "mysql", rpl_gtid_slave_state_table_name.str); @@ -1400,15 +1404,17 @@ Sys_var_gtid_slave_pos::global_value_ptr(THD *thd, LEX_STRING *base) String str; char *p; - if (!rpl_global_gtid_slave_state.loaded) - { - my_error(ER_CANNOT_LOAD_SLAVE_GTID_STATE, MYF(0), "mysql", - rpl_gtid_slave_state_table_name.str); - return NULL; - } - str.length(0); - if (rpl_append_gtid_state(&str, false) || + /* + If the mysql.rpl_slave_pos table could not be loaded, then we cannot + easily automatically try to reload it here - we may be inside a statement + that already has tables locked and so opening more tables is problematic. + + But if the table is not loaded (eg. missing mysql_upgrade_db or some such), + then the slave state must be empty anyway. + */ + if ((rpl_global_gtid_slave_state.loaded && + rpl_append_gtid_state(&str, false)) || !(p= thd->strmake(str.ptr(), str.length()))) { my_error(ER_OUT_OF_RESOURCES, MYF(0));