source include/master-slave.inc; source include/have_innodb.inc; source include/have_binlog_format_statement.inc; source include/not_gtid_enabled.inc; # UNTIL is not supported yet (TODO: support and remove the guard) -- source include/not_mts_slave_parallel_workers.inc connection slave; call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); connection master; call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); SET @@session.binlog_direct_non_transactional_updates= FALSE; disable_warnings; DROP DATABASE IF EXISTS db1; DROP DATABASE IF EXISTS db2; enable_warnings; CREATE DATABASE db1; CREATE DATABASE db2; use db1; CREATE TABLE db1.t1 (a INT) ENGINE=InnoDB; CREATE TABLE db1.t2 (s CHAR(255)) ENGINE=MyISAM; --source include/sync_slave_sql_with_master.inc source include/stop_slave.inc; connection master; echo [on master]; DELIMITER //; CREATE PROCEDURE db1.p1 () BEGIN INSERT INTO t1 VALUES (1); INSERT INTO t1 VALUES (2); INSERT INTO t1 VALUES (3); INSERT INTO t1 VALUES (4); INSERT INTO t1 VALUES (5); END// CREATE PROCEDURE db1.p2 () BEGIN INSERT INTO t1 VALUES (6); INSERT INTO t1 VALUES (7); INSERT INTO t1 VALUES (8); INSERT INTO t1 VALUES (9); INSERT INTO t1 VALUES (10); INSERT INTO t2 VALUES ('executed db1.p2()'); END// DELIMITER ;// INSERT INTO db1.t2 VALUES ('before call db1.p1()'); # Note: the master_log_pos is set to be the position of the BEGIN + 1, # so before fix of BUG#43263 if the BEGIN is ignored, then all the # INSERTS in p1 will be replicated in AUTOCOMMIT=1 mode and the slave # SQL thread will stop right before the first INSERT. After fix of # BUG#43263, BEGIN will not be ignored by the replication db rules, # and then the whole transaction will be executed before slave SQL # stop. let $master_pos= query_get_value(SHOW MASTER STATUS, Position, 1); let $master_pos= `SELECT $master_pos + 1`; use test; BEGIN; CALL db1.p1(); COMMIT; # The position where the following START SLAVE UNTIL will stop at let $master_end_trans_pos= query_get_value(SHOW MASTER STATUS, Position, 1); INSERT INTO db1.t2 VALUES ('after call db1.p1()'); SELECT * FROM db1.t1; SELECT * FROM db1.t2; connection slave; echo [on slave]; replace_result $master_pos MASTER_POS; eval start slave until master_log_file='master-bin.000001', master_log_pos=$master_pos; source include/wait_for_slave_sql_to_stop.inc; let $slave_sql_stop_pos= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1); let $result= query_get_value(SELECT $slave_sql_stop_pos - $master_end_trans_pos as result, result, 1); --echo # --echo # If we got non-zero here, then we're suffering BUG#43263 --echo # eval SELECT $result as 'Must be 0'; SELECT * from db1.t1; SELECT * from db1.t2; connection master; echo [on master]; INSERT INTO db1.t2 VALUES ('before call db1.p2()'); # See comments above. let $master_pos= query_get_value(SHOW MASTER STATUS, Position, 1); let $master_pos= `SELECT $master_pos + 1`; BEGIN; CALL db1.p2(); disable_warnings; ROLLBACK; enable_warnings; let $master_end_trans_pos= query_get_value(SHOW MASTER STATUS, Position, 1); INSERT INTO db1.t2 VALUES ('after call db1.p2()'); SELECT * FROM db1.t1; SELECT * FROM db1.t2; connection slave; echo [on slave]; replace_result $master_pos MASTER_POS; eval start slave until master_log_file='master-bin.000001', master_log_pos=$master_pos; source include/wait_for_slave_sql_to_stop.inc; let $slave_sql_stop_pos= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1); let $result= query_get_value(SELECT $slave_sql_stop_pos - $master_end_trans_pos as result, result, 1); --echo # --echo # If we got non-zero here, then we're suffering BUG#43263 --echo # eval SELECT $result as 'Must be 0'; SELECT * from db1.t1; SELECT * from db1.t2; START SLAVE; source include/wait_for_slave_sql_to_start.inc; --echo # --echo # SAVEPOINT and ROLLBACK TO have the same problem in BUG#43263 --echo # This was reported by BUG#50407 connection master; echo [on master] SET SESSION AUTOCOMMIT=0; let $binlog_start=query_get_value(SHOW MASTER STATUS, Position, 1); BEGIN; INSERT INTO db1.t1 VALUES(20); --echo # --echo # Verify whether this statement is binlogged correctly /*comment*/ SAVEPOINT has_comment; USE db1; INSERT INTO db1.t1 VALUES(30); INSERT INTO db1.t2 VALUES("in savepoint has_comment"); USE db2; SavePoint mixed_cases; USE db1; INSERT INTO db1.t2 VALUES("in savepoint mixed_cases"); INSERT INTO db1.t1 VALUES(40); USE db2; ROLLBACK TO mixed_cases; ROLLBACK TO has_comment; USE db1; INSERT INTO db1.t2 VALUES("after rollback to"); INSERT INTO db1.t1 VALUES(50); USE db2; COMMIT; source include/show_binlog_events.inc; --source include/sync_slave_sql_with_master.inc --echo [on slave] --echo # --echo # Verify INSERT statements in savepoints are executed, for MyISAM table --echo # is not effected by ROLLBACK TO SELECT * FROM db1.t2 WHERE s LIKE '% savepoint %'; --echo # --echo # Verify INSERT statements on the Innodb table are rolled back; SELECT * FROM db1.t1 WHERE a IN (30, 40); --echo --echo # BUG#55798 Slave SQL retry on transaction inserts extra data into --echo # non-transaction table --echo # ---------------------------------------------------------------- --echo # To verify that SQL thread does not retry a transaction which can --echo # not be rolled back safely, even though only a temporary error is --echo # encountered. --echo --echo # [ on master ] connection master; USE db1; DROP TABLE t1, t2; CREATE TABLE t1(c1 INT KEY, c2 CHAR(100)) ENGINE=InnoDB; CREATE TABLE t2(c1 INT) ENGINE=MyISAM; CREATE TABLE t3(c1 INT) ENGINE=InnoDB; INSERT INTO t1 VALUES(1, "master"); SET @@session.binlog_direct_non_transactional_updates= FALSE; --source include/sync_slave_sql_with_master.inc --echo # [ on slave ] USE db1; SET @timeout_old= @@GLOBAL.innodb_lock_wait_timeout; SET GLOBAL innodb_lock_wait_timeout= 1; STOP SLAVE SQL_THREAD; source include/wait_for_slave_sql_to_stop.inc; START SLAVE SQL_THREAD; source include/wait_for_slave_sql_to_start.inc; --echo # Verify the SQL thread doesn't retry the transaction when one of --echo # its statements has modified a non-transactional table. --echo # ---------------------------------------------------------------- --echo --echo # INSERT statement inserts a row to a non-transactional table. let $statement= INSERT INTO t2 VALUES(1); source extra/rpl_tests/rpl_temp_error.test; --echo --echo # INSERT ... SELECT statement inserts a row to a non-transactional table. let $statement= INSERT INTO t2 SELECT 2; source extra/rpl_tests/rpl_temp_error.test; --echo --echo # UPDATE statement updates a row to a non-transactional table. connection master; let $statement= UPDATE t2 SET c1= 3; source extra/rpl_tests/rpl_temp_error.test; --echo --echo # MULTI-UPDATE statement updates a row to a non-transactional table. connection master; let $statement= UPDATE t2, t3 SET t2.c1=4, t3.c1= 4; source extra/rpl_tests/rpl_temp_error.test; --echo --echo # DELETE statement deletes a row from a non-transactional table. connection master; let $statement= DELETE FROM t2; source extra/rpl_tests/rpl_temp_error.test; --echo --echo # CREATE TEMPORARY TABLE statement in the transaction let $statement= CREATE TEMPORARY TABLE IF NOT EXISTS temp_t(c1 INT); source extra/rpl_tests/rpl_temp_error.test; --echo --echo # DROP TEMPORARY TABLE statement in the transaction let $statement= DROP TEMPORARY TABLE IF EXISTS temp_t; source extra/rpl_tests/rpl_temp_error.test; --echo --echo # Verify that the SQL thread doesn't retry the transaction if one --echo # of the sub-statements has modified a non-transactional table. --echo # ---------------------------------------------------------------- connection master; --delimiter | CREATE FUNCTION f_insert() RETURNS INT BEGIN INSERT INTO t2 VALUES(1); RETURN 2; END| CREATE FUNCTION f_insert_select() RETURNS INT BEGIN INSERT INTO t2 SELECT 2; RETURN 2; END| CREATE FUNCTION f_update() RETURNS INT BEGIN UPDATE t2 SET c1=3; RETURN 2; END | CREATE TABLE t4 (c1 INT) | INSERT INTO t4 VAlUES(1),(2) | CREATE FUNCTION f_multi_update() RETURNS INT BEGIN UPDATE t2, t4 SET t2.c1=4, t4.c1= 4; RETURN 2; END | CREATE FUNCTION f_delete() RETURNS INT BEGIN DELETE FROM t2; RETURN 2; END | --delimiter ; --echo --echo # The INSERT statement in a function inserts a row into a --echo # non-transactional table. let $statement= INSERT INTO t3 VALUES(f_insert()); source extra/rpl_tests/rpl_temp_error.test; --echo --echo # The INSERT ... SELECT statement in a function inserts a row into a --echo # non-transactional table. let $statement= INSERT INTO t3 VALUES(f_insert()); source extra/rpl_tests/rpl_temp_error.test; --echo --echo # The UPDATE statement in a function updates a row of a --echo # non-transactional table. connection master; let $statement= INSERT INTO t3 VALUES(f_update()); source extra/rpl_tests/rpl_temp_error.test; --echo --echo # The MULTI-UPDATE statement in a function updates a row of a --echo # non-transactional table. connection master; let $statement= INSERT INTO t3 VALUES(f_multi_update()); source extra/rpl_tests/rpl_temp_error.test; --echo --echo # The DELETE statement in a function deletes a row from a --echo # non-transactional table. connection master; let $statement= INSERT INTO t3 VALUES(f_delete()); source extra/rpl_tests/rpl_temp_error.test; SET @@global.innodb_lock_wait_timeout= @timeout_old; --echo # --echo # Clean up --echo # connection master; DROP DATABASE db1; DROP DATABASE db2; --source include/rpl_end.inc