diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 18:00:34 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 18:00:34 +0000 |
commit | 3f619478f796eddbba6e39502fe941b285dd97b1 (patch) | |
tree | e2c7b5777f728320e5b5542b6213fd3591ba51e2 /mysql-test/suite/rpl/t | |
parent | Initial commit. (diff) | |
download | mariadb-upstream.tar.xz mariadb-upstream.zip |
Adding upstream version 1:10.11.6.upstream/1%10.11.6upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'mysql-test/suite/rpl/t')
784 files changed, 61635 insertions, 0 deletions
diff --git a/mysql-test/suite/rpl/t/circular_serverid0.cnf b/mysql-test/suite/rpl/t/circular_serverid0.cnf new file mode 100644 index 00000000..277aac28 --- /dev/null +++ b/mysql-test/suite/rpl/t/circular_serverid0.cnf @@ -0,0 +1,30 @@ +!include ../my.cnf + +[mysqld.1] +gtid-domain-id=4 +server-id=4 +# +log-slave-updates +slave-parallel-threads=0 +gtid-strict-mode=1 +gtid-ignore-duplicates=1 + +# +# Max-size row events to minimum with the idea to create +# a number of Rows_log_event per Query. +# +binlog-row-event-max-size=1024 + +[mysqld.2] +gtid-domain-id=2 +server-id=2 +# +log-slave-updates +slave-parallel-threads=0 +gtid-strict-mode=1 +gtid-ignore-duplicates=1 +binlog-row-event-max-size=1024 +# The slave will be initialized with a @@global.dbug-var value +skip-slave-start=1 + + diff --git a/mysql-test/suite/rpl/t/circular_serverid0.test b/mysql-test/suite/rpl/t/circular_serverid0.test new file mode 100644 index 00000000..64cf231c --- /dev/null +++ b/mysql-test/suite/rpl/t/circular_serverid0.test @@ -0,0 +1,103 @@ +# +# Testing chain/circular replication scenario of MDEV-9670 +# The effect of the bug was that we got a commit with a GTID with server_id +# + +--source include/have_binlog_format_row.inc +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc + +--let $rpl_topology= 1->2->1 +--source include/rpl_init.inc + +--let $rpl_connection_name= M4 +--let $rpl_server_number= 1 +--source include/rpl_connect.inc + +--let $rpl_connection_name= M2 +--let $rpl_server_number= 2 +--source include/rpl_connect.inc + +# The parameter reflects binlog-row-event-max-size @cnf. +--let $row_size=1024 + +--connection M2 +STOP SLAVE; +SET @old_debug= @@global.debug_dbug; +SET GLOBAL debug_dbug= "d,dbug.rows_events_to_delay_relay_logging"; +START SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_start.inc + +--connection M2 +# This query also creates a Gtid event group whose Gtid will remain in +# ignored status for too long causing a following group split. + +CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY, b VARCHAR(30000)) ENGINE=innodb; +--sync_slave_with_master M4 + +# This INSERT will be logged as two Write_log events which the buggy +# slave applier would split. + +--connection M4 +eval INSERT INTO `t1` VALUES (null, repeat('a', $row_size)), (null, repeat('b', $row_size)); + +# START M2 IO thread and wait for its signal to follow with the SQL +# thread start. At this moment the SQL thread shall be having 2 and +# "half" groups to execute. The "hafl" one would be committed by the +# buggy applier after which the IO is released to queue the rest of +# the 3rd group which the SQL thread commits separately to complete +# the split. + +--connection M2 + +# wait for IO signal to start the SQL thread. IO will be hanging upon that. +SET debug_sync='now WAIT_FOR start_sql_thread'; + +# Now the slave server has relay log whose last group is incomplete. +# An unfixed slave server would go to "insert" a "fake" +# Gtid_list_log_event event which actually would commit the incomplete +# group. However before to actual commit do_apply_event() hits some assert. +# In the fixed server the fake Gtid_list_log_event is *not* inserted +# in the middle of a group. +START SLAVE SQL_THREAD; + +# Sleep for a little time to give SQL thread a chance to commit while +# the IO thread is hanging (see +# DBUG_EXECUTE_IF("dbug.rows_events_to_delay_relay_logging"...) in +# queue_event). Alternatively to reproduce the case when buggy slave +# wait for the 1st group commit + +#--let $count= 1 +#--let $table= t1 +#--source include/wait_until_rows_count.inc + +--sleep 2 + +# Demonstrate either no split group in the correct slave or the 1nd +# group in the buggy one +--source include/show_binlog_events.inc + +# Release the IO thread +SET debug_sync='now SIGNAL go_on_relay_logging'; + +# Sync servers +--sync_slave_with_master M4 +--connection M4 +--sync_slave_with_master M2 +--connection M2 + +# Demonstrate replication goes correctly not to create any split, or +# the 2nd group in the buggy slave +--source include/show_binlog_events.inc + +# +# Cleanup +# +--connection M4 +drop table t1; + +--connection M2 +SET GLOBAL debug_dbug= @old_debug; +SET debug_sync='RESET'; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/create_or_replace.inc b/mysql-test/suite/rpl/t/create_or_replace.inc new file mode 100644 index 00000000..df46cc36 --- /dev/null +++ b/mysql-test/suite/rpl/t/create_or_replace.inc @@ -0,0 +1,227 @@ +# Test CREATE OR REPLACE TABLE in replication +--source include/have_innodb.inc + +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +# Create help tables +create table t2 (a int) engine=myisam; +insert into t2 values (0),(1),(2),(2); +create temporary table t3 (a_in_temporary int) engine=myisam; + +--echo # +--echo # Check how create table and create or replace table are logged +--echo # + +save_master_pos; +connection server_2; +sync_with_master; +create table t1 (to_be_deleted int); + +connection server_1; +CREATE TABLE t1 AS SELECT 1 AS f1; +CREATE OR REPLACE TABLE t1 AS SELECT 2 AS f1; +CREATE OR REPLACE table t1 like t2; +CREATE OR REPLACE table t1 like t3; +drop table t1; + +--echo binlog from server 1 +--source include/show_binlog_events.inc +save_master_pos; +connection server_2; +sync_with_master; +--echo binlog from server 2 +--source include/show_binlog_events.inc + +connection server_1; + +--echo # +--echo # Ensure that also failed create_or_replace are logged +--echo # + +--let $binlog_start=query_get_value(SHOW MASTER STATUS, Position, 1) + +create table t1 (a int); +--error ER_TABLE_MUST_HAVE_COLUMNS +create or replace table t1; +drop table if exists t1; +# The following is not logged as t1 does not exists; +--error ER_DUP_ENTRY +create or replace table t1 (a int primary key) select a from t2; + +create table t1 (a int); +# This should as a delete as we will delete t1 +--error ER_DUP_ENTRY +create or replace table t1 (a int primary key) select a from t2; + +# Same with temporary table +create temporary table t9 (a int); + +--error ER_DUP_ENTRY +create or replace temporary table t9 (a int primary key) select a from t2; + +--echo binlog from server 1 +--source include/show_binlog_events.inc +save_master_pos; +connection server_2; +sync_with_master; +show tables; +connection server_1; + +--let $binlog_start=query_get_value(SHOW MASTER STATUS, Position, 1) +create table t1 (a int); +--error ER_DUP_FIELDNAME +create or replace table t1 (a int, a int) select * from t2; +--source include/show_binlog_events.inc + +drop table if exists t1,t2; +drop temporary table if exists t9; + +--echo # +--echo # Ensure that CREATE are run as CREATE OR REPLACE on slave +--echo # + +save_master_pos; +connection server_2; +sync_with_master; +create table t1 (server_2_to_be_delete int); +connection server_1; +create table t1 (new_table int); + +save_master_pos; +connection server_2; +sync_with_master; + +show create table t1; +connection server_1; +drop table t1; + +--echo # +--echo # Check how CREATE is logged on slave in case of conflicts +--echo # + +save_master_pos; +connection server_2; +sync_with_master; +--let $binlog_start=query_get_value(SHOW MASTER STATUS, Position, 1) +create table t1 (server_2_to_be_delete int); +create table t2 (server_2_to_be_delete int); +create table t4 (server_2_to_be_delete int); +set @org_binlog_format=@@binlog_format; +set @@global.binlog_format="ROW"; +stop slave; +--source include/wait_for_slave_to_stop.inc +start slave; +--source include/wait_for_slave_to_start.inc +connection server_1; +create temporary table t9 (a int); +insert into t9 values(1); +create table t1 (new_table int); +create table t2 select * from t9; +create table t4 like t9; +create table t5 select * from t9; +save_master_pos; +connection server_2; +sync_with_master; +--echo binlog from server 2 +--source include/show_binlog_events.inc +set @@global.binlog_format=@org_binlog_format; +stop slave; +--source include/wait_for_slave_to_stop.inc +start slave; +--source include/wait_for_slave_to_start.inc +connection server_1; +drop table t1,t2,t4,t5,t9; + +--echo # +--echo # Ensure that DROP TABLE is run as DROP IF NOT EXISTS +--echo # + +create table t1 (server_1_ver_1 int); +create table t4 (server_1_ver_2 int); + +save_master_pos; +connection server_2; +sync_with_master; +--let $binlog_start=query_get_value(SHOW MASTER STATUS, Position, 1) + +# Drop the table on the slave +drop table t1; +connection server_1; +drop table t1,t4; +create table t1 (server_2_ver_2 int); +save_master_pos; +connection server_2; +sync_with_master; +show create table t1; +--echo binlog from server 2 +--source include/show_binlog_events.inc +connection server_1; +drop table t1; + +--echo # +--echo # Ensure that CREATE ... SELECT is recorded as one GTID on the slave +--echo # + +save_master_pos; +connection server_2; +sync_with_master; +--let $binlog_start=query_get_value(SHOW MASTER STATUS, Position, 1) +connection server_1; + +create table t1 (a int); +insert into t1 values (0),(1),(2); +create table t2 engine=myisam select * from t1; +create or replace table t2 engine=innodb select * from t1; +save_master_pos; +connection server_2; +sync_with_master; +--echo binlog from server 2 +--source include/show_binlog_events.inc +connection server_1; +drop table t1; + +--echo # +--echo # Check logging of drop temporary table +--echo # + +drop temporary table t3; + +--let $binlog_start=query_get_value(SHOW MASTER STATUS, Position, 1) + +set @org_binlog_format=@@binlog_format; +set binlog_format="STATEMENT"; +create temporary table t5 (a int); +drop temporary table t5; +set binlog_format="ROW"; +create temporary table t6 (a int); +drop temporary table t6; +set binlog_format="STATEMENT"; +create temporary table t7 (a int); +set binlog_format="ROW"; +drop temporary table t7; +create temporary table t8 (a int); +--error ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR +set binlog_format="STATEMENT"; +drop temporary table t8; +set @@binlog_format=@org_binlog_format; + +# MDEV-20091: +# 1. No DROP should be logged for non-existing tmp table, nor +# 2. at the connection close when its creation has not been logged. +set @@session.binlog_format=default; +drop temporary table if exists t9; + +--connect(con1,localhost,root,,) +set session binlog_format=default; +create temporary table t9 (i int); +--echo *** Must be no DROP logged for t9 when there was no CREATE, at disconnect too *** +--disconnect con1 + +--connection server_1 +--source include/show_binlog_events.inc + +# Clean up +drop table t2; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/create_or_replace2.test b/mysql-test/suite/rpl/t/create_or_replace2.test new file mode 100644 index 00000000..f0091db7 --- /dev/null +++ b/mysql-test/suite/rpl/t/create_or_replace2.test @@ -0,0 +1,42 @@ +--source include/have_innodb.inc +--source include/have_binlog_format_row_or_statement.inc +--source include/have_metadata_lock_info.inc +--source include/master-slave.inc + +--echo # +--echo # MDEV-6525 ; Problems with CREATE OR REPLACE under lock +--echo # + +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +CREATE FUNCTION f1() RETURNS INT RETURN ( SELECT MAX(a) FROM t1 ); + +--connect (con1,localhost,root,,test) + +CREATE TEMPORARY TABLE tmp (b INT) ENGINE=InnoDB; +LOCK TABLE t1 WRITE; + +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; + +CREATE OR REPLACE TABLE t1 LIKE tmp; +SHOW CREATE TABLE t1; + +--connection default +set session lock_wait_timeout=1; +--error 1205 +SELECT f1(); + +set session lock_wait_timeout=@@global.lock_wait_timeout; +--send SELECT f1() +--connection con1 +# This is here just in case, any timeout should be ok +--sleep 1 +unlock tables; +--connection default +--error 1054 +--reap +--disconnect con1 + +# Cleanup +drop function f1; +drop table t1; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/create_or_replace_mix.cnf b/mysql-test/suite/rpl/t/create_or_replace_mix.cnf new file mode 100644 index 00000000..03d69b28 --- /dev/null +++ b/mysql-test/suite/rpl/t/create_or_replace_mix.cnf @@ -0,0 +1,9 @@ +!include suite/rpl/my.cnf + +[mysqld.1] +log-slave-updates +loose-innodb + +[mysqld.2] +log-slave-updates +loose-innodb diff --git a/mysql-test/suite/rpl/t/create_or_replace_mix.test b/mysql-test/suite/rpl/t/create_or_replace_mix.test new file mode 100644 index 00000000..0cabef15 --- /dev/null +++ b/mysql-test/suite/rpl/t/create_or_replace_mix.test @@ -0,0 +1,4 @@ +# Testing create or replace table in mixed mode. + +--source include/have_binlog_format_mixed.inc +--source create_or_replace.inc diff --git a/mysql-test/suite/rpl/t/create_or_replace_row.cnf b/mysql-test/suite/rpl/t/create_or_replace_row.cnf new file mode 100644 index 00000000..03d69b28 --- /dev/null +++ b/mysql-test/suite/rpl/t/create_or_replace_row.cnf @@ -0,0 +1,9 @@ +!include suite/rpl/my.cnf + +[mysqld.1] +log-slave-updates +loose-innodb + +[mysqld.2] +log-slave-updates +loose-innodb diff --git a/mysql-test/suite/rpl/t/create_or_replace_row.test b/mysql-test/suite/rpl/t/create_or_replace_row.test new file mode 100644 index 00000000..88dd8fd2 --- /dev/null +++ b/mysql-test/suite/rpl/t/create_or_replace_row.test @@ -0,0 +1,4 @@ +# Testing create or replace table in mixed mode. + +--source include/have_binlog_format_row.inc +--source create_or_replace.inc diff --git a/mysql-test/suite/rpl/t/create_or_replace_statement.cnf b/mysql-test/suite/rpl/t/create_or_replace_statement.cnf new file mode 100644 index 00000000..03d69b28 --- /dev/null +++ b/mysql-test/suite/rpl/t/create_or_replace_statement.cnf @@ -0,0 +1,9 @@ +!include suite/rpl/my.cnf + +[mysqld.1] +log-slave-updates +loose-innodb + +[mysqld.2] +log-slave-updates +loose-innodb diff --git a/mysql-test/suite/rpl/t/create_or_replace_statement.test b/mysql-test/suite/rpl/t/create_or_replace_statement.test new file mode 100644 index 00000000..2709e414 --- /dev/null +++ b/mysql-test/suite/rpl/t/create_or_replace_statement.test @@ -0,0 +1,4 @@ +# Testing create or replace table in mixed mode. + +--source include/have_binlog_format_statement.inc +--source create_or_replace.inc diff --git a/mysql-test/suite/rpl/t/create_select.cnf b/mysql-test/suite/rpl/t/create_select.cnf new file mode 100644 index 00000000..65a4396e --- /dev/null +++ b/mysql-test/suite/rpl/t/create_select.cnf @@ -0,0 +1,16 @@ +!include suite/rpl/my.cnf + +[mysqld.1] + +[mysqld.2] +log-slave-updates +binlog-checksum=CRC32 + +[mysqld.3] +log-slave-updates +binlog-checksum=CRC32 + +[ENV] +SERVER_MYPORT_3= @mysqld.3.port +SERVER_MYSOCK_3= @mysqld.3.socket + diff --git a/mysql-test/suite/rpl/t/create_select.test b/mysql-test/suite/rpl/t/create_select.test new file mode 100644 index 00000000..c1f8fc8f --- /dev/null +++ b/mysql-test/suite/rpl/t/create_select.test @@ -0,0 +1,37 @@ +--source include/have_innodb.inc + +--let $rpl_topology=1->2->3 +--source include/rpl_init.inc + +# +# Test of MDEV-8428 Mangled DML statements on 2nd level slave when enabling +# binlog checksums +# + +connection server_1; + +CREATE DATABASE test_8428; +USE test_8428; +CREATE TABLE t1(i INT) ENGINE=INNODB; +INSERT INTO t1 VALUES(1), (2), (3), (4), (5); +CREATE TABLE t2 AS SELECT * FROM t1; +CREATE TABLE t3 ENGINE=MyISAM AS SELECT * FROM t1; + +save_master_pos; +connection server_2; +sync_with_master; + +SHOW TABLES IN test_8428; + +save_master_pos; +connection server_3; +sync_with_master; + +SHOW TABLES IN test_8428; +SELECT * from test_8428.t1; + +# Cleanup +connection server_1; +DROP DATABASE test_8428; +--source include/rpl_end.inc +--echo # End of test diff --git a/mysql-test/suite/rpl/t/failed_create_view-6409.test b/mysql-test/suite/rpl/t/failed_create_view-6409.test new file mode 100644 index 00000000..5d96e6f8 --- /dev/null +++ b/mysql-test/suite/rpl/t/failed_create_view-6409.test @@ -0,0 +1,24 @@ +# +# MDEV-6409 CREATE VIEW replication problem if error occurs in mysql_register_view +# + +# +# +# verify that failed CREATE VIEW is not replicated + +create table v1 (a int); + +source include/master-slave.inc; + +connection master; +create table t1 (a int); +--error ER_TABLE_EXISTS_ERROR +create view v1 as select * from t1; +show tables; +sync_slave_with_master; +show tables; + +connection master; +drop table if exists t1, v1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/grant_replication_slave.test b/mysql-test/suite/rpl/t/grant_replication_slave.test new file mode 100644 index 00000000..c5aca0a6 --- /dev/null +++ b/mysql-test/suite/rpl/t/grant_replication_slave.test @@ -0,0 +1,39 @@ +--echo # +--echo # MDEV-21743 Split up SUPER privilege to smaller privileges +--echo # + +# Checking that REPLICATION SLAVE is enough to start replication + +create user rpl@localhost; +grant replication slave on *.* to rpl@localhost; + +source include/master-slave.inc; +connection slave; +stop slave; +change master to master_user='rpl'; +connection master; + +create database mysqltest1; +create table mysqltest1.t1 (a int); +insert mysqltest1.t1 values (1),(2),(3); +select * from mysqltest1.t1; +flush tables; +create user foo@localhost; +grant select on *.* to foo@localhost; + +connection slave; +start slave; +connection master; +sync_slave_with_master; +select * from mysqltest1.t1; +show grants for foo@localhost; +connection master; +drop user foo@localhost; +drop database mysqltest1; +sync_slave_with_master; +stop slave; +change master to master_user='root'; +start slave; + +source include/rpl_end.inc; +drop user rpl@localhost; diff --git a/mysql-test/suite/rpl/t/ignore_table_autoinc-9737.test b/mysql-test/suite/rpl/t/ignore_table_autoinc-9737.test new file mode 100644 index 00000000..405d1a92 --- /dev/null +++ b/mysql-test/suite/rpl/t/ignore_table_autoinc-9737.test @@ -0,0 +1,35 @@ +# +# MDEV-9737 Duplicate error in replication with slave triggers and auto increment +# +source include/master-slave.inc; +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); + + +create table t1(id int auto_increment primary key); +create table t2(id int auto_increment primary key); + +sync_slave_with_master; +create table slave_only(id int auto_increment primary key); +insert into slave_only values(NULL); +create trigger t1i after insert on t1 for each row insert into slave_only values(NULL); + +stop slave; +set global replicate_ignore_table="test.t2"; +start slave; + +connection master; +insert into t2 values(NULL); +insert into t1 values(NULL); + +sync_slave_with_master; + +drop table t1, t2, slave_only; +stop slave; +set global replicate_ignore_table=""; +start slave; + +connection master; +drop table t1, t2; + +source include/rpl_end.inc; + diff --git a/mysql-test/suite/rpl/t/kill_hard-6290.test b/mysql-test/suite/rpl/t/kill_hard-6290.test new file mode 100644 index 00000000..76242356 --- /dev/null +++ b/mysql-test/suite/rpl/t/kill_hard-6290.test @@ -0,0 +1,11 @@ +# +# MDEV-6290 Crash in KILL HARD QUERY USER x@y when slave threads are running +# + +# this test doesn't depend on the binlog format, no need to run it three times +--source include/have_binlog_format_mixed.inc + +--source include/master-slave.inc +--connection server_2 +kill user test2@nohost; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/kill_race_condition.test b/mysql-test/suite/rpl/t/kill_race_condition.test new file mode 100644 index 00000000..25a7b18b --- /dev/null +++ b/mysql-test/suite/rpl/t/kill_race_condition.test @@ -0,0 +1,36 @@ +source include/have_debug_sync.inc; +source include/have_binlog_format_row.inc; +source include/master-slave.inc; + +connection master; +create table t1 (a int); +--sync_slave_with_master + +connection slave; +SET @saved_dbug = @@GLOBAL.debug_dbug; +set global debug_dbug='d,rows_log_event_before_open_table'; + +connection master; +insert t1 values (1),(2),(3); + +connection slave; +set debug_sync='now WAIT_FOR before_open_table'; +let $a=`select id from information_schema.processlist where state='debug sync point: now'`; +replace_result $a slave_sql_thread; +eval kill $a; +set debug_sync='now SIGNAL go_ahead_sql'; +--let $slave_sql_errno= 1927 +--source include/wait_for_slave_sql_error.inc +let $error= query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1); +--echo Last_SQL_Error = $error +SET @@GLOBAL.debug_dbug = @saved_dbug; +set debug_sync='RESET'; +connection master; +drop table t1; + +connection slave; +--source include/start_slave.inc +let $error= query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1); +--echo Last_SQL_Error = $error + +source include/rpl_end.inc; diff --git a/mysql-test/suite/rpl/t/last_insert_id.cnf b/mysql-test/suite/rpl/t/last_insert_id.cnf new file mode 100644 index 00000000..1c229e4a --- /dev/null +++ b/mysql-test/suite/rpl/t/last_insert_id.cnf @@ -0,0 +1,20 @@ +!include suite/rpl/my.cnf + +[mysqld.1] +log-slave-updates +loose-innodb + +[mysqld.2] +log-slave-updates +loose-innodb +replicate-ignore-table=db.t2 + +[mysqld.3] +log-slave-updates +loose-innodb + +[ENV] +SERVER_MYPORT_3= @mysqld.3.port +SERVER_MYSOCK_3= @mysqld.3.socket + + diff --git a/mysql-test/suite/rpl/t/last_insert_id.test b/mysql-test/suite/rpl/t/last_insert_id.test new file mode 100644 index 00000000..f23cca40 --- /dev/null +++ b/mysql-test/suite/rpl/t/last_insert_id.test @@ -0,0 +1,30 @@ +--source include/have_innodb.inc +--source include/have_binlog_format_mixed_or_statement.inc +--let $rpl_topology=1->2->3 +--source include/rpl_init.inc + +connection server_1; + +create table t1 (id int not null auto_increment primary key, i int) engine=InnoDB; +insert into t1 (i) values (-1); +insert into t1 (i) values (LAST_INSERT_ID()); +select * from t1; + +save_master_pos; + +connection server_2; + +sync_with_master; +select * from t1; +save_master_pos; + +connection server_3; + +sync_with_master; +select * from t1; + +connection server_1; +drop table t1; + +--source include/rpl_end.inc + diff --git a/mysql-test/suite/rpl/t/mdev-31448_kill_ooo_finish_optimistic.test b/mysql-test/suite/rpl/t/mdev-31448_kill_ooo_finish_optimistic.test new file mode 100644 index 00000000..1297fcda --- /dev/null +++ b/mysql-test/suite/rpl/t/mdev-31448_kill_ooo_finish_optimistic.test @@ -0,0 +1,93 @@ +--source include/master-slave.inc +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_binlog_format_row.inc + +--echo # MDEV-31448 OOO finish event group by killed worker +# The test demonstrates how a killed worker access gco lists +# in finish_event_group() out-of-order to fire +# DBUG_ASSERT(!tmp_gco->next_gco || tmp_gco->last_sub_id > sub_id); +# in the buggy version. + +--echo # Initialize test data +--connection master +call mtr.add_suppression("Slave: Connection was killed"); +call mtr.add_suppression("Slave: Commit failed due to failure of an earlier commit on which this one depends"); +create table t1 (a int) engine=innodb; +create table t2 (a int) engine=innodb; + +insert into t1 values (1); +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc +--let $save_slave_parallel_threads= `SELECT @@global.slave_parallel_threads` +--let $save_slave_parallel_mode= `SELECT @@global.slave_parallel_mode` +--let $save_innodb_lock_wait_timeout= `SELECT @@global.innodb_lock_wait_timeout` +--let $save_transaction_retries= `SELECT @@global.slave_transaction_retries` +set @@global.slave_parallel_threads= 4; +set @@global.slave_parallel_mode= OPTIMISTIC; +set @@global.innodb_lock_wait_timeout= 30; +set @@global.slave_transaction_retries= 0; + +--connection slave1 +BEGIN; +SELECT * FROM t1 WHERE a=1 FOR UPDATE; + +--connection master +SET @old_dbug= @@SESSION.debug_dbug; +SET @@SESSION.debug_dbug="+d,binlog_force_commit_id"; + +# GCO 1 +SET @commit_id= 10000; +# T1 +update t1 set a=2 where a=1; +# T2 +set statement skip_parallel_replication=1 for insert into t2 values (1); + +# GCO 2 +# T3 +drop table t2; + +--connection slave +--source include/start_slave.inc + +--echo # wait for T1 +--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Update_rows_log_event::find_row(-1)%' and command LIKE 'Slave_worker'; +--source include/wait_condition.inc + +--echo # wait for T2 +--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Waiting for prior transaction to commit%' and command LIKE 'Slave_worker'; +--source include/wait_condition.inc +--let $t2_tid= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE 'Waiting for prior transaction to commit%' and command LIKE 'Slave_worker'` +--echo # wait for T3 +--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE 'Waiting for prior transaction to start commit%' and command LIKE 'Slave_worker'; +--source include/wait_condition.inc + +--replace_result $t2_tid T2_TID +--eval kill $t2_tid + +--sleep 1 + +--connection slave1 +# Release the blocked T1 +ROLLBACK; + +--connection master +DROP TABLE t1; +--source include/save_master_gtid.inc + +--connection slave +--echo # +--echo # Cleanup +--source include/stop_slave.inc +eval set @@global.slave_parallel_threads= $save_slave_parallel_threads; +eval set @@global.slave_parallel_mode= $save_slave_parallel_mode; +eval set @@global.innodb_lock_wait_timeout= $save_innodb_lock_wait_timeout; +eval set @@global.slave_transaction_retries= $save_transaction_retries; +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + +--source include/rpl_end.inc + diff --git a/mysql-test/suite/rpl/t/mdev_17588-slave.opt b/mysql-test/suite/rpl/t/mdev_17588-slave.opt new file mode 100644 index 00000000..d73dbeca --- /dev/null +++ b/mysql-test/suite/rpl/t/mdev_17588-slave.opt @@ -0,0 +1 @@ +--loose-disable-innodb --replicate-ignore-table=test.t3 diff --git a/mysql-test/suite/rpl/t/mdev_17588.test b/mysql-test/suite/rpl/t/mdev_17588.test new file mode 100644 index 00000000..44644158 --- /dev/null +++ b/mysql-test/suite/rpl/t/mdev_17588.test @@ -0,0 +1,44 @@ +--source include/master-slave.inc +--source include/have_innodb.inc + +--connection slave +--source include/stop_slave.inc +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection master +create table t1 (a int) engine=innodb; +create table t2 (a int); +create table t3 (a int) engine=innodb; +--save_master_pos + +--connection slave +# Using ER_UNKNOWN_STORAGE_ENGINE wont work +let $slave_sql_errno= 1286; +--source include/wait_for_slave_sql_error_and_skip.inc +--sync_with_master + +--let $assert_text= Status should be 'Slave has read all relay log...' +--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" +#Like "Slave has read all relay log%" +--source include/rpl_assert.inc + +show tables; +show create table t2; +--error ER_NO_SUCH_TABLE +show create table t1; +--error ER_NO_SUCH_TABLE +show create table t3; + +--connection master +drop table if exists t1; +drop table if exists t2; +drop table if exists t3; +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc + + +CALL mtr.add_suppression('Slave: Unknown storage engine .* Error_code: 1286'); +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/mdev_24667.cnf b/mysql-test/suite/rpl/t/mdev_24667.cnf new file mode 100644 index 00000000..58b605ad --- /dev/null +++ b/mysql-test/suite/rpl/t/mdev_24667.cnf @@ -0,0 +1,8 @@ +!include ../my.cnf + +[mysqld.3] +log-slave-updates + +[ENV] +SERVER_MYPORT_3= @mysqld.3.port +SERVER_MYSOCK_3= @mysqld.3.socket diff --git a/mysql-test/suite/rpl/t/mdev_24667.test b/mysql-test/suite/rpl/t/mdev_24667.test new file mode 100644 index 00000000..d8490b33 --- /dev/null +++ b/mysql-test/suite/rpl/t/mdev_24667.test @@ -0,0 +1,56 @@ +# +# MDEV-24667 LOAD DATA INFILE/inserted rows not written to binlog +# +# In this test we will have a replication configuration like 1->2->3 +# 1 will have statement format +# 2 and 3 will have mixed format +# We will make some updates on temporary table which are unsafe , So 2 must +# Log these queries in row format, Since it is on tmp table , It wont be logged +# So the next query which copies the data from tmp table to normal must be logged +# into the row format. Instead of checking for the binlog We will compare the +# results on the 3, If no binlog is lost(ie it is logged into row format), There +# should not be any data loss. +--let $rpl_topology=1->2->3 +--source include/rpl_init.inc +--source include/have_binlog_format_mixed.inc +call mtr.add_suppression('Unsafe statement written to the binary log using '); +--connection server_1 + +set binlog_format=statement; +--echo #first bug +create table t1 (a int); +create temporary table tmp like t1; +--write_file $MYSQLTEST_VARDIR/load_data +1 +2 +EOF +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +eval load data local infile '$MYSQLTEST_VARDIR/load_data' INTO TABLE tmp; +insert into t1 select * from tmp; + +--echo #second bug +create table t2 (a int); +#insert into t2 values(10); +create temporary table tmp2 like t2; +insert into tmp2 values(10); +update tmp2 set a = 20 limit 1; +insert into t2 select * from tmp2; +--save_master_pos + +--connection server_2 +--sync_with_master +--save_master_pos + +--connection server_3 +--sync_with_master +--echo #t1 should have 2 rows +select count(*) = 2 from t1; +--echo #t2 should have 1 rows with a = 20 +select * from t2; + + +# cleanup +--connection server_1 +drop table t1, t2, tmp, tmp2; +--remove_file $MYSQLTEST_VARDIR/load_data +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/myisam_external_lock-slave.opt b/mysql-test/suite/rpl/t/myisam_external_lock-slave.opt new file mode 100644 index 00000000..db53e17d --- /dev/null +++ b/mysql-test/suite/rpl/t/myisam_external_lock-slave.opt @@ -0,0 +1,2 @@ +--log-slave-updates=0 +--skip_external_locking=0 diff --git a/mysql-test/suite/rpl/t/myisam_external_lock.test b/mysql-test/suite/rpl/t/myisam_external_lock.test new file mode 100644 index 00000000..14824fd8 --- /dev/null +++ b/mysql-test/suite/rpl/t/myisam_external_lock.test @@ -0,0 +1,24 @@ +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +# +# MDEV-6871 Multi-value insert on MyISAM table that makes slaves crash +# This only happens if external_lock is enabled +# + +drop table if exists t1; +CREATE TABLE `t1` (`col1` int(11) NOT NULL,`col2` int(11) NOT NULL, + PRIMARY KEY (`col1`,`col2`), + KEY `col2` (`col2`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +INSERT INTO `t1` VALUES (2775,974),(2775,975),(2775,976),(2778,977),(2778,978),(2782,979),(2790,986),(2790,1139),(2792,840),(2792,984),(2792,989),(2793,982),(2793,992),(2793,993),(2793,994),(2795,323),(2795,332),(2797,980),(2797,997),(2797,998),(2798,1103),(2798,1104),(2799,841),(2799,985),(2799,988),(2833,983),(2833,990),(2833,991),(2834,981),(2834,995),(2834,996),(2835,316),(2835,317),(3007,854),(3007,856),(3008,855),(3008,857),(3009,823),(3009,824),(3014,1),(3015,1),(3016,2),(3017,2),(3018,3),(3019,3),(3024,842),(3024,843),(3024,844),(3025,845),(3025,846),(3025,847),(3040,31),(3041,32),(3042,52),(3042,55),(3043,53),(3043,54),(3044,278),(3044,279),(3044,280),(3044,281),(3044,282),(3044,283),(3044,284),(3044,285),(3045,1),(3046,1),(3049,220),(3050,221),(3050,222),(3051,2),(3052,2),(3053,223),(3054,224),(3055,225),(3056,226),(3057,227),(3058,228),(3059,229),(3060,327),(3066,236),(3067,237),(3068,238),(3069,239),(3070,240),(3080,241),(3081,242),(3082,247),(3083,248),(3084,249),(3085,250),(3086,251),(3087,252),(3088,253),(3089,254),(3090,255),(3091,256),(3092,257),(3093,258),(3094,259),(3096,263),(3097,264),(3100,273),(3100,302),(3101,266),(3102,267),(3103,268),(3104,269),(3105,270),(3111,275),(3112,238),(3113,272),(3115,286),(3116,318),(3116,319),(3117,290),(3117,292),(3118,238),(3119,291),(3119,293),(3120,304),(3121,305),(3122,306),(3123,307),(3124,308),(3125,309),(3126,310),(3127,311),(3128,312),(3128,336),(3129,313),(3129,350),(3130,314),(3131,315),(3131,351),(3132,325),(3132,328),(3134,502),(3138,334),(3139,338),(3139,339),(3140,340),(3140,341),(3141,344),(3141,345),(3142,346),(3142,347),(3149,351),(3149,354),(3150,351),(3150,356),(3152,358),(3152,359),(3153,361),(3153,370),(3154,363),(3154,369),(3156,350),(3156,371),(3159,376),(3160,377),(3160,379),(3160,384),(3161,378),(3161,380),(3161,383),(3162,388),(3162,389),(3162,390),(3169,392),(3169,393),(3169,394),(3170,395),(3170,396),(3170,397),(3171,398),(3171,399),(3171,400),(3172,401),(3172,402),(3172,403),(3173,404),(3173,405),(3173,406),(3178,351),(3178,421),(3190,411),(3190,412),(3191,413),(3191,414),(3192,415),(3192,416),(3193,417),(3193,418),(3194,419),(3194,420),(3195,353),(3195,424),(3196,425),(3196,426),(3197,427),(3197,428),(3198,429),(3198,430),(3199,431),(3199,432),(3200,433),(3200,434),(3201,435),(3201,436),(3202,437),(3202,438),(3203,439),(3203,440),(3204,441),(3204,442),(3205,443),(3205,444),(3206,445),(3206,446),(3207,447),(3207,448),(3208,449),(3208,450),(3209,451),(3209,452),(3210,453),(3210,454),(3211,455),(3211,456),(3212,457),(3212,458),(3213,459),(3213,460),(3214,461),(3214,462),(3215,463),(3215,464),(3218,466),(3218,467),(3218,468),(3219,469),(3219,470),(3219,471),(3220,474),(3220,475),(3220,476),(3221,477),(3221,478),(3221,479),(3222,480),(3222,481),(3223,482),(3223,483),(3224,484),(3224,485),(3225,486),(3225,487),(3227,503),(3227,505),(3228,506),(3228,507),(3230,508),(3230,509),(3231,510),(3231,511),(3232,512),(3232,513),(3233,514),(3233,515),(3234,516),(3234,517),(3235,518),(3235,519),(3237,521),(3237,522),(3239,524),(3239,525),(3240,526),(3240,527),(3241,528),(3241,529),(3242,530),(3242,531),(3243,532),(3243,533),(3244,534),(3244,535),(3245,536),(3245,537),(3246,538),(3246,539),(3252,540),(3252,541),(3254,543),(3254,544),(3254,545),(3255,547),(3255,548),(3255,571),(3256,550),(3256,551),(3256,572),(3257,553),(3257,554),(3257,573),(3258,556),(3258,557),(3258,574),(3259,559),(3259,560),(3259,575),(3260,561),(3260,562),(3260,563),(3261,565),(3261,576),(3262,566),(3262,567),(3263,568),(3263,569),(3263,570),(3264,577),(3264,578),(3265,579),(3265,580),(3266,581),(3266,582),(3266,591),(3267,583),(3267,584),(3267,592),(3268,585),(3268,586),(3268,593),(3269,587),(3269,588),(3269,594),(3270,589),(3270,590),(3271,595),(3271,596),(3271,597),(3272,598),(3272,599),(3273,600),(3273,601),(3273,602),(3274,603),(3274,604),(3274,605),(3275,606),(3275,607),(3275,608),(3276,609),(3276,610),(3276,611),(3277,612),(3277,613),(3277,614),(3278,615),(3278,616),(3279,617),(3279,618),(3279,619),(3279,628),(3279,629),(3280,620),(3280,621),(3280,622),(3281,623),(3281,624),(3281,625),(3282,626),(3282,825),(3283,630),(3283,631),(3284,632),(3284,633),(3284,634),(3285,635),(3285,940),(3286,638),(3286,639),(3286,640),(3287,641),(3287,642),(3287,643),(3288,644),(3288,645),(3288,646),(3289,647),(3289,648),(3289,649),(3290,650),(3290,651),(3290,652),(3291,653),(3291,654),(3291,655),(3292,656),(3292,657),(3292,658),(3293,659),(3293,660),(3293,661),(3294,662),(3294,663),(3294,664),(3295,665),(3295,666),(3295,667),(3296,668),(3296,669),(3296,670),(3297,671),(3297,672),(3297,673),(3298,674),(3298,675),(3298,676),(3299,677),(3299,678),(3299,679),(3300,680),(3300,681),(3300,682),(3301,683),(3301,684),(3301,685),(3302,686),(3302,687),(3302,688),(3303,689),(3303,690),(3303,691),(3304,692),(3304,693),(3304,694),(3305,695),(3305,696),(3305,697),(3306,698),(3306,699),(3306,700),(3307,701),(3307,702),(3307,703),(3308,704),(3308,705),(3308,706),(3309,707),(3309,708),(3310,709),(3310,710),(3311,711),(3311,712),(3311,713),(3312,714),(3312,715),(3312,716),(3313,717),(3313,1167),(3314,720),(3314,721),(3314,722),(3315,723),(3315,724),(3315,725),(3316,726),(3316,727),(3316,728),(3317,729),(3317,730),(3317,731),(3318,732),(3318,733),(3318,734),(3319,735),(3319,736),(3319,737),(3320,738),(3320,739),(3320,740),(3321,741),(3321,742),(3322,743),(3322,744),(3323,745),(3323,746),(3323,747),(3324,748),(3324,749),(3324,750),(3325,751),(3325,752),(3325,753),(3326,754),(3326,755),(3327,756),(3327,757),(3328,758),(3328,789),(3329,761),(3329,790),(3330,762),(3330,763),(3331,768),(3331,785),(3331,786),(3332,769),(3332,783),(3332,784),(3335,766),(3336,767),(3343,770),(3343,771),(3344,772),(3344,773),(3345,774),(3345,775),(3347,776),(3347,777),(3347,987),(3348,778),(3348,779),(3349,780),(3372,781),(3372,782),(3373,787),(3373,788),(3376,791),(3376,792),(3377,793),(3377,794),(3378,799),(3378,800),(3379,801),(3379,802),(3380,795),(3380,796),(3381,797),(3381,798),(3383,805),(3384,806),(3384,807),(3385,808),(3385,809),(3386,810),(3386,811),(3387,812),(3387,814),(3388,815),(3388,816),(3391,817),(3391,818),(3391,819),(3392,820),(3392,821),(3392,822),(3393,826),(3393,827),(3394,828),(3394,829),(3395,830),(3395,831),(3396,834),(3396,835),(3397,832),(3397,833),(3398,836),(3398,837),(3399,838),(3399,839),(3410,850),(3410,851),(3411,852),(3411,853),(3412,848),(3412,849),(3419,860),(3419,951),(3420,859),(3420,861),(3422,862),(3422,863),(3423,864),(3423,865),(3424,866),(3424,867),(3424,872),(3424,873),(3425,868),(3425,869),(3425,874),(3425,875),(3426,878),(3426,879),(3427,876),(3427,877),(3428,880),(3432,884),(3432,885),(3432,886),(3434,887),(3434,888),(3434,889),(3441,894),(3441,895),(3442,896),(3442,897),(3444,904),(3445,905),(3449,906),(3449,907),(3450,908),(3450,909),(3453,910),(3458,915),(3458,916),(3459,917),(3459,918),(3463,919),(3463,920),(3485,929),(3486,930),(3487,931),(3488,932),(3489,933),(3493,2),(3494,2),(3501,934),(3502,936),(3503,938),(3504,939),(3505,941),(3506,942),(3507,943),(3508,944),(3509,945),(3510,946),(3511,947),(3512,948),(3514,949),(3514,950),(3515,953),(3516,954),(3517,955),(3518,956),(3519,957),(3520,958),(3521,959),(3527,960),(3527,965),(3528,961),(3528,962),(3529,963),(3529,964),(3530,966),(3530,967),(3531,968),(3531,969),(3535,970),(3535,971),(3536,972),(3536,973),(3540,999),(3540,1000),(3541,1001),(8888,9999); + +drop table t1; + +save_master_pos; +connection slave; +sync_with_master; + +connection master; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/mysql-wsrep#110-2.test b/mysql-test/suite/rpl/t/mysql-wsrep#110-2.test new file mode 100644 index 00000000..2b6d0791 --- /dev/null +++ b/mysql-test/suite/rpl/t/mysql-wsrep#110-2.test @@ -0,0 +1,44 @@ +# +# codership/mysql-wsrep/110 - Assertion `table_found' failed in unpack_row() with SAVEPOINT, trigger, error handler +# + +--source include/have_innodb.inc +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY); +CREATE TABLE t2 (f1 INTEGER PRIMARY KEY); +CREATE TABLE t3 (f1 INTEGER PRIMARY KEY); + +CREATE TRIGGER tr1 AFTER INSERT ON t1 FOR EACH ROW CALL p1(NEW.f1); + +DELIMITER |; + +CREATE PROCEDURE p1 (IN x INT) +BEGIN + DECLARE EXIT HANDLER FOR SQLEXCEPTION + BEGIN + ROLLBACK TO event_logging; + INSERT t3 VALUES (x); + END; + SAVEPOINT event_logging; + + INSERT INTO t2 VALUES (x); + + RELEASE SAVEPOINT event_logging; +END| +DELIMITER ;| + +INSERT INTO t2 VALUES (1); +INSERT INTO t1 VALUES (1); + + +DROP TABLE t3; +DROP TABLE t2; +DROP TABLE t1; + +DROP PROCEDURE p1; + +sync_slave_with_master; +--source include/rpl_end.inc + diff --git a/mysql-test/suite/rpl/t/parallel_backup.test b/mysql-test/suite/rpl/t/parallel_backup.test new file mode 100644 index 00000000..4f5ffa9f --- /dev/null +++ b/mysql-test/suite/rpl/t/parallel_backup.test @@ -0,0 +1,107 @@ +--source include/have_innodb.inc +# The test is not format specific, MIXED is required to optimize testing time +--source include/have_binlog_format_mixed.inc +--source include/master-slave.inc + +--echo # +--echo # MDEV-21953: deadlock between BACKUP STAGE BLOCK_COMMIT and parallel +--echo # replication +--echo # + +--connection master +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE = innodb; +# MDEV-515 takes X-lock on the table for the first insert. +# So concurrent insert won't happen on the table +INSERT INTO t1 VALUES(100); + +--sync_slave_with_master +call mtr.add_suppression("Deadlock found when trying to get lock"); +call mtr.add_suppression("Commit failed due to failure of an earlier commit"); + +--source include/stop_slave.inc +SET @old_parallel_threads= @@GLOBAL.slave_parallel_threads; +SET @old_parallel_mode = @@GLOBAL.slave_parallel_mode; +SET @@global.slave_parallel_threads= 2; +SET @@global.slave_parallel_mode = 'optimistic'; + +--connection master +INSERT INTO t1 VALUES (1); +INSERT INTO t1 VALUES (2); +--save_master_pos + +# The plot: +# Block the 1st of two workers and, at waiting-for-prior-commit by the 2nd, +# issue BACKUP commands. +# BLOCK_COMMIT may hang so it is --send. +# Release the 1st worker to observe a deadlock unless its fixed. + +--connect (aux_slave,127.0.0.1,root,,test,$SLAVE_MYPORT,) +BEGIN; +# block the 1st worker and wait for the 2nd ready to commit +INSERT INTO t1 VALUES (1); + +--connection slave +--source include/start_slave.inc + +--connection aux_slave +--let $wait_condition= SELECT COUNT(*) > 0 FROM information_schema.processlist WHERE state = "Waiting for prior transaction to commit" +--source include/wait_condition.inc + +# While the 1st worker is locked out run backup +--connect (backup_slave,127.0.0.1,root,,test,$SLAVE_MYPORT,) +BACKUP STAGE START; +--send BACKUP STAGE BLOCK_COMMIT + +# release the 1st work +--connection aux_slave +--sleep 1 +ROLLBACK; + +--connection backup_slave +--reap +BACKUP STAGE END; + +--connection slave +--sync_with_master + +--let $diff_tables= master:t1,slave:t1 +--source include/diff_tables.inc + +# +--echo # MDEV-30423: dealock XA COMMIT vs BACKUP +# Prove XA "COMPLETE" 'xid' does not dealock similary to the normal trx case. +# The slave binlog group commit leader is blocked by a local trx like in +# the above normal trx case. +# [Notice a reuse of t1,aux_conn from above.] +# +--let $complete = COMMIT +--source parallel_backup_xa.inc +--let $complete = ROLLBACK +--source parallel_backup_xa.inc + +--let $slave_ooo_error = 1 +--let $complete = COMMIT +--source parallel_backup_xa.inc +--connection slave +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + +--let $slave_ooo_error = 1 +--let $complete = ROLLBACK +--source parallel_backup_xa.inc +--connection slave +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + + +# Clean up. +--connection slave +--source include/stop_slave.inc +SET @@global.slave_parallel_threads= @old_parallel_threads; +SET @@global.slave_parallel_mode = @old_parallel_mode; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/parallel_backup_lsu_off-slave.opt b/mysql-test/suite/rpl/t/parallel_backup_lsu_off-slave.opt new file mode 100644 index 00000000..2f2a9c43 --- /dev/null +++ b/mysql-test/suite/rpl/t/parallel_backup_lsu_off-slave.opt @@ -0,0 +1,2 @@ +--log-slave-updates=0 + diff --git a/mysql-test/suite/rpl/t/parallel_backup_lsu_off.test b/mysql-test/suite/rpl/t/parallel_backup_lsu_off.test new file mode 100644 index 00000000..8e266307 --- /dev/null +++ b/mysql-test/suite/rpl/t/parallel_backup_lsu_off.test @@ -0,0 +1,7 @@ +# +--echo # Specialized --log-slave-updates = 0 version of parallel_backup test. +# +--echo # MDEV-21953: deadlock between BACKUP STAGE BLOCK_COMMIT and parallel +--echo # MDEV-30423: dealock XA COMMIT vs BACKUP +--let $rpl_skip_reset_master_and_slave = 1 +--source parallel_backup.test diff --git a/mysql-test/suite/rpl/t/parallel_backup_slave_binlog_off-slave.opt b/mysql-test/suite/rpl/t/parallel_backup_slave_binlog_off-slave.opt new file mode 100644 index 00000000..a02b6d05 --- /dev/null +++ b/mysql-test/suite/rpl/t/parallel_backup_slave_binlog_off-slave.opt @@ -0,0 +1 @@ +--skip-log-bin
\ No newline at end of file diff --git a/mysql-test/suite/rpl/t/parallel_backup_slave_binlog_off.test b/mysql-test/suite/rpl/t/parallel_backup_slave_binlog_off.test new file mode 100644 index 00000000..7cefbdb3 --- /dev/null +++ b/mysql-test/suite/rpl/t/parallel_backup_slave_binlog_off.test @@ -0,0 +1,7 @@ +# +--echo # Specialized --skip-log-bin slave version of parallel_backup test. +# +--echo # MDEV-21953: deadlock between BACKUP STAGE BLOCK_COMMIT and parallel +--echo # MDEV-30423: dealock XA COMMIT vs BACKUP +--let $rpl_server_skip_log_bin= 1 +--source parallel_backup.test diff --git a/mysql-test/suite/rpl/t/parallel_backup_xa.inc b/mysql-test/suite/rpl/t/parallel_backup_xa.inc new file mode 100644 index 00000000..2d831199 --- /dev/null +++ b/mysql-test/suite/rpl/t/parallel_backup_xa.inc @@ -0,0 +1,79 @@ +# Invoked from parallel_backup.test +# Parameters: +# $complete = COMMIT or ROLLBACK +# $slave_ooo_error = 1 means slave group commit did not succeed +# +--let $kind = Normal +if ($slave_ooo_error) +{ + --let $kind = Errored out +} +--echo # +--echo # $kind XA $complete + +--connection slave +--source include/stop_slave.inc + +--connection master +# val_0 is the first value to insert on master in prepared xa +# val_1 is the next one to insert which is the value to block on slave +--let $val_0 = `SELECT max(a)+1 FROM t1` +--let $val_1 = $val_0 +--inc $val_1 + +--connection aux_slave +BEGIN; +--eval INSERT INTO t1 VALUES ($val_1) + +--connection master +XA START '1'; +--eval INSERT INTO t1 VALUES ($val_0) +XA END '1'; +XA PREPARE '1'; +--connection master1 +--eval INSERT INTO t1 VALUES ($val_1) +--connection master +--eval XA $complete '1' +--source include/save_master_gtid.inc + +--connection slave +if ($slave_ooo_error) +{ + SET @sav_innodb_lock_wait_timeout = @@global.innodb_lock_wait_timeout; + SET @sav_slave_transaction_retries = @@global.slave_transaction_retries; + SET @@global.innodb_lock_wait_timeout =1; + SET @@global.slave_transaction_retries=0; +} +--source include/start_slave.inc +--connection aux_slave +--let $wait_condition= SELECT COUNT(*) = 1 FROM information_schema.processlist WHERE state = "Waiting for prior transaction to commit" +--source include/wait_condition.inc +--echo # Xid '1' must be in the output: +XA RECOVER; +--connection backup_slave + BACKUP STAGE START; +--send BACKUP STAGE BLOCK_COMMIT +--connection aux_slave + --sleep 1 + if ($slave_ooo_error) + { + --let $wait_condition= SELECT COUNT(*) = 0 FROM information_schema.processlist WHERE state = "Waiting for prior transaction to commit" + --source include/wait_condition.inc + } + ROLLBACK; +--let $wait_condition= SELECT COUNT(*) = 1 FROM information_schema.processlist WHERE state = "Waiting for backup lock" +--source include/wait_condition.inc +--connection backup_slave + --reap + BACKUP STAGE END; +--connection slave +if (!$slave_ooo_error) +{ + --source include/sync_with_master_gtid.inc +} +--source include/stop_slave.inc +if ($slave_ooo_error) +{ + SET @@global.innodb_lock_wait_timeout = @sav_innodb_lock_wait_timeout; + SET @@global.slave_transaction_retries= @sav_slave_transaction_retries; +} diff --git a/mysql-test/suite/rpl/t/password_expiration.test b/mysql-test/suite/rpl/t/password_expiration.test new file mode 100644 index 00000000..6934500c --- /dev/null +++ b/mysql-test/suite/rpl/t/password_expiration.test @@ -0,0 +1,53 @@ +# +# Test a slave connection is properly handled when the replication +# user has an expired password +# + +--source include/not_embedded.inc +--source include/have_binlog_format_mixed.inc +--source include/master-slave.inc + +--connection slave +--source include/stop_slave.inc + +--connection master +create user 'repl_user' password expire; +grant replication slave on *.* to repl_user; +flush privileges; +set global disconnect_on_expired_password=ON; + +--connection slave +--let $master_user= query_get_value(SHOW SLAVE STATUS, Master_User, 1) +CHANGE MASTER TO MASTER_USER= 'repl_user'; + +START SLAVE; +# ER_MUST_CHANGE_PASSWORD_LOGIN +--let $slave_io_errno= 1862 +--source include/wait_for_slave_io_error.inc + +# restart slave +--source include/stop_slave_sql.inc +RESET SLAVE; + +--connection master +# force sandbox mode for repl_user +set global disconnect_on_expired_password=OFF; + +--connection slave +START SLAVE; +# ER_MUST_CHANGE_PASSWORD +--let $slave_io_errno= 1820 +--source include/wait_for_slave_io_error.inc + +--connection master +DROP USER 'repl_user'; +set global disconnect_on_expired_password=default; + +--connection slave +--source include/stop_slave_sql.inc +eval CHANGE MASTER TO MASTER_USER='$master_user'; +RESET SLAVE; + +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc + diff --git a/mysql-test/suite/rpl/t/rename.test b/mysql-test/suite/rpl/t/rename.test new file mode 100644 index 00000000..ac499157 --- /dev/null +++ b/mysql-test/suite/rpl/t/rename.test @@ -0,0 +1,33 @@ +--source include/have_binlog_format_mixed.inc +--source include/master-slave.inc + +--echo # +--echo # MDEV-16229 Replication aborts with ER_VIEW_SELECT_TMPTABLE after +--echo # half-failed RENAME +--echo # + +CREATE TABLE t1 (a INT); +CREATE TEMPORARY TABLE t1 (b INT); +RENAME TABLE t1 TO tmp, tmp TO t1; +SHOW CREATE TABLE t1; +--error ER_VIEW_SELECT_TMPTABLE +CREATE VIEW v AS SELECT * FROM t1; + +RENAME TABLE t1 TO tmp, t1 TO t2; +SHOW CREATE TABLE tmp; +SHOW CREATE TABLE t2; +--error ER_VIEW_SELECT_TMPTABLE +CREATE VIEW v AS SELECT * FROM tmp; +CREATE VIEW v AS SELECT * FROM t2; + +--sync_slave_with_master + +# Cleanup + +--connection master + +DROP VIEW v; +DROP TABLE tmp; +DROP TABLE t2; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/replace.test b/mysql-test/suite/rpl/t/replace.test new file mode 100644 index 00000000..36afda0d --- /dev/null +++ b/mysql-test/suite/rpl/t/replace.test @@ -0,0 +1,24 @@ +# +# Test of REPLACE with replication +# + +source include/master-slave.inc; + +# +# Test of doing replace on unique key on table with auto_increment +# + +drop table if exists t1; +CREATE TABLE t1 (pr_id int(10) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY, pr_page int(11) NOT NULL, pr_type varbinary(60) NOT NULL, test int, UNIQUE KEY pr_pagetype (pr_page,pr_type)) ENGINE=myisam AUTO_INCREMENT=136; +insert into t1 (pr_page, pr_type, test) values(1,"one",0),(2,"two",0); +select * from t1; +replace into t1 (pr_page, pr_type,test) values(1,"one",2); +select * from t1; +sync_slave_with_master; +connection slave; +select * from t1; +connection master; +drop table t1; + +# End of 5.5 tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_000010-slave.opt b/mysql-test/suite/rpl/t/rpl_000010-slave.opt new file mode 100644 index 00000000..cbd77ee2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_000010-slave.opt @@ -0,0 +1 @@ +--debug-disconnect-slave-event-count=2 diff --git a/mysql-test/suite/rpl/t/rpl_000010.test b/mysql-test/suite/rpl/t/rpl_000010.test new file mode 100644 index 00000000..9ff2d6c5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_000010.test @@ -0,0 +1,22 @@ +# This tests the offset off by 22 mystery bug +# Must run slave with --disconnect-slave-event-count=1 --master-connect-retry=1 + +source include/master-slave.inc; + +--connection slave +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=NO; +--source include/start_slave.inc +--connection master + +create table t1 (n int not null auto_increment primary key); +insert into t1 values(NULL); +insert into t1 values(2); +sync_slave_with_master; +select n from t1; +connection master; +drop table t1; +sync_slave_with_master; + +# End of 4.1 tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_000011-slave.opt b/mysql-test/suite/rpl/t/rpl_000011-slave.opt new file mode 100644 index 00000000..7c3d2411 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_000011-slave.opt @@ -0,0 +1 @@ +--verbose=1 diff --git a/mysql-test/suite/rpl/t/rpl_000011.test b/mysql-test/suite/rpl/t/rpl_000011.test new file mode 100644 index 00000000..289b79f7 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_000011.test @@ -0,0 +1,34 @@ +# +# Test very simply slave replication (to ensure it works at all) +# In addition, test also: +# MDEV-5829 STOP SLAVE resets global status variables +# + +source include/master-slave.inc; +--connection slave +let $initial_com_insert= query_get_value(show global status like "Com_insert", Value, 1); +--connection master +create table t1 (n int); +insert into t1 values(1); +sync_slave_with_master; +let $current_com_insert= query_get_value(show global status like "Com_insert", Value, 1); +--let $delta_com_insert= `select $current_com_insert - $initial_com_insert from dual` +--echo # Com_insert = $delta_com_insert +stop slave; +let $current_com_insert= query_get_value(show global status like "Com_insert", Value, 1); +--let $delta_com_insert= `select $current_com_insert - $initial_com_insert from dual` +--echo # Com_insert = $delta_com_insert +--source include/wait_for_slave_to_stop.inc +start slave; +--source include/wait_for_slave_to_start.inc +connection master; +insert into t1 values(2); +#let slave catch up +sync_slave_with_master; +select * from t1; +connection master; +drop table t1; +sync_slave_with_master; + +# End of 4.1 tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_000013.test b/mysql-test/suite/rpl/t/rpl_000013.test new file mode 100644 index 00000000..9f1b0666 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_000013.test @@ -0,0 +1,55 @@ +# This test is to verify that DROP TEMPORARY TABLE +# is automatically binlogged and sent to slave +# when a temp table is dropped by disconnection +# of a master's conection. +# So it does not apply to row-based, where we neither need +# nor do this automatic binlogging. And if we run this test +# in row-based, it hangs waiting for an offset which is never +# reached (the "sync_with_master 1"), logically. + +--source include/have_binlog_format_mixed_or_statement.inc +source include/master-slave.inc; + +--disable_query_log +CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); +--enable_query_log + +create table t2(n int); +create temporary table t1 (n int); +insert into t1 values(1),(2),(3); +--disable_warnings +insert into t2 select * from t1; +--enable_warnings +connection master1; +create temporary table t1 (n int); +insert into t1 values (4),(5); +--disable_warnings +insert into t2 select * from t1 as t10; +--enable_warnings +save_master_pos; +disconnect master; +connection slave; +#add 1 to catch drop table +sync_with_master 1; +connection master1; +insert into t2 values(6); +save_master_pos; +disconnect master1; +connection slave; +# same trick to go one more event +sync_with_master 1; +select * from t2; +show status like 'Slave_open_temp_tables'; +# +# Clean up +# +connect (master2,localhost,root,,); +connection master2; + +# We will get a warning for t1 as this is a temporary table that doesn't +# exist in this connection. + +drop table if exists t1,t2; + +--source include/rpl_end.inc +# End of 4.1 tests diff --git a/mysql-test/suite/rpl/t/rpl_000017.test b/mysql-test/suite/rpl/t/rpl_000017.test new file mode 100644 index 00000000..893117e6 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_000017.test @@ -0,0 +1,47 @@ +# ==== Purpose ==== +# +# Unknown. +# +# ==== Notes ==== +# +# This test uses the -slave.opt file to start the slave with +# --skip-slave-start. + +--source include/not_windows.inc + +--let $rpl_skip_start_slave= 1 +--source include/master-slave.inc + +--connection slave +--let $slave_datadir= `SELECT @@datadir` + +--remove_file $slave_datadir/master.info +--write_file $slave_datadir/master.info +master-bin.000001 +4 +127.0.0.1 +replicate +aaaaaaaaaaaaaaab +$MASTER_MYPORT +1 +0 +EOF + +connection master; +grant replication slave on *.* to replicate@localhost identified by 'aaaaaaaaaaaaaaab'; +grant replication slave on *.* to replicate@127.0.0.1 identified by 'aaaaaaaaaaaaaaab'; +connection slave; +--source include/start_slave.inc + +connection master; +create table t1(n int); +insert into t1 values(24); +sync_slave_with_master; +select * from t1; +connection master; +drop table t1; +delete from mysql.user where user="replicate"; + +# End of 4.1 tests +--source include/rpl_end.inc + diff --git a/mysql-test/suite/rpl/t/rpl_15867.test b/mysql-test/suite/rpl/t/rpl_15867.test new file mode 100644 index 00000000..6de39041 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_15867.test @@ -0,0 +1,11 @@ +--source include/master-slave.inc +CREATE TEMPORARY TABLE t (i INT); +CREATE TABLE t AS SELECT * FROM t; + +--sync_slave_with_master + +# Cleanup +--connection master +DROP TEMPORARY TABLE t; +DROP TABLE t; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_15919-slave.opt b/mysql-test/suite/rpl/t/rpl_15919-slave.opt new file mode 100644 index 00000000..62ab6dad --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_15919-slave.opt @@ -0,0 +1 @@ +--lower_case_table_names=1 diff --git a/mysql-test/suite/rpl/t/rpl_15919.test b/mysql-test/suite/rpl/t/rpl_15919.test new file mode 100644 index 00000000..a5b25929 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_15919.test @@ -0,0 +1,18 @@ +--source include/have_case_sensitive_file_system.inc +--source include/have_innodb.inc +--source include/master-slave.inc + +--connection master +create table RPL(a int); +insert into RPL values(1); + +--sync_slave_with_master +select * from rpl; +insert into RPL values(3); +insert into rpl values(4); +select * from rpl; + +--connection master +drop table RPL; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_EE_err.test b/mysql-test/suite/rpl/t/rpl_EE_err.test new file mode 100644 index 00000000..b2ca3aac --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_EE_err.test @@ -0,0 +1,2 @@ +let $engine_type=myisam; +-- source include/rpl_EE_err.test diff --git a/mysql-test/suite/rpl/t/rpl_LD_INFILE.test b/mysql-test/suite/rpl/t/rpl_LD_INFILE.test new file mode 100644 index 00000000..0f02bdcc --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_LD_INFILE.test @@ -0,0 +1,39 @@ +############################################################################# +# Original Author: JBM # +# Original Date: Aug/18/2005 # +############################################################################# +# TEST: To test the LOAD DATA INFILE in rbr # +############################################################################# + +# Includes +-- source include/master-slave.inc + +# Begin clean up test section +--disable_warnings +connection master; +DROP TABLE IF EXISTS test.t1; +--enable_warnings + +# Section 1 test +CREATE TABLE test.t1 (a VARCHAR(255), PRIMARY KEY(a)); +LOAD DATA INFILE '../../std_data/words2.dat' INTO TABLE test.t1; +DELETE FROM test.t1 WHERE a = 'abashed'; +DELETE FROM test.t1; +LOAD DATA INFILE '../../std_data/words2.dat' INTO TABLE test.t1; + + +SELECT * FROM test.t1 ORDER BY a DESC; +save_master_pos; +sync_slave_with_master; +connection slave; +SELECT * FROM test.t1 ORDER BY a DESC; + +# Cleanup +#show binlog events; +connection master; +DROP TABLE test.t1; +sync_slave_with_master; + +# End of 5.0 test case + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_alter.test b/mysql-test/suite/rpl/t/rpl_alter.test new file mode 100644 index 00000000..8b8bcfb3 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_alter.test @@ -0,0 +1,71 @@ +source include/master-slave.inc; +create database mysqltest; + +create table mysqltest.t1 ( n int); +alter table mysqltest.t1 add m int; +insert into mysqltest.t1 values (1,2); +create table mysqltest.t2 (n int); +insert into mysqltest.t2 values (45); +rename table mysqltest.t2 to mysqltest.t3, mysqltest.t1 to mysqltest.t2; +sync_slave_with_master; +select * from mysqltest.t2; +select * from mysqltest.t3; +connection master; +drop database mysqltest; +sync_slave_with_master; + +# End of 4.1 tests + +connection master; +use test; + +--echo # +--echo # Test bug where ALTER TABLE MODIFY didn't replicate properly +--echo # + +create table t1 (a int unsigned primary key, b int); +show create table t1; +insert into t1 (a) values (1),((1<<32)-1); +select * from t1; +alter table t1 modify a bigint; +show create table t1; +select * from t1; +alter table t1 modify a int unsigned; +show create table t1; +select * from t1; +alter table t1 modify a bigint unsigned; +show create table t1; +select * from t1; +sync_slave_with_master; +use test; +select * from t1; +show create table t1; +connection master; +# +create table t2 (a int unsigned auto_increment primary key, b int); +show create table t2; +alter table t2 modify a bigint; +show create table t2; +alter table t2 modify a bigint auto_increment; +show create table t2; +drop table t1,t2; + +--echo # +--echo # MDEV-8432: Slave cannot replicate signed integer-type values +--echo # with high bit set to 1 +--echo # Test replication when we have int on master and bigint on slave +--echo # + +create table t1 (a int unsigned primary key, b int); +sync_slave_with_master; +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_NON_LOSSY'; +alter table t1 modify a bigint unsigned; +connection master; +insert into t1 (a) values (1),((1<<32)-1); +sync_slave_with_master; +select * from t1; +SET GLOBAL SLAVE_TYPE_CONVERSIONS=''; +connection master; +drop table t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_alter_db.test b/mysql-test/suite/rpl/t/rpl_alter_db.test new file mode 100644 index 00000000..f6f07825 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_alter_db.test @@ -0,0 +1,15 @@ +source include/master-slave.inc; + +--echo ==== Verify that alter database does not stop replication ==== + +create database temp_db; +use temp_db; # to be different from initial `test' db of mysqltest client +alter database collate latin1_bin; + +sync_slave_with_master; + +--echo ==== Clean up ==== +connection master; +drop database temp_db; +sync_slave_with_master; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_alter_extra_persistent.test b/mysql-test/suite/rpl/t/rpl_alter_extra_persistent.test new file mode 100644 index 00000000..4e604787 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_alter_extra_persistent.test @@ -0,0 +1,106 @@ +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +--enable_connect_log +--connection master +create table t1(a int primary key); +insert into t1 values(1); +insert into t1 values(2); +insert into t1 values(3); +insert into t1 values(4); + +--sync_slave_with_master +select * from t1 order by a; +alter table t1 add column z1 int as(a+1) virtual, add column z2 int as (a+2) persistent; +select * from t1 order by a; + +--connection master +insert into t1 values(5); +insert into t1 values(6); + +--sync_slave_with_master +select * from t1 order by a; + + +--echo #UPDATE query + +--connection master +update t1 set a = a+10; +select * from t1 order by a; + +--sync_slave_with_master +select * from t1 order by a; + +--connection master +update t1 set a = a-10; +select * from t1 order by a; + +--sync_slave_with_master +select * from t1 order by a; + +--echo #DELETE quert +--connection master +delete from t1 where a > 2 and a < 4; +select * from t1 order by a; + +--sync_slave_with_master +select * from t1 order by a; + +--echo #REPLACE query +--connection master +replace into t1 values(1); +replace into t1 values(3); +replace into t1 values(1); + +--sync_slave_with_master +select * from t1 order by a; + +--echo #SELECT query +--connection master +select * from t1 where a > 2 and a < 4; + +--connection slave +select * from t1 where a > 2 and a < 4; + +--echo #UPDATE with SELECT query +--connection master +update t1 set a = a + 10 where a > 2 and a < 4; +select * from t1 order by a; + +--sync_slave_with_master +select * from t1 order by a; + +--connection master +update t1 set a = a - 10 where a = 13; +select * from t1 order by a; + +--sync_slave_with_master +select * from t1 order by a; + +--echo #Break Unique Constraint +alter table t1 add column z4 int as (a % 6) persistent unique; + +--connection master + +--echo #entering duplicate value for slave persistent column +insert into t1 values(7); +select * from t1 order by a; + +--connection slave +--let $slave_sql_errno= 1062 +--source include/wait_for_slave_sql_error.inc +select * from t1 order by a; +alter table t1 drop column z4; +start slave; + +--source include/wait_for_slave_sql_to_start.inc + +--connection master +--sync_slave_with_master +select * from t1 order by a; + +--connection master +select * from t1 order by a; +drop table t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_alter_instant.test b/mysql-test/suite/rpl/t/rpl_alter_instant.test new file mode 100644 index 00000000..260f7e92 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_alter_instant.test @@ -0,0 +1,50 @@ +source include/have_innodb.inc; +source include/master-slave.inc; + +use test; +create table t1 (id int primary key, c1 int default 10, c2 varchar(20) default 'holiday') engine = innodb; + +insert into t1 values(1, 12345, 'abcde'), (2, default, default), (3, 23456, 'xyzab'); + +set time_zone='+03:00'; +set timestamp = 1; +alter table t1 add column d1 timestamp not null default current_timestamp; + +select * from t1; +sync_slave_with_master; + +connection slave; +set time_zone='+03:00'; +select * from t1; + +connection master; +alter table t1 add column d2 timestamp not null default current_timestamp, ALGORITHM=copy; + +sync_slave_with_master; + +connection slave; +select * from t1; + +connection master; +drop table t1; + + +# datetime +create table t4 (id int primary key, c2 int); +insert into t4 values(1,1),(2,2),(3,3); +set timestamp = 1000; +alter table t4 add column (c3 datetime default current_timestamp(), c4 timestamp not null default current_timestamp()); +select * from t4; +alter table t4 add column c5 time not null default current_timestamp(); +alter table t4 add column c6 date not null default current_timestamp(); + +select * from t4; +sync_slave_with_master; + +connection slave; +select * from t4; + +connection master; +drop table t4; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_alter_rollback.test b/mysql-test/suite/rpl/t/rpl_alter_rollback.test new file mode 100644 index 00000000..c24f01ff --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_alter_rollback.test @@ -0,0 +1,42 @@ +# +# MENT-662: Lag Free Alter On Slave +# + +--echo # +--echo # Test verifies that "ROLLBACK ALTER" is written to binary log upon +--echo #ALTER command execution failure. +--echo # +--source include/have_innodb.inc +--source include/master-slave.inc + +--connection master +--let $binlog_alter_two_phase= `select @@binlog_alter_two_phase` +set global binlog_alter_two_phase = ON; +set binlog_alter_two_phase = ON; + +create table t1 (f1 int primary key) engine=InnoDB; +--error ER_CANT_CREATE_TABLE +create table t2 (f1 int primary key, +constraint c1 foreign key (f1) references t1(f1), +constraint c1 foreign key (f1) references t1(f1)) engine=InnoDB; +create table t2 (f1 int primary key, + constraint c1 foreign key (f1) references t1(f1)) engine=innodb; + +--error ER_CANT_CREATE_TABLE +alter table t2 add constraint c1 foreign key (f1) references t1(f1); +--source include/show_binlog_events.inc + +set foreign_key_checks = 0; +--error ER_DUP_CONSTRAINT_NAME +alter table t2 add constraint c1 foreign key (f1) references t1(f1); +--source include/show_binlog_events.inc +--sync_slave_with_master + +--connection master +drop table t2, t1; +--sync_slave_with_master + +--connection master +--eval set global binlog_alter_two_phase=$binlog_alter_two_phase; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_auto_increment-master.opt b/mysql-test/suite/rpl/t/rpl_auto_increment-master.opt new file mode 100644 index 00000000..a8a6af19 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_auto_increment-master.opt @@ -0,0 +1 @@ +--auto-increment-increment=10 --auto-increment-offset=2 diff --git a/mysql-test/suite/rpl/t/rpl_auto_increment-slave.opt b/mysql-test/suite/rpl/t/rpl_auto_increment-slave.opt new file mode 100644 index 00000000..79ed6f96 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_auto_increment-slave.opt @@ -0,0 +1 @@ +--replicate-ignore-table=test.t_ignored1 diff --git a/mysql-test/suite/rpl/t/rpl_auto_increment.test b/mysql-test/suite/rpl/t/rpl_auto_increment.test new file mode 100644 index 00000000..6d01fdb8 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_auto_increment.test @@ -0,0 +1,7 @@ +##################################### +# Wrapper for rpl_auto_increment.test# +##################################### +-- source include/have_innodb.inc +let $engine_type=innodb; +let $engine_type2=myisam; +-- source include/rpl_auto_increment.test diff --git a/mysql-test/suite/rpl/t/rpl_auto_increment_11932.test b/mysql-test/suite/rpl/t/rpl_auto_increment_11932.test new file mode 100644 index 00000000..1e5f9e53 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_auto_increment_11932.test @@ -0,0 +1,66 @@ +# +# Test of auto_increment +# BUG#11932 +# +# Bug reported that master and slave get out of sync after TRUNCATE +# TABLE. +# +# Test supplied by Are Casilla + +source include/master-slave.inc; +call mtr.add_suppression('Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.'); +--disable_warnings +connection master; +drop database if exists test1; +--enable_warnings +create database test1; +use test1; + +CREATE TABLE `t1` ( + `id` int(10) unsigned NOT NULL auto_increment, + `fname` varchar(100) default NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ; + +INSERT INTO `t1` VALUES (1, 'blablabla'); + +CREATE TABLE `t2` ( + `id` int(10) NOT NULL auto_increment, + `comment` varchar(255) NOT NULL default '', + PRIMARY KEY (`id`) +) ENGINE=MyISAM AUTO_INCREMENT=3 ; + +INSERT INTO `t2` VALUES (1, 'testtest 1'); +INSERT INTO `t2` VALUES (2, 'test 2'); + +DELIMITER $; +CREATE PROCEDURE simpleproc3 () + NOT DETERMINISTIC + BEGIN + INSERT INTO t1 (fname) (SELECT t2.comment FROM t2 WHERE t2.id = '1'); + INSERT INTO t1 (fname) VALUES('test'); + END + $ +DELIMITER ;$ + +--disable_warnings +CALL simpleproc3(); +--enable_warnings + +select * from t2; + +TRUNCATE TABLE `t1`; +--disable_warnings +CALL simpleproc3(); +--enable_warnings + +select * from t1; + +sync_slave_with_master; + +use test1; +select * from t1; + +connection master; +drop database test1; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_auto_increment_bug33029.test b/mysql-test/suite/rpl/t/rpl_auto_increment_bug33029.test new file mode 100644 index 00000000..6f7e0d80 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_auto_increment_bug33029.test @@ -0,0 +1,60 @@ +# BUG#33029 5.0 to 5.1 replication fails on dup key when inserting +# using a trig in SP + +# For all 5.0 up to 5.0.58 exclusive, and 5.1 up to 5.1.12 exclusive, +# if one statement in a SP generated AUTO_INCREMENT value by the top +# statement, all statements after it would be considered generated +# AUTO_INCREMENT value by the top statement, and a erroneous INSERT_ID +# value might be associated with these statement, which could cause +# duplicate entry error and stop the slave. + +# Test if the slave can replicate from such a buggy master + +# The bug33029-slave-relay-bin.000001 file is the +# slave-replay-bin.000003 file generated by run the +# rpl_auto_increment_bug33029.test with clean up statements at the end +# of the test case removed on a buggy 5.0 server + +--let $rpl_skip_start_slave= 1 +--source include/master-slave.inc + +--echo ==== Initialize ==== +--connection slave + +# The binlog we read does funny things with triggers and causes this warning. +--disable_query_log +CALL mtr.add_suppression('Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT'); +--enable_query_log + +# Need to restore this at the end; CHANGE MASTER modifies it (see the +# manual for CHANGE MASTER). +SET @old_relay_log_purge= @@global.relay_log_purge; + +# the relay log contains create t1, t2 tables and load data infile +--let $fake_relay_log = $MYSQL_TEST_DIR/std_data/bug33029-slave-relay-bin.000001 +--source include/setup_fake_relay_log.inc + +--echo ==== Test ==== +start slave sql_thread; +--let $slave_param= Exec_Master_Log_Pos +--let $slave_param_value= 3776 +--source include/wait_for_slave_param.inc + + +echo # Result on slave; +SELECT * FROM t1; +SELECT * FROM t2; + +--echo ==== Clean up ==== + +stop slave sql_thread; +--source include/cleanup_fake_relay_log.inc + +DROP TABLE t1, t2; +DROP PROCEDURE p1; +DROP PROCEDURE p2; +DROP FUNCTION f1; + +SET @@global.relay_log_purge= @old_relay_log_purge; +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_auto_increment_bug45679.test b/mysql-test/suite/rpl/t/rpl_auto_increment_bug45679.test new file mode 100644 index 00000000..25bfa134 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_auto_increment_bug45679.test @@ -0,0 +1,64 @@ +# Test of auto-increment. +# +# BUG#11754117-45670 +# Multipart primary key with the autoincrement part not first in it +# is replication unsafe. +# + +source include/have_binlog_format_mixed.inc; +source include/have_innodb.inc; +source include/master-slave.inc; + +call mtr.add_suppression('Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.'); + +--connection master +create table tm (b int auto_increment, a int, primary key (a,b)) engine= myisam; +--error ER_WRONG_AUTO_KEY +create table ti (b int auto_increment, a int, primary key (a,b)) engine= innodb; +create table ti (b int auto_increment, a int, primary key (b,a)) engine= innodb; + +set @@binlog_format=statement; +--echo *** autoincrement field is not the first in PK warning must be there: *** +insert into tm set b=null, a=1; +show warnings; +--echo *** no warning when autoincrement is the first in PK +insert into ti set b=null, a=1; +show warnings; + +delimiter //; +create function multi_part_pk_with_autoinc (arg int) +returns int +begin + insert into tm set b=null, a=arg; + return arg; +end// +delimiter ;// + +--disable_ps2_protocol +select multi_part_pk_with_autoinc (3); +--enable_ps2_protocol +--echo *** autoincrement field is not the first in PK warning must be there: *** +show warnings; + +set @@binlog_format=mixed; +insert into tm set b=null, a=2; + +sync_slave_with_master; + +if (`select count(*) <> 3 from tm`) +{ + --echo Wrong result from SELECT on the slave side. + select * from tm; + --die +} + +# cleanup + +--connection master + +drop table tm, ti; +drop function multi_part_pk_with_autoinc; + +sync_slave_with_master; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_auto_increment_update_failure.test b/mysql-test/suite/rpl/t/rpl_auto_increment_update_failure.test new file mode 100644 index 00000000..82db8f08 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_auto_increment_update_failure.test @@ -0,0 +1,211 @@ +# +# Bug45677 +# This test verifies the following two properties: +# P1) insert/update in an autoinc column causes statement to +# be logged in row format if binlog_format=mixed. +# P2) if binlog_format=mixed, and a trigger or function contains +# two or more inserts/updates in a table that has an autoinc +# column, then the slave should not go out of sync, even if +# there are concurrent transactions. +# +# Property (P1) is tested by executing an insert and an update on +# a table that has an autoinc column, and verifying that these +# statements result in row events in the binlog. +# Property (P2) is tested by setting up the test scenario and +# verifying that the tables are identical on master and slave. +# + +source include/have_binlog_format_mixed.inc; +source include/have_innodb.inc; +source include/master-slave.inc; + +--echo # Test case1: INVOKES A TRIGGER with after insert action +let $trigger_action = after insert; +source include/rpl_auto_increment_invoke_trigger.test; + +--echo # Test case2: INVOKES A TRIGGER with before insert action +let $trigger_action = before insert; +source include/rpl_auto_increment_invoke_trigger.test; + +--echo # Test case3: INVOKES A TRIGGER with after update action +let $trigger_action = after update; +source include/rpl_auto_increment_invoke_trigger.test; + +--echo # Test case4: INVOKES A TRIGGER with before update action +let $trigger_action = before update; +source include/rpl_auto_increment_invoke_trigger.test; + +--echo # Test case5: INVOKES A TRIGGER with after delete action +let $trigger_action = after delete; +source include/rpl_auto_increment_invoke_trigger.test; + +--echo # Test case6: INVOKES A TRIGGER with before delete action +let $trigger_action = before delete; +source include/rpl_auto_increment_invoke_trigger.test; + +--echo # Test case7: CALLS A FUNCTION which INVOKES A TRIGGER with after insert action +let $insert_action = after insert; +source include/rpl_autoinc_func_invokes_trigger.test; + +--echo # Test case8: CALLS A FUNCTION which INVOKES A TRIGGER with before insert action +let $insert_action = before insert; +source include/rpl_autoinc_func_invokes_trigger.test; + +--echo # Test case9: INSERT DATA INTO VIEW WHICH INVOKES TRIGGERS with after insert action +let $insert_action = after insert; +source include/rpl_auto_increment_insert_view.test; + +--echo # Test case10: INSERT DATA INTO VIEW WHICH INVOKES TRIGGERS with before insert action +let $insert_action = before insert; +source include/rpl_auto_increment_insert_view.test; + +--echo # Test case11: INVOKES A FUNCTION TO INSERT TWO OR MORE VALUES INTO A TABLE WITH AUTOINC COLUMN +connection master; +create table t1(a int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +delimiter //; +CREATE FUNCTION f1_two_inserts() RETURNS INTEGER +BEGIN + INSERT INTO t2(a) values(2); + INSERT INTO t2(a) values(2); + RETURN 1; +END// +delimiter ;// +begin; +insert into t1(a) values(f1_two_inserts()); + +connection master1; +#The default autocommit is set to 1, so the statement is auto committed +insert into t2(a) values(4),(5); + +connection master; +commit; +insert into t1(a) values(f1_two_inserts()); +commit; + +connection master; +--echo #Test result for INVOKES A FUNCTION TO INSERT TWO OR MORE VALUES on master +select * from t2 ORDER BY i1; + +sync_slave_with_master; +connection slave; +--echo #Test result for INVOKES A FUNCTION TO INSERT TWO OR MORE VALUES on slave +select * from t2 ORDER BY i1; + +connection master; +drop table t1; +drop table t2; +drop function f1_two_inserts; +sync_slave_with_master; + +--echo # Test case12: INVOKES A FUNCTION TO UPDATE TWO OR MORE VALUES OF A TABLE WITH AUTOINC COLUMN +connection master; +create table t1(a int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, b int, primary key(i1)) engine=innodb; +delimiter //; +CREATE FUNCTION f1_two_updates() RETURNS INTEGER +BEGIN + update t2 set a = a + 5 where b = 1; + update t2 set a = a + 5 where b = 2; + update t2 set a = a + 5 where b = 3; + update t2 set a = a + 5 where b = 4; + RETURN 1; +END// +delimiter ;// + +connection master1; +#The default autocommit is set to 1, so the statement is auto committed +insert into t2(a,b) values(1,1); +insert into t2(a,b) values(2,2); +insert into t2(a,b) values(3,3); +insert into t2(a,b) values(4,4); +insert into t1(a) values(f1_two_updates()); + +connection master; +begin; +insert into t1(a) values(f1_two_updates()); +commit; + +connection master; +--echo #Test result for INVOKES A FUNCTION TO UPDATE TWO OR MORE VALUES on master +select * from t2 ORDER BY i1; + +sync_slave_with_master; +connection slave; +--echo #Test result for INVOKES A FUNCTION TO UPDATE TWO OR MORE VALUES on slave +select * from t2 ORDER BY i1; + +connection master; +drop table t1; +drop table t2; +drop function f1_two_updates; +sync_slave_with_master; + +--echo # Test case13: UPDATE MORE THAN ONE TABLES ON TOP-STATEMENT +connection master; +create table t1(i1 int not null auto_increment, a int, b int, primary key(i1)) engine=innodb; +create table t2(i1 int not null auto_increment, a int, b int, primary key(i1)) engine=innodb; +begin; +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +insert into t1(a,b) values(1,1),(2,2); +insert into t2(a,b) values(1,1),(2,2); +update t1,t2 set t1.a=t1.a+5, t2.a=t2.a+5 where t1.b=t2.b; +insert into t1(a,b) values(3,3); +insert into t2(a,b) values(3,3); +commit; +--echo # To verify if it works fine when these statements are not be marked as unsafe +source include/show_binlog_events.inc; + +sync_slave_with_master; +--echo #Test if the results are consistent on master and slave +--echo #for 'UPDATE MORE THAN ONE TABLES ON TOP-STATEMENT' +let $diff_tables= master:t1, slave:t1; +source include/diff_tables.inc; +let $diff_tables= master:t2, slave:t2; +source include/diff_tables.inc; + +connection master; +drop table t1; +drop table t2; +sync_slave_with_master; + +--echo # Test case14: INSERT DATA INTO VIEW WHICH INVOLVED MORE THAN ONE TABLES +connection master; +CREATE TABLE t1(i1 int not null auto_increment, c1 INT, primary key(i1)) engine=innodb; +CREATE TABLE t2(i1 int not null auto_increment, c2 INT, primary key(i1)) engine=innodb; +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +begin; +INSERT INTO t1(c1) VALUES (11), (12); +INSERT INTO t2(c2) VALUES (13), (14); + +CREATE VIEW v15 AS SELECT c1, c2 FROM t1, t2; + +INSERT INTO v15(c1) VALUES (15),(16); +INSERT INTO v15(c2) VALUES (17),(18); + +connection master1; +INSERT INTO v15(c1) VALUES (19),(20); +INSERT INTO v15(c2) VALUES (21),(22); + +connection master; +INSERT INTO v15(c1) VALUES (23), (24); +INSERT INTO v15(c2) VALUES (25), (26); +commit; +--echo # To verify if it works fine when these statements are not be marked as unsafe +source include/show_binlog_events.inc; + +sync_slave_with_master; +--echo #Test if the results are consistent on master and slave +--echo #for 'INSERT DATA INTO VIEW WHICH INVOLVED MORE THAN ONE TABLES' +let $diff_tables= master:t1, slave:t1; +source include/diff_tables.inc; +let $diff_tables= master:t2, slave:t2; +source include/diff_tables.inc; + +connection master; +drop table t1; +drop table t2; +drop view v15; +sync_slave_with_master; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_autogen_query_multi_byte_char.test b/mysql-test/suite/rpl/t/rpl_autogen_query_multi_byte_char.test new file mode 100644 index 00000000..a93fcbac --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_autogen_query_multi_byte_char.test @@ -0,0 +1,87 @@ +############################################################################### +# Bug#21205695 DROP TABLE MAY CAUSE SLAVES TO BREAK +# +# Problem: +# ======== +# 1) Drop table queries are re-generated by server +# before writing the events(queries) into binlog +# for various reasons. If table name/db name contains +# a non regular characters (like latin characters), +# the generated query is wrong. Hence it breaks the +# replication. +# 2) In the edge case, when table name contains +# 64 latin characters (latin takes 2 bytes), server is +# throwing an assert (M_TBLLEN < 128) +# +# 3) In the edge case, when db name contains 64 latin +# characters, binlog contents are interpreted wrongly +# which is leading to replication issues. +# +############################################################################### + +--source include/not_windows.inc +--source include/master-slave.inc + +--let iter=1 +# Change iteration to 4 after fixing Bug #22280214 +while ($iter <= 2) +{ + --connection master + if ($iter == 1) + { + --echo Test case 1:- table name with one character latin name. + --let $tblname= REPEAT(CHAR(131),1) + } + if ($iter == 2) + { + --echo Test case 2:- table name and database names with one character latin name. + --let $tblname= REPEAT(CHAR(131),1),"`.`",REPEAT(CHAR(131),1) + --eval SET @s:=CONCAT("CREATE DATABASE `",REPEAT(CHAR(131),1),"`") + PREPARE STMT FROM @s; EXECUTE stmt; + } + # After fixing Bug #22280214 DATADIR LOCATION IS LIMITING + # IDENTIFIER MAX LENGTH, the following two tests (iter 3 and 4) can be + # uncommented. + #if ($iter == 3) + #{ + # --echo Test case 3:- table name and database names with 64 latin characters name. + # --let $tblname= REPEAT(CHAR(131),64),"`.`", REPEAT(CHAR(131),64) + # --eval SET @s:=CONCAT("CREATE DATABASE `",REPEAT(CHAR(131),64),"`") + # PREPARE STMT FROM @s; EXECUTE stmt; + #} + #if ($iter == 4) + #{ + # --echo Test case 4:- table name and database names with 64 Euro(€) characters. + # --let $tblname= REPEAT(CHAR(226,130,172),64),"`.`", REPEAT(CHAR(226,130,172),64) + # --eval SET @s:=CONCAT("CREATE DATABASE `",REPEAT(CHAR(226,130,172),64),"`") + # PREPARE STMT FROM @s; EXECUTE stmt; + #} + --eval SET @s:=CONCAT("CREATE TABLE `",$tblname,"` (a INT)") + PREPARE STMT FROM @s; EXECUTE stmt; + --eval SET @s:=CONCAT("INSERT INTO `",$tblname,"` VALUES (1)") + PREPARE STMT FROM @s; EXECUTE stmt; + --eval SET @s:=CONCAT("DROP TABLE `",$tblname, "`") + PREPARE STMT FROM @s; EXECUTE stmt; + if ($iter == 2) + { + --eval SET @s:=CONCAT("DROP DATABASE `",REPEAT(CHAR(131),1),"`") + PREPARE STMT FROM @s; EXECUTE stmt; + } + # After fixing Bug #22280214 DATADIR LOCATION IS LIMITING + # IDENTIFIER MAX LENGTH, the following two tests (iter 3 and 4) can be + # uncommented. + #if ($iter == 3) + #{ + # --eval SET @s:=CONCAT("DROP DATABASE `",REPEAT(CHAR(131),64),"`") + # PREPARE STMT FROM @s; EXECUTE stmt; + #} + #if ($iter == 4) + #{ + # --eval SET @s:=CONCAT("DROP DATABASE `",REPEAT(CHAR(226,130,172),64),"`") + # PREPARE STMT FROM @s; EXECUTE stmt; + #} + --sync_slave_with_master + --inc $iter +} + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_begin_commit_rollback-master.opt b/mysql-test/suite/rpl/t/rpl_begin_commit_rollback-master.opt new file mode 100644 index 00000000..a8de78ed --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_begin_commit_rollback-master.opt @@ -0,0 +1 @@ +--loose-innodb --binlog-ignore-db=db2 diff --git a/mysql-test/suite/rpl/t/rpl_begin_commit_rollback-slave.opt b/mysql-test/suite/rpl/t/rpl_begin_commit_rollback-slave.opt new file mode 100644 index 00000000..264b1728 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_begin_commit_rollback-slave.opt @@ -0,0 +1 @@ +--loose-innodb --replicate-do-db=db1 diff --git a/mysql-test/suite/rpl/t/rpl_begin_commit_rollback.test b/mysql-test/suite/rpl/t/rpl_begin_commit_rollback.test new file mode 100644 index 00000000..659f074e --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_begin_commit_rollback.test @@ -0,0 +1,173 @@ +source include/have_innodb.inc; +source include/have_binlog_format_statement.inc; +source include/master-slave.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; + +sync_slave_with_master; +source include/stop_slave.inc; +connection 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; + +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; + +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; + +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; +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; +sync_slave_with_master; + +--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 # Clean up +--echo # +connection master; +DROP DATABASE db1; +DROP DATABASE db2; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_binlog_compress.test b/mysql-test/suite/rpl/t/rpl_binlog_compress.test new file mode 100644 index 00000000..ef1e4508 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_binlog_compress.test @@ -0,0 +1,61 @@ +# +# Test of compressed binlog with replication +# + +source include/master-slave.inc; + +set @old_log_bin_compress=@@log_bin_compress; +set @old_log_bin_compress_min_len=@@log_bin_compress_min_len; +set @old_binlog_format=@@binlog_format; +set @old_binlog_row_image=@@binlog_row_image; + +set global log_bin_compress=on; +set global log_bin_compress_min_len=10; + +drop table if exists t1; +CREATE TABLE t1 (pr_id int(10) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY, pr_page int(11) NOT NULL, pr_type varbinary(60) NOT NULL, test int, UNIQUE KEY pr_pagetype (pr_page,pr_type)) ENGINE=myisam AUTO_INCREMENT=136; + +set binlog_format=statement; +insert into t1 (pr_page, pr_type, test) values(1,"one",0),(2,"two",0); +replace into t1 (pr_page, pr_type,test) values(1,"one",2); +update t1 set test=test+1 where pr_page > 1; +delete from t1 where test=1; + +select * from t1; +sync_slave_with_master; +connection slave; +select * from t1; +connection master; + + +set binlog_format=row; +insert into t1 (pr_page, pr_type, test) values(3,"three",0),(4,"four",4),(5, "five", 0); +replace into t1 (pr_page, pr_type,test) values(3,"one",2); +update t1 set test=test+1 where pr_page > 3; +delete from t1 where test=1; + +select * from t1; +sync_slave_with_master; +connection slave; +select * from t1; +connection master; + + +set binlog_row_image=minimal; +insert into t1 (pr_page, pr_type, test) values(6,"six",0),(7,"seven",7),(8, "eight", 0); +replace into t1 (pr_page, pr_type,test) values(6,"six",2); +update t1 set test=test+1 where pr_page > 6; +delete from t1 where test=1; + +select * from t1; +sync_slave_with_master; +connection slave; +select * from t1; +connection master; +drop table t1; + +set global log_bin_compress=@old_log_bin_compress; +set global log_bin_compress_min_len=@old_log_bin_compress_min_len; +set binlog_format=@old_binlog_format; +set binlog_row_image=@old_binlog_row_image; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_binlog_corruption.test b/mysql-test/suite/rpl/t/rpl_binlog_corruption.test new file mode 100644 index 00000000..66b0c80f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_binlog_corruption.test @@ -0,0 +1,50 @@ +# ==== Purpose ==== +# +# Verify that the slave stops gracefully when reading a relay log with +# corrupted data. +# +# ==== Implementation ==== +# +# Setup "fake replication" where the slave only starts the SQL thread, +# not the IO thread, and reads from an existing relay log that has +# been prepared so that it contains the error. This requires some +# extra server options: see the -master.opt file. +# +# ==== Related bugs ==== +# +# BUG#31793: log event corruption causes crash +# BUG#40482: server/mysqlbinlog crashes when reading invalid Incident_log_event + +--source include/master-slave.inc + +# BUG#40482 only manifested itself in debug-compiled binaries. +-- source include/have_debug.inc + +--connection slave +call mtr.add_suppression('Found invalid event in binary log'); +call mtr.add_suppression('Slave SQL.*Relay log read failure: Could not parse relay log event entry.* 1594'); + +# +# BUG#40482: server/mysqlbinlog crashes when reading invalid Incident_log_event +# +# The relay log contains an Incident_log_event with a non-existing +# incident number. + +--echo ==== Initialize ==== +--source include/stop_slave.inc +RESET SLAVE; + +let $fake_relay_log= $MYSQL_TEST_DIR/std_data/bug40482-bin.000001; +source include/setup_fake_relay_log.inc; + +--echo ==== Test ==== +START SLAVE SQL_THREAD; +let $slave_sql_errno= 1594; # ER_SLAVE_RELAY_LOG_READ_FAILURE +source include/wait_for_slave_sql_error.inc; +let $error= query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1); +--echo Last_SQL_Error = $error + +--echo ==== Clean up ==== +source include/cleanup_fake_relay_log.inc; +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_binlog_dump_slave_gtid_state_info.test b/mysql-test/suite/rpl/t/rpl_binlog_dump_slave_gtid_state_info.test new file mode 100644 index 00000000..bba41295 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_binlog_dump_slave_gtid_state_info.test @@ -0,0 +1,121 @@ +# ==== Purpose ==== +# +# Test verifies that Start binlog_dump message will report GTID position +# requested by slave when log_warnings > 1. +# +# ==== Implementation ==== +# +# Steps: +# 0 - Have LOG_WARNINGS=2 +# 1 - On a fresh slave server which has not replicated any GTIDs execute +# "CHANGE MASTER TO MASTER_USE_GTID=slave_pos;" command. Start the +# slave. +# 2 - In Master error log verify that pattern "using_gtid(1), gtid('')" is +# present. +# 3 - On slave server do STOP SLAVE and execute "CHANGE MASTER TO +# MASTER_USE_GTID=no;" command. Start the slave threads. +# 4 - In Master error log verify that pattern "using_gtid(0), gtid('')" is +# present. +# 5- Execute a DDL and DML on master server. This will generated two GTIDs +# on the master server ('0-1-2'). Sync the slave server with master. +# 6 - On slave do STOP SLAVE and execute "CHANGE MASTER TO +# MASTER_USE_GTID=slave_pos;" command. Start slave threads. +# 7 - In Master error verify that pattern "using_gtid(1), gtid('0-1-2')" is +# present. +# 8 - On Master change domain ID to 10 and execute a DML operation. It will +# generate a GTID 10-1-1. +# 9 - On slave do STOP SLAVE and execute "CHANGE MASTER TO +# MASTER_USE_GTID=slave_pos;" command. Start slave threads. +# 10 -In Master error verify that pattern "using_gtid(1), +# gtid('0-1-2,10-1-1')" is present. +# +# ==== References ==== +# +# MDEV-20428: "Start binlog_dump" message doesn't indicate GTID position +# + +--source include/have_binlog_format_mixed.inc +--source include/have_innodb.inc +--source include/master-slave.inc + +--connection master +SET GLOBAL LOG_WARNINGS=2; + +--connection slave +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc + +--connection master +# Check error log for correct messages. +let $log_error_= `SELECT @@GLOBAL.log_error`; +if(!$log_error_) +{ + # MySQL Server on windows is started with --console and thus + # does not know the location of its .err log, use default location + let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.1.err; +} +--echo "Test Case 1: Start binlog_dump to slave_server(#), pos(master-bin.000001, ###), using_gtid(1), gtid('')" +--let SEARCH_FILE=$log_error_ +--let SEARCH_RANGE=-50000 +--let SEARCH_PATTERN=using_gtid\(1\), gtid\(\'\'\).* +--source include/search_pattern_in_file.inc + +--connection slave +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=no; +--source include/start_slave.inc + +--connection master +--echo "Test Case 2: Start binlog_dump to slave_server(#), pos(master-bin.000001, ###), using_gtid(0), gtid('')" +--let SEARCH_FILE=$log_error_ +--let SEARCH_RANGE=-50000 +--let SEARCH_PATTERN=using_gtid\(0\), gtid\(\'\'\).* +--source include/search_pattern_in_file.inc +CREATE TABLE t (f INT) ENGINE=INNODB; +INSERT INTO t VALUES(10); +save_master_pos; + +--connection slave +sync_with_master; + +--connection slave +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc + +--connection master +--echo "Test Case 3: Start binlog_dump to slave_server(#), pos(master-bin.000001, ###), using_gtid(1), gtid('0-1-2')" +--let SEARCH_FILE=$log_error_ +--let SEARCH_RANGE=-50000 +--let SEARCH_PATTERN=using_gtid\(1\), gtid\(\'0-1-2\'\).* +--source include/search_pattern_in_file.inc +SET @@SESSION.gtid_domain_id=10; +INSERT INTO t VALUES(20); +save_master_pos; + +--connection slave +sync_with_master; + +--connection slave +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc + +--connection master +--echo "Test Case 4: Start binlog_dump to slave_server(#), pos(master-bin.000001, ###), using_gtid(1), gtid('0-1-2,10-1-1')" +--let SEARCH_FILE=$log_error_ +--let SEARCH_RANGE=-50000 +--let SEARCH_PATTERN=using_gtid\(1\), gtid\(\'0-1-2,10-1-1\'\).* +--source include/search_pattern_in_file.inc + +--echo "===== Clean up =====" +--connection slave +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=no; +--source include/start_slave.inc + +--connection master +DROP TABLE t; +SET GLOBAL LOG_WARNINGS=default; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_binlog_dup_entry.test b/mysql-test/suite/rpl/t/rpl_binlog_dup_entry.test new file mode 100644 index 00000000..869c715f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_binlog_dup_entry.test @@ -0,0 +1,72 @@ +# ==== Purpose ==== +# +# Test verifies that there are no duplicate entries in binlog (i.e a safe +# statement which follows an unsafe statement gets logged in both row format +# and statement format resulting in duplicate entry) when binlog-format=MIXED +# and LOCK TABLES are enabled. +# +# ==== Implementation ==== +# +# Steps: +# 1 - Create three tables t1,t2 and t3 with AUTO_INCREMENT on. +# 2 - Create a trigger on table t3, so that trigger execution results in +# unsafe statement. Note query that modifies autoinc column in +# sub-statement can make the master and slave inconsistent. Hence they +# are logged in row format. +# 3 - Lock tables t1,t2 and t3. +# 4 - Execute an unsafe update which modifies tables t1 and t3. But since t2 +# table is also locked its table map event also gets written into the +# binary log during the execution of update. +# 5 - Execute a safe DML operation using table 't2' and verify that master +# doesn't report any assert. +# 6 - Ensure that slave is in sync with master and data is consistent. +# +# ==== References ==== +# +# MDEV-19158: MariaDB 10.2.22 is writing duplicate entries into binary log + +--source include/have_binlog_format_mixed.inc +--source include/master-slave.inc + +CREATE TABLE t1 (id mediumint(8) unsigned NOT NULL AUTO_INCREMENT, someLabel varchar(30) NOT NULL, flag tinyint(1) NOT NULL DEFAULT 0, PRIMARY KEY (id)) Engine=MyISAM; +CREATE TABLE t2 (id mediumint(8) unsigned NOT NULL AUTO_INCREMENT, data varchar(30) NOT NULL, status tinyint(1) NOT NULL, PRIMARY KEY (id)) Engine=MyISAM; +CREATE TABLE t3 (id mediumint(8) unsigned NOT NULL AUTO_INCREMENT, t1id mediumint(8) unsigned NOT NULL, flag tinyint(1) NOT NULL DEFAULT 0, status tinyint(1) NOT NULL DEFAULT 0, PRIMARY KEY (id)) Engine=MyISAM; + +INSERT INTO t1 ( id, someLabel, flag ) VALUES ( 1, 'ABC', 0 ); + +DELIMITER |; + +CREATE OR REPLACE TRIGGER doNothing +BEFORE UPDATE ON t1 +FOR EACH ROW + BEGIN + IF + new.someLabel != old.someLabel + THEN + UPDATE t3 SET t3.flag = 0; + END IF; + END| + +DELIMITER ;| + +FLUSH LOGS; + +LOCK TABLES t1 WRITE, t2 WRITE; +INSERT INTO t2 (data, status) VALUES ('1', 4); +UPDATE t1 SET flag = 1 WHERE id = 1; +INSERT INTO t2 (data, status) VALUES ('2', 4); +UNLOCK TABLES; + +sync_slave_with_master; + +let $diff_tables= master:t1, slave:t1; +--source include/diff_tables.inc +let $diff_tables= master:t2, slave:t2; +--source include/diff_tables.inc +let $diff_tables= master:t3, slave:t3; +--source include/diff_tables.inc + +--connection master +DROP TABLE t1, t2, t3; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_binlog_errors-master.opt b/mysql-test/suite/rpl/t/rpl_binlog_errors-master.opt new file mode 100644 index 00000000..f8e46a44 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_binlog_errors-master.opt @@ -0,0 +1 @@ +--max_binlog_size=4096 diff --git a/mysql-test/suite/rpl/t/rpl_binlog_errors.test b/mysql-test/suite/rpl/t/rpl_binlog_errors.test new file mode 100644 index 00000000..4dbd8eca --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_binlog_errors.test @@ -0,0 +1,447 @@ +# +# This include file is used by more than one test suite +# (currently rpl and binlog_encryption). +# Please check all dependent tests after modifying it +# +# Usage: +# --let $binlog_limit= X[,Y] # optional +# +# Semantics of the value is the same as in include/show_binlog_events.inc +# which the script calls as a part of the test flow. +# The goal is to print the event demonstrating the triggered error, +# so normally Y should be 1 (print the exact event only); +# however, depending on test-specific server options, the offset X +# can be different. +# + +# BUG#46166: MYSQL_BIN_LOG::new_file_impl is not propagating error +# when generating new name. +# +# WHY +# === +# +# We want to check whether error is reported or not when +# new_file_impl fails (this may happen when rotation is not +# possible because there is some problem finding an +# unique filename). +# +# HOW +# === +# +# Test cases are documented inline. + +-- source include/have_innodb.inc +-- source include/have_debug.inc +-- source include/master-slave.inc + +-- echo ####################################################################### +-- echo ####################### PART 1: MASTER TESTS ########################## +-- echo ####################################################################### + + +### ACTION: stopping slave as it is not needed for the first part of +### the test + +-- connection slave +-- source include/stop_slave.inc +-- connection master + +call mtr.add_suppression("Can't generate a unique log-filename"); +call mtr.add_suppression("Writing one row to the row-based binary log failed.*"); +call mtr.add_suppression("Error writing file .*"); +call mtr.add_suppression("Could not use master-bin for logging"); + +SET @old_debug= @@global.debug_dbug; + +### ACTION: create a large file (> 4096 bytes) that will be later used +### in LOAD DATA INFILE to check binlog errors in its vacinity +-- let $load_file= $MYSQLTEST_VARDIR/tmp/bug_46166.data +-- let $MYSQLD_DATADIR= `select @@datadir` +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--disable_ps2_protocol +-- eval SELECT repeat('x',8192) INTO OUTFILE '$load_file' +--enable_ps2_protocol + +### ACTION: create a small file (< 4096 bytes) that will be later used +### in LOAD DATA INFILE to check for absence of binlog errors +### when file loading this file does not force flushing and +### rotating the binary log +-- let $load_file2= $MYSQLTEST_VARDIR/tmp/bug_46166-2.data +-- let $MYSQLD_DATADIR= `select @@datadir` +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--disable_ps2_protocol +-- eval SELECT repeat('x',10) INTO OUTFILE '$load_file2' +--enable_ps2_protocol + +RESET MASTER; + +-- echo ###################### TEST #1 + +### ASSERTION: no problem flushing logs (should show two binlogs) +FLUSH LOGS; +-- echo # assert: must show two binlogs +-- source include/show_binary_logs.inc + +-- echo ###################### TEST #2 + +### ASSERTION: check that FLUSH LOGS actually fails and reports +### failure back to the user if find_uniq_filename fails +### (should show just one binlog) + +RESET MASTER; +SET @@global.debug_dbug="d,error_unique_log_filename"; +-- error ER_NO_UNIQUE_LOGFILE +FLUSH LOGS; +-- echo # assert: must show one binlog +-- source include/show_binary_logs.inc + +### ACTION: clean up and move to next test +SET @@global.debug_dbug=@old_debug; +RESET MASTER; + +-- echo ###################### TEST #3 + +### ACTION: create some tables (t1, t2, t4) and insert some values in +### table t1 +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a VARCHAR(16384)) Engine=InnoDB; +CREATE TABLE t4 (a VARCHAR(16384)); +INSERT INTO t1 VALUES (1); +RESET MASTER; + +### ASSERTION: we force rotation of the binary log because it exceeds +### the max_binlog_size option (should show two binary +### logs) + +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- eval LOAD DATA INFILE '$load_file' INTO TABLE t2 + +# shows two binary logs +-- echo # assert: must show two binlog +-- source include/show_binary_logs.inc + +# clean up the table and the binlog to be used in next part of test +SET @@global.debug_dbug=@old_debug; +DELETE FROM t2; +RESET MASTER; + +-- echo ###################### TEST #4 + +### ASSERTION: load the big file into a transactional table and check +### that it reports error. The table will contain the +### changes performed despite the fact that it reported an +### error. + +SET @@global.debug_dbug="d,error_unique_log_filename"; +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- error ER_NO_UNIQUE_LOGFILE +-- eval LOAD DATA INFILE '$load_file' INTO TABLE t2 + +# show table +-- echo # assert: must show one entry +SELECT count(*) FROM t2; + +# clean up the table and the binlog to be used in next part of test +SET @@global.debug_dbug=@old_debug; +DELETE FROM t2; +RESET MASTER; + +-- echo ###################### TEST #5 + +### ASSERTION: load the small file into a transactional table and +### check that it succeeds + +SET @@global.debug_dbug="d,error_unique_log_filename"; +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- eval LOAD DATA INFILE '$load_file2' INTO TABLE t2 + +# show table +-- echo # assert: must show one entry +SELECT count(*) FROM t2; + +# clean up the table and the binlog to be used in next part of test +SET @@global.debug_dbug=@old_debug; +DELETE FROM t2; +RESET MASTER; + +-- echo ###################### TEST #6 + +### ASSERTION: check that even if one is using a transactional table +### and explicit transactions (no autocommit) if rotation +### fails we get the error. Transaction is not rolledback +### because rotation happens after the commit. + +SET @@global.debug_dbug="d,error_unique_log_filename"; +SET AUTOCOMMIT=0; +INSERT INTO t2 VALUES ('muse'); +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- eval LOAD DATA INFILE '$load_file' INTO TABLE t2 +INSERT INTO t2 VALUES ('muse'); +-- error ER_NO_UNIQUE_LOGFILE +COMMIT; + +### ACTION: Show the contents of the table after the test +-- echo # assert: must show three entries +SELECT count(*) FROM t2; + +### ACTION: clean up and move to the next test +SET AUTOCOMMIT= 1; +SET @@global.debug_dbug=@old_debug; +DELETE FROM t2; +RESET MASTER; + +-- echo ###################### TEST #7 + +### ASSERTION: check that on a non-transactional table, if rotation +### fails then an error is reported and an incident event +### is written to the current binary log. + +SET @@global.debug_dbug="d,error_unique_log_filename"; + +# Disable logging Annotate_rows events to preserve events count. +let $binlog_annotate_row_events_saved= `SELECT @@binlog_annotate_row_events`; +SET @@binlog_annotate_row_events= 0; + +SELECT count(*) FROM t4; +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- error ER_NO_UNIQUE_LOGFILE +-- eval LOAD DATA INFILE '$load_file' INTO TABLE t4 + +-- echo # assert: must show 1 entry +SELECT count(*) FROM t4; + +-- echo ### check that the incident event is written to the current log +SET @@global.debug_dbug=@old_debug; +if (!$binlog_limit) +{ + -- let $binlog_limit= 4,1 +} +-- source include/show_binlog_events.inc + +# clean up and move to next test +DELETE FROM t4; + +--disable_query_log +eval SET @@binlog_annotate_row_events= $binlog_annotate_row_events_saved; +--enable_query_log + +RESET MASTER; + +-- echo ###################### TEST #8 + +### ASSERTION: check that statements end up in error but they succeed +### on changing the data. + +SET @@global.debug_dbug="d,error_unique_log_filename"; +-- echo # must show 0 entries +SELECT count(*) FROM t4; +SELECT count(*) FROM t2; + +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- error ER_NO_UNIQUE_LOGFILE +-- eval LOAD DATA INFILE '$load_file' INTO TABLE t4 +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- error ER_NO_UNIQUE_LOGFILE +-- eval LOAD DATA INFILE '$load_file' INTO TABLE t2 +-- error ER_NO_UNIQUE_LOGFILE +INSERT INTO t2 VALUES ('aaa'), ('bbb'), ('ccc'); + +-- echo # INFO: Count(*) Before Offending DELETEs +-- echo # assert: must show 1 entry +SELECT count(*) FROM t4; +-- echo # assert: must show 4 entries +SELECT count(*) FROM t2; + +-- error ER_NO_UNIQUE_LOGFILE +DELETE FROM t4; +-- error ER_NO_UNIQUE_LOGFILE +DELETE FROM t2; + +-- echo # INFO: Count(*) After Offending DELETEs +-- echo # assert: must show zero entries +SELECT count(*) FROM t4; +SELECT count(*) FROM t2; + +# remove fault injection +SET @@global.debug_dbug=@old_debug; + +-- echo ###################### TEST #9 + +### ASSERTION: check that if we disable binlogging, then statements +### succeed. +SET @@global.debug_dbug="d,error_unique_log_filename"; +SET SQL_LOG_BIN=0; +INSERT INTO t2 VALUES ('aaa'), ('bbb'), ('ccc'), ('ddd'); +INSERT INTO t4 VALUES ('eee'), ('fff'), ('ggg'), ('hhh'); +-- echo # assert: must show four entries +SELECT count(*) FROM t2; +SELECT count(*) FROM t4; +DELETE FROM t2; +DELETE FROM t4; +-- echo # assert: must show zero entries +SELECT count(*) FROM t2; +SELECT count(*) FROM t4; +SET SQL_LOG_BIN=1; +SET @@global.debug_dbug=@old_debug; + +-- echo ###################### TEST #10 + +### ASSERTION: check that error is reported if there is a failure +### while registering the index file and the binary log +### file or failure to write the rotate event. + +call mtr.add_suppression("MYSQL_BIN_LOG::open failed to sync the index file."); +call mtr.add_suppression("Could not use .*"); + +RESET MASTER; +SHOW WARNINGS; + +# +d,fault_injection_registering_index => injects fault on MYSQL_BIN_LOG::open +SET @@global.debug_dbug="d,fault_injection_registering_index"; +-- replace_regex /\.[\\\/]master/master/ +-- error ER_CANT_OPEN_FILE +FLUSH LOGS; +SET @@global.debug_dbug=@old_debug; + +-- error ER_NO_BINARY_LOGGING +SHOW BINARY LOGS; + +# issue some statements and check that they don't fail +CREATE TABLE t5 (a INT); +INSERT INTO t4 VALUES ('bbbbb'); +INSERT INTO t2 VALUES ('aaaaa'); +DELETE FROM t4; +DELETE FROM t2; +DROP TABLE t5; +flush tables; + +-- echo ###################### TEST #11 + +### ASSERTION: check that error is reported if there is a failure +### while opening the index file and the binary log file or +### failure to write the rotate event. + +# restart the server so that we have binlog again +--let $rpl_server_number= 1 +--source include/rpl_restart_server.inc + +# +d,fault_injection_openning_index => injects fault on MYSQL_BIN_LOG::open_index_file +SET @@global.debug_dbug="d,fault_injection_openning_index"; +-- replace_regex /\.[\\\/]master/master/ +-- error ER_CANT_OPEN_FILE +FLUSH LOGS; +SET @@global.debug_dbug=@old_debug; + +-- error ER_FLUSH_MASTER_BINLOG_CLOSED +RESET MASTER; + +# issue some statements and check that they don't fail +CREATE TABLE t5 (a INT); +INSERT INTO t4 VALUES ('bbbbb'); +INSERT INTO t2 VALUES ('aaaaa'); +DELETE FROM t4; +DELETE FROM t2; +DROP TABLE t5; +flush tables; + +# restart the server so that we have binlog again +--let $rpl_server_number= 1 +--source include/rpl_restart_server.inc + +-- echo ###################### TEST #12 + +### ASSERTION: check that error is reported if there is a failure +### while writing the rotate event when creating a new log +### file. + +# +d,fault_injection_new_file_rotate_event => injects fault on MYSQL_BIN_LOG::MYSQL_BIN_LOG::new_file_impl +SET @@global.debug_dbug="d,fault_injection_new_file_rotate_event"; +-- error ER_ERROR_ON_WRITE +FLUSH LOGS; +SET @@global.debug_dbug=@old_debug; + +-- error ER_FLUSH_MASTER_BINLOG_CLOSED +RESET MASTER; + +# issue some statements and check that they don't fail +CREATE TABLE t5 (a INT); +INSERT INTO t4 VALUES ('bbbbb'); +INSERT INTO t2 VALUES ('aaaaa'); +DELETE FROM t4; +DELETE FROM t2; +DROP TABLE t5; +flush tables; + +# restart the server so that we have binlog again +--let $rpl_server_number= 1 +--source include/rpl_restart_server.inc + +## clean up +DROP TABLE t1, t2, t4; +RESET MASTER; + +# restart slave again +-- connection slave +-- source include/start_slave.inc +-- connection master + +-- echo ####################################################################### +-- echo ####################### PART 2: SLAVE TESTS ########################### +-- echo ####################################################################### + +### setup +--source include/rpl_reset.inc +-- connection slave + +# Slave tests rely on logic of non-gtid mode +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=NO; +--source include/start_slave.inc + +# slave suppressions + +call mtr.add_suppression("Slave I/O: Relay log write failure: could not queue event from master.*"); +call mtr.add_suppression("Error writing file .*"); +call mtr.add_suppression("Could not use .*"); +call mtr.add_suppression("MYSQL_BIN_LOG::open failed to sync the index file."); +call mtr.add_suppression("Can't generate a unique log-filename .*"); +-- echo ###################### TEST #13 + +#### ASSERTION: check against unique log filename error +-- let $io_thd_injection_fault_flag= error_unique_log_filename +-- let $slave_io_errno= 1595 +-- let $show_slave_io_error= 1 +-- source include/io_thd_fault_injection.inc + +-- echo ###################### TEST #14 + +#### ASSERTION: check against rotate failing +-- let $io_thd_injection_fault_flag= fault_injection_new_file_rotate_event +-- let $slave_io_errno= 1595 +-- let $show_slave_io_error= 1 +-- source include/io_thd_fault_injection.inc + +-- echo ###################### TEST #15 + +#### ASSERTION: check against relay log open failure +-- let $io_thd_injection_fault_flag= fault_injection_registering_index +-- let $slave_io_errno= 1595 +-- let $show_slave_io_error= 1 +-- source include/io_thd_fault_injection.inc + +-- echo ###################### TEST #16 + +#### ASSERTION: check against relay log index open failure +-- let $io_thd_injection_fault_flag= fault_injection_openning_index +-- let $slave_io_errno= 1595 +-- let $show_slave_io_error= 1 +-- source include/io_thd_fault_injection.inc + +### clean up +-- source include/stop_slave_sql.inc +RESET SLAVE; +RESET MASTER; +--remove_file $load_file +--remove_file $load_file2 +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_binlog_grant.test b/mysql-test/suite/rpl/t/rpl_binlog_grant.test new file mode 100644 index 00000000..f8513021 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_binlog_grant.test @@ -0,0 +1,42 @@ +-- source include/have_innodb.inc +-- source include/not_embedded.inc +-- source include/have_binlog_format_mixed_or_statement.inc +source include/master-slave.inc; + +let $VERSION=`select version()`; + +# Bug #21975: grant/revoke statements in transaction +# used to disappear from binlog upon rallback. +# Now GRANT/REVOKE do implicitly commit +# transaction + +create database d1; +use d1; +create table t (s1 int) engine=innodb; +set @@autocommit=0; +start transaction; +insert into t values (1); +create user x@y; +grant select on t to x@y; +let $wait_binlog_event= grant select; +source include/wait_for_binlog_event.inc; +# +# There is no active transaction here +# +rollback; +show grants for x@y; +start transaction; +insert into t values (2); +revoke select on t from x@y; +let $wait_binlog_event= revoke select; +source include/wait_for_binlog_event.inc; +# +# There is no active transaction here +# +commit; +select * from t; +show grants for x@y; +drop user x@y; +drop database d1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_binlog_index.test b/mysql-test/suite/rpl/t/rpl_binlog_index.test new file mode 100644 index 00000000..6112affb --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_binlog_index.test @@ -0,0 +1,217 @@ +# ==== Purpose ==== +# +# Test that server can work fine after moving binlog or relay log +# files to another directory and setting binlog or relay log paths to +# the new path. +# +# ==== Method ==== +# +# Start replication, and then shutdown the master, move the binary +# logs and the log index file to a another directory and then restart +# the server with option to set the new binlog directory. After master +# restarted successfully, do the similar on slave to check the relay +# log of slave. +# +# ==== Reference ==== +# +# BUG#12133 master.index file keeps mysqld from starting if bin log has been moved +# BUG#42576 Relay logs in relay-log.info&localhost-relay-bin.index not processed after move + +# Since this test relies heavily on filesystem operations (like +# moving files around, backslashes and so forth) we avoid messing +# around with windows access violations for not cluttering the +# test case any further. It is prepared to support windows, but +# it is not 100% compliant. +--source include/not_windows.inc + +source include/master-slave.inc; +# There is no need to run this test case on all binlog format +source include/have_binlog_format_row.inc; + +connection master; +--let $master_datadir= `select @@datadir` +connection slave; +--let $slave_datadir= `select @@datadir` +connection master; +--let $dirname= `select uuid()` +--let $tmpdir= $MYSQLTEST_VARDIR/tmp/$dirname +--mkdir $tmpdir + +CREATE TABLE t1 (a INT); +# flush to generate one more binlog file. +FLUSH BINARY LOGS; +INSERT INTO t1 VALUES (1); + +sync_slave_with_master; +--source include/stop_slave.inc +# +# Test on master +# +connection master; +--echo # Shutdown master +--let $rpl_server_number=1 +source include/rpl_stop_server.inc; + +--echo # Move the master binlog files and the index file to a new place +--move_file $master_datadir/master-bin.000001 $tmpdir/master-bin.000001 +--move_file $master_datadir/master-bin.000002 $tmpdir/master-bin.000002 +--move_file $master_datadir/master-bin.index $tmpdir/master-bin.index + +--echo # Restart master with log-bin option set to the new path +--let $rpl_server_parameters=--log-bin=$tmpdir/master-bin --log-bin-index=$tmpdir/master-bin +--let $keep_include_silent=1 +source include/rpl_start_server.inc; +--let $keep_include_silent=0 + +--echo # Master has restarted successfully +--connection slave +--source include/start_slave.inc +--connection master +# +# Test master can handle old format with directory path in index file +# +--let $is_windows= `select convert(@@version_compile_os using latin1) in ('Win32', 'Win64', 'Windows')` + +# write_var_to_file.inc will call SELECT INTO DUMPFILE, which has to be +# done before shutdown the server +--echo # Create the master-bin.index file with the old format +--let $write_to_file= $master_datadir/master-bin.index +if ($is_windows) +{ + --let $write_var= .\\\\master-bin.000001\n.\\\\master-bin.000002\n.\\\\master-bin.000003\n +} +if (!$is_windows) +{ + --let $write_var= ./master-bin.000001\n./master-bin.000002\n./master-bin.000003\n +} +--disable_query_log +source include/write_var_to_file.inc; +--enable_query_log +--sync_slave_with_master +--source include/stop_slave.inc + +--connection master +--echo # Shutdown master +--let $rpl_server_number=1 +source include/rpl_stop_server.inc; + +--echo # Move back the master binlog files +--move_file $tmpdir/master-bin.000001 $master_datadir/master-bin.000001 +--move_file $tmpdir/master-bin.000002 $master_datadir/master-bin.000002 +--move_file $tmpdir/master-bin.000003 $master_datadir/master-bin.000003 + +--echo # Remove the unneeded master-bin.index file +--remove_file $tmpdir/master-bin.index + +--echo # Restart master with log-bin option set to default +--let $rpl_server_parameters=--log-bin=$master_datadir/master-bin --log-bin-index=$master_datadir/master-bin +--let $keep_include_silent=1 +source include/rpl_start_server.inc; +--let $keep_include_silent=0 + +--echo # Master has restarted successfully +--connection slave +--source include/start_slave.inc + +--connection master +--sync_slave_with_master +--echo # stop slave +--source include/stop_slave.inc +--let $rpl_server_number= 2 +--source include/rpl_stop_server.inc + +# switch to master because the slave has been shutdown +# and relocate_binlogs requires a running server to do +# SQL operations +--connection master + +--let $relocate_disable_query_log= 1 +--let $relocate_is_windows= $is_windows +--let $relocate_from=$slave_datadir +--let $relocate_into=$tmpdir + +--echo # relocate binlogs +--let $relocate_index_file=$slave_datadir/slave-bin.index +--source include/relocate_binlogs.inc + +--echo # relocate relay logs +--let $relocate_index_file=$slave_datadir/slave-relay-bin.index +--source include/relocate_binlogs.inc + +--echo # Restart slave with options log-bin, relay-log set to the new paths +--let $rpl_server_parameters=--log-bin=$tmpdir/slave-bin --relay-log=$tmpdir/slave-relay-bin --relay-log-index=$tmpdir/slave-relay-bin.index +--let $keep_include_silent=1 +--let $rpl_server_number= 2 +source include/rpl_start_server.inc; +--let $keep_include_silent=0 + +--connection slave + +--echo # Slave server has restarted successfully +--source include/start_slave.inc +--source include/stop_slave.inc + +connection master; +FLUSH LOGS; +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (2); + +FLUSH LOGS; + +connection slave; +FLUSH LOGS; +--source include/start_slave.inc +connection master; +sync_slave_with_master; +--let $diff_tables= master:t1,slave:t1 +source include/diff_tables.inc; + +connection master; +DROP TABLE t1; +--sync_slave_with_master +--source include/stop_slave.inc +--let $rpl_server_number= 2 +--source include/rpl_stop_server.inc + +--connection master + +--let $relocate_from=$tmpdir +--let $relocate_into=$slave_datadir +--let $relocate_recreate_index= 1 + +# binlogs +--let $relocate_index_file=$tmpdir/slave-bin.index +--source include/relocate_binlogs.inc + +# relay logs + +# since the complete fix for the relocation of logs is +# done in BUG#13428851 it does not help here to try +# to start the slave as it would fail (relay-log.info is +# tainted with the full path in the RELAY_LOG_FILE position). +# Instead, we reset the slave and let the test clean up. +--let $relocate_fix_relay_log_info= $slave_datadir/relay-log.info +--let $relocate_index_file=$tmpdir/slave-relay-bin.index +--source include/relocate_binlogs.inc + +--echo # remove tmpdir +--remove_files_wildcard $tmpdir * +--rmdir $tmpdir + +--echo # restarted with previous slave settings +--let $rpl_server_parameters=--log-bin=$slave_datadir/slave-bin --relay-log=$slave_datadir/slave-relay-bin --relay-log-index=$slave_datadir/slave-relay-bin.index +--let $keep_include_silent=1 +--let $rpl_server_number= 2 +--source include/rpl_start_server.inc +--let $keep_include_silent=0 + +--connection slave + +# The slave will restart if we have fixed the relay-log.info +# correctly +--source include/start_slave.inc + +--connection master +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_binlog_rollback_cleanup.test b/mysql-test/suite/rpl/t/rpl_binlog_rollback_cleanup.test new file mode 100644 index 00000000..ed4d713f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_binlog_rollback_cleanup.test @@ -0,0 +1,46 @@ +# ==== Purpose ==== +# +# Test verifies that when flushing an event to binary log fails the transaction +# is successfully rolled back and following COMMIT command doesn't report any +# assert. +# +# ==== Implementation ==== +# +# Steps: +# 0 - SET max_binlog_cache_size=64K +# 1 - Create an Innodb table and insert required amount of data. Execute an +# UPDATE operation which generates a big update event whose size exceeds +# max_binlog_cache_size. +# 2 - Wait for error 1197. Execute COMMIT command. +# 3 - COMMIT should be successful. +# +# ==== References ==== +# +# MDEV-18514: Assertion `!writer.checksum_len || writer.remains == 0' failed +# +--source include/have_innodb.inc +--source include/have_binlog_format_row.inc +--source include/master-slave.inc +--connection master +let $old_max_binlog_cache_size= query_get_value(SHOW VARIABLES LIKE "max_binlog_cache_size", Value, 1); +SET GLOBAL max_binlog_cache_size = 65536; +CREATE TABLE t1(a INT PRIMARY KEY, data VARCHAR(30000)) ENGINE=INNODB; +let $data = `select concat('"', repeat('a',6000), '"')`; +let $data1 = `select concat('"', repeat('b',6000), '"')`; +--disable_query_log +eval INSERT INTO t1 (a, data) VALUES (1, CONCAT($data, $data)); +eval INSERT INTO t1 (a, data) VALUES (2, CONCAT($data, $data)); +eval INSERT INTO t1 (a, data) VALUES (3, CONCAT($data, $data)); +eval INSERT INTO t1 (a, data) VALUES (4, CONCAT($data, $data)); +eval INSERT INTO t1 (a, data) VALUES (5, CONCAT($data, $data)); +START TRANSACTION; +--error ER_TRANS_CACHE_FULL +eval UPDATE t1 SET data=$data1; +COMMIT; +--enable_query_log + +--replace_result $old_max_binlog_cache_size ORIGINAL_VALUE +--eval SET GLOBAL max_binlog_cache_size= $old_max_binlog_cache_size +DROP TABLE t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_bit.test b/mysql-test/suite/rpl/t/rpl_bit.test new file mode 100644 index 00000000..305a2abc --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_bit.test @@ -0,0 +1,92 @@ +############################################################################# +# Original Author: JBM # +# Original Date: Sept/15/2005 # +############################################################################# +# Test: To test the replication of the bit field # +############################################################################# +# Change Author: JBM +# Change Date: 2006-01-16 +########## + +-- source include/master-slave.inc + + +# Begin clean up test section +connection master; +--disable_warnings +DROP TABLE IF EXISTS test.t1; +--enable_warnings +# End of cleanup + +# Begin test section 1 + +CREATE TABLE test.t1 ( + dummyKey INTEGER NOT NULL, + f01 TINYINT, + f10 TINYINT, + f12 TINYINT, + f15 TINYINT, + f16 TINYINT, + f7 TINYINT, + f9 TINYINT, + f29 TINYINT, + f0 TINYINT, + fA1 TINYINT, + C32 TINYINT, + A42 TINYINT, + CA3 TINYINT, + A044 TINYINT, + f001 TINYINT, + A3002 TINYINT, + fC003 TINYINT, + CA300 TINYINT, + A305 TINYINT, + CA321 TINYINT, + r001 TINYINT, + bit1 BIT(6), + bit2 BIT(6), + bit3 BIT(6), + State1 TINYINT, + State2 TINYINT, + State3 TINYINT, + State4 TINYINT, + SubState TINYINT, + gState TINYINT, + oSupp TINYINT, + tSupp TINYINT, + sSuppD TINYINT, + mSuppf TINYINT, + GSuppDf TINYINT, + VNotSupp TINYINT, + x034 TINYINT, +PRIMARY KEY USING HASH (dummyKey) ); + +LOCK TABLES test.t1 WRITE; +INSERT INTO test.t1 VALUES (6,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'111111',b'111110',b'110101',4,5,5,5,5,5,5,5,5,5,3,2,1); +INSERT INTO test.t1 VALUES (1,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'111111',b'000000',b'100100',4,5,5,5,5,5,5,5,5,5,3,2,1); +INSERT INTO test.t1 VALUES (2,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'000000',b'101010',b'010101',4,5,5,5,5,5,5,5,5,5,3,2,1); +INSERT INTO test.t1 VALUES (3,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'101010',b'111111',b'000000',4,5,5,5,5,5,5,5,5,5,3,2,1); +INSERT INTO test.t1 VALUES (4,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,4,5,5,5,5,5,5,5,5,5,3,2,1); +INSERT INTO test.t1 VALUES (5,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,4,5,5,5,5,5,5,5,5,5,3,2,1); +INSERT INTO test.t1 VALUES (7,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,4,5,5,5,5,5,5,5,5,5,3,2,1); +INSERT INTO test.t1 VALUES (8,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,4,5,5,5,5,5,5,5,5,5,3,2,1); +UNLOCK TABLES; + + +SELECT oSupp, sSuppD, GSuppDf, VNotSupp, x034 FROM test.t1; +SELECT hex(bit1) FROM test.t1 ORDER BY bit1; +SELECT hex(bit2) from test.t1 ORDER BY bit2; +SELECT hex(bit3) from test.t1 ORDER BY bit3; +sync_slave_with_master; + +SELECT oSupp, sSuppD, GSuppDf, VNotSupp, x034 FROM test.t1; +SELECT hex(bit1) FROM test.t1 ORDER BY bit1; +SELECT hex(bit2) from test.t1 ORDER BY bit2; +SELECT hex(bit3) from test.t1 ORDER BY bit3; + +connection master; +DROP TABLE IF EXISTS test.t1; +sync_slave_with_master; + +# End of 5.0 test case +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_bit_npk.test b/mysql-test/suite/rpl/t/rpl_bit_npk.test new file mode 100644 index 00000000..d65ef66a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_bit_npk.test @@ -0,0 +1,113 @@ +############################################################################# +# Original Author: JBM # +# Original Date: Sept/15/2005 # +############################################################################# +# Test: To test the replication of the bit field # +############################################################################# + +-- source include/master-slave.inc + + +# Begin clean up test section +connection master; +--disable_warnings +DROP TABLE IF EXISTS test.t1; +--enable_warnings +# End of cleanup + +# Begin test section 1 + +CREATE TABLE test.t1 ( + dummyKey INTEGER NOT NULL, + f01 TINYINT, + f10 TINYINT, + f12 TINYINT, + f15 TINYINT, + f16 TINYINT, + f7 TINYINT, + f9 TINYINT, + f29 TINYINT, + f0 TINYINT, + fA1 TINYINT, + C32 TINYINT, + A42 TINYINT, + CA3 TINYINT, + A044 TINYINT, + f001 TINYINT, + A3002 TINYINT, + fC003 TINYINT, + CA300 TINYINT, + A305 TINYINT, + CA321 TINYINT, + r001 TINYINT, + bit1 BIT(6), + bit2 BIT(6), + bit3 BIT(6), + State1 TINYINT, + State2 TINYINT, + State3 TINYINT, + State4 TINYINT, + SubState TINYINT, + gState TINYINT, + oSupp TINYINT, + tSupp TINYINT, + sSuppD TINYINT, + mSuppf TINYINT, + GSuppDf TINYINT, + VNotSupp TINYINT, + x034 TINYINT); + +LOCK TABLES test.t1 WRITE; +INSERT INTO test.t1 VALUES (6,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'111111',b'111110',b'110101',4,5,5,5,5,5,5,5,5,5,3,NULL,1); +INSERT INTO test.t1 VALUES (1,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'111111',b'000000',b'100100',4,5,5,5,5,5,5,5,5,5,3,2,1); +INSERT INTO test.t1 VALUES (2,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'000000',b'101010',b'010101',4,5,5,5,5,5,5,5,5,5,3,2,1); +INSERT INTO test.t1 VALUES (3,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'101010',b'111111',b'000000',4,5,5,5,5,5,5,5,5,5,3,2,1); +INSERT INTO test.t1 VALUES (4,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'0',1,1,4,5,5,5,5,5,5,5,5,5,3,2,1); +INSERT INTO test.t1 VALUES (5,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,4,5,5,5,5,5,5,5,5,5,3,2,1); +INSERT INTO test.t1 VALUES (7,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,4,5,5,5,5,5,5,5,5,5,3,2,1); +INSERT INTO test.t1 VALUES (8,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,4,5,5,5,5,5,5,5,5,5,3,2,1); +UNLOCK TABLES; + +UPDATE test.t1 set x034 = 50 where bit3 = b'000000'; +UPDATE test.t1 set VNotSupp = 33 where bit1 = b'0'; +SELECT oSupp, sSuppD, GSuppDf, VNotSupp, x034 + FROM test.t1 + ORDER BY oSupp, sSuppD, GSuppDf, VNotSupp, x034; +SELECT hex(bit1) from test.t1 ORDER BY bit1; +SELECT hex(bit2) from test.t1 ORDER BY bit2; +SELECT hex(bit3) from test.t1 ORDER BY bit3; +sync_slave_with_master; + +SELECT oSupp, sSuppD, GSuppDf, VNotSupp, x034 + FROM test.t1 + ORDER BY oSupp, sSuppD, GSuppDf, VNotSupp, x034; +SELECT hex(bit1) from test.t1 ORDER BY bit1; +SELECT hex(bit2) from test.t1 ORDER BY bit2; +SELECT hex(bit3) from test.t1 ORDER BY bit3; + +connection master; +CREATE TABLE test.t2 (a INT, b BIT(1)); +INSERT INTO test.t2 VALUES (1, b'0'); +INSERT INTO test.t2 VALUES (1, b'1'); +UPDATE test.t2 SET a = 2 WHERE b = b'1'; + +CREATE TABLE test.t3 (a INT, b INT); +INSERT INTO test.t3 VALUES (1, NULL); +INSERT INTO test.t3 VALUES (1, 0); +UPDATE test.t3 SET a = 2 WHERE b = 0; + +SELECT a, hex(b) FROM test.t2 ORDER BY a,b; +SELECT * FROM test.t3 ORDER BY a,b; +sync_slave_with_master; + +SELECT a, hex(b) FROM test.t2 ORDER BY a,b; +SELECT * FROM test.t3 ORDER BY a,b; + +connection master; +DROP TABLE IF EXISTS test.t1; +DROP TABLE IF EXISTS test.t2; +DROP TABLE IF EXISTS test.t3; +sync_slave_with_master; + +# End of 5.0 test case +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_blackhole.test b/mysql-test/suite/rpl/t/rpl_blackhole.test new file mode 100644 index 00000000..927f0d80 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_blackhole.test @@ -0,0 +1,25 @@ +# PURPOSE. Test that blackhole works with replication in all three +# modes: STATEMENT, MIXED, and ROW. +# +# METHOD. We start by creating a table on the master and then change +# the engine to use blackhole on the slave. +# +# After insert/update/delete of one or more rows, the test the +# proceeds to check that replication is running after replicating an +# change, that the blackhole engine does not contain anything (which +# is just a check that the correct engine is used), and that something +# is written to the binary log. +# +# Whe check INSERT, UPDATE, and DELETE statement for tables with no +# key (forcing a range search on the slave), primary keys (using a +# primary key lookup), and index/key with multiple matches (forcing an +# index search). + +source include/have_blackhole.inc; +source include/master-slave.inc; + +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); + +source include/rpl_blackhole_basic.test; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_blackhole_row_annotate-master.opt b/mysql-test/suite/rpl/t/rpl_blackhole_row_annotate-master.opt new file mode 100644 index 00000000..91302791 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_blackhole_row_annotate-master.opt @@ -0,0 +1 @@ +--binlog_annotate_row_events --timezone=GMT-3 diff --git a/mysql-test/suite/rpl/t/rpl_blackhole_row_annotate-slave.opt b/mysql-test/suite/rpl/t/rpl_blackhole_row_annotate-slave.opt new file mode 100644 index 00000000..7ac6a84f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_blackhole_row_annotate-slave.opt @@ -0,0 +1 @@ +--binlog_annotate_row_events --replicate_annotate_row_events diff --git a/mysql-test/suite/rpl/t/rpl_blackhole_row_annotate.test b/mysql-test/suite/rpl/t/rpl_blackhole_row_annotate.test new file mode 100644 index 00000000..f7aefd62 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_blackhole_row_annotate.test @@ -0,0 +1,49 @@ +# ==== Purpose ==== +# +# Test verifies that when "replicate_annotate_row_events" are enabled on slave +# the DML operations on blackhole engine will be successful. It also ensures +# that Annotate events are logged into slave's binary log. +# +# ==== Implementation ==== +# +# Steps: +# 0 - Enable "replicate_annotate_row_events" on slave and do DML operations +# on master. +# 1 - Slave server will successfully apply the DML operations and it is in +# sync with master. +# 2 - Verify that the "show binlog events" prints all annotate events. +# 3 - Stream the slave's binary log using "mysqlbinlog" tool and verify +# that the Annotate events are being displayed. +# +# ==== References ==== +# +# MDEV-11094: Blackhole table updates on slave fail when row annotation is +# enabled + +source include/have_blackhole.inc; +source include/have_binlog_format_row.inc; +source include/binlog_start_pos.inc; +source include/master-slave.inc; + +SET timestamp=1000000000; +RESET MASTER; +connection slave; +SET timestamp=1000000000; +RESET MASTER; + +connection master; +source include/rpl_blackhole_basic.test; + +# Verify on slave. +connection slave; +FLUSH LOGS; +--replace_column 2 # 5 # +--replace_result $binlog_start_pos <start_pos> +--replace_regex /table_id: [0-9]+/table_id: #/ /\/\* xid=.* \*\//\/* xid= *\// +--eval show binlog events in 'slave-bin.000001' from $binlog_start_pos + +let $MYSQLD_DATADIR= `select @@datadir`; +--replace_regex /server id [0-9]*/server id #/ /server v [^ ]*/server v #.##.##/ /exec_time=[0-9]*/exec_time=#/ /thread_id=[0-9]*/thread_id=#/ /table id [0-9]*/table id #/ /mapped to number [0-9]*/mapped to number #/ /end_log_pos [0-9]*/end_log_pos #/ /# at [0-9]*/# at #/ /CRC32 0x[0-9a-f]*/CRC32 XXX/ /xid=\d*/xid=<xid>/ +--exec $MYSQL_BINLOG --base64-output=decode-rows --skip-gtid-strict-mode $MYSQLD_DATADIR/slave-bin.000001 + +source include/rpl_end.inc; diff --git a/mysql-test/suite/rpl/t/rpl_bug26395.test b/mysql-test/suite/rpl/t/rpl_bug26395.test new file mode 100644 index 00000000..0c1b2a7a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_bug26395.test @@ -0,0 +1,93 @@ +# ==== Purpose ==== +# +# Tests that an autocommitted XA transaction where the master crashes +# just before writing the XID log event is executed correctly. The +# master rolls back, so the slave should not execute statement. +# +# ==== Method ==== +# +# We want master to be alive so that it can replicate the statement to +# the slave. So in the test case, we must not crash the +# master. Instead, we fake the crash by just not writing the XID event +# to the binlog. This is done by the @@debug_dbug='d,do_not_write_xid' +# flag. This, in turn, requires us to do 'source +# include/have_debug.inc' +# +# So, unlike if the master had crashed, the master *will* execute the +# statement. But the slave should not execute it. Hence, after the +# test is executed, the expected result on master is a table with one +# row, and on slave a table with no rows. +# +# To simulate the slave correctly, we wait until everything up to but +# not including the XID is replicated. This has to be done with +# include/sync_slave_io_with_master.inc, not sync_slave_with_master, +# since the latter waits until the slave *SQL* thread has caught up +# with the master's position, which it will never do. +# +# +# ==== Related bugs ==== +# +# BUG#26395: if crash during autocommit update to transactional table on master, slave fails + +source include/have_innodb.inc; +# have_debug is needed since we use the @@debug variable on master +source include/have_debug.inc; +source include/master-slave.inc; + + +--echo ==== Initialize ==== + +--connection master + +CREATE TABLE tinnodb (a INT) ENGINE = INNODB; +SHOW CREATE TABLE tinnodb; + +# do_not_write_xid stops the master from writing an XID event. +set @old_debug= @@debug; +set @@debug_dbug= 'd,do_not_write_xid'; + + +--echo ==== Test ==== + +# Save the position up to which the slave SQL thread should execute. +save_master_pos; + +# Execute query and check that the row made it to the table. +INSERT INTO tinnodb VALUES (1); +SELECT * FROM tinnodb ORDER BY a; + +# Sync slave's IO thread. +--echo [on slave] +source include/sync_slave_io_with_master.inc; + +# Sync slave's SQL thread. +sync_with_master 0; + + +--echo ==== Verify results on slave ==== + +source include/stop_slave.inc; +let $tmp= query_get_value("SHOW SLAVE STATUS", Slave_IO_State, 1); +eval SELECT "$tmp" AS Slave_IO_State; +let $tmp= query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1); +eval SELECT "$tmp" AS Last_SQL_Error; +let $tmp= query_get_value("SHOW SLAVE STATUS", Last_IO_Error, 1); +eval SELECT "$tmp" AS Last_IO_Error; +SELECT * FROM tinnodb ORDER BY a; + + +--echo ==== Clean up ==== + +# Easiest to clean up master and slave separately, without +# replication, since master and slave are out of sync. + +connection master; +DROP TABLE tinnodb; +set @@debug_dbug= @old_debug; + +connection slave; +DROP TABLE tinnodb; + +# Warning: do not add more tests here. The binlog is in a bad state. +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_bug31076.test b/mysql-test/suite/rpl/t/rpl_bug31076.test new file mode 100644 index 00000000..7e523297 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_bug31076.test @@ -0,0 +1,151 @@ +if (`SELECT $PS_PROTOCOL != 0`) +{ + --skip Need regular protocol but ps-protocol was specified +} + +source include/have_binlog_format_mixed_or_row.inc; +source include/master-slave.inc; + +SET @saved_slave_type_conversions = @@slave_type_conversions; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = 'ALL_NON_LOSSY'; + +CREATE DATABASE track; +USE track; + +CREATE TABLE `visits` ( + `visits_id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `myid` varchar(32) NOT NULL DEFAULT '', + `src` varchar(64) NOT NULL DEFAULT '', + `ip` int(10) unsigned NOT NULL DEFAULT '0', + `cc` char(2) NOT NULL DEFAULT '', + `org` varchar(80) DEFAULT NULL, + `ref` varchar(255) NOT NULL DEFAULT '', + `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `host` varchar(30) NOT NULL DEFAULT '', + `entry` varchar(255) NOT NULL DEFAULT '', + `visit_exit` varchar(255) NOT NULL DEFAULT '', + `user_id` int(11) unsigned NOT NULL DEFAULT '0', + `visit_start` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + PRIMARY KEY (`visits_id`), + KEY `ip` (`ip`), + KEY `time` (`time`), + KEY `user_id` (`user_id`) +) ENGINE=MyISAM AUTO_INCREMENT=21293381 DEFAULT CHARSET=latin1; + +CREATE TABLE `visits_events` ( + `event_id` mediumint(8) unsigned NOT NULL DEFAULT '0', + `visit_id` int(11) unsigned NOT NULL DEFAULT '0', + `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `src` varchar(64) NOT NULL DEFAULT '', + `data` varchar(255) NOT NULL DEFAULT '', + `visits_events_id` int(11) unsigned NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`visits_events_id`), + KEY `event_id` (`event_id`), + KEY `visit_id` (`visit_id`), + KEY `data` (`data`) +) ENGINE=MyISAM AUTO_INCREMENT=33900731 DEFAULT CHARSET=latin1; + +/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/; +/*!40019 SET @@session.max_delayed_threads=0*/; +/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; +--delimiter /*!*/; + +# at 4 (0x4) +#071204 14:29:31 server id 1 end_log_pos 106 +# Position Timestamp Type Master ID Size Master Pos Flags +# 4 3b 56 55 47 0f 01 00 00 00 66 00 00 00 6a 00 00 00 00 00 +# 17 04 00 35 2e 31 2e 32 33 2d 72 63 2d 64 65 62 75 |..5.1.23.rc.debu| +# 27 67 2d 6c 6f 67 00 00 00 00 00 00 00 00 00 00 00 |g.log...........| +# 37 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +# 47 00 00 00 00 3b 56 55 47 13 38 0d 00 08 00 12 00 |.....VUG.8......| +# 57 04 04 04 04 12 00 00 53 00 04 1a 08 00 00 00 08 |.......S........| +# 67 08 08 02 |...| +# Start: binlog v 4, server v 5.1.23-rc-debug-log created 071204 14:29:31 at startup + +BINLOG ' +O1ZVRw8BAAAAZgAAAGoAAAAAAAQANS4xLjIzLXJjLWRlYnVnLWxvZwAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAA7VlVHEzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC +'/*!*/; + +# at 164170623 +# at 164170679 +#7918 3:59:2 server id 436 end_log_pos 164170679 +# 9c90b7f 06 4d ef 46 13 b4 01 00 00 38 00 00 00 b7 0b c9 |.M.F.....8......| +# 9c90b8f 09 00 00 99 57 17 02 00 00 00 00 05 74 72 61 63 |....W.......trac| +# 9c90b9f 6b 00 0d 76 69 |k..vi| +# Table_map: `track`.`visits_events` mapped to number 35084185 +#7918 3:59:2 server id 436 end_log_pos 164170769 +# 9c90bb7 06 4d ef 46 17 b4 01 00 00 5a 00 00 00 11 0c c9 |.M.F.....Z......| +# 9c90bc7 09 10 00 99 57 17 02 00 00 01 00 06 ff c0 20 4e |....W..........N| +# 9c90bd7 00 be f5 43 01 06 4d ef 46 00 2b 44 6f 77 6e 6c |...C..M.F..Downl| +# 9c90be7 6f 61 64 73 2f 4d 79 53 51 4c 2d 34 2e 31 2f 6d |oads.MySQL.4.1.m| +# 9c90bf7 79 73 71 6c 2d 34 2e |ysql.4.| +# Write_rows: table id 35084185 flags: STMT_END_F + +BINLOG ' +Bk3vRhO0AQAAOAAAALcLyQkAAJlXFwIAAAAABXRyYWNrAA12aXNpdHNfZXZlbnRzAAYJAwcPDwM= +Bk3vRhe0AQAAWgAAABEMyQkQAJlXFwIAAAEABv/AIE4AvvVDAQZN70YAK0Rvd25sb2Fkcy9NeVNR +TC00LjEvbXlzcWwtNC4xLjEyYS13aW4zMi56aXBPaAIC +'/*!*/; +# at 164170769 +#7918 3:59:2 server id 436 end_log_pos 164170797 +# 9c90c11 06 4d ef 46 05 b4 01 00 00 |.M.F.....| +# Intvar +SET INSERT_ID=21231039/*!*/; +# at 164170797 +#7918 3:59:2 server id 436 end_log_pos 164171293 +# 9c90c2d 06 4d ef 46 02 b4 01 00 00 f0 01 00 00 1d 0e c9 |.M.F............| +# 9c90c3d 09 10 00 28 80 af 01 00 00 00 00 05 00 00 1f 00 |................| +# 9c90c4d 00 00 40 00 00 01 00 00 00 00 00 00 00 00 06 03 |................| +# 9c90c5d 73 74 64 04 08 00 08 00 08 00 05 03 55 54 43 74 |std.........UTCt| +# 9c90c6d 72 61 63 6b 00 49 4e 53 45 52 54 20 49 4e 54 4f |rack.INSERT.INTO| +# 9c90c7d 20 76 69 73 69 74 73 20 28 6d 79 69 64 2c 20 75 |.visits..myid..u| +# 9c90c8d 73 65 72 5f 69 64 2c 20 73 72 63 2c 20 69 70 2c |ser.id..src..ip.| +# 9c90c9d 20 63 63 2c 20 6f 72 67 2c 20 72 65 66 2c 20 74 |.cc..org..ref..t| +# 9c90cad 69 6d 65 2c 20 68 6f 73 74 2c 20 65 6e 74 72 79 |ime..host..entry| +# 9c90cbd 2c 20 76 69 73 69 74 5f 65 78 69 74 2c 20 76 69 |..visit.exit..vi| +# 9c90ccd 73 69 74 5f 73 74 61 72 74 29 0a 09 09 09 56 41 |sit.start.....VA| +# 9c90cdd 4c 55 45 53 20 28 27 33 6d 33 6c 34 72 68 73 36 |LUES...3m3l4rhs6| +# 9c90ced 64 6f 30 73 66 35 70 31 69 39 6c 72 39 34 67 39 |do0sf5p1i9lr94g9| +# 9c90cfd 32 38 61 32 37 32 76 27 2c 20 27 27 2c 20 27 27 |28a272v.........| +# 9c90d0d 2c 20 49 4e 45 54 5f 41 54 4f 4e 28 27 37 31 2e |..INET.ATON..71.| +# 9c90d1d 31 31 38 2e 31 32 34 2e 39 38 27 29 2c 20 27 27 |118.124.98......| +# 9c90d2d 2c 20 27 27 2c 20 27 68 74 74 70 3a 2f 2f 64 65 |.......http...de| +# 9c90d3d 76 2e 6d 79 73 71 6c 2e 63 6f 6d 2f 64 6f 77 6e |v.mysql.com.down| +# 9c90d4d 6c 6f 61 64 73 2f 63 6f 6e 6e 65 63 74 6f 72 2f |loads.connector.| +# 9c90d5d 6a 2f 33 2e 30 2e 68 74 6d 6c 27 2c 20 4e 55 4c |j.3.0.html...NUL| +# 9c90d6d 4c 2c 20 27 64 65 76 2e 6d 79 73 71 6c 2e 63 6f |L...dev.mysql.co| +# 9c90d7d 6d 27 2c 20 27 2f 67 65 74 2f 44 6f 77 6e 6c 6f |m.....get.Downlo| +# 9c90d8d 61 64 73 2f 43 6f 6e 6e 65 63 74 6f 72 2d 4a 2f |ads.Connector.J.| +# 9c90d9d 6d 79 73 71 6c 2d 63 6f 6e 6e 65 63 74 6f 72 2d |mysql.connector.| +# 9c90dad 6a 61 76 61 2d 33 2e 30 2e 31 37 2d 67 61 2e 7a |java.3.0.17.ga.z| +# 9c90dbd 69 70 2f 66 72 6f 6d 2f 70 69 63 6b 27 2c 20 27 |ip.from.pick....| +# 9c90dcd 2f 67 65 74 2f 44 6f 77 6e 6c 6f 61 64 73 2f 43 |.get.Downloads.C| +# 9c90ddd 6f 6e 6e 65 63 74 6f 72 2d 4a 2f 6d 79 73 71 6c |onnector.J.mysql| +# 9c90ded 2d 63 6f 6e 6e 65 63 74 6f 72 2d 6a 61 76 61 2d |.connector.java.| +# 9c90dfd 33 2e 30 2e 31 37 2d 67 61 2e 7a 69 70 |3.0.17.ga.zip| +# Query thread_id=28278824 exec_time=0 error_code=0 +/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/; +use track/*!*/; +SET TIMESTAMP=1190087942/*!*/; +SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1/*!*/; +SET @@session.sql_mode=0/*!*/; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/; +SET @@session.time_zone='UTC'/*!*/; +INSERT INTO visits (myid, user_id, src, ip, cc, org, ref, time, host, entry, visit_exit, visit_start) +VALUES ('3m3l4rhs6do0sf5p1i9lr94g928a272v', '', '', INET_ATON('71.118.124.98'), '', '', 'http://dev.mysql.com/downloads/connector/j/3.0.html', NULL, 'dev.mysql.com', '/get/Downloads/Connector-J/mysql-connector-java-3.0.17-ga.zip/from/pick', '/get/Downloads/Connector-J/mysql-connector-java-3.0.17-ga.zip/from/pick', NOW())/*!*/; +# at 164171293 + +--delimiter ; + +SELECT * FROM visits; +SELECT * FROM visits_events; + +SET GLOBAL SLAVE_TYPE_CONVERSIONS = @saved_slave_type_conversions; + +# Cleanup +DROP DATABASE track; +sync_slave_with_master; + +--echo End of 5.1 tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_bug33931.test b/mysql-test/suite/rpl/t/rpl_bug33931.test new file mode 100644 index 00000000..0b2cbb63 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_bug33931.test @@ -0,0 +1,49 @@ +# Test for +# Bug #33931 assertion at write_ignored_events_info_to_relay_log if init_slave_thread() fails +# Bug #33932 assertion at handle_slave_sql if init_slave_thread() fails + +source include/have_debug.inc; +source include/master-slave.inc; + +connection slave; + +# Add suppression for expected warnings in slaves error log +call mtr.add_suppression("Failed during slave I/O thread initialization"); +call mtr.add_suppression("Slave SQL.*Failed during slave thread initialization.* 1593"); + +--source include/stop_slave.inc +reset slave; + +# Set debug flags on slave to force errors to occur +SET @saved_dbug = @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="d,simulate_io_slave_error_on_init,simulate_sql_slave_error_on_init"; + +--disable_query_log +eval CHANGE MASTER TO MASTER_USER='root', + MASTER_CONNECT_RETRY=1, + MASTER_HOST='127.0.0.1', + MASTER_PORT=$MASTER_MYPORT; +--enable_query_log + +start slave; + +# +# slave is going to stop because of emulated failures +# but there won't be any crashes nor asserts hit. +# + +# 1593 = ER_SLAVE_FATAL_ERROR +--let $slave_sql_errno= 1593 +--let $show_slave_sql_error= 1 +--source include/wait_for_slave_sql_error.inc + +# +# Cleanup +# +SET @@GLOBAL.debug_dbug = @saved_dbug; + +# Clear Last_SQL_Error +RESET SLAVE; + +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_bug37426.test b/mysql-test/suite/rpl/t/rpl_bug37426.test new file mode 100644 index 00000000..18e80a5f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_bug37426.test @@ -0,0 +1,22 @@ +############################################################# +# Purpose: Test for BUG#37426 +# RBR breaks for CHAR() UTF8 fields > 85 chars +############################################################# + +source include/have_binlog_format_row.inc; +source include/master-slave.inc; + +connection master; +CREATE TABLE char128_utf8 (i1 INT NOT NULL, c CHAR(128) CHARACTER SET utf8 NOT NULL, i2 INT NOT NULL); +INSERT INTO char128_utf8 VALUES ( 1, "123", 1 ); + +SELECT * FROM char128_utf8; +sync_slave_with_master; + +SELECT * FROM char128_utf8; + +# Clean up +connection master; +DROP TABLE char128_utf8; +sync_slave_with_master; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_bug38694-slave.opt b/mysql-test/suite/rpl/t/rpl_bug38694-slave.opt new file mode 100644 index 00000000..b457a7eb --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_bug38694-slave.opt @@ -0,0 +1 @@ +--loose-debug-dbug=d,simulate_slave_delay_at_terminate_bug38694 diff --git a/mysql-test/suite/rpl/t/rpl_bug38694.test b/mysql-test/suite/rpl/t/rpl_bug38694.test new file mode 100644 index 00000000..57d7dde0 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_bug38694.test @@ -0,0 +1,13 @@ +# Testing replication threads stopping concurrency issue +# at the server shutdown +# Related bugs: bug#38694, bug#29968, bug#25306 +# The test checks if a delay at the termination phase of slave threads +# DBUG_EXECUTE_IF("simulate_slave_delay_at_terminate_bug38694", sleep(5);); +# could cause any issue. + +source include/master-slave.inc; + +call mtr.add_suppression("Aborted connection"); + +# End of tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_bug41902.test b/mysql-test/suite/rpl/t/rpl_bug41902.test new file mode 100644 index 00000000..bb6c5725 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_bug41902.test @@ -0,0 +1,67 @@ +# Test for Bug #41902 MYSQL_BIN_LOG::reset_logs() doesn't call my_error() +# in face of an error +# + +source include/have_debug.inc; +source include/master-slave.inc; + +# +# test checks that +# a. there is no crash when find_log_pos() returns with an error +# that tests expect to receive; +# b. in the case of multiple error messages the first error message is +# reported to the user and others are available as warnings. +# + +connection slave; +stop slave; +SET @saved_dbug = @@GLOBAL.debug_dbug; +SET @@debug_dbug="d,simulate_find_log_pos_error"; + +--error ER_UNKNOWN_TARGET_BINLOG +reset slave; +show warnings; + +SET @@debug_dbug=""; +reset slave; +change master to master_host='dummy'; + +SET @@debug_dbug="d,simulate_find_log_pos_error"; + +--error ER_UNKNOWN_TARGET_BINLOG +change master to master_host='dummy'; + +SET @@debug_dbug=""; +reset slave; +change master to master_host='dummy'; + +connection master; +SET @saved_dbug_m = @@global.debug_dbug; +SET @@debug_dbug="d,simulate_find_log_pos_error"; +--error ER_UNKNOWN_TARGET_BINLOG +reset master; + +SET @@debug_dbug=""; +reset master; + +SET @@debug_dbug="d,simulate_find_log_pos_error"; +--error ER_UNKNOWN_TARGET_BINLOG +purge binary logs to 'master-bin.000001'; + +SET @@debug_dbug=""; +purge binary logs to 'master-bin.000001'; + +--disable_query_log +call mtr.add_suppression("Failed to locate old binlog or relay log files"); +call mtr.add_suppression("MYSQL_BIN_LOG::purge_logs was called with file ..master-bin.000001 not listed in the index"); +set @@global.debug_dbug = @saved_dbug_m; +connection slave; +call mtr.add_suppression("Failed to locate old binlog or relay log files"); +call mtr.add_suppression("MYSQL_BIN_LOG::purge_logs was called with file ..master-bin.000001 not listed in the index"); +--enable_query_log +SET @@GLOBAL.debug_dbug = @saved_dbug; + +--echo ==== clean up ==== +CHANGE MASTER TO MASTER_HOST = '127.0.0.1'; +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_cant_read_event_incident.test b/mysql-test/suite/rpl/t/rpl_cant_read_event_incident.test new file mode 100644 index 00000000..7c1d0ea2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_cant_read_event_incident.test @@ -0,0 +1,88 @@ +# +# This include file is used by more than one test suite +# (currently rpl and binlog_encryption). +# Please check all dependent tests after modifying it +# + +# +# Bug#11747416 : 32228 A disk full makes binary log corrupt. +# +# +# The test demonstrates reading from binlog error propagation to slave +# and reporting there. +# Conditions for the bug include a crash at time of the last event to +# the binlog was written partly. With the fixes the event is not sent out +# any longer, but rather the dump thread sends out a sound error message. +# +# Crash is not simulated. A binlog with partly written event in its end is installed +# and replication is started from it. +# + +--source include/have_binlog_format_mixed.inc +--source include/master-slave.inc + +--connection slave +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=NO; +--source include/start_slave.inc + +# Make sure the slave is stopped while we are messing with master. +# Otherwise we get occasional failures as the slave manages to re-connect +# to the newly started master and we get extra events applied, causing +# conflicts. +--source include/stop_slave.inc + +--connection master +call mtr.add_suppression("Error in Log_event::read_log_event()"); +--let $datadir= `SELECT @@datadir` + +--let $rpl_server_number= 1 +--source include/rpl_stop_server.inc + +--remove_file $datadir/master-bin.000001 +--copy_file $MYSQL_TEST_DIR/std_data/bug11747416_32228_binlog.000001 $datadir/master-bin.000001 + +--let $rpl_server_number= 1 +--source include/rpl_start_server.inc + +--source include/wait_until_connected_again.inc + +# evidence of the partial binlog +--error ER_ERROR_WHEN_EXECUTING_COMMAND +show binlog events; + +--connection slave +call mtr.add_suppression("Slave I/O: Got fatal error 1236 from master when reading data from binary log"); +--let $master_use_gtid_option= No +--source include/reset_slave.inc +start slave; + +# ER_MASTER_FATAL_ERROR_READING_BINLOG 1236 +--let $slave_param=Last_IO_Errno +--let $slave_param_value=1236 +--source include/wait_for_slave_param.inc + +--let $slave_field_result_replace= / at [0-9]*/ at XXX/ +--let $status_items= Last_IO_Errno, Last_IO_Error +--source include/show_slave_status.inc + +# +# Cleanup +# + +--connection master +reset master; + +--connection slave +stop slave; +reset slave; +# Table was created from binlog, it may not be created if SQL thread is running +# slowly and IO thread reaches incident before SQL thread applies it. +--disable_warnings +drop table if exists t; +--enable_warnings +reset master; + +--echo End of the tests +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_change_master.test b/mysql-test/suite/rpl/t/rpl_change_master.test new file mode 100644 index 00000000..2758f9d6 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_change_master.test @@ -0,0 +1,117 @@ +# Verify that after CHANGE MASTER, replication (I/O thread and SQL +# thread) restart from where SQL thread left, not from where +# I/O thread left (some old bug fixed in 4.0.17) + +source include/master-slave.inc; +call mtr.add_suppression("Slave I/O: The slave I/O thread stops because a fatal error is encountered when it tried to SET @master_binlog_checksum"); + +connection master; +# Make SQL slave thread advance a bit +create table t1(n int); +sync_slave_with_master; +select * from t1; +# Now stop it and make I/O slave thread be ahead +stop slave sql_thread; +connection master; +insert into t1 values(1); +insert into t1 values(2); +save_master_pos; +let $slave_param= Read_Master_Log_Pos; +let $slave_param_value= query_get_value(SHOW MASTER STATUS, Position, 1); +connection slave; +source include/wait_for_slave_param.inc; +source include/stop_slave.inc; + +let $read_pos= query_get_value(SHOW SLAVE STATUS, Read_Master_Log_Pos, 1); +let $exec_pos= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1); +if ($read_pos == $exec_pos) +{ + source include/show_rpl_debug_info.inc; + echo 'Read_Master_Log_Pos: $read_pos' == 'Exec_Master_Log_Pos: $exec_pos'; + die Failed because Read_Master_Log_Pos is equal to Exec_Master_Log_Pos; +} +change master to master_user='root'; +let $read_pos= query_get_value(SHOW SLAVE STATUS, Read_Master_Log_Pos, 1); +let $exec_pos= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1); +if ($read_pos != $exec_pos) +{ + source include/show_rpl_debug_info.inc; + echo 'Read_Master_Log_Pos: $read_pos' <> 'Exec_Master_Log_Pos: $exec_pos'; + die Failed because Read_Master_Log_Pos is not equal to Exec_Master_Log_Pos; +} + +start slave; +sync_with_master; +select * from t1; +connection master; +drop table t1; +sync_slave_with_master; + +# End of 4.1 tests + +# +# BUG#12190 CHANGE MASTER has differ path requiremts on MASTER_LOG_FILE and RELAY_LOG_FILE +# + +if ($bug_59037_is_fixed == 'true') { +--source include/rpl_reset.inc + +connection master; +create table t1 (a int); +insert into t1 values (1); +flush logs; +insert into t1 values (2); + +# Note: the master positon saved by this will also be used by the +# 'sync_with_master' below. +sync_slave_with_master; + +# Check if the table t1 and t2 are identical on master and slave; +let $diff_tables= master:t1,slave:t1 +source include/diff_tables.inc; + +connection slave; +source include/stop_slave.inc; +delete from t1 where a=2; + +# start replication from the second insert, after fix of BUG#12190, +# relay_log_file does not use absolute path, only the filename is +# required +# +# Note: the follow change master will automatically reset +# relay_log_purge to false, save the old value to restore +let $relay_log_purge= `select @@global.relay_log_purge`; +CHANGE MASTER TO relay_log_file='slave-relay-bin.000005', relay_log_pos=4; +start slave sql_thread; +source include/wait_for_slave_sql_to_start.inc; + +# Sync to the same position saved by the 'sync_slave_with_master' above. +sync_with_master; + +# Check if the table t1 and t2 are identical on master and slave; +let $diff_tables= master:t1,slave:t1 +source include/diff_tables.inc; + +# clean up +connection slave; +start slave io_thread; +source include/wait_for_slave_io_to_start.inc; +eval set global relay_log_purge=$relay_log_purge; +connection master; +drop table t1; +} + +--connection master +# MDEV-22741: *SAN: ERROR: AddressSanitizer: use-after-poison on address in +# instrings/strmake.c:36 from change_master (on optimized builds) +CHANGE MASTER TO MASTER_USER='root', MASTER_SSL=0, MASTER_SSL_CA='', MASTER_SSL_CERT='', + MASTER_SSL_KEY='', MASTER_SSL_CRL='', MASTER_SSL_CRLPATH=''; +CHANGE MASTER TO MASTER_USER='root', MASTER_PASSWORD='', MASTER_SSL=0; + + +# MDEV-20122: Deprecate MASTER_USE_GTID=Current_Pos to favor new MASTER_DEMOTE_TO_SLAVE option +--echo "Usage of CURRENT_POS in CHANGE MASTER MASTER_USE_GTID is dreprecated. +CHANGE MASTER TO MASTER_USE_GTID=CURRENT_POS; +CHANGE MASTER TO MASTER_USE_GTID=SLAVE_POS; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_change_master_demote.test b/mysql-test/suite/rpl/t/rpl_change_master_demote.test new file mode 100644 index 00000000..15b55014 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_change_master_demote.test @@ -0,0 +1,470 @@ +# +# Purpose: +# +# This test suite ensures that the MASTER_DEMOTE_TO_SLAVE option of +# CHANGE MASTER TO will merge the binlog GTID position (gtid_binlog_pos) into +# the replication state (gtid_slave_pos). +# +# +# Methodology: +# +# A series of test cases validate that MASTER_DEMOTE_TO_SLAVE correctly +# merges the binlog GTID state into the replication state. Each test case +# sets up the context in which it will demote the master to a slave, and then +# calls into an include file to perform the actual demotion and validation. +# Specifically, the include file will demote the master to be the slave, +# promote the slave to be the master, ensure that gtid_slave_pos matches +# gtid_current_pos, ensure replication works correctly in this new +# configuration, and return the master and slave to their previous roles. +# +# The test cases are as follows: +# 1) When both gtid_binlog_pos and gtid_slave_pos are empty, +# MASTER_DEMOTE_TO_SLAVE=1 results in no change to replication state. +# +# 2) If gtid_slave_pos is empty, gtid_binlog_pos will completely +# overwrite it with MASTER_DEMOTE_TO_SLAVE=1. +# +# 3) Using a single domain id, if neither gtid_slave_pos nor +# gtid_binlog_pos are empty, and gtid_binlog_pos is more recent, then +# gtid_binlog_pos will overwrite gtid_slave_pos when MASTER_DEMOTE_TO_SLAVE=1. +# +# 4) If gtid_slave_pos and gtid_binlog_pos are equivalent, +# MASTER_DEMOTE_TO_SLAVE=1 will not change gtid_slave_pos. +# +# 5) If multiple new domain ids are added into gtid_binlog_pos while +# gtid_slave_pos already has a state, MASTER_DEMOTE_TO_SLAVE=1 will append +# new GTIDs to gtid_slave_pos with the latest seq_no from each domain. +# +# 6) If gtid_slave_pos has multiple GTID positions and gtid_binlog_pos +# contains updates on existing domain ids, new domains, and differing +# server_ids, MASTER_DEMOTE_TO_SLAVE=1 will update gtid_slave_pos such that +# it will have the seq_nos only from the GTIDs last applied by this server. +# In other words, any GTIDs with server ids that don't match that of the +# demoting server will be ignored in the update. +# +# 7) If MASTER_DEMOTE_TO_SLAVE=1 is combined with IGNORE_DOMAIN_IDS such +# that gtid_binlog_pos has more recent GTIDs than gtid_slave_pos in ignored +# domains, the CHANGE MASTER TO command will still update gtid_slave_pos with +# the most recent transactions from gtid_binlog_pos, despite being ignored by +# CHANGE MASTER TO because they were already applied on the server. +# +# 8) If gtid_binlog_pos is more recent than gtid_slave_pos, and +# MASTER_DEMOTE_TO_SLAVE=1 is combined with a later call to +# START SLAVE UNTIL master_gtid_pos=<G> such that +# gtid_slave_pos < G < gtid_binlog_pos, then the slave should stop +# immediately after SSU because gtid_slave_pos should already be after the +# UNTIL GTID. +# +# 9) If gtid_slave_pos is more recent than gtid_binlog_pos when demoting +# the master to become a slave, the replication state should be preserved. +# +# 10) MASTER_DEMOTE_TO_SLAVE=0 should not change replication state, +# regardless of gtid_slave_pos in comparison to gtid_binlog_pos. +# +# +# Error cases: +# Error Case 1) MASTER_DEMOTE_TO_SLAVE=1 combined with +# MASTER_USE_GTID=NO should result in an error. +# +# Error Case 2) Error when MASTER_DEMOTE_TO_SLAVE=1 is used without +# binary logging enabled. +# +# Error Case 3) Error when MASTER_DEMOTE_TO_SLAVE is provided a +# non-boolean value. +# +# +# References: +# MDEV-19801: Change defaults for CHANGE MASTER TO so that GTID-based +# replication is used by default if master supports it +# +--source include/master-slave.inc +--source include/have_log_bin.inc +--source include/have_binlog_format_mixed.inc + +--connection slave +--source include/stop_slave.inc +change master to master_use_gtid=slave_pos; +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + +--echo # +--echo # Test Case 1: When both gtid_binlog_pos and gtid_slave_pos are +--echo # empty, MASTER_DEMOTE_TO_SLAVE=1 results in no change to replication +--echo # state. +--echo # +--source include/rpl_change_master_demote.inc + + +--echo # +--echo # Test Case 2: If gtid_slave_pos is empty, gtid_binlog_pos will +--echo # completely overwrite it with MASTER_DEMOTE_TO_SLAVE=1. +--echo # +--connection slave +--source include/stop_slave.inc +RESET MASTER; +set @@global.gtid_slave_pos=""; +--source include/start_slave.inc +--connection master +RESET MASTER; +set @@global.gtid_slave_pos=""; +set session gtid_domain_id= 0; +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (1); +--source include/save_master_gtid.inc +--connection slave +--source include/sync_with_master_gtid.inc +--source include/rpl_change_master_demote.inc + + +--echo # +--echo # Test Case 3: Using a single domain id, if neither gtid_slave_pos nor +--echo # gtid_binlog_pos are empty, and gtid_binlog_pos is more recent, then +--echo # gtid_binlog_pos will overwrite gtid_slave_pos when +--echo # MASTER_DEMOTE_TO_SLAVE=1. +--echo # +--connection master +INSERT INTO t1 VALUES (2); +--source include/save_master_gtid.inc +--connection slave +--source include/sync_with_master_gtid.inc +--source include/rpl_change_master_demote.inc + + +--echo # +--echo # Test Case 4: If gtid_slave_pos and gtid_binlog_pos are equivalent, +--echo # MASTER_DEMOTE_TO_SLAVE=1 will not change gtid_slave_pos. +--echo # +--connection master + +--echo # update gtid_binlog_pos and demote it (we have proven this works) +INSERT INTO t1 VALUES (3); +--echo # Update to account for statements to verify replication in include file +--replace_result $SLAVE_MYPORT SLAVE_PORT +--eval CHANGE MASTER TO master_host='127.0.0.1', master_port=$SLAVE_MYPORT, master_user='root', master_use_gtid=slave_pos, master_demote_to_slave=1 +RESET SLAVE ALL; + +--source include/save_master_gtid.inc +--connection slave +--source include/sync_with_master_gtid.inc +--source include/rpl_change_master_demote.inc + + +--echo # +--echo # Test Case 5: If a new domain id is added into gtid_binlog_pos while +--echo # gtid_slave_pos already has a state, MASTER_DEMOTE_TO_SLAVE=1 will +--echo # append a new GTID to gtid_slave_pos with the latest seq_no from that +--echo # domain. +--echo # +--connection master + +--echo # Domain_id +set session gtid_domain_id= 0; +INSERT INTO t1 VALUES (4); + +set session gtid_domain_id= 1; +CREATE TABLE t2 (a int); +INSERT INTO t2 VALUES (1); + +--source include/save_master_gtid.inc +--connection slave +--source include/sync_with_master_gtid.inc +--source include/rpl_change_master_demote.inc + + +--echo # +--echo # Test Case 6: If gtid_slave_pos has multiple GTID positions and +--echo # gtid_binlog_pos contains updates on existing domain ids, new +--echo # domains, and differing server_ids, MASTER_DEMOTE_TO_SLAVE=1 will +--echo # update gtid_slave_pos such that it will have the seq_nos only from +--echo # the GTIDs last applied by this server. In other words, any GTIDs +--echo # with server ids that don't match that of the demoting server will be +--echo # ignored in the update. +--echo # + +--connection master +--echo # Update to account for statements to verify replication in include file +set session gtid_domain_id= 0; +INSERT INTO t1 VALUES (5); +--replace_result $SLAVE_MYPORT SLAVE_PORT +--eval CHANGE MASTER TO master_host='127.0.0.1', master_port=$SLAVE_MYPORT, master_user='root', master_use_gtid=slave_pos, master_demote_to_slave=1 +RESET SLAVE ALL; + +set session gtid_domain_id= 1; +INSERT INTO t2 VALUES (2); + +set session gtid_domain_id= 2; +CREATE TABLE t3 (a int); +INSERT INTO t3 VALUES (1); + +--echo # The following events have a different server_id and should not go into +--echo # gtid_slave_pos +set @old_server_id = @@server_id; +set session gtid_domain_id= 1; +set session server_id= 3; +INSERT INTO t2 VALUES (3); + +set session gtid_domain_id= 4; +set session server_id= 3; +CREATE TABLE t5 (a int); +INSERT INTO t5 VALUES (1); +set session server_id= @old_server_id; + +--source include/save_master_gtid.inc +--connection slave +--source include/sync_with_master_gtid.inc +--source include/rpl_change_master_demote.inc + + +--echo # +--echo # Test Case 7: If MASTER_DEMOTE_TO_SLAVE=1 is combined with +--echo # IGNORE_DOMAIN_IDS such that gtid_binlog_pos has more recent GTIDs +--echo # than gtid_slave_pos in ignored domains, the CHANGE MASTER TO command +--echo # will still update gtid_slave_pos with the most recent transactions +--echo # from gtid_binlog_pos, despite being ignored by CHANGE MASTER TO +--echo # because they were already applied on the server. +--echo # +--connection master + +set session gtid_domain_id= 2; +INSERT INTO t3 VALUES (2); + +set session gtid_domain_id= 3; +CREATE TABLE t4 (a int); +INSERT INTO t4 VALUES (1); + +--source include/save_master_gtid.inc +--connection slave +--source include/sync_with_master_gtid.inc +--let $ignore_domain_ids=2,3 +--source include/rpl_change_master_demote.inc + + +--echo # +--echo # Test Case 8: If gtid_binlog_pos is more recent than gtid_slave_pos, +--echo # and MASTER_DEMOTE_TO_SLAVE=1 is combined with a later call to +--echo # START SLAVE UNTIL master_gtid_pos=<G> such that +--echo # gtid_slave_pos < G < gtid_binlog_pos, then the slave should stop +--echo # immediately after SSU because gtid_slave_pos should be updated to be +--echo # after G. +--echo # + +--connection master +set session gtid_domain_id= 0; +INSERT INTO t1 VALUES (6); +--let $ssu_middle_binlog_pos= `SELECT @@GLOBAL.gtid_binlog_pos` +--echo # Tagging ssu_middle_binlog_pos here to be used for START SLAVE UNTIL +INSERT INTO t1 VALUES (7); +--source include/save_master_gtid.inc + +--echo # Ensure slave is up-to-date with master and then disable slave status +--connection slave +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc + +--connection master +SELECT VARIABLE_NAME, GLOBAL_VALUE FROM INFORMATION_SCHEMA.SYSTEM_VARIABLES WHERE VARIABLE_NAME LIKE 'gtid_binlog_pos' OR VARIABLE_NAME LIKE 'gtid_slave_pos' ORDER BY VARIABLE_NAME ASC; +--replace_result $SLAVE_MYPORT SLAVE_PORT +--eval CHANGE MASTER TO master_host='127.0.0.1', master_port=$SLAVE_MYPORT, master_user='root', master_use_gtid=Slave_Pos, master_demote_to_slave=1 +SELECT VARIABLE_NAME, GLOBAL_VALUE FROM INFORMATION_SCHEMA.SYSTEM_VARIABLES WHERE VARIABLE_NAME LIKE 'gtid_binlog_pos' OR VARIABLE_NAME LIKE 'gtid_slave_pos' ORDER BY VARIABLE_NAME ASC; + +--echo # GTID ssu_middle_binlog_pos should be considered in the past because +--echo # gtid_slave_pos should be updated using the latest binlog gtids. +--echo # The following call to sync_with_master_gtid.inc uses the latest +--echo # binlog position and should still succeed despite the SSU stop +--echo # position pointing to a previous event (because +--echo # master_demote_to_slave=1 merges gtid_binlog_pos into gtid_slave_pos). +--replace_result $ssu_middle_binlog_pos ssu_middle_binlog_pos +eval START SLAVE UNTIL master_gtid_pos="$ssu_middle_binlog_pos"; + +--echo # Slave needs time to start and stop automatically +# Note sync_with_master_gtid.inc, wait_for_slave_to_start.inc, and +# wait_for_slave_to_stop.inc won't work due to replication state and race +# conditions +--sleep 1 + +--echo # Validating neither SQL nor IO threads are running.. +--let $io_state= query_get_value("SHOW SLAVE STATUS", Slave_IO_State, 1) +if (`SELECT strcmp("$io_state","") != 0`) +{ + die "IO thread should not be running after START SLAVE UNTIL master_gtid_pos using a pre-existing GTID"; +} +--let $sql_state= query_get_value("SHOW SLAVE STATUS", Slave_SQL_Running_State, 1) +if (`SELECT strcmp("$sql_state","") != 0`) +{ + die "SQL thread should not be running after START SLAVE UNTIL master_gtid_pos using a pre-existing GTID"; +} +--echo # ..success + +--echo # Clean slave state of master +RESET SLAVE ALL; + + +--echo # +--echo # Test Case 9: If gtid_slave_pos is more recent than gtid_binlog_pos +--echo # when demoting the master to become a slave, the replication state +--echo # should be preserved. +--echo # + +--echo # rpl_change_master_demote.inc should force +--echo # gtid_slave_pos > gtid_binlog_pos in domain 0 (due to the step which +--echo # validates replication works) +--connection master +--source include/rpl_change_master_demote.inc + +--let $current_pos= `SELECT @@gtid_current_pos` + +--echo # Demote master to slave with the more recent gtid_slave_pos +--connection master +--let $old_slave_pos= `SELECT @@gtid_slave_pos` +--replace_result $SLAVE_MYPORT SLAVE_PORT +--eval CHANGE MASTER TO master_host='127.0.0.1', master_port=$SLAVE_MYPORT, master_user='root', master_use_gtid=slave_pos, master_demote_to_slave=1 +--let $new_slave_pos= `SELECT @@gtid_slave_pos` + +--echo # Validating gtid_slave_pos is unchanged.. +if ($old_slave_pos != $new_slave_pos) +{ + SELECT VARIABLE_NAME, GLOBAL_VALUE FROM INFORMATION_SCHEMA.SYSTEM_VARIABLES WHERE VARIABLE_NAME LIKE 'gtid_binlog_pos' OR VARIABLE_NAME LIKE 'gtid_slave_pos' OR VARIABLE_NAME LIKE 'gtid_current_pos' ORDER BY VARIABLE_NAME ASC; + die "gtid_slave_pos should not change when MASTER_DEMOTE_TO_SLAVE=0"; +} +--echo # ..success + +--echo # Validating gtid_slave_pos == gtid_binlog_pos.. +if ($new_slave_pos != $current_pos) +{ + SELECT VARIABLE_NAME, GLOBAL_VALUE FROM INFORMATION_SCHEMA.SYSTEM_VARIABLES WHERE VARIABLE_NAME LIKE 'gtid_binlog_pos' OR VARIABLE_NAME LIKE 'gtid_slave_pos' OR VARIABLE_NAME LIKE 'gtid_current_pos' ORDER BY VARIABLE_NAME ASC; + die gtid_slave_pos calculation after master_demote_to_slave=1 differs from gtid_current_pos; +} +--echo # ..success + +--echo # Clean slave state of master +RESET SLAVE ALL; + + +--echo # +--echo # Test Case 10: MASTER_DEMOTE_TO_SLAVE=0 should not change replication +--echo # state, regardless of gtid_slave_pos in comparison to gtid_binlog_pos. +--echo # + +--echo # In domain 0, make gtid_slave_pos > gtid_binlog_pos +--connection master +--source include/rpl_change_master_demote.inc + +--echo # Tag gtid_slave_pos now (before binlog updates) for later comparison +--let $old_slave_pos= `SELECT @@gtid_slave_pos` + +--connection master +--echo # In domain 1, make gtid_slave_pos < gtid_binlog_pos +set session gtid_domain_id= 1; +INSERT INTO t2 VALUES (4); + +--echo # In domains 2, 3 and 4, gtid_slave_pos == gtid_binlog_pos + +--echo # Include a new domain id (5) +set session gtid_domain_id= 5; +CREATE TABLE t6 (a int); +INSERT INTO t6 VALUES (1); + +SELECT VARIABLE_NAME, GLOBAL_VALUE FROM INFORMATION_SCHEMA.SYSTEM_VARIABLES WHERE VARIABLE_NAME LIKE 'gtid_binlog_pos' OR VARIABLE_NAME LIKE 'gtid_slave_pos' ORDER BY VARIABLE_NAME ASC; +--replace_result $SLAVE_MYPORT SLAVE_PORT +--eval CHANGE MASTER TO master_host='127.0.0.1', master_port=$SLAVE_MYPORT, master_user='root', master_use_gtid=slave_pos, master_demote_to_slave=0 + +--echo # Validating gtid_slave_pos is unchanged.. +--let $new_slave_pos= `SELECT @@gtid_slave_pos` +if ($old_slave_pos != $new_slave_pos) +{ + SELECT VARIABLE_NAME, GLOBAL_VALUE FROM INFORMATION_SCHEMA.SYSTEM_VARIABLES WHERE VARIABLE_NAME LIKE 'gtid_binlog_pos' OR VARIABLE_NAME LIKE 'gtid_slave_pos' ORDER BY VARIABLE_NAME ASC; + die gtid_slave_pos should not change when MASTER_DEMOTE_TO_SLAVE=0; +} +--echo # ..success + +--echo # Clean slave state of master +--replace_result $SLAVE_MYPORT SLAVE_PORT +--eval CHANGE MASTER TO master_host='127.0.0.1', master_port=$SLAVE_MYPORT, master_user='root', master_use_gtid=slave_pos, master_demote_to_slave=1 +RESET SLAVE ALL; +SELECT VARIABLE_NAME, GLOBAL_VALUE FROM INFORMATION_SCHEMA.SYSTEM_VARIABLES WHERE VARIABLE_NAME LIKE 'gtid_binlog_pos' OR VARIABLE_NAME LIKE 'gtid_slave_pos' ORDER BY VARIABLE_NAME ASC; + + +--echo # +--echo # +--echo # Stop slave for error test cases +--connection slave +--source include/stop_slave.inc + +--echo # +--echo # Error Case 1: MASTER_DEMOTE_TO_SLAVE=1 combined with +--echo # MASTER_USE_GTID=NO should result in an error. +--echo # +--connection master +--replace_result $SLAVE_MYPORT SLAVE_PORT +--error 4191 +--eval CHANGE MASTER TO master_host='127.0.0.1', master_port=$SLAVE_MYPORT, master_user='root', master_use_gtid=no, master_demote_to_slave=1 + + +--echo # +--echo # Error Case 2: Error when MASTER_DEMOTE_TO_SLAVE=1 is used without +--echo # binary logging enabled. +--echo # +--connection master + +--echo # Restarting master without binary log +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait +EOF +--shutdown_server +--source include/wait_until_disconnected.inc +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart: --skip-slave-start=1 --skip-log-bin +EOF +--enable_reconnect +--source include/wait_until_connected_again.inc + +--replace_result $SLAVE_MYPORT SLAVE_PORT +--error 1381 +--eval CHANGE MASTER TO master_host='127.0.0.1', master_port=$SLAVE_MYPORT, master_user='root', master_use_gtid=Slave_Pos, master_demote_to_slave=1 + +--echo # Restarting master to re-enable binary log +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait +EOF +--shutdown_server +--source include/wait_until_disconnected.inc +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart: --skip-slave-start=1 +EOF +--enable_reconnect +--source include/wait_until_connected_again.inc + +--connection server_1 +--enable_reconnect +--source include/wait_until_connected_again.inc + +--connection default +--enable_reconnect +--source include/wait_until_connected_again.inc + + +--echo # +--echo # Error Case 3: Error when MASTER_DEMOTE_TO_SLAVE is provided a +--echo # non-boolean value. +--echo # + +--connection master +--replace_result $SLAVE_MYPORT SLAVE_PORT +--error 1064 +--eval CHANGE MASTER TO master_host='127.0.0.1', master_port=$SLAVE_MYPORT, master_user='root', master_use_gtid=Slave_Pos, master_demote_to_slave=invalid + + +--echo # +--echo # Cleanup +--echo # +--connection master +DROP TABLE t1, t2, t3, t4, t5, t6; +--source include/save_master_gtid.inc + +--connection slave +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + +--source include/rpl_end.inc +--echo # +--echo ### End rpl_change_master_demote.test diff --git a/mysql-test/suite/rpl/t/rpl_change_master_find_log_pos_err.test b/mysql-test/suite/rpl/t/rpl_change_master_find_log_pos_err.test new file mode 100644 index 00000000..d1c2c03f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_change_master_find_log_pos_err.test @@ -0,0 +1,93 @@ +# +# Purpose: +# This test ensures that issuing a CHANGE MASTER will not put a replica into +# an inconsistent state if the slave cannot find the log files (i.e. the call to +# find_log_pos in reset_logs fails). More specifically, right before a replica +# purges the relay logs (part of the `CHANGE MASTER TO` logic), the relay log is +# temporarily closed with state LOG_TO_BE_OPENED. If the server is issued a +# CHANGE MASTER and it errors in-between the temporary log closure and purge, +# i.e. during the function find_log_pos, the log should be closed. The bug +# reported by MDEV-25284 revealed the log is not properly closed, such that +# future relay log updates fail, and future CHANGE MASTER calls crash the +# server. +# +# Methodology: +# This test ensures that the relay log is properly closed by ensuring future +# updates and CHANGE MASTER calls succeed. +# +# References: +# MDEV-25284: Assertion `info->type == READ_CACHE || +# info->type == WRITE_CACHE' failed +# +--source include/master-slave.inc +--source include/have_debug.inc + +--echo # +--echo # Failed CHANGE MASTER TO should not change relay log status +--echo # + +--connection slave +--source include/stop_slave.inc +SET @@debug_dbug="d,simulate_find_log_pos_error"; +error 1373; +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(1), MASTER_USE_GTID=SLAVE_POS; +SET @@debug_dbug=""; +--source include/start_slave.inc + + +--echo # +--echo # Ensure relay log can be updated after a failed CHANGE MASTER +--echo # + +FLUSH RELAY LOGS; +--let $slave_param= Relay_Log_File +--let $slave_param_value= slave-relay-bin.000003 +--source include/wait_for_slave_param.inc + + +--echo # +--echo # Slave should continue to receive data from old master after failed +--echo # CHANGE MASTER TO +--echo # + +--connection master +CREATE TABLE t1 (a int); +insert into t1 values (1); +--let $master_checksum= `CHECKSUM TABLE t1` +--sync_slave_with_master + +--connection slave +if ($master_checksum != `CHECKSUM TABLE t1`) +{ + die("Replica failed to pull data from primary after failed CHANGE MASTER TO"); +} + + +--echo # +--echo # Future CHANGE MASTER calls should succeed +--echo # + +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=SLAVE_POS; +--source include/start_slave.inc + + +--echo ######################## +--echo # Cleanup +--echo ######################## + +--connection master +DROP TABLE t1; + +--connection slave +--source include/stop_slave.inc +RESET SLAVE ALL; +--replace_result $MASTER_MYPORT MASTER_MYPORT +eval change master to master_port=$MASTER_MYPORT, master_host='127.0.0.1', master_user='root'; +--source include/start_slave.inc + +--disable_query_log +call mtr.add_suppression("Failed to locate old binlog or relay log files"); +--enable_query_log + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_charset.test b/mysql-test/suite/rpl/t/rpl_charset.test new file mode 100644 index 00000000..31ea2bc8 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_charset.test @@ -0,0 +1,2 @@ +let $engine_type=myisam; +source include/rpl_charset.test; diff --git a/mysql-test/suite/rpl/t/rpl_charset_sjis.test b/mysql-test/suite/rpl/t/rpl_charset_sjis.test new file mode 100644 index 00000000..af4e8ff5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_charset_sjis.test @@ -0,0 +1,54 @@ +source include/have_sjis.inc; +source include/master-slave.inc; + +--disable_warnings +drop table if exists t1; +drop procedure if exists p1; +--enable_warnings +create table t1 (a varchar(255) character set sjis); +create procedure p1 (in a varchar(255) character set sjis) insert into t1 values (a); + +SET NAMES binary; +CALL p1 ('–\\'); +select hex(a) from t1 ; +sync_slave_with_master; +connection slave; +select hex(a) from t1; +connection master; +drop table t1; +drop procedure p1; +sync_slave_with_master; +connection master; + +# End of 5.0 tests + +--echo # +--echo # Start of 5.5 tests +--echo # + +--echo # +--echo # Bug#MDEV-4489 Replication of big5, cp932, gbk, sjis strings makes wrong values on slave +--echo # + +connection master; +SET NAMES sjis; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (0x31),(X'31'),('1'); +PREPARE stmt FROM 'INSERT INTO t1 (a) VALUES (?)'; +SET @a='1'; +EXECUTE stmt USING @a; +DROP PREPARE stmt; +SELECT * FROM t1; +sync_slave_with_master; +connection slave; +SELECT * FROM t1; +connection master; +DROP TABLE t1; +sync_slave_with_master; +connection master; + +--echo # +--echo # End of 5.5 tests +--echo # + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_checksum-master.opt b/mysql-test/suite/rpl/t/rpl_checksum-master.opt new file mode 100644 index 00000000..a6e99a9f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_checksum-master.opt @@ -0,0 +1 @@ +--binlog-checksum=CRC32 diff --git a/mysql-test/suite/rpl/t/rpl_checksum.test b/mysql-test/suite/rpl/t/rpl_checksum.test new file mode 100644 index 00000000..fc765744 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_checksum.test @@ -0,0 +1,342 @@ +# +# This include file is used by more than one test suite +# (currently rpl and binlog_encryption). +# Please check all dependent tests after modifying it +# + +# WL2540 replication events checksum +# Testing configuration parameters + +--source include/have_debug.inc +--source include/have_binlog_format_mixed.inc +--source include/master-slave.inc + +--connection slave +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=NO; +--source include/start_slave.inc + +--connection master +call mtr.add_suppression('Slave can not handle replication events with the checksum that master is configured to log'); +call mtr.add_suppression('Replication event checksum verification failed'); +# due to C failure simulation +call mtr.add_suppression('Relay log write failure: could not queue event from master'); +call mtr.add_suppression('Master is configured to log replication events with checksum, but will not send such events to slaves that cannot process them'); + +# A. read/write access to the global vars: +# binlog_checksum master_verify_checksum slave_sql_verify_checksum + +connection master; + +set @master_save_binlog_checksum= @@global.binlog_checksum; +set @save_master_verify_checksum = @@global.master_verify_checksum; + +select @@global.binlog_checksum as 'must be CRC32 because of the command line option'; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +select @@session.binlog_checksum as 'no session var'; + +select @@global.master_verify_checksum as 'must be zero because of default'; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +select @@session.master_verify_checksum as 'no session var'; + +connection slave; + +set @slave_save_binlog_checksum= @@global.binlog_checksum; +set @save_slave_sql_verify_checksum = @@global.slave_sql_verify_checksum; + +select @@global.slave_sql_verify_checksum as 'must be one because of default'; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +select @@session.slave_sql_verify_checksum as 'no session var'; + +connection master; + +source include/show_binary_logs.inc; +set @@global.binlog_checksum = NONE; +select @@global.binlog_checksum; +--echo *** must be rotations seen *** +source include/show_binary_logs.inc; + +set @@global.binlog_checksum = default; +select @@global.binlog_checksum; + +# testing lack of side-effects in non-effective update of binlog_checksum: +set @@global.binlog_checksum = CRC32; +select @@global.binlog_checksum; +set @@global.binlog_checksum = CRC32; + +set @@global.master_verify_checksum = 0; +set @@global.master_verify_checksum = default; + +--error ER_WRONG_VALUE_FOR_VAR +set @@global.binlog_checksum = ADLER32; +--error ER_WRONG_VALUE_FOR_VAR +set @@global.master_verify_checksum = 2; # the var is of bool type + +connection slave; + +set @@global.slave_sql_verify_checksum = 0; +set @@global.slave_sql_verify_checksum = default; +--error ER_WRONG_VALUE_FOR_VAR +set @@global.slave_sql_verify_checksum = 2; # the var is of bool type + +# +# B. Old Slave to New master conditions +# +# while master does not send a checksum-ed binlog the Old Slave can +# work with the New Master + +connection master; + +set @@global.binlog_checksum = NONE; +create table t1 (a int); + +# testing that binlog rotation preserves opt_binlog_checksum value +flush logs; +flush logs; +-- source include/wait_for_binlog_checkpoint.inc +flush logs; + +sync_slave_with_master; +#connection slave; +# checking that rotation on the slave side leaves slave stable +flush logs; +flush logs; +flush logs; +select count(*) as zero from t1; + +source include/stop_slave.inc; + +connection master; +set @@global.binlog_checksum = CRC32; +-- source include/wait_for_binlog_checkpoint.inc +insert into t1 values (1) /* will not be applied on slave due to simulation */; + +# instruction to the dump thread + +connection slave; +set @saved_dbug = @@global.debug_dbug; +set @@global.debug_dbug='d,simulate_slave_unaware_checksum'; +start slave; +--let $slave_io_errno= 1236 +--let $show_slave_io_error= 1 +source include/wait_for_slave_io_error.inc; + +select count(*) as zero from t1; + +set @@global.debug_dbug = @saved_dbug; + +connection slave; +source include/start_slave.inc; + +# +# C. checksum failure simulations +# + +# C1. Failure by a client thread +connection master; +set @@global.master_verify_checksum = 1; +set @save_dbug = @@session.debug_dbug; +set @@session.debug_dbug='d,simulate_checksum_test_failure'; +--error ER_ERROR_WHEN_EXECUTING_COMMAND +show binlog events; +SET debug_dbug= @save_dbug; +set @@global.master_verify_checksum = default; + +#connection master; +sync_slave_with_master; + +connection slave; +source include/stop_slave.inc; + +connection master; +create table t2 (a int); +let $pos_master= query_get_value(SHOW MASTER STATUS, Position, 1); + +connection slave; + +# C2. Failure by IO thread +# instruction to io thread +set @saved_dbug = @@global.debug_dbug; +set @@global.debug_dbug='d,simulate_checksum_test_failure'; +start slave io_thread; +# When the checksum error is detected, the slave sets error code 1913 +# (ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE) in queue_event(), then immediately +# sets error 1595 (ER_SLAVE_RELAY_LOG_WRITE_FAILURE) in handle_slave_io(). +# So we usually get 1595, but it is occasionally possible to get 1913. +--let $slave_io_errno= 1595,1913 +--let $show_slave_io_error= 0 +source include/wait_for_slave_io_error.inc; +set @@global.debug_dbug = @saved_dbug; + +# to make IO thread re-read it again w/o the failure +start slave io_thread; +let $slave_param= Read_Master_Log_Pos; +let $slave_param_value= $pos_master; +source include/wait_for_slave_param.inc; + +# C3. Failure by SQL thread +# instruction to sql thread; +set @@global.slave_sql_verify_checksum = 1; + +set @@global.debug_dbug='d,simulate_checksum_test_failure'; + +start slave sql_thread; +--let $slave_sql_errno= 1593 +--let $show_slave_sql_error= 1 +source include/wait_for_slave_sql_error.inc; + +# resuming SQL thread to parse out the event w/o the failure + +set @@global.debug_dbug = @saved_dbug; +source include/start_slave.inc; + +connection master; +sync_slave_with_master; + +#connection slave; +select count(*) as 'must be zero' from t2; + +# +# D. Reset slave, Change-Master, Binlog & Relay-log rotations with +# random value on binlog_checksum on both master and slave +# +connection slave; +stop slave; +--let $master_use_gtid_option= No +--source include/reset_slave.inc + +# randomize slave server's own checksum policy +set @@global.binlog_checksum= IF(floor((rand()*1000)%2), "CRC32", "NONE"); +flush logs; + +connection master; +set @@global.binlog_checksum= CRC32; +reset master; +flush logs; +create table t3 (a int, b char(5)); + +connection slave; +source include/start_slave.inc; + +connection master; +sync_slave_with_master; + +#connection slave; +select count(*) as 'must be zero' from t3; +source include/stop_slave.inc; +--replace_result $MASTER_MYPORT MASTER_PORT +eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root'; + +connection master; +flush logs; +reset master; +insert into t3 value (1, @@global.binlog_checksum); + +connection slave; +source include/start_slave.inc; +flush logs; + +connection master; +sync_slave_with_master; + +#connection slave; +select count(*) as 'must be one' from t3; + +connection master; +set @@global.binlog_checksum= IF(floor((rand()*1000)%2), "CRC32", "NONE"); +insert into t3 value (1, @@global.binlog_checksum); +sync_slave_with_master; + +#connection slave; + +#clean-up + +connection master; +drop table t1, t2, t3; +set @@global.binlog_checksum = @master_save_binlog_checksum; +set @@global.master_verify_checksum = @save_master_verify_checksum; + +# +# BUG#58564: flush_read_lock fails in mysql-trunk-bugfixing after merging with WL#2540 +# +# Sanity check that verifies that no assertions are triggered because +# of old FD events (generated by versions prior to server released with +# checksums feature) +# +# There is no need for query log, if something wrong this should trigger +# an assertion + +--disable_query_log + +BINLOG ' +MfmqTA8BAAAAZwAAAGsAAAABAAQANS41LjctbTMtZGVidWctbG9nAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAx+apMEzgNAAgAEgAEBAQEEgAAVAAEGggAAAAICAgCAA== +'; + +--enable_query_log + +#connection slave; +sync_slave_with_master; + + +--echo *** Bug#59123 / MDEV-5799: INCIDENT_EVENT checksum written to error log as garbage characters *** + +--connection master + +--source include/wait_for_binlog_checkpoint.inc +CREATE TABLE t4 (a INT PRIMARY KEY); +INSERT INTO t4 VALUES (1); + +SET sql_log_bin=0; +CALL mtr.add_suppression("\\[ERROR\\] Can't generate a unique log-filename"); +SET sql_log_bin=1; +SET @old_dbug= @@GLOBAL.debug_dbug; +SET debug_dbug= '+d,binlog_inject_new_name_error'; +--error ER_NO_UNIQUE_LOGFILE +FLUSH LOGS; +SET debug_dbug= @old_dbug; + +INSERT INTO t4 VALUES (2); + +--connection slave +--let $slave_sql_errno= 1590 +--source include/wait_for_slave_sql_error.inc + +# Search the error log for the error message. +# The bug was that 4 garbage bytes were output in the middle of the error +# message; by searching for a pattern that spans that location, we can +# catch the error. +let $log_error_= `SELECT @@GLOBAL.log_error`; +if(!$log_error_) +{ + # MySQL Server on windows is started with --console and thus + # does not know the location of its .err log, use default location + let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.2.err; +} +--let SEARCH_FILE= $log_error_ +--let SEARCH_PATTERN= Slave SQL: The incident LOST_EVENTS occurred on the master\. Message: error writing to the binary log, Internal MariaDB error code: 1590 +--source include/search_pattern_in_file.inc + +SELECT * FROM t4 ORDER BY a; +STOP SLAVE IO_THREAD; +SET sql_slave_skip_counter= 1; +--source include/start_slave.inc + +--connection master +--save_master_pos + +--connection slave +--sync_with_master +SELECT * FROM t4 ORDER BY a; + + +--connection slave +set @@global.binlog_checksum = @slave_save_binlog_checksum; +set @@global.slave_sql_verify_checksum = @save_slave_sql_verify_checksum; + +--echo End of tests + +--connection master +DROP TABLE t4; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_checksum_cache.test b/mysql-test/suite/rpl/t/rpl_checksum_cache.test new file mode 100644 index 00000000..e04f618b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_checksum_cache.test @@ -0,0 +1,261 @@ +# +# This include file is used by more than one test suite +# (currently rpl and binlog_encryption). +# Please check all dependent tests after modifying it +# + +-- source include/have_innodb.inc +-- source include/master-slave.inc + +--disable_warnings +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. .*Statement: insert into t2 set data=repeat.*'a', @act_size.*"); +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. .*Statement: insert into t1 values.* NAME_CONST.*'n',.*, @data .*"); +--enable_warnings + +connection master; +set @save_binlog_cache_size = @@global.binlog_cache_size; +set @save_binlog_checksum = @@global.binlog_checksum; +set @save_master_verify_checksum = @@global.master_verify_checksum; +set @@global.binlog_cache_size = 4096; +set @@global.binlog_checksum = CRC32; +set @@global.master_verify_checksum = 1; + +# restart slave to force the dump thread to verify events (on master side) +connection slave; +source include/stop_slave.inc; +source include/start_slave.inc; + +connection master; + +# +# Testing a critical part of checksum handling dealing with transaction cache. +# The cache's buffer size is set to be less than the transaction's footprint +# in binlog. +# +# To verify combined buffer-by-buffer read out of the file and fixing crc per event +# there are the following parts: +# +# 1. the event size is much less than the cache's buffer +# 2. the event size is bigger than the cache's buffer +# 3. the event size if approximately the same as the cache's buffer +# 4. all in above + +# +# 1. the event size is much less than the cache's buffer +# + +flush status; +show status like "binlog_cache_use"; +show status like "binlog_cache_disk_use"; +--disable_warnings +drop table if exists t1; +--enable_warnings + +# +# parameter to ensure the test slightly varies binlog content +# between different invocations +# +let $deviation_size=32; +eval create table t1 (a int PRIMARY KEY, b CHAR($deviation_size)) engine=innodb; + +# Now we are going to create transaction which is long enough so its +# transaction binlog will be flushed to disk... + +delimiter |; +create procedure test.p_init (n int, size int) +begin + while n > 0 do + select round(RAND() * size) into @act_size; + set @data = repeat('a', @act_size); + insert into t1 values(n, @data ); + set n= n-1; + end while; +end| + +delimiter ;| + +let $1 = 4000; # PB2 can run it slow to time out on following sync_slave_with_master:s + +begin; +--disable_warnings +# todo: check if it is really so. +#+Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statement uses a system function whose value may differ on slave. +eval call test.p_init($1, $deviation_size); +--enable_warnings +commit; + +show status like "binlog_cache_use"; +--echo *** binlog_cache_disk_use must be non-zero *** +show status like "binlog_cache_disk_use"; + +sync_slave_with_master; + +let $diff_tables=master:test.t1, slave:test.t1; +source include/diff_tables.inc; + +# undoing changes with verifying the above once again +connection master; + +begin; +delete from t1; +commit; + +sync_slave_with_master; + + +# +# 2. the event size is bigger than the cache's buffer +# +connection master; + +flush status; +let $t2_data_size= `select 3 * @@global.binlog_cache_size`; +let $t2_aver_size= `select 2 * @@global.binlog_cache_size`; +let $t2_max_rand= `select 1 * @@global.binlog_cache_size`; + +eval create table t2(a int auto_increment primary key, data VARCHAR($t2_data_size)) ENGINE=Innodb; +let $1=100; +--disable_query_log +begin; +while ($1) +{ + eval select round($t2_aver_size + RAND() * $t2_max_rand) into @act_size; + set @data = repeat('a', @act_size); + insert into t2 set data = @data; + dec $1; +} +commit; +--enable_query_log +show status like "binlog_cache_use"; +--echo *** binlog_cache_disk_use must be non-zero *** +show status like "binlog_cache_disk_use"; + +sync_slave_with_master; + +let $diff_tables=master:test.t2, slave:test.t2; +source include/diff_tables.inc; + +# undoing changes with verifying the above once again +connection master; + +begin; +delete from t2; +commit; + +sync_slave_with_master; + +# +# 3. the event size if approximately the same as the cache's buffer +# + +connection master; + +flush status; +let $t3_data_size= `select 2 * @@global.binlog_cache_size`; +let $t3_aver_size= `select (9 * @@global.binlog_cache_size) / 10`; +let $t3_max_rand= `select (2 * @@global.binlog_cache_size) / 10`; + +eval create table t3(a int auto_increment primary key, data VARCHAR($t3_data_size)) engine=innodb; + +let $1= 300; +--disable_query_log +begin; +while ($1) +{ + eval select round($t3_aver_size + RAND() * $t3_max_rand) into @act_size; + insert into t3 set data= repeat('a', @act_size); + dec $1; +} +commit; +--enable_query_log +show status like "binlog_cache_use"; +--echo *** binlog_cache_disk_use must be non-zero *** +show status like "binlog_cache_disk_use"; + +sync_slave_with_master; + +let $diff_tables=master:test.t3, slave:test.t3; +source include/diff_tables.inc; + +# undoing changes with verifying the above once again +connection master; + +begin; +delete from t3; +commit; + +sync_slave_with_master; + + +# +# 4. all in above +# + +connection master; +flush status; + +delimiter |; +eval create procedure test.p1 (n int) +begin + while n > 0 do + case (select (round(rand()*100) % 3) + 1) + when 1 then + select round(RAND() * $deviation_size) into @act_size; + set @data = repeat('a', @act_size); + insert into t1 values(n, @data); + when 2 then + begin + select round($t2_aver_size + RAND() * $t2_max_rand) into @act_size; + insert into t2 set data=repeat('a', @act_size); + end; + when 3 then + begin + select round($t3_aver_size + RAND() * $t3_max_rand) into @act_size; + insert into t3 set data= repeat('a', @act_size); + end; + end case; + set n= n-1; + end while; +end| +delimiter ;| + +let $1= 1000; +set autocommit= 0; +begin; +--disable_warnings +eval call test.p1($1); +--enable_warnings +commit; + +show status like "binlog_cache_use"; +--echo *** binlog_cache_disk_use must be non-zero *** +show status like "binlog_cache_disk_use"; + +sync_slave_with_master; + +let $diff_tables=master:test.t1, slave:test.t1; +source include/diff_tables.inc; + +let $diff_tables=master:test.t2, slave:test.t2; +source include/diff_tables.inc; + +let $diff_tables=master:test.t3, slave:test.t3; +source include/diff_tables.inc; + + +connection master; + +begin; +delete from t1; +delete from t2; +delete from t3; +commit; + +drop table t1, t2, t3; +set @@global.binlog_cache_size = @save_binlog_cache_size; +set @@global.binlog_checksum = @save_binlog_checksum; +set @@global.master_verify_checksum = @save_master_verify_checksum; +drop procedure test.p_init; +drop procedure test.p1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_circular_for_4_hosts.cnf b/mysql-test/suite/rpl/t/rpl_circular_for_4_hosts.cnf new file mode 100644 index 00000000..3ff94e45 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_circular_for_4_hosts.cnf @@ -0,0 +1,24 @@ +!include ../my.cnf + +[mysqld.1] +log-slave-updates +loose-innodb + +[mysqld.2] +log-slave-updates +loose-innodb + +[mysqld.3] +log-slave-updates +loose-innodb + +[mysqld.4] +log-slave-updates +loose-innodb + +[ENV] +SERVER_MYPORT_3= @mysqld.3.port +SERVER_MYSOCK_3= @mysqld.3.socket + +SERVER_MYPORT_4= @mysqld.4.port +SERVER_MYSOCK_4= @mysqld.4.socket diff --git a/mysql-test/suite/rpl/t/rpl_circular_for_4_hosts.test b/mysql-test/suite/rpl/t/rpl_circular_for_4_hosts.test new file mode 100644 index 00000000..aeb849b8 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_circular_for_4_hosts.test @@ -0,0 +1,339 @@ +# ==== Purpose ==== +# +# Setup: circular replication on four hosts, i.e., topology +# server_1 -> server_2 -> server_3 -> server_4 -> server_1 +# +# Tested properties: +# - Correctly configured autoinc works. +# - Manual failover works. +# +# ==== Related bugs and worklogs ==== +# +# WL#3754 +# BUG#49978 + +--source include/have_innodb.inc + +# Use wait_for_slave_to_(start|stop) for current connections +let $keep_connection= 1; + +# Set up circular ring and new names for servers +--echo *** Set up circular replication on four servers *** +--let $rpl_topology= 1->2->3->4->1 +--source include/rpl_init.inc +--echo + +#set auto inc variables at each server +--let $_rpl_server= $rpl_server_count +while ($_rpl_server) +{ + connection server_$_rpl_server; + eval SET auto_increment_increment= $rpl_server_count; + eval SET auto_increment_offset= $_rpl_server; + + --dec $_rpl_server +} + +# Preparing data. +--echo *** Preparing data *** +--connection server_1 +CREATE TABLE t1 (a INT NOT NULL AUTO_INCREMENT, b VARCHAR(100), c INT NOT NULL, PRIMARY KEY(a)) ENGINE=MyISAM; +CREATE TABLE t2 (a INT NOT NULL AUTO_INCREMENT, b VARCHAR(100), c INT NOT NULL, PRIMARY KEY(a)) ENGINE=InnoDB; +# MDEV-515 takes X-lock on the table. So it won't allow +# concurrent DML to happen at the same time +INSERT INTO t2 (b,c) VALUES('MDEV-515', 100); +--source include/rpl_sync.inc +--connection server_4 +call mtr.add_suppression("Slave SQL.*Request to stop slave SQL Thread received while applying a group that has non-transactional changes; waiting for completion of the group"); +--echo + +# +# Testing +# + +--echo *** Testing schema A->B->C->D->A *** +--echo +# insert data via all hosts +--connection server_1 +INSERT INTO t1(b,c) VALUES('A',1); +--sync_slave_with_master server_2 +INSERT INTO t1(b,c) VALUES('B',1); +--sync_slave_with_master server_3 +INSERT INTO t1(b,c) VALUES('C',1); +--sync_slave_with_master server_4 +INSERT INTO t1(b,c) VALUES('D',1); + +--source include/rpl_sync.inc + +--connection server_1 +SELECT 'Master A',a,b FROM t1 WHERE c = 1 ORDER BY a,b; +--connection server_2 +SELECT 'Master B',a,b FROM t1 WHERE c = 1 ORDER BY a,b; +--connection server_3 +SELECT 'Master C',a,b FROM t1 WHERE c = 1 ORDER BY a,b; +--connection server_4 +SELECT 'Master D',a,b FROM t1 WHERE c = 1 ORDER BY a,b; +--echo + +--echo *** Testing schema A->B->D->A if C has failure *** +--echo +--echo * Do failure for C and then make new connection B->D * + +# Note: server_N has auto_increment_offset=N. Below, we insert value 6 +# in the autoinc column on server_3 (and prevent it from replicating +# further using SQL_SLAVE_SKIP_COUNTER on server_4). Due to the +# auto_increment_offset setting, the autoinc value 6 is normally +# generated on server_2. When we later insert a row on server_2, we +# thus cause a duplicate key error on server_3. + +# Do not replicate next event from C +--connection server_4 +STOP SLAVE; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1; +source include/start_slave.inc; +--connection server_3 +INSERT INTO t1 VALUES(6,'C',2); +--sync_slave_with_master server_4 + +--connection server_2 +INSERT INTO t1(b,c) VALUES('B',2); +# Wait while C will stop. +--connection server_3 +# 1062 = ER_DUP_ENTRY +call mtr.add_suppression("Slave SQL.*Duplicate entry .6. for key .PRIMARY.* error.* 1062"); +--let $slave_sql_errno= 1062 +--source include/wait_for_slave_sql_error.inc +--connection server_1 +INSERT INTO t1(b,c) VALUES('A',2); +--connection server_4 +INSERT INTO t1(b,c) VALUES('D',2); + + +# Sync all servers except C +--connection server_2 +let $wait_condition= SELECT COUNT(*)=3 FROM t1 WHERE a > 4; +--let $server_connection= server_1 +--source include/wait_condition.inc + +--echo +--echo * Data on servers (C failed) * +# Masters C,D shouldn't have correct data +--connection server_1 +SELECT 'Master A',a,b FROM t1 WHERE c = 2 ORDER BY a,b; +--connection server_2 +SELECT 'Master B',a,b FROM t1 WHERE c = 2 ORDER BY a,b; +--connection server_3 +SELECT 'Master C',a,b FROM t1 WHERE c = 2 ORDER BY a,b; +--connection server_4 +SELECT 'Master D',a,b FROM t1 WHERE c = 2 ORDER BY a,b; +--echo + +--echo * Reconfigure replication to schema A->B->D->A * +# Exclude Master C +--connection server_3 +--source include/stop_slave_io.inc +--let $pos_c= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1) +--let $file_c= query_get_value(SHOW SLAVE STATUS, Master_Log_File, 1) + +--connection server_4 +--source include/stop_slave.inc + +--let $rpl_topology= 1->2->4->1,2->3 +--let $rpl_master_log_file= 4:$file_c +--let $rpl_master_log_pos= 4:$pos_c +--source include/rpl_change_topology.inc + +#--replace_result $SERVER_MYPORT_2 SERVER_MYPORT_2 $file_c LOG_FILE $pos_c LOG_POS +#--eval CHANGE MASTER TO master_host='127.0.0.1',master_port=$SERVER_MYPORT_2,master_user='root',master_log_file='$file_c',master_log_pos=$pos_c +source include/start_slave.inc; +--connection server_2 +--sync_slave_with_master server_4 +--sync_slave_with_master server_1 +--echo + +--echo * Check data inserted before failure * +--connection server_1 +SELECT 'Master A',a,b FROM t1 WHERE c = 2 ORDER BY a,b; +--connection server_2 +SELECT 'Master B',a,b FROM t1 WHERE c = 2 ORDER BY a,b; +--connection server_3 +SELECT 'Master C',a,b FROM t1 WHERE c = 2 ORDER BY a,b; +--connection server_4 +SELECT 'Master D',a,b FROM t1 WHERE c = 2 ORDER BY a,b; +--echo + +--echo * Check data inserted after failure * +--connection server_1 +INSERT INTO t1(b,c) VALUES('A',3); +--connection server_2 +INSERT INTO t1(b,c) VALUES('B',3); +--connection server_4 +INSERT INTO t1(b,c) VALUES('D',3); +connection server_1; + +--let $rpl_only_running_threads= 1 +--source include/rpl_sync.inc + +--connection server_1 +SELECT 'Master A',a,b FROM t1 WHERE c = 3 ORDER BY a,b; +--connection server_2 +SELECT 'Master B',a,b FROM t1 WHERE c = 3 ORDER BY a,b; +--connection server_3 +SELECT 'Master C',a,b FROM t1 WHERE c = 3 ORDER BY a,b; +--connection server_4 +SELECT 'Master D',a,b FROM t1 WHERE c = 3 ORDER BY a,b; +--connection server_1 +--echo + +--echo *** Testing restoring scheme A->B->C->D->A after failure *** +--echo +# Master D will ignore a next event from C so that event will not be +# distributed to other servers +--echo * Remove wrong event from C and restore B->C->D * +--connection server_4 +source include/stop_slave.inc; +--connection server_3 +DELETE FROM t1 WHERE a = 6; +--source include/start_slave.inc +--connection server_2 +--sync_slave_with_master server_3 +RESET MASTER; +--let $file_d= query_get_value(SHOW MASTER STATUS, File, 1) +--let $pos_d= query_get_value(SHOW MASTER STATUS, Position, 1) +--connection server_4 +RESET SLAVE; +--let $rpl_topology= 1->2->3->4->1 +--let $rpl_master_log_file= 4:$file_d +--let $rpl_master_log_pos= 4:$pos_d +--source include/rpl_change_topology.inc +#--replace_result $SERVER_MYPORT_3 SERVER_MYPORT_3 $file_d LOG_FILE $pos_d LOG_POS +#--eval CHANGE MASTER TO master_host='127.0.0.1',master_port=$SERVER_MYPORT_3,master_user='root',master_log_file='$file_d',master_log_pos=$pos_d +--source include/start_slave.inc +--connection server_3 +--sync_slave_with_master server_4 +--source include/rpl_sync.inc + +--echo +--echo * Check data inserted before restoring schema A->B->C->D->A * +--connection server_1 +SELECT 'Master A',a,b FROM t1 WHERE c IN (2,3) ORDER BY a,b; +--sync_slave_with_master server_2 +SELECT 'Master B',a,b FROM t1 WHERE c IN (2,3) ORDER BY a,b; +--sync_slave_with_master server_3 +SELECT 'Master C',a,b FROM t1 WHERE c IN (2,3) ORDER BY a,b; +--sync_slave_with_master server_4 +SELECT 'Master D',a,b FROM t1 WHERE c IN (2,3) ORDER BY a,b; +--sync_slave_with_master server_1 +--echo + +--echo * Check data inserted after restoring schema A->B->C->D->A * +--connection server_1 +INSERT INTO t1(b,c) VALUES('A',4); +--connection server_2 +INSERT INTO t1(b,c) VALUES('B',4); +--connection server_3 +INSERT INTO t1(b,c) VALUES('C',4); +--connection server_4 +INSERT INTO t1(b,c) VALUES('D',4); +--connection server_1 + +--source include/rpl_sync.inc + +--connection server_1 +SELECT 'Master A',a,b FROM t1 WHERE c = 4 ORDER BY a,b; +--connection server_2 +SELECT 'Master B',a,b FROM t1 WHERE c = 4 ORDER BY a,b; +--connection server_3 +SELECT 'Master C',a,b FROM t1 WHERE c = 4 ORDER BY a,b; +--connection server_4 +SELECT 'Master D',a,b FROM t1 WHERE c = 4 ORDER BY a,b; +--connection server_1 +--echo + +--echo * Transactions with commits * +# Testing mixing of transactions and regular inserts +--connection server_1 +BEGIN; +--connection server_3 +BEGIN; +let $counter= 100; +--connection server_1 +--disable_query_log +while ($counter) { + --connection server_1 + INSERT INTO t2(b,c) VALUES('A',1); + --connection server_2 + INSERT INTO t2(b,c) VALUES('B',1); + --connection server_3 + INSERT INTO t2(b,c) VALUES('C',1); + --connection server_4 + INSERT INTO t2(b,c) VALUES('D',1); + dec $counter; +} +--connection server_1 +COMMIT; +--connection server_3 +COMMIT; +--connection server_1 +--enable_query_log + +--source include/rpl_sync.inc + +--connection server_1 +SELECT 'Master A',b,COUNT(*) FROM t2 WHERE c = 1 GROUP BY b ORDER BY b; +--connection server_2 +SELECT 'Master B',b,COUNT(*) FROM t2 WHERE c = 1 GROUP BY b ORDER BY b; +--connection server_3 +SELECT 'Master C',b,COUNT(*) FROM t2 WHERE c = 1 GROUP BY b ORDER BY b; +--connection server_4 +SELECT 'Master D',b,COUNT(*) FROM t2 WHERE c = 1 GROUP BY b ORDER BY b; +--connection server_1 +--echo + +--echo * Transactions with rollbacks * +# Testing mixing of transactions with rollback and regular inserts +--connection server_1 +BEGIN; +--connection server_3 +BEGIN; +let $counter= 100; +--connection server_1 +--disable_query_log +while ($counter) { + --connection server_1 + INSERT INTO t2(b,c) VALUES('A',2); + --connection server_2 + INSERT INTO t2(b,c) VALUES('B',2); + --connection server_3 + INSERT INTO t2(b,c) VALUES('C',2); + --connection server_4 + INSERT INTO t2(b,c) VALUES('D',2); + dec $counter; +} +--connection server_1 +ROLLBACK; +--connection server_3 +ROLLBACK; +--connection server_1 +--enable_query_log + +--source include/rpl_sync.inc + +--connection server_1 +SELECT 'Master A',b,COUNT(*) FROM t2 WHERE c = 2 GROUP BY b ORDER BY b; +--connection server_2 +SELECT 'Master B',b,COUNT(*) FROM t2 WHERE c = 2 GROUP BY b ORDER BY b; +--connection server_3 +SELECT 'Master C',b,COUNT(*) FROM t2 WHERE c = 2 GROUP BY b ORDER BY b; +--connection server_4 +SELECT 'Master D',b,COUNT(*) FROM t2 WHERE c = 2 GROUP BY b ORDER BY b; +--connection server_1 + +--echo + +# Clean up +--echo *** Clean up *** +--connection server_1 +DROP TABLE t1,t2; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_circular_semi_sync.cnf b/mysql-test/suite/rpl/t/rpl_circular_semi_sync.cnf new file mode 100644 index 00000000..be39fea9 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_circular_semi_sync.cnf @@ -0,0 +1,11 @@ +!include suite/rpl/rpl_1slave_base.cnf +!include include/default_client.cnf + + +[mysqld.1] +log-slave-updates +sync-binlog=1 + +[mysqld.2] +log-slave-updates +sync-binlog=1 diff --git a/mysql-test/suite/rpl/t/rpl_circular_semi_sync.test b/mysql-test/suite/rpl/t/rpl_circular_semi_sync.test new file mode 100644 index 00000000..267fa621 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_circular_semi_sync.test @@ -0,0 +1,188 @@ +# ==== References ==== +# +# MDEV-27760 event may non stop replicate in circular semisync setup +# MDEV-28609 refine gtid-strict-mode to ignore same server-id gtid from the past +# on semisync slave +--source include/have_innodb.inc +--source include/have_binlog_format_mixed.inc +--source include/master-slave.inc + +# The following tests prove +# A. +# no out-of-order gtid error is done to the stict gtid mode semisync +# slave receives the same server-id gtid event from the past (of its gtid +# state). Such transaction is silently ignored similarly to +# replicate_same_sever_id; and +# B. +# In contrast to A. the out-of-order gtid error is thrown when a "foreign" +# server-id transaction makes its round-trip to the originator server. + +--echo # Master server_1 and Slave server_2 initialization ... +--connection server_2 +--source include/stop_slave.inc + +# Initial master +--connection server_1 +RESET MASTER; +set @@session.gtid_domain_id=10; +set @@global.rpl_semi_sync_master_enabled = 1; +set @@global.rpl_semi_sync_master_wait_point=AFTER_SYNC; + +--connection server_2 +RESET MASTER; +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +set @@session.gtid_domain_id=20; +set @@global.rpl_semi_sync_slave_enabled = 1; +--echo # a 1948 warning is expected +set @@global.gtid_slave_pos = ""; +CHANGE MASTER TO master_use_gtid= slave_pos; +--source include/start_slave.inc +--echo # server_1 -> server_2 semisync link is set up. + +--connection server_1 +CREATE TABLE t1 (a INT PRIMARY KEY, b INT default 0) ENGINE=Innodb; +INSERT INTO t1(a) VALUES (1); +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc + +--echo # Circular configuration server_1 -> server_2 -> server_1 ... +--connection server_1 +set @@global.gtid_strict_mode = true; +set @@global.rpl_semi_sync_slave_enabled = 1; + +evalp CHANGE MASTER TO master_host='127.0.0.1', master_port=$SERVER_MYPORT_2, master_user='root', master_use_gtid=SLAVE_POS; +--source include/start_slave.inc +--echo ... is done. + +--echo ## A. no out-of-order gtid error for own transaction made round trip + +# A0. server_1 has already originated the transaction +--let $wait_condition=select @@gtid_slave_pos=@@gtid_binlog_pos +--source include/wait_condition.inc + +# A1. server_2 originates +--connection server_2 +set @@global.gtid_strict_mode = true; +set @@global.rpl_semi_sync_master_enabled = 1; +INSERT INTO t1(a) VALUES (2); +--source include/save_master_gtid.inc + +--connection server_1 +--echo # +--echo # the successful sync is a required proof +--echo # +--source include/sync_with_master_gtid.inc +# A2. server_1 is originating now +update t1 set b=b+1 where a=2; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc + +--echo # Post-execution state check on both servers synchronized with each other +--connection server_1 +--echo # ... the gtid states on server_1 +--let $wait_condition=select @@gtid_slave_pos=@@gtid_binlog_pos +--source include/wait_condition.inc +SHOW VARIABLES LIKE 'gtid_slave_pos'; +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +SELECT * from t1; + +--connection server_2 +--echo # The gtid states on server_2 must be equal to ... +--let $wait_condition=select @@gtid_slave_pos=@@gtid_binlog_pos +--source include/wait_condition.inc +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +SHOW VARIABLES LIKE 'gtid_slave_pos'; +SELECT * from t1; + +--echo ## B. out-of-order gtid error for a "foreign" server-id transaction +# B1. circulation starts from server_1 + +--connection server_1 +set statement sql_log_bin=0 for call mtr.add_suppression("Slave: An attempt was made to binlog GTID 10-2-4"); +set @@session.server_id=2; +INSERT INTO t1(a) VALUES (3); +set @@session.server_id=default; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc +INSERT INTO t1(a) VALUES (4); +--source include/save_master_gtid.inc + +--connection server_1 +--let $slave_sql_errno = 1950 +--source include/wait_for_slave_sql_error.inc +set sql_slave_skip_counter=1; +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + +# B2. circulation starts from server_2 +--connection server_2 +set statement sql_log_bin=0 for call mtr.add_suppression("Slave: An attempt was made to binlog GTID 20-1-3"); +set @@session.server_id=1; +INSERT INTO t1(a) VALUES (5); +set @@session.server_id=default; +--source include/save_master_gtid.inc + +--connection server_1 +--source include/sync_with_master_gtid.inc +INSERT INTO t1(a) VALUES (6); +--source include/save_master_gtid.inc + + +--connection server_2 +--let $slave_sql_errno = 1950 +--source include/wait_for_slave_sql_error.inc +set sql_slave_skip_counter=1; +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + +--echo # Post-execution state check on both servers synchronized with each other +--connection server_1 +--echo # ... the gtid states on server_1 +--let $wait_condition=select @@gtid_slave_pos=@@gtid_binlog_pos +--source include/wait_condition.inc +SHOW VARIABLES LIKE 'gtid_slave_pos'; +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +SELECT * from t1; + +--connection server_2 +--source include/sync_with_master_gtid.inc +--echo # The gtid states on server_2 must be equal to ... +--let $wait_condition=select @@gtid_slave_pos=@@gtid_binlog_pos +--source include/wait_condition.inc +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +SHOW VARIABLES LIKE 'gtid_slave_pos'; +SELECT * from t1; + +--echo # +--echo # Cleanup +--echo # +--connection server_1 +DROP TABLE t1; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc + +--connection server_1 +--source include/stop_slave.inc +set @@global.rpl_semi_sync_master_enabled = default; +set @@global.rpl_semi_sync_slave_enabled = default; +set @@global.rpl_semi_sync_master_wait_point=default; +set @@global.gtid_ignore_duplicates = default; +set @@global.gtid_strict_mode = default; + +--connection server_2 +--source include/stop_slave.inc +set @@global.gtid_ignore_duplicates = default; +set @@global.rpl_semi_sync_master_enabled = default; +set @@global.rpl_semi_sync_slave_enabled = default; +set @@global.gtid_strict_mode = default; +--source include/start_slave.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_colSize.test b/mysql-test/suite/rpl/t/rpl_colSize.test new file mode 100644 index 00000000..23c8bdc3 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_colSize.test @@ -0,0 +1,228 @@ +################################################################## +# rpl_colSize # +# # +# This test is designed to test the changes included in WL#3228. # +# The changes include the ability to replicate with the master # +# having columns that are smaller (shorter) than the slave. # +################################################################## + +-- source include/master-slave.inc + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +--echo **** Testing WL#3228 changes. **** +--echo *** Create "wider" table on slave *** +sync_slave_with_master; +STOP SLAVE; +--source include/wait_for_slave_to_stop.inc +--source include/reset_slave.inc + +SET @saved_slave_type_conversions = @@slave_type_conversions; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = 'ALL_NON_LOSSY'; + +eval CREATE TABLE t1 ( + a float (47), + b double (143,9), + c decimal (65,30), + d numeric (4,0), + e bit (32), + f char (21), + g varchar (1300), + h binary (33), + j varbinary (200), + k enum ('5','6','7', '8','9','0'), + l set ('1','2','3','4','5','6','7','8','9','0','11','12','13','14','15','16','17','18','19','21','22','23','24','25','26','27','28','29'), + m TINYBLOB, + n BLOB, + o MEDIUMBLOB, + p LONGBLOB, + q TINYTEXT, + r TEXT, + s MEDIUMTEXT, + t LONGTEXT +); + +--echo *** Create same table on master but with narrow columns *** +connection master; +eval CREATE TABLE t1 ( + a float (44), + b double (10,3), + c decimal (10,2), + d numeric (3,0), + e bit (16), + f char (10), + g varchar (100), + h binary (20), + j varbinary (20), + k enum ('5','6','7'), + l set ('1','2','3','4','5','6','7','8','9','0'), + m TINYBLOB, + n BLOB, + o MEDIUMBLOB, + p LONGBLOB, + q TINYTEXT, + r TEXT, + s MEDIUMTEXT, + t LONGTEXT +); + +RESET MASTER; + +--echo *** Start replication *** +connection slave; +START SLAVE; +--source include/wait_for_slave_to_start.inc + +--echo *** Insert data on master and display it. *** +connection master; + +INSERT INTO t1 () VALUES ( + 17.567, + 2.123, + 10.20, + 125, + hex(64), + 'TEST', + 'This is a test', + 'binary data', + 'more binary data', + '6', + '7', + "blob 1", + "blob 2", + "blob 3", + "blob 4", + "text 1", + "text 2", + "text 3", + "text 4"); + +# Replace values in columns that display differently between SBR & RBR +--replace_column 5 # 8 # +SELECT * FROM t1 ORDER BY a; + +--echo *** Select data from slave to compare *** +sync_slave_with_master; +connection slave; + +# Replace values in columns that display differently between SBR & RBR +--replace_column 5 # 8 # +SELECT * FROM t1 ORDER BY a; + +# Test boundary limits of varchar and char fields +# Master/Slave +# <256/<256 with m < s, m > s, and m == s <-- col a +# >255/<256 with m < s, m > s, and m == s <-- error will be caught in BUG#22086 +# <256/>255 with m < s, m > s, and m == s <-- col b +# >255/>255 with m < s, m > s, and m == s <-- col c +# +# Test boundary limits of CHAR fields +# Master/Slave +# <256/<256 with m < s, m > s, and m == s <-- col d +# >255/<256 with m < s, m > s, and m == s <-- error char limited to 255 chars +# <256/>255 with m < s, m > s, and m == s <-- error char limited to 255 chars +# >255/>255 with m < s, m > s, and m == s <-- error char limited to 255 chars + +connection master; +DROP TABLE t1; + +--echo Create varchar table on master +CREATE TABLE t1 ( + a VARCHAR(50), + b VARCHAR(100), + c VARCHAR(300), + d CHAR(5) +); + +sync_slave_with_master slave; + +--echo Alter varchar table on slave +ALTER TABLE t1 CHANGE COLUMN a a VARCHAR(100); +ALTER TABLE t1 CHANGE COLUMN b b VARCHAR(400); +ALTER TABLE t1 CHANGE COLUMN c c VARCHAR(500); +ALTER TABLE t1 CHANGE COLUMN d d CHAR(100); + +connection master; + +--echo Insert some values and select them on master +INSERT INTO t1 VALUES ("This is a test of col a.", + "This is another test of col b.", + "This is a test of the large col c.", + "Col d"); +SELECT * FROM t1; +--replace_result default DEFAULT +SHOW CREATE TABLE t1; + +sync_slave_with_master slave; + +--echo Insert some values and select them on slave +SELECT * FROM t1; +--replace_result default DEFAULT +SHOW CREATE TABLE t1; + + +# Test boundary limits of bit fields +# m < s, m % 8 != 0, and s % 8 == 0 col a +# m < s, m % 8 == 0, and s % 8 != 0 col b +# m < s, m % 8 != 0, and s % 8 != 0 col c +# m > s, m % 8 != 0, and s % 8 == 0 <-- error will be caught in BUG#22086 +# m > s, m % 8 == 0, and s % 8 != 0 <-- error will be caught in BUG#22086 +# m > s, m % 8 != 0, and s % 8 != 0 <-- error will be caught in BUG#22086 + +connection master; +DROP TABLE t1; + +--echo Create bit table on master +CREATE TABLE t1 ( + a BIT(7), + b BIT(8), + c BIT(21), + d BIT(11), + e BIT(11) +); + +sync_slave_with_master slave; + +--echo Create bit table on slave +DROP TABLE t1; +CREATE TABLE t1 ( + a BIT(16), + b BIT(22), + c BIT(54), + d BIT(25), + e BIT(13) +); + +connection master; + +--echo Insert some values and select them on master +INSERT INTO t1 VALUES ( + b'1010101', + b'10101011', + b'101010110101010101111', + b'10101010101', + b'10101011111' + ); + +SELECT BIN(a), BIN(b), BIN(c), BIN(d), BIN(e) FROM t1; +--replace_result default DEFAULT +SHOW CREATE TABLE t1; + +sync_slave_with_master slave; + +--echo Insert some values and select them on master +SELECT BIN(a), BIN(b), BIN(c), BIN(d), BIN(e) FROM t1; +--replace_result default DEFAULT +SHOW CREATE TABLE t1; + +--echo *** Cleanup *** +connection master; +DROP TABLE t1; +sync_slave_with_master; + +SET GLOBAL SLAVE_TYPE_CONVERSIONS = @saved_slave_type_conversions; + +# END 5.1 Test Case +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_commit_after_flush.test b/mysql-test/suite/rpl/t/rpl_commit_after_flush.test new file mode 100644 index 00000000..5d547908 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_commit_after_flush.test @@ -0,0 +1,5 @@ +-- source include/have_innodb.inc +-- source include/master-slave.inc +let $engine_type=innodb; +-- source include/rpl_commit_after_flush.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_concurrency_error-master.opt b/mysql-test/suite/rpl/t/rpl_concurrency_error-master.opt new file mode 100644 index 00000000..3f82baff --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_concurrency_error-master.opt @@ -0,0 +1 @@ +--loose-innodb-lock-wait-timeout=1 diff --git a/mysql-test/suite/rpl/t/rpl_concurrency_error.test b/mysql-test/suite/rpl/t/rpl_concurrency_error.test new file mode 100644 index 00000000..72179ef2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_concurrency_error.test @@ -0,0 +1,150 @@ +############################################################################### +#BUG#44581 Slave stops when transaction with non-transactional table gets +#lock wait timeout +# +# In STMT and MIXED modes, a statement that changes both non-transactional and +# transactional tables must be written to the binary log whenever there are +# changes to non-transactional tables. This means that the statement gets into +# the # binary log even when the changes to the transactional tables fail. In +# particular, in the presence of a failure such statement is annotated with the +# error number and wrapped in a begin/rollback. On the slave, while applying +# the statement, it is expected the same failure and the rollback prevents the +# transactional changes to be persisted. + +# This test aims to verify if a statement that updates both transactional and +# non-transacitonal tables and fails due to concurrency problems is correctly +# processed by the slave in the sense that the statements get into the binary +# log, the error is ignored and only the non-transactional tables are changed. +############################################################################### + +--source include/have_innodb.inc +--source include/have_binlog_format_statement.inc +--source include/master-slave.inc + +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); + +--echo ######################################################################## +--echo # Environment +--echo ######################################################################## +connection master; + +CREATE TABLE t (i INT, PRIMARY KEY(i), f CHAR(8)) engine = Innodb; +CREATE TABLE n (d DATETIME, f CHAR(32)) engine = MyIsam; + +DELIMITER |; +CREATE TRIGGER tr AFTER UPDATE ON t FOR EACH ROW +BEGIN + INSERT INTO n VALUES ( now(), concat( 'updated t: ', old.f, ' -> ', new.f ) ); +END | +DELIMITER ;| + +INSERT INTO t VALUES (4,'black'), (2,'red'), (3,'yelow'), (1,'cyan'); + +connect (conn1, 127.0.0.1,root,,); +connect (conn2, 127.0.0.1,root,,); + +--echo ######################################################################## +--echo # Testing ER_LOCK_WAIT_TIMEOUT +--echo ######################################################################## + +let $type=2; + +while ($type) +{ + let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); + connection conn1; + if ($type == 2) + { + SET AUTOCOMMIT = 1; + BEGIN; + } + if ($type == 1) + { + SET AUTOCOMMIT = 0; + } + eval UPDATE t SET f = 'yellow $type' WHERE i = 3; + + connection conn2; + if ($type == 2) + { + SET AUTOCOMMIT = 1; + BEGIN; + } + if ($type == 1) + { + SET AUTOCOMMIT = 0; + } + --error ER_LOCK_WAIT_TIMEOUT + eval UPDATE IGNORE t SET f = 'magenta $type' WHERE f = 'red'; + eval INSERT INTO t VALUES (5 + ($type * 10),"brown"); + INSERT INTO n VALUES (now(),"brown"); + + connection conn1; + COMMIT; + + connection conn2; + ROLLBACK; + --source include/show_binlog_events.inc + + let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); + connection conn1; + if ($type == 2) + { + SET AUTOCOMMIT = 1; + BEGIN; + } + if ($type == 1) + { + SET AUTOCOMMIT = 0; + } + eval UPDATE t SET f = 'gray $type' WHERE i = 3; + + connection conn2; + if ($type == 2) + { + SET AUTOCOMMIT = 1; + BEGIN; + } + if ($type == 1) + { + SET AUTOCOMMIT = 0; + } + --error ER_LOCK_WAIT_TIMEOUT + eval UPDATE IGNORE t SET f = 'dark blue $type' WHERE f = 'red'; + eval INSERT INTO t VALUES (6 + ($type * 10),"brown"); + INSERT INTO n VALUES (now(),"brown"); + + connection conn1; + COMMIT; + + connection conn2; + COMMIT; + --source include/show_binlog_events.inc + + dec $type; +} + +connection master; +sync_slave_with_master; + +let $rpl_diff_statement= SELECT * FROM t order by i; +source include/rpl_diff.inc; + +let $rpl_diff_statement= SELECT * FROM n order by d, f; +source include/rpl_diff.inc; + +--echo ######################################################################## +--echo # Cleanup +--echo ######################################################################## + +connection master; +DROP TRIGGER tr; +DROP TABLE t; +DROP TABLE n; + +sync_slave_with_master; + +connection master; +disconnect conn1; +disconnect conn2; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_conditional_comments.test b/mysql-test/suite/rpl/t/rpl_conditional_comments.test new file mode 100644 index 00000000..6e4ec874 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_conditional_comments.test @@ -0,0 +1,84 @@ +############################################################################### +# After the patch for BUG#49124: +# - Use ' ' instead of '!' in the conditional comments which are not applied on +# master. So they become common comments and will not be applied on slave. +# +# - Example: +# 'INSERT INTO t1 VALUES (1) /*!10000, (2)*/ /*!999999 ,(3)*/ +# will be binlogged as +# 'INSERT INTO t1 VALUES (1) /*!10000, (2)*/ /* 99999 ,(3)*/'. +############################################################################### +source include/have_binlog_format_statement.inc; +source include/master-slave.inc; + +CREATE TABLE t1(c1 INT); +source include/show_binlog_events.inc; +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); + +--echo +--echo # Case 1: +--echo # ------------------------------------------------------------------ +--echo # In a statement, some CCs are applied while others are not. The CCs +--echo # which are not applied on master will be binlogged as common comments. + +/*!999999 --- */INSERT /*!INTO*/ /*!10000 t1 */ VALUES(10) /*!999999 ,(11)*/; + +source include/show_binlog_events.inc; +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +sync_slave_with_master; +--let $diff_tables= master:t1,slave:t1 +--source include/diff_tables.inc + +--echo +--echo # Case 2: +--echo # ----------------------------------------------------------------- +--echo # Verify whether it can be binlogged correctly when executing prepared +--echo # statement. +--connection master +PREPARE stmt FROM 'INSERT INTO /*!999999 blabla*/ t1 VALUES(60) /*!999999 ,(61)*/'; +EXECUTE stmt; +DROP TABLE t1; +CREATE TABLE t1(c1 INT); +EXECUTE stmt; + +sync_slave_with_master; +--let $diff_tables= master:t1,slave:t1 +--source include/diff_tables.inc + +--connection master +--echo +SET @value=62; +PREPARE stmt FROM 'INSERT INTO /*!999999 blabla */ t1 VALUES(?) /*!999999 ,(63)*/'; +EXECUTE stmt USING @value; +DROP TABLE t1; +CREATE TABLE t1(c1 INT); +EXECUTE stmt USING @value; + +source include/show_binlog_events.inc; +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); + +sync_slave_with_master; +--let $diff_tables= master:t1,slave:t1 +--source include/diff_tables.inc + +--echo +--echo # Case 3: +--echo # ----------------------------------------------------------------- +--echo # Verify it can restore the '!', if the it is an uncomplete conditional +--echo # comments +--connection master +--error 1064 +SELECT c1 FROM /*!999999 t1 WHEREN; #*/ + +# +# Bug#28388217 - SERVER CAN FAIL WHILE REPLICATING CONDITIONAL COMMENTS +# +insert t1 values (/*!50505 1 /* foo */ */ + 2); +insert t1 values (/*!999999 10 /* foo */ */ + 20); +source include/show_binlog_events.inc; +sync_slave_with_master; +select * from t1; +connection master; + +DROP TABLE t1; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_connection.test b/mysql-test/suite/rpl/t/rpl_connection.test new file mode 100644 index 00000000..31024006 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_connection.test @@ -0,0 +1,24 @@ +--source include/not_embedded.inc +--source include/have_binlog_format_mixed.inc +--source include/master-slave.inc + +# +# BUG#13427949: CHANGE MASTER TO USER='' (EMPTY USER) CAUSES ERRORS ON VALGRING +# + +--connection slave +call mtr.add_suppression(".*Invalid .* username when attempting to connect to the master server.*"); + + +# Assert that we disallow empty users and that no problem +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USER= '', MASTER_PASSWORD= ''; +START SLAVE; +--let $slave_io_errno= 1045, 1593 +--source include/wait_for_slave_io_error.inc +--source include/stop_slave.inc + +CHANGE MASTER TO MASTER_USER= 'root', MASTER_PASSWORD= ''; +START SLAVE; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_corruption-master.opt b/mysql-test/suite/rpl/t/rpl_corruption-master.opt new file mode 100644 index 00000000..2612c17a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_corruption-master.opt @@ -0,0 +1 @@ +--binlog-checksum=CRC32 --master-verify-checksum=1 diff --git a/mysql-test/suite/rpl/t/rpl_corruption-slave.opt b/mysql-test/suite/rpl/t/rpl_corruption-slave.opt new file mode 100644 index 00000000..b32a5240 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_corruption-slave.opt @@ -0,0 +1 @@ +--binlog-checksum=CRC32 --slave-sql-verify-checksum=1 diff --git a/mysql-test/suite/rpl/t/rpl_corruption.test b/mysql-test/suite/rpl/t/rpl_corruption.test new file mode 100644 index 00000000..cd2a1cc7 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_corruption.test @@ -0,0 +1,181 @@ +# +# This include file is used by more than one test suite +# (currently rpl and binlog_encryption). +# Please check all dependent tests after modifying it +# + +############################################################ +# Purpose: WL#5064 Testing with corrupted events. +# The test emulates the corruption at the vary stages +# of replication: +# - in binlog file +# - in network +# - in relay log +############################################################ + +# +# The tests intensively utilize @@global.debug. Note, +# Bug#11765758 - 58754, +# @@global.debug is read by the slave threads through dbug-interface. +# Hence, before a client thread set @@global.debug we have to ensure that: +# (a) the slave threads are stopped, or (b) the slave threads are in +# sync and waiting. + +--source include/have_debug.inc +--source include/master-slave.inc + +--connection slave +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=NO; +--source include/start_slave.inc +--connection master + +# Block legal errors for MTR +call mtr.add_suppression('Found invalid event in binary log'); +call mtr.add_suppression('Slave I/O: Relay log write failure: could not queue event from master'); +call mtr.add_suppression('event read from binlog did not pass crc check'); +call mtr.add_suppression('Replication event checksum verification failed'); +call mtr.add_suppression('Event crc check failed! Most likely there is event corruption'); +call mtr.add_suppression('Slave SQL: Error initializing relay log position: I/O error reading event at position .*, error.* 1593'); + +SET @old_master_verify_checksum = @@master_verify_checksum; + +# Creating test table/data and set corruption position for testing +--echo # 1. Creating test table/data and set corruption position for testing +--connection master +--echo * insert/update/delete rows in table t1 * +# Corruption algorithm modifies only the first event and +# then will be reset. To avoid checking always the first event +# from binlog (usually it is FD) we randomly execute different +# statements and set position for corruption inside events. + +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b VARCHAR(10), c VARCHAR(100)); +--disable_query_log +let $i=`SELECT 3+CEILING(10*RAND())`; +let $j=1; +let $pos=0; +while ($i) { + eval INSERT INTO t1 VALUES ($j, 'a', NULL); + if (`SELECT RAND() > 0.7`) + { + eval UPDATE t1 SET c = REPEAT('a', 20) WHERE a = $j; + } + if (`SELECT RAND() > 0.8`) + { + eval DELETE FROM t1 WHERE a = $j; + } + if (!$pos) { + let $pos= query_get_value(SHOW MASTER STATUS, Position, 1); + --sync_slave_with_master + --source include/stop_slave.inc + --disable_query_log + --connection master + } + dec $i; + inc $j; +} +--enable_query_log + + +# Emulate corruption in binlog file when SHOW BINLOG EVENTS is executing +--echo # 2. Corruption in master binlog and SHOW BINLOG EVENTS +SET @saved_dbug = @@global.debug_dbug; +SET @@global.debug_dbug="d,corrupt_read_log_event_char"; +--echo SHOW BINLOG EVENTS; +--disable_query_log +send_eval SHOW BINLOG EVENTS FROM $pos; +--enable_query_log +--error ER_ERROR_WHEN_EXECUTING_COMMAND +reap; + +SET @@global.debug_dbug=@saved_dbug; + +# Emulate corruption on master with crc checking on master +--echo # 3. Master read a corrupted event from binlog and send the error to slave + +# We have a rare but nasty potential race here: if the dump thread on +# the master for the _old_ slave connection has not yet discovered +# that the slave has disconnected, we will inject the corrupt event on +# the wrong connection, and the test will fail +# (+d,corrupt_read_log_event2 corrupts only one event). +# So kill any lingering dump thread (we need to kill; otherwise dump thread +# could manage to send all events down the socket before seeing it close, and +# hang forever waiting for new binlog events to be created). +let $id= `select id from information_schema.processlist where command = "Binlog Dump"`; +if ($id) +{ + --disable_query_log + --error 0,1094 + eval kill $id; + --enable_query_log +} +let $wait_condition= + SELECT COUNT(*)=0 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE command = 'Binlog Dump'; +--source include/wait_condition.inc + +SET @@global.debug_dbug="d,corrupt_read_log_event2_set"; +--connection slave +START SLAVE IO_THREAD; +let $slave_io_errno= 1236; +--let $slave_timeout= 10 +--source include/wait_for_slave_io_error.inc +--connection master +SET @@global.debug_dbug=@saved_dbug; + +# Emulate corruption on master without crc checking on master +--echo # 4. Master read a corrupted event from binlog and send it to slave +--connection master +SET GLOBAL master_verify_checksum=0; +SET @@global.debug_dbug="d,corrupt_read_log_event2_set"; +--connection slave +START SLAVE IO_THREAD; +# When the checksum error is detected, the slave sets error code 1743 +# (ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE) in queue_event(), then immediately +# sets error 1595 (ER_SLAVE_RELAY_LOG_WRITE_FAILURE) in handle_slave_io(). +# So we usually get 1595, but it is occasionally possible to get 1743. +let $slave_io_errno= 1595,1743; # ER_SLAVE_RELAY_LOG_WRITE_FAILURE, ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE +--source include/wait_for_slave_io_error.inc +--connection master +SET @@global.debug_dbug=@saved_dbug; +SET GLOBAL master_verify_checksum=1; + +# Emulate corruption in network +--echo # 5. Slave. Corruption in network +--connection slave +SET @saved_dbug_slave = @@GLOBAL.debug_dbug; +SET @@global.debug_dbug="d,corrupt_queue_event"; +START SLAVE IO_THREAD; +let $slave_io_errno= 1595,1743; # ER_SLAVE_RELAY_LOG_WRITE_FAILURE, ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE +--source include/wait_for_slave_io_error.inc +SET @@global.debug_dbug=@saved_dbug_slave; + +# Emulate corruption in relay log +--echo # 6. Slave. Corruption in relay log + +SET @@global.debug_dbug="d,corrupt_read_log_event_char"; + +START SLAVE SQL_THREAD; +let $slave_sql_errno= 1593; +--source include/wait_for_slave_sql_error.inc + +SET @@global.debug_dbug=@saved_dbug_slave; + +# Start normal replication and compare same table on master +# and slave +--echo # 7. Seek diff for tables on master and slave +--connection slave +--source include/start_slave.inc +--connection master +--sync_slave_with_master +let $diff_tables= master:test.t1, slave:test.t1; +--source include/diff_tables.inc + +# Clean up +--echo # 8. Clean up +--connection master +set @@global.debug_dbug = @saved_dbug; +SET GLOBAL master_verify_checksum = @old_master_verify_checksum; +DROP TABLE t1; +--sync_slave_with_master + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_create_database-master.opt b/mysql-test/suite/rpl/t/rpl_create_database-master.opt new file mode 100644 index 00000000..85660a17 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_create_database-master.opt @@ -0,0 +1 @@ +--binlog-do-db=mysqltest_sisyfos --binlog-do-db=mysqltest_prometheus diff --git a/mysql-test/suite/rpl/t/rpl_create_database-slave.opt b/mysql-test/suite/rpl/t/rpl_create_database-slave.opt new file mode 100644 index 00000000..96d630c9 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_create_database-slave.opt @@ -0,0 +1 @@ +--replicate-do-db=mysqltest_sisyfos --replicate-do-db=mysqltest_prometheus diff --git a/mysql-test/suite/rpl/t/rpl_create_database.test b/mysql-test/suite/rpl/t/rpl_create_database.test new file mode 100644 index 00000000..5eac3de0 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_create_database.test @@ -0,0 +1,73 @@ +# +# Tests for replication of statements that manipulate databases. +# +# For this test file, we have a number of databases. All databases +# with "greek" names will be replicated on the slave, while other names +# (e.g., american) will not be replicated. +# + +source include/master-slave.inc; + +# Bug#6391 (binlog-do-db rules ignored) +# In this case, 'mysqltest_bob' should not be replicated to the slave. +--disable_warnings +DROP DATABASE IF EXISTS mysqltest_prometheus; +DROP DATABASE IF EXISTS mysqltest_sisyfos; +DROP DATABASE IF EXISTS mysqltest_bob; +sync_slave_with_master; +# This database is not replicated +DROP DATABASE IF EXISTS mysqltest_bob; +--enable_warnings + +connection master; +CREATE DATABASE mysqltest_prometheus; +CREATE DATABASE mysqltest_sisyfos; +CREATE DATABASE mysqltest_bob; + +USE mysqltest_sisyfos; +# These should be replicated +CREATE TABLE t1 (b int); +INSERT INTO t1 VALUES(1); + +USE mysqltest_bob; +# These should *not* be replicated +CREATE TABLE t2 (b int); +INSERT INTO t2 VALUES(2); + +# Current database is now 'mysqltest_bob' +# The following should be replicated +ALTER DATABASE mysqltest_sisyfos CHARACTER SET latin1; + +USE mysqltest_sisyfos; +# The following should *not* be replicated +ALTER DATABASE mysqltest_bob CHARACTER SET latin1; + +SHOW DATABASES LIKE 'mysql%'; +sync_slave_with_master; +SHOW DATABASES LIKE 'mysql%'; + +connection master; +DROP DATABASE IF EXISTS mysqltest_sisyfos; +USE mysqltest_prometheus; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1); +CREATE DATABASE mysqltest_sisyfos; +USE mysqltest_sisyfos; +CREATE TABLE t2 (a INT); +let $VERSION=`select version()`; +SHOW DATABASES LIKE 'mysql%'; +sync_slave_with_master; +SHOW DATABASES LIKE 'mysql%'; +USE mysqltest_prometheus; +SHOW TABLES; +USE mysqltest_sisyfos; +SHOW TABLES; + +connection master; +DROP DATABASE IF EXISTS mysqltest_prometheus; +DROP DATABASE IF EXISTS mysqltest_sisyfos; +DROP DATABASE IF EXISTS mysqltest_bob; +sync_slave_with_master; + +# End of 4.1 tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_create_drop_db.test b/mysql-test/suite/rpl/t/rpl_create_drop_db.test new file mode 100644 index 00000000..04721c9c --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_create_drop_db.test @@ -0,0 +1,33 @@ +--source include/master-slave.inc + +connection master; + +CREATE DATABASE db1; +CREATE DATABASE IF NOT EXISTS db1; +CREATE OR REPLACE DATABASE db2; +CREATE OR REPLACE DATABASE db1; +sync_slave_with_master; + +SHOW DATABASES LIKE 'db%'; + +connection master; +--error ER_DB_CREATE_EXISTS +CREATE DATABASE db1; + +--error ER_DB_DROP_EXISTS +DROP DATABASE db3; + +CREATE DATABASE IF NOT EXISTS db3; +sync_slave_with_master; + +SHOW DATABASES LIKE 'db%'; + +connection master; +DROP DATABASE db1; +DROP DATABASE db2; +DROP DATABASE IF EXISTS db3; +sync_slave_with_master; + +SHOW DATABASES LIKE 'db%'; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_create_drop_event.test b/mysql-test/suite/rpl/t/rpl_create_drop_event.test new file mode 100644 index 00000000..96a7e82d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_create_drop_event.test @@ -0,0 +1,27 @@ +--source include/master-slave.inc + +connection master; +SET GLOBAL event_scheduler=off; + +CREATE TABLE t1 (a INT); +CREATE EVENT ev1 ON SCHEDULE EVERY 1 SECOND DO INSERT INTO t1 VALUES (10); +--error ER_EVENT_ALREADY_EXISTS +CREATE EVENT ev1 ON SCHEDULE EVERY 1 SECOND DO INSERT INTO t1 VALUES (11); +CREATE OR REPLACE EVENT ev1 ON SCHEDULE EVERY 1 SECOND DO INSERT INTO t1 VALUES (11); +SELECT EVENT_NAME,STATUS,EVENT_DEFINITION FROM INFORMATION_SCHEMA.EVENTS; + +SET GLOBAL event_scheduler=on; +let $wait_condition= SELECT count(*)>0 FROM t1; +--source include/wait_condition.inc +SET GLOBAL event_scheduler=off; +SELECT DISTINCT a FROM t1; +DELETE FROM t1; + +--echo # Syncing slave with master +sync_slave_with_master; +SELECT EVENT_NAME,STATUS,EVENT_DEFINITION FROM INFORMATION_SCHEMA.EVENTS; +connection master; +DROP TABLE t1; +DROP EVENT ev1; +sync_slave_with_master; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_create_drop_function.test b/mysql-test/suite/rpl/t/rpl_create_drop_function.test new file mode 100644 index 00000000..5ae0b765 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_create_drop_function.test @@ -0,0 +1,54 @@ +--source include/master-slave.inc + +connection master; + +CREATE FUNCTION hello (str CHAR(20)) RETURNS CHAR(50) DETERMINISTIC RETURN +CONCAT('Hello, ', str, '!'); + +--error ER_SP_ALREADY_EXISTS +CREATE FUNCTION hello (str CHAR(20)) RETURNS CHAR(50) DETERMINISTIC RETURN +CONCAT('Hello, ', str, '!'); + +sync_slave_with_master; + +SHOW CREATE FUNCTION hello; + +connection master; + +--error ER_WRONG_USAGE +CREATE OR REPLACE FUNCTION IF NOT EXISTS hello (str CHAR(20)) RETURNS CHAR(50) DETERMINISTIC RETURN +CONCAT('Hello, ', str, '!'); + +CREATE OR REPLACE FUNCTION hello (str CHAR(20)) RETURNS CHAR(50) DETERMINISTIC RETURN +CONCAT('Hello, ', str, '!'); + +SELECT hello('master'); +sync_slave_with_master; + +SELECT hello('slave'); + +connection master; +CREATE FUNCTION IF NOT EXISTS hello (str CHAR(20)) RETURNS CHAR(50) DETERMINISTIC RETURN +CONCAT('Hello, ', str, '!'); + +CREATE OR REPLACE FUNCTION bye (str CHAR(20)) RETURNS CHAR(50) DETERMINISTIC RETURN +CONCAT('Bye, ', str, '!'); + +SELECT hello('master'); +SELECT bye('master'); +sync_slave_with_master; + +SELECT hello('slave'); +SELECT bye('slave'); + +connection master; +DROP FUNCTION hello; +DROP FUNCTION IF EXISTS bye; +sync_slave_with_master; + +--error ER_SP_DOES_NOT_EXIST +DROP FUNCTION hello; + +DROP FUNCTION IF EXISTS bye; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_create_drop_index.test b/mysql-test/suite/rpl/t/rpl_create_drop_index.test new file mode 100644 index 00000000..f1b65349 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_create_drop_index.test @@ -0,0 +1,17 @@ +--source include/master-slave.inc + +connection master; + +CREATE TABLE t1 (a INT, b INT); +CREATE INDEX i1 ON t1 (a); +CREATE OR REPLACE INDEX i1 ON t1 (a, b); +sync_slave_with_master; + +SHOW CREATE TABLE t1; + +connection master; +SHOW CREATE TABLE t1; +DROP TABLE t1; +sync_slave_with_master; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_create_drop_procedure.test b/mysql-test/suite/rpl/t/rpl_create_drop_procedure.test new file mode 100644 index 00000000..6fb0313c --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_create_drop_procedure.test @@ -0,0 +1,81 @@ +--source include/master-slave.inc + +connection master; +CREATE TABLE t1 (id INT); +DELIMITER $$; +CREATE PROCEDURE proc1 (OUT cnt INT) BEGIN SELECT COUNT(*) INTO cnt FROM t1; END$$ +DELIMITER ;$$ +CALL proc1(@cnt); +SELECT @cnt; +INSERT INTO t1 VALUES (1), (2), (3); +CALL proc1(@cnt); +SELECT @cnt; + +--echo # Syncing with slave +sync_slave_with_master; + +CALL proc1(@cnt); +SELECT @cnt; + +connection master; +DELIMITER $$; +--error ER_SP_ALREADY_EXISTS +CREATE PROCEDURE proc1 (OUT cnt INT) BEGIN SELECT COUNT(*) INTO cnt FROM t1; END$$ + +CREATE PROCEDURE IF NOT EXISTS proc1 (OUT cnt INT) BEGIN SELECT COUNT(*) INTO cnt FROM t1; END$$ + +--error ER_WRONG_USAGE +CREATE OR REPLACE PROCEDURE IF NOT EXISTS proc1 (OUT cnt INT) BEGIN SELECT COUNT(*) INTO cnt FROM t1; END$$ + +CREATE OR REPLACE PROCEDURE proc1 (OUT cnt INT) BEGIN SELECT COUNT(*) INTO cnt FROM t1; END$$ +DELIMITER ;$$ + +--echo # Syncing with slave +sync_slave_with_master; + +CALL proc1(@cnt); +SELECT @cnt; + +connection master; +DROP PROCEDURE proc1; +DELIMITER $$; +CREATE PROCEDURE IF NOT EXISTS proc1 (OUT cnt INT) BEGIN SELECT COUNT(*) INTO cnt FROM t1; END$$ +DELIMITER ;$$ +INSERT INTO t1 VALUES (1), (2), (3); +CALL proc1(@cnt); +SELECT @cnt; + +--echo # Syncing with slave +sync_slave_with_master; + +CALL proc1(@cnt); +SELECT @cnt; + +connection master; +DROP PROCEDURE proc1; +DELIMITER $$; +CREATE OR REPLACE PROCEDURE proc1 (OUT cnt INT) BEGIN SELECT COUNT(*) INTO cnt FROM t1; END$$ +DELIMITER ;$$ +INSERT INTO t1 VALUES (1), (2), (3); +CALL proc1(@cnt); +SELECT @cnt; + +--echo # Syncing with slave +sync_slave_with_master; + +CALL proc1(@cnt); +SELECT @cnt; + +connection master; +DROP TABLE IF EXISTS t1; +DROP PROCEDURE proc1; + +DROP PROCEDURE IF EXISTS proc2; + +--echo # Syncing with slave +sync_slave_with_master; + +--error ER_SP_DOES_NOT_EXIST +DROP PROCEDURE proc1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_create_drop_role.test b/mysql-test/suite/rpl/t/rpl_create_drop_role.test new file mode 100644 index 00000000..7260b473 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_create_drop_role.test @@ -0,0 +1,48 @@ +--source include/master-slave.inc + +connection master; +CREATE ROLE role_1; +sync_slave_with_master; + +SELECT User FROM mysql.user WHERE is_role='Y' ORDER BY User; + +connection master; +CREATE ROLE IF NOT EXISTS role_1; +CREATE ROLE IF NOT EXISTS role_2; +sync_slave_with_master; + +SELECT User FROM mysql.user WHERE is_role='Y' ORDER BY User; + +connection master; + +--error ER_WRONG_USAGE +CREATE OR REPLACE ROLE IF NOT EXISTS role_3; + +CREATE OR REPLACE ROLE role_3; +CREATE OR REPLACE ROLE role_2; +sync_slave_with_master; + +SELECT User FROM mysql.user WHERE is_role='Y' ORDER BY User; + +connection master; +--error ER_CANNOT_USER +CREATE ROLE role_2; + +sync_slave_with_master; + +SELECT User FROM mysql.user WHERE is_role='Y' ORDER BY User; + +connection master; +DROP ROLE role_1; +DROP ROLE IF EXISTS role_2; +DROP ROLE IF EXISTS role_3; +DROP ROLE IF EXISTS role_4; + +--error ER_CANNOT_USER +DROP ROLE role_4; + +sync_slave_with_master; + +SELECT User FROM mysql.user WHERE is_role='Y' ORDER BY User; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_create_drop_trigger.test b/mysql-test/suite/rpl/t/rpl_create_drop_trigger.test new file mode 100644 index 00000000..568d4e22 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_create_drop_trigger.test @@ -0,0 +1,48 @@ +--source include/master-slave.inc + +--echo # Part 1 - initial creation +connection master; +CREATE DATABASE db1; +USE db1; +CREATE TABLE t1 (val INT); +CREATE TRIGGER val_sum BEFORE INSERT ON t1 FOR EACH ROW SET @sum = @sum + NEW.val + 1; +SET @sum=0; +INSERT INTO t1 VALUES (10), (20), (30); +SELECT ACTION_STATEMENT AS ACTION_STATEMENT_Master FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum'; +sync_slave_with_master; +SELECT ACTION_STATEMENT AS ACTION_STATEMENT_Slave FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum'; + +--echo # Part 2 - CREATE IF NOT EXISTS (on a existing trigger) +connection master; +CREATE TRIGGER IF NOT EXISTS val_sum AFTER INSERT ON t1 FOR EACH ROW SET @sum = @sum + NEW.val + 2; +SELECT ACTION_STATEMENT AS ACTION_STATEMENT_Master FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum'; +sync_slave_with_master; +SELECT ACTION_STATEMENT AS ACTION_STATEMENT_Slave FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum'; + +--echo # Part 3 - CREATE OR REPLACE (on a existing trigger) +connection master; +CREATE OR REPLACE TRIGGER val_sum BEFORE INSERT ON t1 FOR EACH ROW SET @sum = @sum + NEW.val + 3; +SELECT ACTION_STATEMENT AS ACTION_STATEMENT_Master FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum'; +sync_slave_with_master; +SELECT ACTION_STATEMENT AS ACTION_STATEMENT_Slave FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum'; + +--echo # Clearing up +connection master; +DROP TRIGGER val_sum; +DROP TABLE t1; +DROP TRIGGER IF EXISTS val_sum; + +--error ER_TRG_DOES_NOT_EXIST +DROP TRIGGER random_trigger; +DROP DATABASE db1; + +--error ER_NO_DB_ERROR +DROP TRIGGER IF EXISTS val_sum; + +--echo # Syncing slave with master +sync_slave_with_master; + +--error ER_TRG_DOES_NOT_EXIST +DROP TRIGGER val_sum; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_create_drop_udf.test b/mysql-test/suite/rpl/t/rpl_create_drop_udf.test new file mode 100644 index 00000000..af24cabd --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_create_drop_udf.test @@ -0,0 +1,56 @@ +--source include/have_udf.inc +--source include/master-slave.inc + +connection master; + +--replace_result $UDF_EXAMPLE_SO UDF_EXAMPLE_LIB +eval CREATE FUNCTION metaphon RETURNS STRING SONAME "$UDF_EXAMPLE_SO"; +SELECT metaphon('master'); + +--replace_result $UDF_EXAMPLE_SO UDF_EXAMPLE_LIB +--error ER_UDF_EXISTS +eval CREATE FUNCTION metaphon RETURNS INT SONAME "$UDF_EXAMPLE_SO"; + +sync_slave_with_master; + +SELECT metaphon('slave'); + +connection master; + +--replace_result $UDF_EXAMPLE_SO UDF_EXAMPLE_LIB +eval CREATE FUNCTION IF NOT EXISTS metaphon RETURNS STRING SONAME "$UDF_EXAMPLE_SO"; +DROP FUNCTION IF EXISTS random_function_name; +--replace_result $UDF_EXAMPLE_SO UDF_EXAMPLE_LIB +eval CREATE FUNCTION IF NOT EXISTS metaphon RETURNS STRING SONAME "$UDF_EXAMPLE_SO"; + +--replace_result $UDF_EXAMPLE_SO UDF_EXAMPLE_LIB +--error ER_WRONG_USAGE +eval CREATE OR REPLACE FUNCTION IF NOT EXISTS metaphon RETURNS STRING SONAME "$UDF_EXAMPLE_SO"; +sync_slave_with_master; + +SELECT metaphon('slave'); + +connection master; +DROP FUNCTION metaphon; + +--replace_result $UDF_EXAMPLE_SO UDF_EXAMPLE_LIB +eval CREATE OR REPLACE FUNCTION metaphon RETURNS STRING SONAME "$UDF_EXAMPLE_SO"; + +--replace_result $UDF_EXAMPLE_SO UDF_EXAMPLE_LIB +--error ER_UDF_EXISTS +eval CREATE FUNCTION metaphon RETURNS STRING SONAME "$UDF_EXAMPLE_SO"; +sync_slave_with_master; + +SELECT metaphon('slave'); + +connection master; +DROP FUNCTION metaphon; +DROP FUNCTION IF EXISTS metaphon; +sync_slave_with_master; + +--error ER_SP_DOES_NOT_EXIST +DROP FUNCTION metaphon; + +DROP FUNCTION IF EXISTS metaphon; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_create_drop_user.test b/mysql-test/suite/rpl/t/rpl_create_drop_user.test new file mode 100644 index 00000000..c5f193a0 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_create_drop_user.test @@ -0,0 +1,57 @@ +--source include/master-slave.inc + +connection master; +CREATE USER u1@localhost IDENTIFIED BY 'abcdefghijk'; +connect (user_a, localhost, u1,'abcdefghijk',); +connection user_a; +SELECT CURRENT_USER; +disconnect user_a; + +connection master; +CREATE USER IF NOT EXISTS u2@localhost; +connect (user_a, localhost, u2,,); +connection user_a; +SELECT CURRENT_USER; +disconnect user_a; + +connection master; +--sorted_result +SELECT user,password,plugin,authentication_string FROM mysql.user WHERE user LIKE 'u%' ; +sync_slave_with_master; +--sorted_result +SELECT user,password,plugin,authentication_string FROM mysql.user WHERE user LIKE 'u%' ; + +connection master; +CREATE OR REPLACE USER u1@localhost IDENTIFIED BY 'abcdefghijk2'; +connect (user_a, localhost, u1,'abcdefghijk2',); +connection user_a; +SELECT CURRENT_USER; +disconnect user_a; +connection master; +--sorted_result +SELECT user,password,plugin,authentication_string FROM mysql.user WHERE user LIKE 'u%' ; +sync_slave_with_master; +--sorted_result +SELECT user,password,plugin,authentication_string FROM mysql.user WHERE user LIKE 'u%' ; + +connection master; +--error ER_CANNOT_USER +CREATE USER u1@localhost; + +--error ER_CANNOT_USER +DROP USER u3@localhost; + +sync_slave_with_master; +--sorted_result +SELECT user,password,plugin,authentication_string FROM mysql.user WHERE user LIKE 'u%' ; + +connection master; +DROP USER IF EXISTS u1@localhost; +DROP USER u2@localhost; +DROP USER IF EXISTS u3@localhost; +sync_slave_with_master; + +--sorted_result +SELECT user,password,plugin,authentication_string FROM mysql.user WHERE user LIKE 'u%' ; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_create_drop_view.test b/mysql-test/suite/rpl/t/rpl_create_drop_view.test new file mode 100644 index 00000000..4abb3ffb --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_create_drop_view.test @@ -0,0 +1,56 @@ +--source include/master-slave.inc + +connection master; +CREATE TABLE t1(id INT); +CREATE VIEW v1 AS SELECT * FROM t1 WHERE id>10; +INSERT INTO t1 VALUES (5), (8), (10), (20), (30); +SELECT * FROM t1; +SELECT * FROM v1; + +--echo # Syncing slave with master +sync_slave_with_master; +SELECT * FROM t1; +SELECT * FROM v1; + +connection master; +--error ER_TABLE_EXISTS_ERROR +CREATE VIEW v1 AS SELECT * FROM t1 WHERE id>10; + +CREATE VIEW IF NOT EXISTS v1 AS SELECT * FROM t1 WHERE id>10; + +--error ER_WRONG_USAGE +CREATE OR REPLACE VIEW IF NOT EXISTS v1 AS SELECT * FROM t1 WHERE id>10; + +--echo # Syncing slave with master +sync_slave_with_master; +SELECT * FROM t1; +SELECT * FROM v1; + +connection master; +CREATE OR REPLACE VIEW v1 AS SELECT * FROM t1 WHERE id>10; +INSERT INTO t1 VALUES (50), (80), (3), (2), (40); +SELECT * FROM t1; +SELECT * FROM v1; + +--echo # Syncing slave with master +sync_slave_with_master; +SELECT * FROM t1; +SELECT * FROM v1; + +connection master; +RENAME TABLE v1 TO v2; +DROP VIEW v2; +DROP TABLE t1; + +--error ER_UNKNOWN_VIEW +DROP VIEW v1; + +DROP VIEW IF EXISTS v2; + +--echo # Syncing slave with master +sync_slave_with_master; + +--error ER_NO_SUCH_TABLE +SELECT * FROM v1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_create_if_not_exists.test b/mysql-test/suite/rpl/t/rpl_create_if_not_exists.test new file mode 100644 index 00000000..b27250f9 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_create_if_not_exists.test @@ -0,0 +1,195 @@ +# BUG#45574: +# SP: CREATE DATABASE|TABLE IF NOT EXISTS not binlogged if routine exists. +# +# There is an inconsistency with DROP DATABASE|TABLE|EVENT IF EXISTS and +# CREATE DATABASE|TABLE|EVENT IF NOT EXISTS. DROP IF EXISTS statements are +# binlogged even if either the DB, TABLE or EVENT does not exist. In +# contrast, Only the CREATE EVENT IF NOT EXISTS is binlogged when the EVENT +# exists. +# +# This problem caused some of the tests to fail randomly on PB or PB2. +# +# Description: +# Fixed this bug by adding calls to write_bin_log in: +# mysql_create_db +# mysql_create_table_no_lock +# mysql_create_like_table +# create_table_from_items +# +# Test is implemented as follows: +# i) test each "CREATE IF NOT EXISTS" (DDL), found in MySQL 5.1 manual +# exclude CREATE TEMPORARY TABLE, on existent objects; +# +# Note: +# rpl_create_tmp_table_if_not_exists.test tests CREATE TEMPORARY TABLE cases. +# +# References: +# http://dev.mysql.com/doc/refman/5.1/en/sql-syntax-data-definition.html +# + +source include/master-slave.inc; +disable_warnings; +DROP DATABASE IF EXISTS mysqltest; + +CREATE DATABASE IF NOT EXISTS mysqltest; +USE mysqltest; +CREATE TABLE IF NOT EXISTS t(c1 int); +CREATE TABLE IF NOT EXISTS t1 LIKE t; +CREATE TABLE IF NOT EXISTS t2 SELECT * FROM t; +CREATE EVENT IF NOT EXISTS e +ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR +DO SELECT now(); +sync_slave_with_master; + +connection slave; +#DROP database from slave. +#The database and all tables can be recreated in slave +#if binlog of the second CREATE command is recorded and sent from master to slave. +DROP DATABASE mysqltest; + +connection master; +CREATE DATABASE IF NOT EXISTS mysqltest; +USE mysqltest; +CREATE TABLE IF NOT EXISTS t(c1 int); +CREATE TABLE IF NOT EXISTS t1 LIKE t; +# The following will not be logged because t2 existed and we will not +# put the data of SELECT into the binary log +CREATE TABLE IF NOT EXISTS t2 SELECT * FROM t; +CREATE EVENT IF NOT EXISTS e +ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR +DO SELECT now(); +sync_slave_with_master; + +connection slave; +SHOW TABLES in mysqltest; +#Execution time changes in each run. So we disregard it by calling replace_column. +replace_column 6 #; +SHOW EVENTS in mysqltest; + + +connection master; +DROP DATABASE IF EXISTS mysqltest; + +# +# BUG#47418 RBR fails, failure with mixup of base/temporary/view TABLE DDL +# +# Before the patch for this bug, 'CREATE TABLE IF NOT EXIST ... SELECT' +# statement was binlogged as a TEMPORARY table if the object existed as +# a temporary table. This was caused by that the temporary table was opened +# and the results of the 'SELECT' was inserted into the temporary table if +# a temporary table existed with the same name. +# +# After the patch for this bug, the base table is created and the results of +# the 'SELECT' are inserted into it, even though a temporary table exists with +# the same name, and the statement is still binlogged as a base table. +# + +echo -------------BUG#47418-------------; +connection master; +USE test; +DROP TABLE IF EXISTS t3; +--enable_warnings +CREATE TABLE t3(c1 INTEGER); +INSERT INTO t3 VALUES(33); + +CREATE TEMPORARY TABLE t1(c1 INTEGER); +CREATE TEMPORARY TABLE t2(c1 INTEGER); +INSERT INTO t1 VALUES(1); +INSERT INTO t2 VALUES(1); + +CREATE TABLE IF NOT EXISTS t1(c1 INTEGER) SELECT c1 FROM t3; +CREATE TABLE t2(c1 INTEGER) SELECT c1 FROM t3; + +# In these two statements, t1 and t2 are the temporary table. there is only +# value '1' in them. The records of t2 are not inserted into them. +SELECT * FROM t1; +SELECT * FROM t2; +sync_slave_with_master; + +# In these two statements, t1 and t2 are the base table. The records of t2 +# are inserted into it when CREATE TABLE ... SELECT was executed. +SELECT * FROM t1; +SELECT * FROM t2; + +connection master; +DROP TEMPORARY TABLE t1; +DROP TEMPORARY TABLE t2; +#In these two statements, t1 and t2 are the base table. +SELECT * FROM t1; +SELECT * FROM t2; + +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; + +--echo # WL#5370 +--echo # The behavior of statement 'CREATE TABLE SELECT IF NOT EXISTS' is changed. +--echo # After the worklog, it will insert nothing and the statement will not be +--echo # binlogged if the table already exists. +--echo # After the worklog, some bugs will disappear automotically. +--source include/rpl_reset.inc + +--echo +--echo # Case 1: BUG#47132 +connection master; +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.*"); + +CREATE TABLE t1 (id int); +CREATE TABLE t2 (id int); +INSERT INTO t1 VALUES (1), (1); +INSERT INTO t2 VALUES (2), (2); + +CREATE VIEW v1 AS SELECT id FROM t2; +--let binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1) +CREATE TABLE IF NOT EXISTS v1(a int, b int) SELECT id, id as di FROM t1; +--source include/show_binlog_events.inc + +SHOW CREATE TABLE v1; +SELECT * FROM t2; +SELECT * FROM v1; +DROP VIEW v1; + +# the warning only happens on SBR, so we disable it. +--disable_warnings +CREATE TEMPORARY TABLE tt1 AS SELECT id FROM t2; +--enable_warnings + +--let binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1) +CREATE TEMPORARY TABLE IF NOT EXISTS tt1(a int, b int) SELECT id, id FROM t1; +--source include/show_binlog_events.inc +SELECT * FROM t2; +SELECT * FROM tt1; +DROP TEMPORARY TABLE tt1; + +--echo +--echo # Case 1: BUG#47132 +--echo # RBR breaks on CREATE TABLE IF EXISTS <existing VIEW> AS SELECT +CREATE VIEW v1 AS SELECT 1 as a; +--let binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1) +CREATE TABLE IF NOT EXISTS v1 SELECT 2 as a; +--source include/show_binlog_events.inc +sync_slave_with_master; + +connection master; +DROP VIEW v1; + +DROP TABLE t1, t2; + + +--echo # +--echo # Test case which has failed on assertion after refactoring which was +--echo # made as part of fix for bug #27480 "Extend CREATE TEMPORARY TABLES +--echo # privilege to allow temp table operations". +--echo # +CREATE TEMPORARY TABLE t1 (id int); +CREATE TABLE IF NOT EXISTS t2 LIKE t1; +--echo # The below statement should succeed with warning and +--echo # should not crash due to failing assertion. +CREATE TABLE IF NOT EXISTS t2 LIKE t1; +--echo # Clean-up. +DROP TABLE t1, t2; +sync_slave_with_master; +connection master; + + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_create_or_replace_fail.test b/mysql-test/suite/rpl/t/rpl_create_or_replace_fail.test new file mode 100644 index 00000000..8624d3c9 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_create_or_replace_fail.test @@ -0,0 +1,56 @@ +# ==== Purpose ==== +# +# Test verifies that failed CREATE OR REPLACE TEMPORARY TABLE statement which +# dropped the table but failed at a later stage of creation of temporary table +# is written to binarylog in row based replication. +# +# ==== Implementation ==== +# +# Steps: +# 0 - Have mixed based replication mode. +# 1 - Create a temporary table. It will be replicated as mixed replication +# mode is in use. +# 2 - Execute an unsafe statement which will switch current statement +# binlog format to 'ROW'. i.e If binlog_format=MIXED, there are open +# temporary tables, and an unsafe statement is executed, then subsequent +# statements are logged in row format. +# 3 - Execute a CREATE OR REPLACE TEMPORARY TABLE statement which tries to +# create partitions on temporary table. Since it is not supported it will +# fail. +# 4 - Check the binary log output to ensure that the failed statement is +# written to the binary log. +# 5 - Slave should be up and running and in sync with master. +# +# ==== References ==== +# +# MDEV-18930: Failed CREATE OR REPLACE TEMPORARY not written into binary log +# makes data on master and slave diverge +# + +--source include/have_partition.inc +--source include/have_binlog_format_mixed.inc +--source include/master-slave.inc + +CREATE TEMPORARY TABLE t1 (a INT NOT NULL); + +# Execute an unsafe statement which switches replication mode internally from +# "STATEMENT" to "ROW". +--error ER_NO_SUCH_TABLE +LOAD DATA INFILE 'x' INTO TABLE x; + +--error ER_FEATURE_NOT_SUPPORTED_WITH_PARTITIONING +CREATE OR REPLACE TEMPORARY TABLE t1 (x INT) PARTITION BY HASH(x); + +--echo "************** DROP TEMPORARY TABLE Should be present in Binary log **************" +--source include/show_binlog_events.inc + +CREATE TABLE t1 (b INT); +INSERT INTO t1 VALUES (NULL); +--sync_slave_with_master + +# Cleanup +--connection master +DROP TABLE t1; + +--source include/rpl_end.inc + diff --git a/mysql-test/suite/rpl/t/rpl_create_tmp_table_if_not_exists.test b/mysql-test/suite/rpl/t/rpl_create_tmp_table_if_not_exists.test new file mode 100644 index 00000000..3107fdfa --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_create_tmp_table_if_not_exists.test @@ -0,0 +1,45 @@ +# BUG#45574: +# SP: CREATE DATABASE|TABLE IF NOT EXISTS not binlogged if routine exists. +# +# There is an inconsistency with DROP DATABASE|TABLE|EVENT IF EXISTS and +# CREATE DATABASE|TABLE|EVENT IF NOT EXISTS. DROP IF EXISTS statements are +# binlogged even if either the DB, TABLE or EVENT does not exist. In +# contrast, Only the CREATE EVENT IF NOT EXISTS is binlogged when the EVENT +# exists. +# +# This problem caused some of the tests to fail randomly on PB or PB2. +# +# Test is implemented as follows: +# +# i) test each "CREATE TEMPORARY TABLE IF EXISTS" (DDL), found in MySQL +# 5.1 manual, on existent objects; +# ii) show binlog events; +# +# Note: +# rpl_create_if_not_exists.test tests other cases. +# +# References: +# http://dev.mysql.com/doc/refman/5.1/en/sql-syntax-data-definition.html +# + +#CREATE TEMPORARY TABLE statements are not binlogged in row mode, +#So it must be test by itself. +source include/have_binlog_format_mixed_or_statement.inc; +source include/master-slave.inc; +disable_warnings; + +DROP DATABASE IF EXISTS mysqltest; + +CREATE TEMPORARY TABLE IF NOT EXISTS tmp(c1 int); +CREATE TEMPORARY TABLE IF NOT EXISTS tmp(c1 int); +CREATE TEMPORARY TABLE IF NOT EXISTS tmp1 LIKE tmp; +CREATE TEMPORARY TABLE IF NOT EXISTS tmp1 LIKE tmp; +CREATE TEMPORARY TABLE IF NOT EXISTS tmp2 SELECT * FROM tmp; +CREATE TEMPORARY TABLE IF NOT EXISTS tmp2 SELECT * FROM tmp; +source include/show_binlog_events.inc; + +DROP TEMPORARY TABLE tmp; +DROP TEMPORARY TABLE tmp1; +DROP TEMPORARY TABLE tmp2; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_create_xa_prepared.inc b/mysql-test/suite/rpl/t/rpl_create_xa_prepared.inc new file mode 100644 index 00000000..b823ebf6 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_create_xa_prepared.inc @@ -0,0 +1,9 @@ +# param $xid to name xa and take part in the connection name +# param $query to execute as the xa body +# param $db_ign the default database + +--connect (master_$xid, 127.0.0.1,root,,$db,$MASTER_MYPORT,) +--eval xa start '$xid' +--eval $query +--eval xa end '$xid' +--eval xa prepare '$xid'; diff --git a/mysql-test/suite/rpl/t/rpl_critical_errors.test b/mysql-test/suite/rpl/t/rpl_critical_errors.test new file mode 100644 index 00000000..bc0d7096 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_critical_errors.test @@ -0,0 +1,66 @@ +# Test for BUG#26551 +# + +# This test is unfortunately very fragile and very dependent on the +# load of the computer. The test is therefore disabled normally. It is +# entered here to demonstrate how to check that the bug is actually +# solved. + +--echo Turn on parsing to run this test + +disable_parsing; + +source include/master-slave.inc; + +connection master; +CREATE TABLE t1 (data LONGBLOB) ENGINE=MYISAM; +CREATE TABLE t2 (data LONGBLOB) ENGINE=MYISAM; + +INSERT INTO t1 (data) VALUES (repeat('a',1024*1024)); +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +sync_slave_with_master; + +connection master; +send INSERT INTO t2 SELECT * FROM t1; + +connection master1; + +# This sleep is picked so that the query above has started to insert +# some rows into t2. If it hasn't the slave will not stop below. +let $wait_condition= SELECT COUNT(*) > 1000 FROM t1; +--source include/wait_condition.inc + +# SHOW PROCESSLIST; + +# Code for the 5.1 server to get the thread id of the thread executing +# the query above. +# +#SET @id = 0; +#SELECT id INTO @id +# FROM information_schema.processlist +# WHERE info LIKE 'INSERT INTO t2%'; + +# This is the connection that is executing the INSERT INTO t2... +KILL QUERY 2; + +connection slave; + +# Here the slave will only stop if the query above actually started +# inserting some rows into t2. Otherwise, it will hang forever. ... and there +# the error code should be 1317 (ER_QUERY_INTERRUPTED) +--let $slave_sql_errno= 1317 +--let $show_slave_sql_error= 1 +--source include/wait_for_slave_sql_error.inc + +# The following should be 0 +SELECT COUNT(*) FROM t2; + +--source include/rpl_end.inc +enable_parsing; diff --git a/mysql-test/suite/rpl/t/rpl_cross_version-master.opt b/mysql-test/suite/rpl/t/rpl_cross_version-master.opt new file mode 100644 index 00000000..815a8f81 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_cross_version-master.opt @@ -0,0 +1 @@ +--replicate-same-server-id --relay-log=slave-relay-bin diff --git a/mysql-test/suite/rpl/t/rpl_cross_version.test b/mysql-test/suite/rpl/t/rpl_cross_version.test new file mode 100644 index 00000000..94c9f043 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_cross_version.test @@ -0,0 +1,48 @@ +# ==== Purpose ==== +# +# Verify cross-version replication from an old master to the up-to-date slave +# +# ==== Implementation ==== +# +# Feed to the slave server a binlog recorded on an old version master +# via setting up slave-to-slave replication. The latter is done by means of +# the opt file and include/setup_fake_relay_log.inc. +# The master's binlog is treated as a relay log that the SQL thread executes. +# + +--source include/master-slave.inc + +# +# Bug#31240 load data infile replication between (4.0 or 4.1) and 5.1 fails +# + +--echo ==== Initialize ==== +--connection slave + +--disable_query_log +# The binlog contains the function RAND which is unsafe. +CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); +--enable_query_log + +--source include/stop_slave.inc +RESET SLAVE; + +# the relay log contains create t1, t3 tables and load data infile +--let $fake_relay_log = $MYSQL_TEST_DIR/suite/binlog/std_data/binlog_old_version_4_1.000001 +--source include/setup_fake_relay_log.inc + +--echo ==== Test ==== +start slave sql_thread; +--let $slave_param = Exec_Master_Log_Pos +# end_log_pos of the last event of the relay log +--let $slave_param_value = 149436 +--source include/wait_for_slave_param.inc +--echo ==== a prove that the fake has been processed successfully ==== +SELECT COUNT(*) - 17920 as zero FROM t3; + +--echo ==== Clean up ==== +--source include/stop_slave_sql.inc +--source include/cleanup_fake_relay_log.inc +drop table t1, t3; +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_ctype_latin1.test b/mysql-test/suite/rpl/t/rpl_ctype_latin1.test new file mode 100644 index 00000000..4c3535a1 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_ctype_latin1.test @@ -0,0 +1,44 @@ +--source include/have_lowercase0.inc +--disable_warnings +--source include/master-slave.inc +--enable_warnings + +--echo # +--echo # Start of 10.2 tests +--echo # + + +--echo # +--echo # MDEV-14249 Wrong character set info of Query_log_event and the query in Query_log_event constructed by different charsets cause error when slave apply the event. +--echo # + +# +# The below tests uses a sequence of bytes 0xD191, +# which in a utf8 console looks like Ñ‘ (CYRILIC SMALL LETTER YO). +# Don't be mislead. This sequence is used in latin1 context and +# represents a sequence of two characters: +# U+00D1 CAPITAL LATIN LETTER N WITH TILDE (_latin1 0xD1) +# U+2018 LEFT SINGLE QUOTATION MARK (_latin1 0x91) +# + +SET NAMES latin1; +CREATE TABLE `tÑ‘` (`tÑ‘` INT); +CREATE VIEW `vÑ‘` AS SELECT 'vÑ‘'; +CREATE PROCEDURE `pÑ‘`() SELECT 'pÑ‘'; + +select hex(table_name) from information_schema.tables where table_schema="test" and table_name like "t%"; +select hex(table_name) from information_schema.tables where table_schema="test" and table_name like "v%"; + +--sync_slave_with_master +select hex(table_name) from information_schema.tables where table_schema="test" and table_name like "t%"; +select hex(table_name) from information_schema.tables where table_schema="test" and table_name like "v%"; +--replace_column 5 ts 6 ts +SHOW PROCEDURE STATUS WHERE Name LIKE 'p%' and Db = 'test'; + +--connection master +DROP TABLE `tÑ‘`; +DROP VIEW `vÑ‘`; +DROP PROCEDURE `pÑ‘`; +--sync_slave_with_master + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_current_user.cnf b/mysql-test/suite/rpl/t/rpl_current_user.cnf new file mode 100644 index 00000000..58b605ad --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_current_user.cnf @@ -0,0 +1,8 @@ +!include ../my.cnf + +[mysqld.3] +log-slave-updates + +[ENV] +SERVER_MYPORT_3= @mysqld.3.port +SERVER_MYSOCK_3= @mysqld.3.socket diff --git a/mysql-test/suite/rpl/t/rpl_current_user.test b/mysql-test/suite/rpl/t/rpl_current_user.test new file mode 100644 index 00000000..391606e3 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_current_user.test @@ -0,0 +1,225 @@ +############################################################################## +# BUG#48321 CURRENT_USER() incorrectly replicated for DROP/RENAME USER, +# REVOKE, GRANT, ALTER EVENT +# +# Calling CURRENT_USER() results into inconsistency between slave and master, +# as the slave SQL thread has different user with common users. +# +# After the patch for bug#48321, session's user will be written into query log +# event if CURRENT_USER() is called in 'DROP/RENAME USER', 'REVOKE', 'GRANT', +# 'ALTER EVENT'. +# +############################################################################## + +source include/have_binlog_format_statement.inc; + +--let $rpl_topology= 1->2->3 +--source include/rpl_init.inc + +--let $rpl_connection_name= master +--let $rpl_server_number= 1 +--source include/rpl_connect.inc + +--let $rpl_connection_name= slave +--let $rpl_server_number= 2 +--source include/rpl_connect.inc + +--disable_query_log +--connection server_1 +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.*"); +--connection server_2 +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.*"); +--connection server_3 +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.*"); +--enable_query_log + +--connection master + +CREATE TABLE t1(c1 char(100)); +CREATE VIEW test.v_user AS SELECT * FROM mysql.user WHERE User LIKE 'bug48321%'; +CREATE VIEW test.v_tables_priv AS SELECT * FROM mysql.tables_priv WHERE User LIKE 'bug48321%'; +CREATE VIEW test.v_procs_priv AS SELECT * FROM mysql.procs_priv WHERE User LIKE 'bug48321%'; +CREATE VIEW test.v_event AS SELECT definer FROM mysql.event WHERE name = 'e1'; +CREATE PROCEDURE p1() SELECT 1; +--echo # bug48321_1-01234 has the max length(16) of user. +CREATE USER 'bug48321_1-01234'@'localhost'; +GRANT ALL PRIVILEGES ON *.* TO 'bug48321_1-01234'@'localhost' WITH GRANT OPTION; + +--echo +--echo # Test the max lengths of user and host names +--echo # the user name is too long +--error ER_WRONG_STRING_LENGTH +GRANT CREATE USER ON *.* TO '012345678901234567890123456789012345678901234567890123456789012345678901234567890'@'fakehost'; +--echo # the host name is too long +--error ER_WRONG_STRING_LENGTH +GRANT CREATE USER ON *.* TO 'fakename'@'0123456789012345678901234567890123456789012345678901234567890'; + +--echo +--echo # User 'bug48321_1-01234' connects to master by conn1 +connect (conn1, 127.0.0.1, 'bug48321_1-01234'@'localhost',,); +connection conn1; +--echo # Verify 'REVOKE ALL' statement +REVOKE ALL PRIVILEGES, GRANT OPTION FROM CURRENT_USER(); +--source include/rpl_sync.inc +let $diff_tables= server_1:v_user, server_2:v_user, server_3:v_user; +source include/diff_tables.inc; + +--echo +--echo # Verify 'GRANT ... ON TABLE ...' statement +GRANT CREATE, INSERT, SELECT ON TABLE test.t1 TO CURRENT_USER(); +--source include/rpl_sync.inc +let $diff_tables= server_1:v_tables_priv, server_2:v_tables_priv, server_3:v_tables_priv; +source include/diff_tables.inc; + +--echo +--echo # Verify 'GRANT ... ON PROCEDURE...' statement +GRANT ALTER ROUTINE, EXECUTE ON PROCEDURE p1 TO CURRENT_USER(); +--source include/rpl_sync.inc +let $diff_tables= server_1:v_procs_priv, server_2:v_procs_priv, server_3:v_procs_priv; +source include/diff_tables.inc; + +--echo +--echo # Verify 'GRANT ... ON *.* ...' statement +GRANT ALL PRIVILEGES ON *.* TO CURRENT_USER() WITH GRANT OPTION; +--source include/rpl_sync.inc +let $diff_tables= server_1:v_procs_priv, server_2:v_procs_priv, server_3:v_procs_priv; +source include/diff_tables.inc; + +--echo +--echo # Verify 'REVOKE ... ON TABLE ...' statement +REVOKE CREATE, INSERT, SELECT ON TABLE t1 FROM CURRENT_USER(); +--source include/rpl_sync.inc +let $diff_tables= server_1:v_tables_priv, server_2:v_tables_priv, server_3:v_tables_priv; +source include/diff_tables.inc; + +--echo +--echo # Verify 'REVOKE ... ON PROCEDURE...' statement +REVOKE ALTER ROUTINE, EXECUTE ON PROCEDURE p1 FROM CURRENT_USER(); +--source include/rpl_sync.inc +let $diff_tables= server_1:v_procs_priv, server_2:v_procs_priv, server_3:v_procs_priv; +source include/diff_tables.inc; + +--echo +--echo # Verify 'REVOKE ... ON *.* ...' statement +REVOKE ALL PRIVILEGES ON *.* FROM CURRENT_USER(); +--source include/rpl_sync.inc +let $diff_tables= server_1:v_user, server_2:v_user, server_3:v_user; +source include/diff_tables.inc; + +--echo +--echo # Verify 'GRANT ...' statement in the procedure +CREATE PROCEDURE my_grant() + GRANT CREATE, INSERT, SELECT ON TABLE test.t1 TO CURRENT_USER(); +call my_grant; +--source include/rpl_sync.inc +let $diff_tables= server_1:v_tables_priv, server_2:v_tables_priv, server_3:v_tables_priv; +source include/diff_tables.inc; + +--echo +--echo # Verify 'REVOKE ... ON TABLE ...' statement in the procedure +CREATE PROCEDURE my_revoke() + REVOKE CREATE, INSERT, SELECT ON TABLE t1 FROM CURRENT_USER(); +call my_revoke; +--source include/rpl_sync.inc +let $diff_tables= server_1:v_tables_priv, server_2:v_tables_priv, server_3:v_tables_priv; +source include/diff_tables.inc; + +--echo +--echo # Verify 'RENAME USER ...' statement +RENAME USER CURRENT_USER TO 'bug48321_2'@'localhost'; +--source include/rpl_sync.inc +let $diff_tables= server_1:v_user, server_2:v_user, server_3:v_user; +source include/diff_tables.inc; + +disconnect conn1; + +--echo +--echo # Verify 'DROP USER ...' statement +connection master; +GRANT CREATE USER ON *.* TO 'bug48321_2'@'localhost'; +connect (conn1, 127.0.0.1, 'bug48321_2'@'localhost',,); +connection conn1; +DROP USER CURRENT_USER(); +--source include/rpl_sync.inc +let $diff_tables= server_1:v_user, server_2:v_user, server_3:v_user; +source include/diff_tables.inc; + +--echo +--echo # Verify 'ALTER EVENT...' statement +connection master; +CREATE EVENT e1 ON SCHEDULE EVERY 1 DAY DO SELECT * FROM t1; + +--echo # Explicitly assign CURRENT_USER() to definer +ALTER DEFINER=CURRENT_USER() EVENT e1 ENABLE; +--source include/rpl_sync.inc +let $diff_tables= server_1:v_event, server_2:v_event, server_3:v_event; +source include/diff_tables.inc; + +--echo +--echo # Session user will be set as definer, if the statement does not assign +--echo # a definer +ALTER EVENT e1 ENABLE; +--source include/rpl_sync.inc +let $diff_tables= server_1:v_event, server_2:v_event, server_3:v_event; +source include/diff_tables.inc; + +--echo +--echo # Verify that this patch does not affect the calling of CURRENT_USER() +--echo # in the other statements +connection master; +INSERT INTO t1 VALUES(CURRENT_USER()), ('1234'); +SELECT * FROM t1; +sync_slave_with_master; +SELECT * FROM t1; +sync_slave_with_master server_3; +SELECT * FROM t1; + +connection master; +UPDATE t1 SET c1=CURRENT_USER() WHERE c1='1234'; +SELECT * FROM t1; +sync_slave_with_master; +SELECT * FROM t1; +sync_slave_with_master server_3; +SELECT * FROM t1; + +connection master; +DELETE FROM t1 WHERE c1=CURRENT_USER(); +SELECT * FROM t1; +sync_slave_with_master; +SELECT * FROM t1; +sync_slave_with_master server_3; +SELECT * FROM t1; + +connection master; +CREATE TABLE t2(c1 char(100)); + +DELIMITER |; +CREATE FUNCTION my_user() RETURNS VARCHAR(64) + SQL SECURITY INVOKER +BEGIN + INSERT INTO t2 VALUES(CURRENT_USER()); + RETURN CURRENT_USER(); +END | +DELIMITER ;| + +INSERT INTO t1 VALUES(my_user()); +SELECT * FROM t1; +SELECT * FROM t2; +sync_slave_with_master; +SELECT * FROM t1; +SELECT * FROM t2; +sync_slave_with_master server_3; +SELECT * FROM t1; +SELECT * FROM t2; + +--echo +--echo # END +connection master; +DROP TABLE t1, t2; +DROP VIEW v_user, v_tables_priv, v_procs_priv, v_event; +DROP PROCEDURE p1; +DROP PROCEDURE my_grant; +DROP PROCEDURE my_revoke; +DROP FUNCTION my_user; +DROP EVENT e1; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_ddl-slave.opt b/mysql-test/suite/rpl/t/rpl_ddl-slave.opt new file mode 100644 index 00000000..21356507 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_ddl-slave.opt @@ -0,0 +1 @@ +--loose-skip-innodb diff --git a/mysql-test/suite/rpl/t/rpl_ddl.test b/mysql-test/suite/rpl/t/rpl_ddl.test new file mode 100644 index 00000000..b11a6927 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_ddl.test @@ -0,0 +1,32 @@ +######################## rpl_ddl.test ######################## +# # +# DDL statements (sometimes with implicit COMMIT) executed # +# by the master and it's propagation into the slave # +# # +############################################################## + +# +# NOTE, PLEASE BE CAREFUL, WHEN MODIFYING THE TESTS !! +# +# 1. !All! objects to be dropped, renamed, altered ... must be created +# in AUTOCOMMIT= 1 mode before AUTOCOMMIT is set to 0 and the test +# sequences start. +# +# 2. Never use a test object, which was direct or indirect affected by a +# preceding test sequence again. +# Except table d1.t1 where ONLY DML is allowed. +# +# If one preceding test sequence hits a (sometimes not good visible, +# because the sql error code of the statement might be 0) bug +# and these rules are ignored, a following test sequence might earn ugly +# effects like failing 'sync_slave_with_master', crashes of the slave or +# abort of the test case etc.. +# +--source include/have_innodb.inc +--source include/master-slave.inc +let $engine_type= InnoDB; +let $temp_engine_type= MEMORY; +let $show_binlog = 0; +let $manipulate = 0; +-- source include/rpl_ddl.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_deadlock_innodb-slave.opt b/mysql-test/suite/rpl/t/rpl_deadlock_innodb-slave.opt new file mode 100644 index 00000000..f516b1b7 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_deadlock_innodb-slave.opt @@ -0,0 +1 @@ +--loose-innodb-lock-wait-timeout=4 --slave-transaction-retries=2 --max-relay-log-size=4096 diff --git a/mysql-test/suite/rpl/t/rpl_deadlock_innodb.test b/mysql-test/suite/rpl/t/rpl_deadlock_innodb.test new file mode 100644 index 00000000..e2311cb0 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_deadlock_innodb.test @@ -0,0 +1,4 @@ +-- source include/have_innodb.inc +-- source include/long_test.inc +let $engine_type=innodb; +-- source include/rpl_deadlock.test diff --git a/mysql-test/suite/rpl/t/rpl_default.test b/mysql-test/suite/rpl/t/rpl_default.test new file mode 100644 index 00000000..9adf15c9 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_default.test @@ -0,0 +1,29 @@ +# +# Test of replicating default values +# As the table is using non deterministic functions, replication must +# switch to binlog format. +# + +-- source include/have_binlog_format_mixed_or_row.inc +-- source include/master-slave.inc + +connection master; + +create table t1 (a int DEFAULT (1+1), b bigint default uuid_short(), u blob default user()); +insert into t1 (a) values(1); + +let $b=query_get_value(select * from t1, b, 1); +let $u=query_get_value(select * from t1, u, 1); + +sync_slave_with_master; +connection slave; + +show create table t1; +--disable_query_log +eval select a,"$b"=b as uuid,"$u"=u as user from t1; +--enable_query_log +connection master; + +drop table t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_delayed_slave.combinations b/mysql-test/suite/rpl/t/rpl_delayed_slave.combinations new file mode 100644 index 00000000..bac7cb33 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_delayed_slave.combinations @@ -0,0 +1,4 @@ +[nonparallel] + +[parallel] +--slave-parallel-threads=10 diff --git a/mysql-test/suite/rpl/t/rpl_delayed_slave.test b/mysql-test/suite/rpl/t/rpl_delayed_slave.test new file mode 100644 index 00000000..d00e796b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_delayed_slave.test @@ -0,0 +1,428 @@ +# ==== Purpose ==== +# +# Test the time-delayed replication feature, i.e., +# CHANGE MASTER TO MASTER_DELAY=X: +# +# - Verify that slave has executed the events after but not before the +# delay timeout. +# +# - Verify that delay is correct when slave is already lagging +# due to slow queries. +# +# - Verify that Seconds_Behind_Master is greater than or equal to the +# delay if the slave still has unprocessed events in the relay log +# and more time than the delay has elapsed since the last event was +# executed on the master. +# +# - Verify that STOP SLAVE works instantly even during a delay, and +# that it does not cause the waited-for event to be executed too +# early on slave. +# +# - Verify that changing back to no delay works. +# +# - Verify that RESET SLAVE sets the delay to 0. +# +# - Verify that setting a bad value for the delay gives an error. +# +# ==== Implementation ==== +# +# We run the slave with 10 seconds lag. +# +# In general, to test that a query has not been executed by the slave +# before this time, we wait until the slave IO thread has received the +# event, and then 5 seconds more, and check that the table has not +# been updated. To test that a query has been executed after this +# time, we wait 10 seconds more. +# +# To simulate that the slave lags due to slow queries, we invoke a +# stored function that executes SLEEP if @@gloval.server_id==2. This +# requires that we run with binlog_format=STATEMENT. +# +# ==== Related Bugs and Worklogs ==== +# +# WL#344: Time-delayed replication +# BUG#28760: Simulating a replication lag +# [duplicate] BUG#22072: configurable delayed replication +# [duplicate] BUG#21639: Add Replication Delay parameter +# BUG#56442: Slave executes delayed statements when STOP SLAVE is issued +# +# ==== Issues with this Test Case ==== +# +# The test is inherently timing-sensitive (i.e., contains races) and +# is likely to fail sporadically on a loaded host. +# +# The test takes a long time; it sleeps for around 20*10 seconds. + +--source include/big_test.inc +--source include/not_valgrind.inc +--source include/master-slave.inc +# Needed so that sleeps get executed in the slave SQL thread. +--source include/have_binlog_format_statement.inc + + +call mtr.add_suppression("Unsafe statement written to the binary log using statement format"); +--connection slave +call mtr.add_suppression("Unsafe statement written to the binary log using statement format"); +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=NO; +--source include/start_slave.inc +--connection master + + +# We assume that any simple operation takes zero time, with an error +# margin of $time1 seconds. Hence, if we run with a delay of $time2 +# seconds, we expect that: +# - If we execute a query on master and wait $time1 seconds, then the +# query has been copied to slave but not yet executed. +# - If we execute a query on master and wait $time3 seconds, then the +# query has been executed. +--let $time1= 10 +if (`SELECT '$max_query_execution_time' > 0`) { + --let $time1= $max_query_execution_time +} +--let $time2= `SELECT 2 * $time1` +--let $time3= `SELECT 3 * $time1` + + +--echo [on master] +CREATE TABLE t1 (a VARCHAR(100), b INT); +INSERT INTO t1 VALUES ("zero", 0); + + +--echo ==== Normal setup ==== + +--echo [on slave] +--sync_slave_with_master + +--source include/stop_slave.inc + +--echo # CHANGE MASTER TO MASTER_DELAY = 2*T +--disable_query_log +eval CHANGE MASTER TO MASTER_DELAY = $time2; +--enable_query_log + +--source include/start_slave.inc + +--let $assert_text= SHOW SLAVE STATUS should return the same delay that we set with CHANGE MASTER +--let $assert_cond= [SHOW SLAVE STATUS, SQL_Delay, 1] = $time2 +--source include/rpl_assert.inc + +--echo [on master] +--connection master +INSERT INTO t1 VALUES ('normal setup', 1); + +--let $query_number= 1 +--source include/delayed_slave_wait_on_query.inc + + +--echo ==== Slave lags "naturally" after master ==== + +--echo [on master] +--connection master + +--disable_query_log +--echo # CREATE FUNCTION delay_on_slave(time_units INT) RETURNS INT BEGIN IF @@GLOBAL.server_id = 2 THEN RETURN SLEEP(time_units * T); ELSE RETURN 0; END IF; END +--eval CREATE FUNCTION delay_on_slave(time_units INT) RETURNS INT BEGIN IF @@GLOBAL.server_id = 2 THEN RETURN SLEEP(time_units * $time1); ELSE RETURN 0; END IF; END +--enable_query_log + +INSERT INTO t1 SELECT delay_on_slave(3), 2; + +--save_master_pos +INSERT INTO t1 VALUES ('slave is already lagging: this statement should execute immediately', 3); +INSERT INTO t1 SELECT delay_on_slave(2), 4; + +--echo [on slave] +--source include/sync_slave_io_with_master.inc +--echo # sleep 1*T +--sleep $time1 + +--let $assert_text= No query executed +--let $assert_cond= MAX(b) = 1 FROM t1 +--source include/rpl_assert.inc + +--let $assert_text= Status should be 'Waiting until MASTER_DELAY...' +--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" LIKE "Waiting until MASTER_DELAY%" +--source include/rpl_assert.inc + +--echo # wait for first query to execute +--sync_with_master + +--echo # sleep 1*T +--sleep $time1 + +--let $assert_text= Second query executed +--let $assert_cond= MAX(b) = 3 FROM t1 +--source include/rpl_assert.inc + +let $parallel= `SELECT @@GLOBAL.slave_parallel_threads`; +if (!$parallel) +{ + let $assert_text= Status should be executing third query (i.e., 'User sleep'); + let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" = "User sleep"; + source include/rpl_assert.inc; +} + +--echo # sleep 2*T +--sleep $time2 + +--let $assert_text= Third query executed +--let $assert_cond= MAX(b) = 4 FROM t1 +--source include/rpl_assert.inc + +--let $assert_text= Status should be 'Has read all relay log...' +--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" LIKE "Slave has read all relay log%" +--source include/rpl_assert.inc + + +--echo ==== Seconds_Behind_Master ==== + +--echo # Bring slave to sync. +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_DELAY = 0; +--source include/start_slave.inc + +--connection master +INSERT INTO t1 VALUES ('Syncing slave', 5); +--sync_slave_with_master + +--source include/stop_slave.inc +--echo # CHANGE MASTER TO MASTER_DELAY = 2*T +--disable_query_log +eval CHANGE MASTER TO MASTER_DELAY = $time2; +--enable_query_log +--source include/start_slave.inc + +--connection master +INSERT INTO t1 VALUES (delay_on_slave(1), 6); +--save_master_pos +--connection slave + +--echo # sleep 1*T +--sleep $time1 + +--let $assert_cond= [SHOW SLAVE STATUS, Seconds_Behind_Master, 1] >= 0 AND <1> < $time2 +--let $assert_text= Seconds_Behind_Master should be between 0 and the 2*T +--source include/rpl_assert.inc + +--echo # sleep 1*T +--sleep $time1 + +--let $assert_cond= [SHOW SLAVE STATUS, Seconds_Behind_Master, 1] >= $time2 +--let $assert_text= Seconds_Behind_Master should be at least 2*T +--source include/rpl_assert.inc + +--sync_with_master + + +--echo ==== STOP SLAVE / START SLAVE + DML ==== + +# Set up a longer delay. +--source include/stop_slave.inc + +--echo # CHANGE MASTER TO MASTER_DELAY = 3*T +--disable_query_log +eval CHANGE MASTER TO MASTER_DELAY = $time3; +--enable_query_log + +--source include/start_slave.inc + +--echo [on master] +--connection master +INSERT INTO t1 VALUES ('stop slave and start slave: DML', 7); + +--echo [on slave] +--connection slave +--echo # sleep 1*T +--sleep $time1 +--let $timestamp_before_stop= `SELECT UNIX_TIMESTAMP()` +--let $relay_log_pos_before_stop= query_get_value(SHOW SLAVE STATUS, Relay_Log_Pos, 1) +--source include/stop_slave.inc + +--let $assert_text= STOP SLAVE should finish quickly, not wait for the ongoing sleep to finish +--let $assert_cond= UNIX_TIMESTAMP() - $timestamp_before_stop < $time1 +--source include/rpl_assert.inc + +--let $assert_text= SQL thread position should not increase after STOP SLAVE +--let $assert_cond= [SHOW SLAVE STATUS, Relay_Log_Pos, 1] = $relay_log_pos_before_stop +--source include/rpl_assert.inc + +--let $assert_text= Query should not be executed after STOP SLAVE +--let $assert_cond= MAX(b) = 6 FROM t1 +--source include/rpl_assert.inc + +--let $assert_text= Status should be '' after STOP SLAVE +--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" = "" +--source include/rpl_assert.inc + +--source include/start_slave.inc + +--let $assert_text= START SLAVE should finish quickly +--let $assert_cond= UNIX_TIMESTAMP() - $timestamp_before_stop < $time1 +--source include/rpl_assert.inc + +--let $query_number= 7 +--source include/delayed_slave_wait_on_query.inc + + +--echo ==== STOP SLAVE / START SLAVE + DDL ==== + +--echo This verifies BUG#56442 + +--echo [on master] +--connection master +CREATE TABLE t_check_dml_not_executed_prematurely (a INT); +--source include/save_master_pos.inc + +--echo [on slave] +--connection slave +--echo # sleep 1*T +--sleep $time1 + +--let $timestamp_before_stop= `SELECT UNIX_TIMESTAMP()` +--let $relay_log_pos_before_stop= query_get_value(SHOW SLAVE STATUS, Relay_Log_Pos, 1) +--source include/stop_slave.inc + +--let $assert_text= STOP SLAVE should finish quickly, not wait for the ongoing sleep to finish +--let $assert_cond= UNIX_TIMESTAMP() - $timestamp_before_stop < $time1 +--source include/rpl_assert.inc + +--let $assert_text= SQL thread position should not increase after STOP SLAVE +--let $assert_cond= [SHOW SLAVE STATUS, Relay_Log_Pos, 1] = $relay_log_pos_before_stop +--source include/rpl_assert.inc + +--let $assert_text= Query should not be executed after STOP SLAVE +--let $assert_cond= COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = "t_check_dml_not_executed_prematurely" +--source include/rpl_assert.inc + +--let $assert_text= Status should be '' after STOP SLAVE +--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" = "" +--source include/rpl_assert.inc + +--source include/start_slave.inc + +--let $assert_text= START SLAVE should finish quickly +--let $assert_cond= UNIX_TIMESTAMP() - $timestamp_before_stop < $time1 +--source include/rpl_assert.inc + +--echo # sleep 1*T +--sleep $time1 + +--let $assert_text= DDL Query should not be executed after START SLAVE +--let $assert_cond= COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = "t_check_dml_not_executed_prematurely" +--source include/rpl_assert.inc + +--let $assert_text= Status should be 'Waiting until MASTER_DELAY...' +--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" LIKE "Waiting until MASTER_DELAY%" +--source include/rpl_assert.inc + +--echo # sleep 1*T +--sleep $time1 + +--echo # sync with master (with timeout 1*T) +--source include/sync_with_master.inc + +--let $assert_text= DDL Query should be executed +--let $assert_cond= COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = "t_check_dml_not_executed_prematurely" +--source include/rpl_assert.inc + +--let $assert_text= Status should be 'Has read all relay log...' +--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" LIKE "Slave has read all relay log%" +--source include/rpl_assert.inc + +--source include/check_slave_is_running.inc + + +--echo ==== Change back to no delay ==== + +--echo [on slave] +--connection slave +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_DELAY = 0; + +--let $assert_text= Delay should be 0 when we set it to 0 +--let $assert_cond= [SHOW SLAVE STATUS, SQL_Delay, 1] = 0 +--source include/rpl_assert.inc + +--source include/start_slave.inc + +--echo [on master] +--connection master +INSERT INTO t1 VALUES ('change back to no delay', 8); + +--echo [on slave] +--source include/sync_slave_io_with_master.inc +--echo # sleep 1*T +--sleep $time1 + +--let $assert_text= Query should be executed +--let $assert_cond= MAX(b) = 8 FROM t1 +--source include/rpl_assert.inc + +--let $assert_text= Status should be 'Slave has read all relay log...' +--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" Like "Slave has read all relay log%" +--source include/rpl_assert.inc + + +--echo ==== Reset delay with RESET SLAVE ==== + +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_DELAY = 71; +--source include/start_slave.inc + +--let $assert_text= Delay should be 71 when we set it to 71 +--let $assert_cond= [SHOW SLAVE STATUS, SQL_Delay, 1] = 71 +--source include/rpl_assert.inc + +--source include/stop_slave.inc +--let $master_use_gtid_option= No +--source include/reset_slave.inc +--echo [on master] +--connection master +RESET MASTER; +--echo [on slave] +--connection slave +--source include/start_slave.inc + +--let $assert_text= Delay should be 0 after RESET SLAVE +--let $assert_cond= [SHOW SLAVE STATUS, SQL_Delay, 1] = 0 +--source include/rpl_assert.inc + + +--echo ==== Set an invalid value for the delay ==== + +--source include/stop_slave.inc + +--echo # Expect error for setting negative delay +--error ER_PARSE_ERROR +CHANGE MASTER TO MASTER_DELAY = -1; + +--echo # Expect that it's ok to set delay of 2^31-1 +CHANGE MASTER TO MASTER_DELAY = 2147483647; +--echo # Expect error for setting delay between 2^31 and 2^32-1 +--error ER_MASTER_DELAY_VALUE_OUT_OF_RANGE +CHANGE MASTER TO MASTER_DELAY = 2147483648; + +--echo # Expect error for setting delay to nonsense +--error ER_PARSE_ERROR +CHANGE MASTER TO MASTER_DELAY = blah; + +# todo: CHANGE MASTER TO MASTER_DELAY = 999999999999999999999999999 +# should give error + +CHANGE MASTER TO MASTER_DELAY = 0; +--source include/start_slave.inc + + +--echo ==== Clean up ==== + +--echo [on master] +--connection master +DROP TABLE t1, t_check_dml_not_executed_prematurely; +DROP FUNCTION delay_on_slave; + +--echo [on slave] +--sync_slave_with_master +SELECT @@GLOBAL.slave_parallel_mode; +SELECT @@GLOBAL.slave_parallel_threads; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_delayed_slave2.test b/mysql-test/suite/rpl/t/rpl_delayed_slave2.test new file mode 100644 index 00000000..68e8f8e1 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_delayed_slave2.test @@ -0,0 +1,65 @@ +--source include/have_innodb.inc +--source include/master-slave.inc + +# This test file tests delayed slave for parallel replication (and GTID). +# Uses a different approach from rpl_delayed_slave.test, setting @@timestamp +# to simulate events logged on master at different times. + +--connection master +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(100)); +INSERT INTO t1 VALUES (1, "a"); +--save_master_pos + +--connection slave +--sync_with_master +--source include/stop_slave.inc +CHANGE MASTER TO master_use_gtid=slave_pos; +SET @old_mode= @@GLOBAL.slave_parallel_mode; +SET GLOBAL slave_parallel_mode=optimistic; +SET @old_threads= @@GLOBAL.slave_parallel_threads; +SET GLOBAL slave_parallel_threads=10; + +--connection master +INSERT INTO t1 VALUES (2, "b"); +INSERT INTO t1 VALUES (3, "b"); +INSERT INTO t1 VALUES (4, "b"); +--let $gtid1= `SELECT @@gtid_binlog_pos` +# Simulate an event a days in the future, for delayed slave to wait on. +SET timestamp= @@timestamp + 24*60*60; +INSERT INTO t1 VALUES (5, "c"); +INSERT INTO t1 VALUES (6, "c"); +SET timestamp= 0; +--let $gtid2= `SELECT @@gtid_binlog_pos` +--source include/save_master_gtid.inc + +--connection slave +CHANGE MASTER TO master_delay=1; +--source include/start_slave.inc +--replace_result $gtid1 GTID1 +# First sync halfways, to avoid timing-dependent test failures. +eval SELECT MASTER_GTID_WAIT('$gtid1'); +# Try to sync up, should timeout because slave is waiting for one day. +--replace_result $gtid2 GTID2 +eval SELECT MASTER_GTID_WAIT('$gtid2', 2); + +# Check that we can stop slave while delaying. +--source include/stop_slave.inc +SELECT * FROM t1 ORDER BY a; +CHANGE MASTER TO master_delay=0; +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; + + +--connection slave +--source include/stop_slave.inc +CHANGE MASTER TO master_use_gtid=no, master_delay=0; +SET GLOBAL slave_parallel_mode=@old_mode; +SET GLOBAL slave_parallel_threads=@old_threads; +--source include/start_slave.inc + +--connection master +DROP TABLE t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_delete_no_where.test b/mysql-test/suite/rpl/t/rpl_delete_no_where.test new file mode 100644 index 00000000..c07649cb --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_delete_no_where.test @@ -0,0 +1,4 @@ +-- source include/master-slave.inc +let $engine_type=myisam; +-- source include/rpl_delete_no_where.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_do_grant.test b/mysql-test/suite/rpl/t/rpl_do_grant.test new file mode 100644 index 00000000..1350585f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_do_grant.test @@ -0,0 +1,350 @@ +# Works in statement-based and row-based binlogging. +# Test that GRANT and other user management commands are replicated to the slave + +-- source include/master-slave.inc + +# test replication of GRANT +connection master; +create user rpl_do_grant@localhost; +grant select on *.* to rpl_do_grant@localhost; +grant drop on test.* to rpl_do_grant@localhost; +sync_slave_with_master; +show grants for rpl_do_grant@localhost; + +# test replication of SET PASSWORD +connection master; +set password for rpl_do_grant@localhost=password("does it work?"); +sync_slave_with_master; +select authentication_string<>'' from mysql.user where user='rpl_do_grant'; + +# +# Bug#24158 SET PASSWORD in binary log fails under ANSI_QUOTES +# +connection master; +update mysql.global_priv set priv=json_remove(priv, '$.authentication_string') where user='rpl_do_grant'; +flush privileges; +select authentication_string<>'' from mysql.user where user='rpl_do_grant'; +set sql_mode='ANSI_QUOTES'; +set password for rpl_do_grant@localhost=password('does it work?'); +set sql_mode=''; +sync_slave_with_master; +select authentication_string<>'' from mysql.user where user='rpl_do_grant'; + +# clear what we have done, to not influence other tests. +connection master; +drop user rpl_do_grant@localhost; +sync_slave_with_master; + +# End of 4.1 tests + +connection master; +--error 1141 +show grants for rpl_do_grant@localhost; +connection slave; +--error 1141 +show grants for rpl_do_grant@localhost; + +connection master; +create user rpl_do_grant@localhost; +show grants for rpl_do_grant@localhost; +--error 1141 +show grants for rpl_do_grant2@localhost; +sync_slave_with_master; +show grants for rpl_do_grant@localhost; +--error 1141 +show grants for rpl_do_grant2@localhost; + +connection master; +rename user rpl_do_grant@localhost to rpl_do_grant2@localhost; +show grants for rpl_do_grant2@localhost; +sync_slave_with_master; +show grants for rpl_do_grant2@localhost; + +connection master; +grant DELETE,INSERT on mysqltest1.* to rpl_do_grant2@localhost; +show grants for rpl_do_grant2@localhost; +sync_slave_with_master; +show grants for rpl_do_grant2@localhost; + +connection master; +revoke DELETE on mysqltest1.* from rpl_do_grant2@localhost; +show grants for rpl_do_grant2@localhost; +sync_slave_with_master; +show grants for rpl_do_grant2@localhost; + +connection master; +revoke all privileges, grant option from rpl_do_grant2@localhost; +show grants for rpl_do_grant2@localhost; +sync_slave_with_master; +show grants for rpl_do_grant2@localhost; + +connection master; +drop user rpl_do_grant2@localhost; +--error 1141 +show grants for rpl_do_grant2@localhost; +sync_slave_with_master; +--error 1141 +show grants for rpl_do_grant2@localhost; + +##################################################### +# Purpose +# Test whether mysql.procs_priv get replicated +# Related bugs: +# BUG42217 mysql.procs_priv does not get replicated +##################################################### +connection master; +call mtr.add_suppression("Slave: Operation DROP USER failed for 'create_rout_db'@'localhost' error.* 1396"); +sync_slave_with_master; +connection master; + +--disable_warnings +DROP DATABASE IF EXISTS bug42217_db; +--enable_warnings +CREATE DATABASE bug42217_db; + +GRANT CREATE ROUTINE ON bug42217_db.* TO 'create_rout_db'@'localhost' + IDENTIFIED BY 'create_rout_db' WITH GRANT OPTION; + +-- sync_slave_with_master +-- connection master + +connect (create_rout_db_master, localhost, create_rout_db, create_rout_db, bug42217_db,$MASTER_MYPORT,); +connect (create_rout_db_slave, localhost, create_rout_db, create_rout_db, bug42217_db, $SLAVE_MYPORT,); + +connection create_rout_db_master; + + +USE bug42217_db; + +DELIMITER //; +CREATE FUNCTION upgrade_del_func() RETURNS CHAR(30) +BEGIN + RETURN "INSIDE upgrade_del_func()"; +END// + +DELIMITER ;// + +connection master; + +USE bug42217_db; +--replace_column 8 # +SELECT * FROM mysql.procs_priv; +SELECT upgrade_del_func(); + +sync_slave_with_master; +--replace_column 8 # +SELECT * FROM mysql.procs_priv; +SHOW GRANTS FOR 'create_rout_db'@'localhost'; + +USE bug42217_db; +SHOW CREATE FUNCTION upgrade_del_func; +SELECT upgrade_del_func(); + +--echo "Check whether the definer user will be able to execute the replicated routine on slave" +connection create_rout_db_slave; +USE bug42217_db; +SHOW CREATE FUNCTION upgrade_del_func; +SELECT upgrade_del_func(); + +connection slave; +DELETE FROM mysql.procs_priv; +FLUSH PRIVILEGES; +USE bug42217_db; +--echo "Can't execute the replicated routine on slave like before after procs privilege is deleted " +--error 1370 +SELECT upgrade_del_func(); + +--echo "Test the user who creates a function on master doesn't exist on slave." +--echo "Hence SQL thread ACL_GLOBAL privilege jumps in and no mysql.procs_priv is inserted" +DROP USER 'create_rout_db'@'localhost'; + +connection create_rout_db_master; +DELIMITER //; +CREATE FUNCTION upgrade_alter_func() RETURNS CHAR(30) +BEGIN + RETURN "INSIDE upgrade_alter_func()"; +END// +DELIMITER ;// + +connection master; +SELECT upgrade_alter_func(); + +sync_slave_with_master; +SHOW CREATE FUNCTION upgrade_alter_func; +--echo "Should no privilege record for upgrade_alter_func in mysql.procs_priv" +--replace_column 8 # +SELECT * FROM mysql.procs_priv; +--error 1449 +SELECT upgrade_alter_func(); + +###### CLEAN UP SECTION ############## +disconnect create_rout_db_master; +disconnect create_rout_db_slave; +connection master; +USE bug42217_db; +DROP FUNCTION upgrade_del_func; +DROP FUNCTION upgrade_alter_func; +DROP DATABASE bug42217_db; +-- sync_slave_with_master +-- connection master + +# user was already dropped in the slave before +# so we should not replicate this statement. +SET SQL_LOG_BIN= 0; +DROP USER 'create_rout_db'@'localhost'; +SET SQL_LOG_BIN= 1; + +# finish entire clean up (remove binlogs) +# so that we leave a pristine environment for the +# following tests +--let $rpl_only_running_threads= 1 +-- source include/rpl_reset.inc +USE test; + +# BUG#49119: Master crashes when executing 'REVOKE ... ON +# {PROCEDURE|FUNCTION} FROM ...' +# +# The tests are divided into two test cases: +# +# i) a test case that mimics the one in the bug report. +# +# - We show that, despite the fact, that a revoke command fails +# when binlogging is active, the master will not hit an +# assertion. +# +# ii) a test case that partially succeeds on the master will also +# partially succeed on the slave. +# +# - The revoke statement that partially succeeds tries to revoke +# an EXECUTE grant for two users, and only one of the user has +# the specific grant. This will cause mysql to drop one of the +# grants and report error for the statement. The slave should +# also drop the grants that the master succeed and the SQL +# thread should not stop on statement failure. + +-- echo ######## BUG#49119 ####### +-- echo ### i) test case from the 'how to repeat section' + +-- connection master + +CREATE TABLE t1(c1 INT); +DELIMITER |; +CREATE PROCEDURE p1() SELECT * FROM t1 | +DELIMITER ;| +-- error ER_NONEXISTING_PROC_GRANT +REVOKE EXECUTE ON PROCEDURE p1 FROM 'root'@'localhost'; + +-- sync_slave_with_master + +-- connection master +DROP TABLE t1; +DROP PROCEDURE p1; + +-- sync_slave_with_master + +-- echo ### ii) Test case in which REVOKE partially succeeds + +-- connection master +-- source include/rpl_reset.inc +-- connection master + +CREATE TABLE t1(c1 INT); +DELIMITER |; +CREATE PROCEDURE p1() SELECT * FROM t1 | +DELIMITER ;| + +CREATE USER 'user49119'@'localhost'; +GRANT EXECUTE ON PROCEDURE p1 TO 'user49119'@'localhost'; + +-- echo ############################################################## +-- echo ### Showing grants for both users: root and user49119 (master) +SHOW GRANTS FOR 'user49119'@'localhost'; +SHOW GRANTS FOR CURRENT_USER; +-- echo ############################################################## + +-- sync_slave_with_master + +-- echo ############################################################## +-- echo ### Showing grants for both users: root and user49119 (master) +SHOW GRANTS FOR 'user49119'@'localhost'; +SHOW GRANTS FOR CURRENT_USER; +-- echo ############################################################## + +-- connection master + +-- echo ## This statement will make the revoke fail because root has no +-- echo ## execute grant. However, it will still revoke the grant for +-- echo ## user49119. +-- error ER_NONEXISTING_PROC_GRANT +REVOKE EXECUTE ON PROCEDURE p1 FROM 'user49119'@'localhost', 'root'@'localhost'; + +-- echo ############################################################## +-- echo ### Showing grants for both users: root and user49119 (master) +-- echo ### after revoke statement failure +SHOW GRANTS FOR 'user49119'@'localhost'; +SHOW GRANTS FOR CURRENT_USER; +-- echo ############################################################## + +-- sync_slave_with_master + +-- echo ############################################################# +-- echo ### Showing grants for both users: root and user49119 (slave) +-- echo ### after revoke statement failure (should match +SHOW GRANTS FOR 'user49119'@'localhost'; +SHOW GRANTS FOR CURRENT_USER; +-- echo ############################################################## + +-- connection master +DROP TABLE t1; +DROP PROCEDURE p1; +DROP USER 'user49119'@'localhost'; + +-- sync_slave_with_master + +# +# Bug #51987 revoke privileges logs wrong error code +# + +-- source include/rpl_reset.inc +-- connection master + +grant all on *.* to foo@"1.2.3.4"; +-- error ER_REVOKE_GRANTS +revoke all privileges, grant option from "foo"; + +## assertion: revoke is logged +-- source include/show_binlog_events.inc + +-- sync_slave_with_master + +## assertion: slave replicates revoke and does not fail because master +## logged revoke with correct expected error code +--source include/check_slave_no_error.inc + +-- connection master +DROP USER foo@"1.2.3.4"; +-- sync_slave_with_master + +--echo +--echo # Bug#27606 GRANT statement should be replicated with DEFINER information +--source include/rpl_reset.inc +--connection master +GRANT SELECT, INSERT ON mysql.user TO user_bug27606@localhost; + +SELECT Grantor FROM mysql.tables_priv WHERE User='user_bug27606'; +sync_slave_with_master; +SELECT Grantor FROM mysql.tables_priv WHERE User='user_bug27606'; + +--connection master +REVOKE SELECT ON mysql.user FROM user_bug27606@localhost; +SELECT Grantor FROM mysql.tables_priv WHERE User='user_bug27606'; +sync_slave_with_master; +SELECT Grantor FROM mysql.tables_priv WHERE User='user_bug27606'; + +--connection master +DROP USER user_bug27606@localhost; +select priv into @root_priv from mysql.global_priv where user='root' and host='127.0.0.1'; +update mysql.global_priv set priv=@root_priv where user='root' and host='localhost'; + + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_domain_id_filter.test b/mysql-test/suite/rpl/t/rpl_domain_id_filter.test new file mode 100644 index 00000000..2b8ac17c --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_domain_id_filter.test @@ -0,0 +1,400 @@ +--source include/have_innodb.inc +--source include/master-slave.inc + +# +# Test for DO_DOMAIN_IDS=(M1, M2, ..) and IGNORE_DOMAIN_IDS=(N1, N2, ..) +# + +connection slave; +call mtr.add_suppression("Both DO_DOMAIN_IDS & IGNORE_DOMAIN_IDS lists can't be non-empty at the same time"); +call mtr.add_suppression("DO_DOMAIN_IDS or IGNORE_DOMAIN_IDS lists can't be non-empty in non-GTID mode.*"); + +connection master; +SET @@session.gtid_domain_id= 1; +SELECT @@session.gtid_domain_id; +CREATE TABLE t1(i INT) ENGINE=INNODB; +INSERT INTO t1 VALUES(1); +SELECT * FROM t1; +--source include/save_master_gtid.inc + +connection slave; +--source include/sync_with_master_gtid.inc +##### Case 0 : When both DO_DOMAIN_IDS and IGNORE_DOMAIN_IDS are empty. +SELECT * FROM t1; + +##### Case 1: When DO_DOMAIN_IDS is non-empty. +--source include/stop_slave.inc +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +# Replicate events belonging to "domain_id 1". +CHANGE MASTER TO DO_DOMAIN_IDS=(1), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +connection master; +# Lets change the session domain_id to 2(not in DO_DOMAIN_IDS). +SET @@session.gtid_domain_id= 2; +# Should get filtered out on slave. +INSERT INTO t1 VALUES(2); +# Change it back to 1 (in DO_DOMAIN_IDS). +SET @@session.gtid_domain_id= 1; +# Should get applied on slave. +INSERT INTO t1 VALUES(3); + +SELECT * FROM t1; +--source include/save_master_gtid.inc + +connection slave; +--source include/sync_with_master_gtid.inc +SELECT * FROM t1; + +##### Case 2: When IGNORE_DOMAIN_IDS is non-empty. +--source include/stop_slave.inc +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +# Ignore events belonging to "domain_id 1". +CHANGE MASTER TO DO_DOMAIN_IDS=(), IGNORE_DOMAIN_IDS=(1), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +connection master; +# @@session.gtid_domain_id = 1 (in IGNORE_DOMAIN_IDS) +SELECT @@session.gtid_domain_id; +# Should get filtered out on slave. +INSERT INTO t1 VALUES(4); +# Change it to 2 (not in IGNORE_DOMAIN_IDS). +SET @@session.gtid_domain_id= 2; +# Should get applied on slave. +INSERT INTO t1 VALUES(5); + +SELECT * FROM t1; +--source include/save_master_gtid.inc + +connection slave; +--source include/sync_with_master_gtid.inc +SELECT * FROM t1; + +##### Case 3: When both DO_DOMAIN_IDS and IGNORE_DOMAIN_IDS are non-empty + +--source include/stop_slave.inc +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +--error ER_MASTER_INFO +CHANGE MASTER TO DO_DOMAIN_IDS=(1), IGNORE_DOMAIN_IDS=(2), MASTER_USE_GTID=slave_pos; + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +##### Case 4: Multiple domain ids. + +--source include/stop_slave.inc +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +# Replicate events belonging to "domain_id 1". +CHANGE MASTER TO DO_DOMAIN_IDS=(4,4,5,1,7,7,7,1,1,2,6,8,1,4,5,5,9,3), IGNORE_DOMAIN_IDS=(), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +connection master; +# @@session.gtid_domain_id = 1 (in DO_DOMAIN_IDS) +SELECT @@session.gtid_domain_id; +# Should get applied on slave. +INSERT INTO t1 VALUES(8); +# Change it to 7 (in DO_DOMAIN_IDS). +SET @@session.gtid_domain_id= 7; +# Should get applied on slave. +INSERT INTO t1 VALUES(9); +# Change it to 10 (no in DO_DOMAIN_IDS). +SET @@session.gtid_domain_id= 10; +# Following should get filtered out on slave. +INSERT INTO t1 VALUES(10); +INSERT INTO t1 VALUES(11); +START TRANSACTION; +INSERT INTO t1 VALUES(12); +INSERT INTO t1 VALUES(13); +COMMIT; +INSERT INTO t1 VALUES(14); +INSERT INTO t1 VALUES(15); +--source include/save_master_gtid.inc + +connection slave; +--source include/sync_with_master_gtid.inc +SELECT * FROM t1; + +##### Case 5: Seconds_Behind_Master +connection slave; +--echo # Seconds_Behind_Master should be zero here because the slave is fully caught up and idle. +--let $status_items= Seconds_Behind_Master +--source include/show_slave_status.inc + +##### Case 6: Stop slave before a transaction (involving MyISAM and InnoDB +# table) being filtered commits. + +connection slave; +--source include/stop_slave.inc +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +# IGNORE_DOMAIN_IDS=(1) +CHANGE MASTER TO DO_DOMAIN_IDS=(), IGNORE_DOMAIN_IDS=(1), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +connection master; +# following statements should not get filtered. +SET @@session.gtid_domain_id=2; +CREATE TABLE t2(i int) ENGINE=MYISAM; +CREATE TABLE t3(i int) ENGINE=INNODB; + +SET @@session.gtid_domain_id=1; +BEGIN; +INSERT INTO t2 VALUES(1); +INSERT INTO t3 VALUES(1); + +# Now switch to slave to stop replication. +connection slave; +--source include/stop_slave.inc +--source include/wait_for_slave_to_stop.inc + +# Back to master to finish the transaction. +connection master; +INSERT INTO t2 VALUES(2); +INSERT INTO t3 VALUES(2); +COMMIT; +--source include/save_master_gtid.inc + +# On slave to start replication. +connection slave; +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + +SELECT * FROM t2; +SELECT * FROM t3; + +##### Case 7: Stop slave before a transaction (involving MyISAM and InnoDB +# table) being filtered commits and start it back with filtering +# disabled. + +connection master; +SET @@session.gtid_domain_id=1; +BEGIN; +INSERT INTO t2 VALUES(3); +INSERT INTO t3 VALUES(3); +--source include/save_master_gtid.inc + +connection slave; +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +# Clear IGNORE_DOMAIN_IDS +CHANGE MASTER TO DO_DOMAIN_IDS=(), IGNORE_DOMAIN_IDS=(), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +connection master; +INSERT INTO t2 VALUES(4); +INSERT INTO t3 VALUES(4); +COMMIT; +--source include/save_master_gtid.inc + +connection slave; +--source include/sync_with_master_gtid.inc +SELECT * FROM t2; +SELECT * FROM t3; + +##### Case 8: Stop slave into the middle of a transaction and start it back +# with filtering enabled. + +connection master; +SET @@session.gtid_domain_id=1; +BEGIN; +INSERT INTO t2 VALUES(5); +INSERT INTO t3 VALUES(5); +--source include/save_master_gtid.inc + +connection slave; +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +# IGNORE_DOMAIN_IDS(1) +CHANGE MASTER TO DO_DOMAIN_IDS=(), IGNORE_DOMAIN_IDS=(1), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +connection master; +INSERT INTO t2 VALUES(6); +INSERT INTO t3 VALUES(6); +COMMIT; +--source include/save_master_gtid.inc + +connection slave; +--source include/sync_with_master_gtid.inc +SELECT * FROM t2; +SELECT * FROM t3; + +##### Case 9: Initially filter out events belonging to domain_id=2 and then +# remove the rule to check if event are not being filtered out. + +connection slave; +--source include/stop_slave.inc +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +# IGNORE_DOMAIN_IDS(2) +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(2), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +connection master; +SET @@session.gtid_domain_id=2; +BEGIN; +INSERT INTO t2 VALUES(7); +INSERT INTO t3 VALUES(7); +COMMIT; +--source include/save_master_gtid.inc + +# Clear the filter +connection slave; +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +# IGNORE_DOMAIN_IDS() +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +connection master; +SET @@session.gtid_domain_id=2; +BEGIN; +INSERT INTO t2 VALUES(8); +INSERT INTO t3 VALUES(8); +COMMIT; +--source include/save_master_gtid.inc + +connection slave; +--source include/sync_with_master_gtid.inc +SELECT * FROM t2; +SELECT * FROM t3; + +##### Case 10: Test CHANGE MASTER with various "incompatible" combinations. +connection slave; +--source include/stop_slave.inc + +# 10a: Both DO_DOMAIN_IDS & IGNORE_DOMAIN_IDS can't be non-empty at the same +# time. + +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +--error ER_MASTER_INFO +CHANGE MASTER TO DO_DOMAIN_IDS=(1), IGNORE_DOMAIN_IDS=(1), MASTER_USE_GTID=SLAVE_POS; +CHANGE MASTER TO DO_DOMAIN_IDS=(1), MASTER_USE_GTID=SLAVE_POS; +--error ER_MASTER_INFO +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(1), MASTER_USE_GTID=SLAVE_POS; +CHANGE MASTER TO DO_DOMAIN_IDS=(), IGNORE_DOMAIN_IDS=(1), MASTER_USE_GTID=SLAVE_POS; +--error ER_MASTER_INFO +CHANGE MASTER TO DO_DOMAIN_IDS=(1), MASTER_USE_GTID=SLAVE_POS; + +# 10b: Neither DO_DOMAIN_IDS nor IGNORE_DOMAIN_IDS can be set when +# MASTER_USE_GTID=NO + +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +# MASTER_USE_GTID can't be set to NO when either of IGNORE_DOMAIN_IDS or +# DO_DOMAIN_IDS is non-empty. +--error ER_MASTER_INFO +CHANGE MASTER TO MASTER_USE_GTID=NO; +CHANGE MASTER TO DO_DOMAIN_IDS=(), IGNORE_DOMAIN_IDS=(), MASTER_USE_GTID=NO; +--error ER_MASTER_INFO +CHANGE MASTER TO DO_DOMAIN_IDS=(1), MASTER_USE_GTID=NO; +--error ER_MASTER_INFO +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(1), MASTER_USE_GTID=NO; + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(1), DO_DOMAIN_IDS=(), MASTER_USE_GTID=SLAVE_POS; +--source include/start_slave.inc + +# Cleanup +connection master; +SET @@session.gtid_domain_id=2; +DROP TABLE t1, t2, t3; +--source include/save_master_gtid.inc + +connection slave; +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc +CHANGE MASTER TO DO_DOMAIN_IDS=(), IGNORE_DOMAIN_IDS=(); +--source include/start_slave.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_domain_id_filter_io_crash.test b/mysql-test/suite/rpl/t/rpl_domain_id_filter_io_crash.test new file mode 100644 index 00000000..a949da0c --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_domain_id_filter_io_crash.test @@ -0,0 +1,384 @@ +--source include/have_debug.inc +--source include/have_innodb.inc +--source include/master-slave.inc + +connection master; +SET @@session.gtid_domain_id= 1; +SELECT @@session.gtid_domain_id; +CREATE TABLE t1(i INT) ENGINE=INNODB; +INSERT INTO t1 VALUES(1); +SELECT * FROM t1; +sync_slave_with_master; + +connection slave; + +call mtr.add_suppression("Slave I/O: Relay log write failure: could not queue event from master.*"); + +--echo # Case 0 : Start slave with IGNORE_DOMAIN_IDS=(), then restart +--echo # replication with IGNORE_DOMAIN_IDS=() after IO thread is +--echo # killed due to DBUG_EXECUTE_IF("+d,kill_slave_io_before_commit"). + +SELECT * FROM t1; + +--source include/stop_slave.inc +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc +sync_with_master; + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +SET @saved_dbug = @@GLOBAL.debug_dbug; +SET @@global.debug_dbug="d,kill_slave_io_before_commit"; + +connection master; + +START TRANSACTION; +INSERT INTO t1 VALUES(2); +INSERT INTO t1 VALUES(3); +COMMIT; +save_master_pos; +SELECT * FROM t1; + +connection slave; +--let $slave_io_errno= 1595 +--source include/wait_for_slave_io_error.inc +SELECT * FROM t1; +SET @@global.debug_dbug=@saved_dbug; + +START SLAVE io_thread; +--source include/wait_for_slave_io_to_start.inc +sync_with_master; +SELECT * FROM t1; + +--echo # Case 1 : Start slave with IGNORE_DOMAIN_IDS=(1), then restart +--echo # replication with IGNORE_DOMAIN_IDS=(1) after IO thread is +--echo # killed due to DBUG_EXECUTE_IF("+d,kill_slave_io_before_commit"). + +--source include/stop_slave.inc +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(1), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc +sync_with_master; + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +SET @@global.debug_dbug="d,kill_slave_io_before_commit"; + +connection master; + +START TRANSACTION; +INSERT INTO t1 VALUES(4); +INSERT INTO t1 VALUES(5); +COMMIT; + +save_master_pos; +SELECT * FROM t1; + +connection slave; +--let $slave_io_errno= 1595 +--source include/wait_for_slave_io_error.inc +SELECT * FROM t1; +SET @@global.debug_dbug=@saved_dbug; + +START SLAVE io_thread; +--source include/wait_for_slave_io_to_start.inc +sync_with_master; +SELECT * FROM t1; + +--echo # Case 2 : Start slave with IGNORE_DOMAIN_IDS=(), then restart +--echo # replication with IGNORE_DOMAIN_IDS=(1) after IO thread is +--echo # killed due to DBUG_EXECUTE_IF("+d,kill_slave_io_before_commit"). + +--source include/stop_slave.inc +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc +sync_with_master; + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +SET @@global.debug_dbug="d,kill_slave_io_before_commit"; + +connection master; + +START TRANSACTION; +INSERT INTO t1 VALUES(6); +INSERT INTO t1 VALUES(7); +COMMIT; # IO thread gets killed here. + +START TRANSACTION; +INSERT INTO t1 VALUES(8); +INSERT INTO t1 VALUES(9); +COMMIT; + +SET @@session.gtid_domain_id= 2; + +START TRANSACTION; +INSERT INTO t1 VALUES(10); +INSERT INTO t1 VALUES(11); +COMMIT; + +save_master_pos; +SELECT * FROM t1; + +connection slave; +--let $slave_io_errno= 1595 +--source include/wait_for_slave_io_error.inc +SELECT * FROM t1; + +SET @@global.debug_dbug=@saved_dbug; + +--source include/stop_slave.inc +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(1), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc +sync_with_master; + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +SELECT * FROM t1; + +--echo # Case 3 : Start slave with IGNORE_DOMAIN_IDS=(1), then restart +--echo # replication with IGNORE_DOMAIN_IDS=() after IO thread is +--echo # killed due to DBUG_EXECUTE_IF("+d,kill_slave_io_before_commit"). + +--source include/stop_slave.inc +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(1), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc +sync_with_master; + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +SET @@global.debug_dbug="d,kill_slave_io_before_commit"; + +connection master; + +SET @@session.gtid_domain_id= 1; + +START TRANSACTION; +INSERT INTO t1 VALUES(12); +INSERT INTO t1 VALUES(13); +COMMIT; # IO thread gets killed here. + +START TRANSACTION; +INSERT INTO t1 VALUES(14); +INSERT INTO t1 VALUES(15); +COMMIT; + +SET @@session.gtid_domain_id= 2; +START TRANSACTION; +INSERT INTO t1 VALUES(16); +INSERT INTO t1 VALUES(17); +COMMIT; + +save_master_pos; +SELECT * FROM t1; + +connection slave; +--let $slave_io_errno= 1595 +--source include/wait_for_slave_io_error.inc +SELECT * FROM t1; + +SET @@global.debug_dbug=@saved_dbug; + +--source include/stop_slave.inc +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc +sync_with_master; + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +SELECT * FROM t1; + +--echo # Case 4 : Start slave with IGNORE_DOMAIN_IDS=(1), then restart +--echo # replication with IGNORE_DOMAIN_IDS=() after IO thread is +--echo # killed due to DBUG_EXECUTE_IF("+d,kill_slave_io_after_2_events"). + +--source include/stop_slave.inc +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(1), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc +sync_with_master; + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +SET @@global.debug_dbug="d,kill_slave_io_after_2_events"; + +connection master; + +SET @@session.gtid_domain_id= 1; + +START TRANSACTION; +INSERT INTO t1 VALUES(18); +INSERT INTO t1 VALUES(19); # IO thread gets killed here. +COMMIT; + +START TRANSACTION; +INSERT INTO t1 VALUES(20); +INSERT INTO t1 VALUES(21); +COMMIT; + +SET @@session.gtid_domain_id= 2; +START TRANSACTION; +INSERT INTO t1 VALUES(22); +INSERT INTO t1 VALUES(23); +COMMIT; + +save_master_pos; +SELECT * FROM t1; + +connection slave; +--let $slave_io_errno= 1595 +--source include/wait_for_slave_io_error.inc +SELECT * FROM t1; + +SET @@global.debug_dbug=@saved_dbug; + +--source include/stop_slave.inc +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc +sync_with_master; + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +SELECT * FROM t1; + +--echo # Case 5 : Start slave with IGNORE_DOMAIN_IDS=(), then restart +--echo # replication with IGNORE_DOMAIN_IDS=(1) after IO thread is +--echo # killed due to DBUG_EXECUTE_IF("+d,kill_slave_io_after_2_events"). + +--source include/stop_slave.inc +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc +sync_with_master; + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +SET @@global.debug_dbug="d,kill_slave_io_after_2_events"; + +connection master; + +SET @@session.gtid_domain_id= 1; + +START TRANSACTION; +INSERT INTO t1 VALUES(24); +INSERT INTO t1 VALUES(25); # IO thread gets killed here. +COMMIT; + +START TRANSACTION; +INSERT INTO t1 VALUES(26); +INSERT INTO t1 VALUES(27); +COMMIT; + +SET @@session.gtid_domain_id= 2; +START TRANSACTION; +INSERT INTO t1 VALUES(28); +INSERT INTO t1 VALUES(29); +COMMIT; + +save_master_pos; +SELECT * FROM t1; + +connection slave; +--let $slave_io_errno= 1595 +--source include/wait_for_slave_io_error.inc +SELECT * FROM t1; + +SET @@global.debug_dbug=@saved_dbug; + +--source include/stop_slave.inc +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(1), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc +sync_with_master; + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +SELECT * FROM t1; + +# Cleanup +connection master; +DROP TABLE t1; +sync_slave_with_master; + +connection slave; +--source include/stop_slave.inc +CHANGE MASTER TO DO_DOMAIN_IDS=(), IGNORE_DOMAIN_IDS=(); +--source include/start_slave.inc +SET @@GLOBAL.debug_dbug = @saved_dbug; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_domain_id_filter_master_crash.test b/mysql-test/suite/rpl/t/rpl_domain_id_filter_master_crash.test new file mode 100644 index 00000000..6dafab19 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_domain_id_filter_master_crash.test @@ -0,0 +1,87 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +# Valgrind does not work well with test that crashes the server +--source include/not_valgrind.inc +--source include/master-slave.inc + +connection master; + +call mtr.add_suppression("mysqld: Table '.*gtid_slave_pos' is marked as crashed and should be repaired"); +call mtr.add_suppression("Checking table: './mysql/gtid_slave_pos'"); +call mtr.add_suppression("mysql.gtid_slave_pos: 1 client is using or hasn't closed the table properly"); +SET @@session.gtid_domain_id= 0; + +create table ti (a int auto_increment primary key) engine=innodb; +create table tm (a int auto_increment primary key) engine=myisam; + +insert into ti set a=null; +insert into tm set a=null; + +save_master_pos; + +connection slave; +sync_with_master; +--source include/stop_slave.inc + +select * from ti; +select * from tm; + +connection master; +SET @@session.gtid_domain_id= 1; + +begin; +insert into ti set a=null; +insert into tm set a=null; +commit; + +SET @@session.gtid_domain_id= 0; +insert into ti set a=null; +insert into tm set a=null; + +set @@global.debug_dbug="+d,crash_before_send_xid"; +--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect + +connection slave; +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +# IGNORE_DOMAIN_IDS=(1) +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(1), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +connection master; +--source include/wait_until_disconnected.inc +--enable_reconnect +--let $rpl_server_number=1 +--source include/rpl_start_server.inc +#--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +--source include/wait_until_connected_again.inc +--echo # Master has restarted successfully +save_master_pos; + +--connection slave +--source include/stop_slave.inc +--source include/start_slave.inc +sync_with_master; +select * from ti; +select * from tm; + +# Cleanup +--connection master +drop table ti; +drop table tm; +sync_slave_with_master; + +--connection slave +--source include/stop_slave.inc +CHANGE MASTER TO DO_DOMAIN_IDS=(), IGNORE_DOMAIN_IDS=(), MASTER_USE_GTID=NO; +--source include/start_slave.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_domain_id_filter_parallel.test b/mysql-test/suite/rpl/t/rpl_domain_id_filter_parallel.test new file mode 100644 index 00000000..902f6b52 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_domain_id_filter_parallel.test @@ -0,0 +1,196 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +--connection server_2 +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=10; + +##### Case 0 : When both DO_DOMAIN_IDS and IGNORE_DOMAIN_IDS are empty. + +--connection server_2 +CHANGE MASTER TO master_use_gtid=slave_pos, DO_DOMAIN_IDS=(), IGNORE_DOMAIN_IDS=(); +--source include/start_slave.inc + +--connection server_1 +SELECT @@session.gtid_domain_id; +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM; +CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1); +--save_master_pos + +--connection server_2 +--sync_with_master + +# Block the table t1 to simulate a replicated query taking a long time. +--connect (con_temp1,127.0.0.1,root,,test,$SERVER_MYPORT_2,) +LOCK TABLE t1 WRITE; + +--connection server_1 +SET @@session.gtid_domain_id=1; +# This query will be blocked on the slave until UNLOCK TABLES. +INSERT INTO t1 VALUES (2); +SET @@session.gtid_domain_id=0; +# These t2 queries can be replicated in parallel with the prior t1 query, as +# they are in a separate replication domain. +INSERT INTO t2 VALUES (2); +INSERT INTO t2 VALUES (3); +BEGIN; +INSERT INTO t2 VALUES (4); +INSERT INTO t2 VALUES (5); +COMMIT; +INSERT INTO t2 VALUES (6); + +--connection server_2 +--let $wait_condition= SELECT COUNT(*) = 6 FROM t2 +--source include/wait_condition.inc + +SELECT * FROM t2 ORDER by a; + +--connection con_temp1 +SELECT * FROM t1; +UNLOCK TABLES; + +--connection server_2 +--let $wait_condition= SELECT COUNT(*) = 2 FROM t1 +--source include/wait_condition.inc + +SELECT * FROM t1 ORDER BY a; + +##### Case 1 : When DO_DOMAIN_IDS=(1) + +--connection server_2 +--source include/stop_slave.inc +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +# Replicate events belonging to "domain_id 1". +CHANGE MASTER TO DO_DOMAIN_IDS=(1), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc +sync_with_master; + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +--connection server_2 +--sync_with_master + +# Block the table t1 to simulate a replicated query taking a long time. +--connection con_temp1 +LOCK TABLE t1 WRITE; + +--connection server_1 +SET @@session.gtid_domain_id=0; +# This query will be blocked on the slave until UNLOCK TABLES. +# But, since DO_DOMAIN_IDS=(1), it will be filtered out on slave. +INSERT INTO t1 VALUES (3); + +SET @@session.gtid_domain_id=1; +# These t2 queries can be replicated in parallel with the prior t1 query, as +# they are in a separate replication domain. +INSERT INTO t2 VALUES (7); +INSERT INTO t2 VALUES (8); +BEGIN; +INSERT INTO t2 VALUES (9); +INSERT INTO t2 VALUES (10); +COMMIT; +INSERT INTO t2 VALUES (11); + +--connection server_2 +--let $wait_condition= SELECT COUNT(*) = 11 FROM t2 +--source include/wait_condition.inc + +SELECT * FROM t2 ORDER by a; + +--connection con_temp1 +SELECT * FROM t1; +UNLOCK TABLES; + +--connection server_2 +--let $wait_condition= SELECT COUNT(*) = 2 FROM t1 +--source include/wait_condition.inc + +SELECT * FROM t1 ORDER BY a; + +##### Case 2 : When IGNORE_DOMAIN_IDS=(1) + +--connection server_2 +--source include/stop_slave.inc +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +# Replicate events belonging to "domain_id 1". +CHANGE MASTER TO DO_DOMAIN_IDS=(), IGNORE_DOMAIN_IDS=(1), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc +sync_with_master; + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +--connection server_2 +--sync_with_master + +# Block the table t1 to simulate a replicated query taking a long time. +--connection con_temp1 +LOCK TABLE t1 WRITE; + +--connection server_1 +SET @@session.gtid_domain_id=1; +# This query will be blocked on the slave until UNLOCK TABLES. However, since +# IGNORE_DOMAIN_IDS=(1), it will be filtered out on slave. +INSERT INTO t1 VALUES (4); +SET @@session.gtid_domain_id=0; +# These t2 queries can be replicated in parallel with the prior t1 query, as +# they are in a separate replication domain. +INSERT INTO t2 VALUES (12); +INSERT INTO t2 VALUES (13); +BEGIN; +INSERT INTO t2 VALUES (14); +INSERT INTO t2 VALUES (15); +COMMIT; +INSERT INTO t2 VALUES (16); + +--connection server_2 +--let $wait_condition= SELECT COUNT(*) = 16 FROM t2 +--source include/wait_condition.inc + +SELECT * FROM t2 ORDER by a; + +--connection con_temp1 +SELECT * FROM t1; +UNLOCK TABLES; + +--connection server_2 +--let $wait_condition= SELECT COUNT(*) = 2 FROM t1 +--source include/wait_condition.inc + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2; + +--echo # Restore original settings. +--connection server_1 +SET @@session.gtid_domain_id=0; +DROP TABLE t1, t2; +--save_master_pos + +--connection server_2 +--sync_with_master +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads= @old_parallel_threads; +CHANGE MASTER TO DO_DOMAIN_IDS=(), IGNORE_DOMAIN_IDS=(); +--source include/start_slave.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_domain_id_filter_restart.test b/mysql-test/suite/rpl/t/rpl_domain_id_filter_restart.test new file mode 100644 index 00000000..8083b8f2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_domain_id_filter_restart.test @@ -0,0 +1,73 @@ +--source include/master-slave.inc + +# +# Test for domain-id based filter on slave restart in GTID-mode. +# + + +connection slave; + +source include/stop_slave.inc; +let $do_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_before= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (BEFORE) : $do_domain_ids_before +--echo IGNORE_DOMAIN_IDS (BEFORE) : $ignore_domain_ids_before + +# Ignore events belonging to "domain_id 1". +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(1), MASTER_USE_GTID=slave_pos; +source include/start_slave.inc; + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +connection master; +SET @@session.gtid_domain_id= 0; +CREATE TABLE t1(i INT); +CREATE TABLE t2(i INT); + +INSERT INTO t1 VALUES(1); +SELECT * FROM t1; + +SET @@session.gtid_domain_id= 1; +# the following will get filtered out. +INSERT INTO t2 VALUES(1); +SELECT * FROM t2; + +sync_slave_with_master; + +connection slave; +SELECT * FROM t1; +SELECT * FROM t2; + +# restart the slave +--let $rpl_server_number= 2 +--source include/rpl_restart_server.inc + +# Replicate_Do_Domain_Ids/Replicate_Ignore_Domain_Ids should reinitialize +# properly on restart. +connection slave; +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER RESTART) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER RESTART) : $ignore_domain_ids_after + +# Now, lets clear IGNORE_DOMAIN_IDS. +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(); +--source include/start_slave.inc + +let $do_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ignore_domain_ids_after= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +--echo DO_DOMAIN_IDS (AFTER) : $do_domain_ids_after +--echo IGNORE_DOMAIN_IDS (AFTER) : $ignore_domain_ids_after + +SELECT * FROM t1; +SELECT * FROM t2; + +connection master; +SET @@session.gtid_domain_id= 0; +DROP TABLE t1, t2; +sync_slave_with_master; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_drop.test b/mysql-test/suite/rpl/t/rpl_drop.test new file mode 100644 index 00000000..7b887334 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_drop.test @@ -0,0 +1,12 @@ +# Testcase for BUG#4552 (DROP on two tables, one of which does not +# exist, must be binlogged with a non-zero error code) +source include/master-slave.inc; + +create table t1 (a int); +--error 1051 +drop table t1, t2; +--sync_slave_with_master + +# End of 4.1 tests + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_drop_db.test b/mysql-test/suite/rpl/t/rpl_drop_db.test new file mode 100644 index 00000000..245ab8b6 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_drop_db.test @@ -0,0 +1,66 @@ +# test case for BUG#4680 -- if there are extra files in the db directory +# dropping the db on the master causes replication problems + +-- source include/master-slave.inc +connection master; + +--disable_warnings +drop database if exists mysqltest1; +--enable_warnings +create database mysqltest1; +create table mysqltest1.t1 (n int); +insert into mysqltest1.t1 values (1); +--enable_prepare_warnings +--disable_ps2_protocol +select * from mysqltest1.t1 into outfile 'mysqltest1/f1.txt'; +--disable_prepare_warnings +--enable_ps2_protocol +create table mysqltest1.t2 (n int); +create table mysqltest1.t3 (n int); +--replace_result \\ / 66 39 93 39 17 39 247 39 41 39 "File exists" "Directory not empty" +--error ER_DB_DROP_RMDIR +drop database mysqltest1; +use mysqltest1; +show tables; + +# test the branch of the code that deals with the query buffer overflow + +--disable_query_log +let $1=50; +while ($1) +{ + eval create table mysqltest1.mysqltest_long_table_name$1 (n int); + dec $1; +} +--enable_query_log + +--replace_result \\ / 66 39 93 39 17 39 247 39 41 39 "File exists" "Directory not empty" +--error ER_DB_DROP_RMDIR +drop database mysqltest1; +use mysqltest1; +show tables; +use test; +create table t1 (n int); +insert into t1 values (1234); +sync_slave_with_master; + +connection slave; +use mysqltest1; +show tables; +use test; +select * from t1; + +#cleanup +connection master; + +# Remove the "extra" file created above +let $MYSQLD_DATADIR= `select @@datadir`; +remove_file $MYSQLD_DATADIR/mysqltest1/f1.txt; + +use test; +drop table t1; +drop database mysqltest1; + +sync_slave_with_master; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_drop_db_fail.test b/mysql-test/suite/rpl/t/rpl_drop_db_fail.test new file mode 100644 index 00000000..c13bae1c --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_drop_db_fail.test @@ -0,0 +1,34 @@ +############################################################################### +# Bug#20041860: SLAVE ERROR WHEN DROP DATABASE +# +# Test: +# ===== +# Create two databases such that one database has a dependency over the other +# database and try to drop the database which has a dependency. This should +# not cause slave to break. +############################################################################### +--source include/have_innodb.inc +--source include/master-slave.inc + +connection master; +CREATE DATABASE IF NOT EXISTS db1; +CREATE DATABASE IF NOT EXISTS db2; + +use db1; +CREATE TABLE a(id INT); +CREATE VIEW v AS SELECT * FROM a; +CREATE TABLE table_father(id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(20)) ENGINE=INNODB; +--sync_slave_with_master + +connection master; +use db2; +CREATE TABLE table_child(id INT PRIMARY KEY, info VARCHAR(20), father_id INT) ENGINE=INNODB; +ALTER TABLE table_child ADD CONSTRAINT aaa FOREIGN KEY (father_id) REFERENCES db1.table_father(id); + +--error ER_ROW_IS_REFERENCED_2 +DROP DATABASE db1; +DROP DATABASE db2; +--sync_slave_with_master +--connection master +DROP DATABASE db1; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_drop_temp-slave.opt b/mysql-test/suite/rpl/t/rpl_drop_temp-slave.opt new file mode 100644 index 00000000..2f9244c6 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_drop_temp-slave.opt @@ -0,0 +1,2 @@ +--replicate-ignore-table=mysqltest.t2 + diff --git a/mysql-test/suite/rpl/t/rpl_drop_temp.test b/mysql-test/suite/rpl/t/rpl_drop_temp.test new file mode 100644 index 00000000..7158e2a8 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_drop_temp.test @@ -0,0 +1,94 @@ +############################################## +# Change Author: JBM +# Change Date: 2006-02-07 +# Change: Added ENGINE=MyISAM +############################################## +source include/have_binlog_format_mixed_or_statement.inc; +source include/master-slave.inc; + +--disable_warnings +create database if not exists mysqltest; +--enable_warnings + +connect (con_temp,127.0.0.1,root,,test,$MASTER_MYPORT,); + +connection con_temp; +use mysqltest; +create temporary table mysqltest.t1 (n int)ENGINE=MyISAM; +create temporary table mysqltest.t2 (n int)ENGINE=MyISAM; + +disconnect con_temp; +--source include/wait_until_disconnected.inc + +connection master; +-- let $wait_binlog_event= DROP +-- source include/wait_for_binlog_event.inc +sync_slave_with_master; + +connection slave; +show status like 'Slave_open_temp_tables'; +# Cleanup +connection master; +drop database mysqltest; +sync_slave_with_master; + +# +# Bug#49137 +# This test verifies if DROP MULTI TEMPORARY TABLE +# will cause different errors on master and slave, +# when one or more of these tables do not exist. +# + +connection master; +DROP TEMPORARY TABLE IF EXISTS tmp1; +CREATE TEMPORARY TABLE t1 ( a int ); +--error 1051 +DROP TEMPORARY TABLE t1, t2; +--error 1051 +DROP TEMPORARY TABLE tmp2; +sync_slave_with_master; + +connection slave; +stop slave; +wait_for_slave_to_stop; + +connection master; +CREATE TEMPORARY TABLE tmp3 (a int); +DROP TEMPORARY TABLE tmp3; + +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; + +connection master; +sync_slave_with_master; + + +# +# BUG#54842: DROP TEMPORARY TABLE not binlogged after manual switching binlog format to ROW +# + +--source include/rpl_reset.inc +--connection master + +CREATE TABLE t1 ( i INT ); +--sync_slave_with_master +SHOW STATUS LIKE 'Slave_open_temp_tables'; + +--connect(con1,localhost,root,,) +CREATE TEMPORARY TABLE ttmp1 ( i INT ); +SET SESSION binlog_format=ROW; +--disconnect con1 + +-- connection master +--let $wait_binlog_event= DROP +--source include/wait_for_binlog_event.inc +--sync_slave_with_master +SHOW STATUS LIKE 'Slave_open_temp_tables'; + +--connection master +--source include/show_binlog_events.inc +DROP TABLE t1; + +# End of 4.1 tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_drop_temp_table_invalid_lex.test b/mysql-test/suite/rpl/t/rpl_drop_temp_table_invalid_lex.test new file mode 100644 index 00000000..475afef1 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_drop_temp_table_invalid_lex.test @@ -0,0 +1,41 @@ +# ==== Purpose ==== +# +# Test verifies that no ASAN issues are reported at the time of writing DROP +# TEMPORARY TABLE statements to binary log as part of session cleanup. +# +# ==== Implementation ==== +# +# Steps: +# 1 - Create a new connection named 'con1'. +# 2 - Create a temporary table named 'tmp' as part of connection 'con1'. +# 3 - Try to disconnect the current session when a CREATE .. SELECT +# statement is in the middle of execution. +# 4 - Observe that no ASAN issue is reported. +# +# ==== References ==== +# +# MDEV-19716: ASAN use-after-poison in Query_log_event::Query_log_event / +# THD::log_events_and_free_tmp_shares + +--source include/have_binlog_format_mixed_or_statement.inc +--source include/master-slave.inc + +--connect (con1,localhost,root,,) +CREATE TEMPORARY TABLE tmp (a INT); + +--send CREATE TABLE non_existing_db.t SELECT 1 AS b +--disconnect con1 +--source include/wait_until_disconnected.inc + +--connection master +--let $wait_binlog_event= DROP +--source include/wait_for_binlog_event.inc +sync_slave_with_master; + +--connection slave +--let $open_temp_tbl_count=query_get_value(show status like 'Slave_open_temp_tables', Value, 1) +--let $assert_cond= "open_temp_tbl_count" = 0 +--let $assert_text= "Slave_open_temp_tables count should be 0" +--source include/assert.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_drop_view.test b/mysql-test/suite/rpl/t/rpl_drop_view.test new file mode 100644 index 00000000..1893dd21 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_drop_view.test @@ -0,0 +1,35 @@ +# test case for bug#30998 +# Drop View breaks replication if view does not exist +# + +source include/master-slave.inc; +--disable_warnings +drop table if exists t1, t2; +drop view if exists v1, v2, v3, not_exist_view; +--enable_warnings +create table t1 (a int); +create table t2 (b int); +create table t3 (c int); +create view v1 as select * from t1; +create view v2 as select * from t2; +create view v3 as select * from t3; +--error ER_UNKNOWN_VIEW +drop view not_exist_view; +--error ER_UNKNOWN_VIEW +drop view v1, not_exist_view; +--error 1146 +select * from v1; +drop view v2, v3; +sync_slave_with_master; +--error 1146 +select * from v1; +--error 1146 +select * from v2; +--error 1146 +select * from v3; + +--echo ==== clean up ==== +connection master; +drop table t1, t2, t3; +sync_slave_with_master; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_dual_pos_advance.test b/mysql-test/suite/rpl/t/rpl_dual_pos_advance.test new file mode 100644 index 00000000..618576f5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_dual_pos_advance.test @@ -0,0 +1,97 @@ +# This test checks that in a dual-head setup +# A->B->A, where A has --log-slave-updates (why would it? +# assume that there is a C as slave of A), +# then the Exec_master_log_pos of SHOW SLAVE STATUS does +# not stay too low on B(BUG#13023 due to events ignored because +# of their server id). +# It also will test BUG#13861. + +source include/have_innodb.inc; + +--let $rpl_topology= 1->2->1 +--source include/rpl_init.inc + +# now we test it + +connection server_2; + +create table t1 (n int); +let $master_log_file= query_get_value(SHOW MASTER STATUS, File, 1); +let $master_log_pos_1= query_get_value(SHOW MASTER STATUS, Position, 1); +let $master_log_pos_1= `SELECT $master_log_pos_1 + 3`; + +--sync_slave_with_master server_1 + +# +# BUG#13861 - START SLAVE UNTIL may stop 1 evnt too late if +# log-slave-updates and circul repl +# +source include/stop_slave.inc; + +create table t2 (n int); # create one ignored event + +--sync_slave_with_master server_2 + +show tables; + +create table t3 (n int) engine=innodb; +let $master_log_pos_2= query_get_value(SHOW MASTER STATUS, Position, 1); +let $master_log_pos_2= `SELECT $master_log_pos_2 + 5`; +set @a=1; +insert into t3 values(@a); +let $master_log_pos_3= query_get_value(SHOW MASTER STATUS, Position, 1); +let $master_log_pos_3= `SELECT $master_log_pos_3 + 5`; +begin; +insert into t3 values(2); +insert into t3 values(3); +commit; +insert into t3 values(4); + + +connection server_1; + +# bug is that START SLAVE UNTIL may stop too late, we test that by +# asking it to stop before creation of t3. + +--replace_result $master_log_file MASTER_LOG_FILE $master_log_pos_1 MASTER_LOG_POS +eval start slave until master_log_file="$master_log_file",master_log_pos=$master_log_pos_1; +--source include/wait_for_slave_sql_to_stop.inc + +# then BUG#13861 causes t3 to show up below (because stopped too +# late). + +show tables; + +# ensure that we do not break set @a=1; insert into t3 values(@a); +--replace_result $master_log_file MASTER_LOG_FILE $master_log_pos_2 MASTER_LOG_POS +eval start slave until master_log_file="$master_log_file",master_log_pos=$master_log_pos_2; +--source include/wait_for_slave_sql_to_stop.inc +select * from t3; + +# ensure that we do not break transaction +--replace_result $master_log_file MASTER_LOG_FILE $master_log_pos_3 MASTER_LOG_POS +eval start slave until master_log_file="$master_log_file",master_log_pos=$master_log_pos_3; +--source include/wait_for_slave_sql_to_stop.inc +select * from t3; + +source include/start_slave.inc; + +# BUG#13023 is that Exec_master_log_pos may stay too low "forever": + +connection server_1; + +create table t4 (n int); # create 3 ignored events +create table t5 (n int); +create table t6 (n int); + +--sync_slave_with_master server_2 + +# then BUG#13023 caused hang below ("master" looks behind, while it's +# not in terms of updates done). +--sync_slave_with_master server_1 + +show tables; + +# cleanup +drop table t1, t2, t3, t4, t5, t6; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_dump_request_retry_warning.test b/mysql-test/suite/rpl/t/rpl_dump_request_retry_warning.test new file mode 100644 index 00000000..1ee04362 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_dump_request_retry_warning.test @@ -0,0 +1,66 @@ +# ==== Purpose ==== +# +# Test verifies that, due to a temporary network error, if request dump +# command specific packet write operation fails then the write error gets +# handled appropriately. Further retry will be initiated with appropriate +# slave registration on master. This will ensure that master has all the +# details of slave and no warnings are reported on the master side. +# +# ==== Implementation ==== +# +# Steps: +# 0 - Skip the slave start. +# 1 - Enable debug simulation which will simulate packet write error during +# dump request command execution. +# 2 - Start the slave. Observe that slave is able to reconnect post +# temporary network write error. +# +# ==== References ==== +# +# MDEV-14203: rpl.rpl_extra_col_master_myisam, +# rpl.rpl_slave_load_tmpdir_not_exist failed in buildbot with a +# warning +# +# MDEV-13258: rpl.rpl_skip_replication, rpl.rpl_set_statement_default_master +# failed in buildbot +# + +--source include/have_debug.inc +--source include/have_debug_sync.inc +--let $rpl_skip_start_slave=1 +--source include/master-slave.inc + +# Do an insert on master +CREATE TABLE t1(a int); +INSERT INTO t1 VALUES(1); + +# Add a debug point and start the slave so that dump request fails. +connection slave; +SET @saved_dbug = @@GLOBAL.debug_dbug; +SET @@global.debug_dbug= 'd,simulate_error_on_packet_write'; + +START SLAVE; +SET DEBUG_SYNC= 'now WAIT_FOR parked'; +SET @@GLOBAL.debug_dbug = @saved_dbug; +SET DEBUG_SYNC= 'now SIGNAL continue'; + +# Ensure the last DEBUG_SYNC signal was received by the target thread before +# reset; otherwise, the reset can drop the last signal before it gets +# acknowledged +let $wait_condition= select count(*)=0 from information_schema.processlist where state like "%debug%"; +source include/wait_condition.inc; +SET DEBUG_SYNC= 'RESET'; + +--source include/wait_for_slave_io_to_start.inc +--source include/wait_for_slave_sql_to_start.inc + +# Sync the slave and verify that slave has caught up with the master. +connection master; +--source include/sync_slave_sql_with_master.inc +SELECT * FROM t1; + +# Cleanup +connection master; +DROP TABLE t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_empty_master_host.test b/mysql-test/suite/rpl/t/rpl_empty_master_host.test new file mode 100644 index 00000000..0fc2d11a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_empty_master_host.test @@ -0,0 +1,53 @@ +# +# BUG +# --- +# BUG#28796: CHANGE MASTER TO MASTER_HOST="" leads to invalid master.info +# +# Description +# ----------- +# +# This test aims at: +# i) verifying that an error is thrown when setting MASTER_HOST='' +# ii) no error is thrown when setting non empty MASTER_HOST +# iii) replication works after setting a correct host name/ip +# +# Implementation is performed by feeding different values (according +# to i), ii) and iii) ) to CHANGE MASTER TO MASTER_HOST= x and checking +# along the way if error/no error is thrown and/or if replication starts +# working when expected. + +--source include/have_binlog_format_mixed.inc +--source include/master-slave.inc + +connection slave; +STOP SLAVE; +--source include/wait_for_slave_to_stop.inc + +let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +--echo Master_Host = '$master_host' (expected '127.0.0.1') + +# attempt to change to an empty master host should +# result in error ER_WRONG_ARGUMENTS: "Incorrect arguments to ..." +error ER_WRONG_ARGUMENTS; +CHANGE MASTER TO MASTER_HOST=""; + +# show slave status still holds previous information +let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +--echo Master_Host = '$master_host' (expected '127.0.0.1') + +# changing master to other than empty master host succeeds +CHANGE MASTER TO MASTER_HOST="foo"; + +# show slave status should hold "foo" as master host +let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +--echo Master_Host = '$master_host' (expected 'foo') + +# changing back to localhost +CHANGE MASTER TO MASTER_HOST="127.0.0.1"; +let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +--echo Master_Host = '$master_host' (expected '127.0.0.1') + +# start slave must succeed. +START SLAVE; +--source include/wait_for_slave_to_start.inc +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_empty_string_is_null.test b/mysql-test/suite/rpl/t/rpl_empty_string_is_null.test new file mode 100644 index 00000000..a0fecbb5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_empty_string_is_null.test @@ -0,0 +1,15 @@ +--source include/master-slave.inc +--source include/have_binlog_format_row.inc + +--echo # +--echo # MDEV-18918 SQL mode EMPTY_STRING_IS_NULL breaks RBR upon CREATE TABLE .. SELECT +--echo # + +SET SQL_MODE= 'EMPTY_STRING_IS_NULL'; +CREATE TABLE t1 AS SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE 1 = 0; +--sync_slave_with_master +SHOW CREATE TABLE t1; +--connection master +DROP TABLE t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_err_ignoredtable-slave.opt b/mysql-test/suite/rpl/t/rpl_err_ignoredtable-slave.opt new file mode 100644 index 00000000..cb49119b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_err_ignoredtable-slave.opt @@ -0,0 +1 @@ +--replicate-ignore-table=test.t1 --replicate-ignore-table=test.t2 --replicate-ignore-table=test.t3 diff --git a/mysql-test/suite/rpl/t/rpl_err_ignoredtable.test b/mysql-test/suite/rpl/t/rpl_err_ignoredtable.test new file mode 100644 index 00000000..9aee3582 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_err_ignoredtable.test @@ -0,0 +1,70 @@ +# Test for +# Bug #797: If a query is ignored on slave (replicate-ignore-table) the slave +# still checks that it has the same error as on the master. +########################################################################## + +-- source include/master-slave.inc + +-- disable_query_log +CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT."); +-- enable_query_log + +connection master; +create table t1 (a int primary key); +create table t4 (a int primary key); +# generate an error that goes to the binlog +--error 1022, ER_DUP_ENTRY +insert into t1 values (1),(1); +insert into t4 values (1),(2); +# as the t1 table is ignored on the slave, the slave should be able to sync +sync_slave_with_master; +# check that the table has been ignored, because otherwise the test is nonsense +show tables like 't1'; +show tables like 't4'; +SELECT * FROM test.t4 ORDER BY a; +connection master; +drop table t1; +sync_slave_with_master; + +# Now test that even critical errors (connection killed) +# are ignored if rules allow it. +# The "kill" idea was copied from rpl000001.test. + +connection master1; +select get_lock('crash_lock%20C', 10); + +connection master; +create table t2 (a int primary key); +insert into t2 values(1); +create table t3 (id int); +insert into t3 values(connection_id()); +send update t2 set a = a + 1 + get_lock('crash_lock%20C', 10); + +connection master1; +let $wait_condition= SELECT count(*) > 0 FROM information_schema.processlist WHERE info LIKE 'update%' AND state='User lock'; +source include/wait_condition.inc; +select (@id := id) - id from t3; +kill @id; +let $id= `SELECT @id`; +let $wait_condition= SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID = $id; +source include/wait_condition.inc; +drop table t2,t3; +insert into t4 values (3),(4); +connection master; +# The get_lock function causes warning for unsafe statement. +--disable_warnings +--error 0,1317,2013 +reap; +--enable_warnings +connection master1; +sync_slave_with_master; +SELECT * FROM test.t4 ORDER BY a; + +connection master1; +DROP TABLE test.t4; +sync_slave_with_master; +# End of 4.1 tests +# Adding comment for force manual merge 5.0 -> wl1012. delete me if needed + + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_events.test b/mysql-test/suite/rpl/t/rpl_events.test new file mode 100644 index 00000000..1d66c327 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_events.test @@ -0,0 +1,249 @@ +################################################################## +# Author: Giuseppe # +# Date: 2006-12-20 # +# Purpose: To test that event effects are replicated. # +################################################################## + +if (`SELECT $PS_PROTOCOL != 0`) +{ + --skip Need regular protocol but ps-protocol was specified +} + +--source include/master-slave.inc + +SET @old_event_scheduler = @@global.event_scheduler; +set global event_scheduler=1; + +# first, we need a table to record something from an event + +eval CREATE TABLE `t1` ( + `id` INT(10) UNSIGNED NOT NULL, + `c` VARCHAR(50) NOT NULL, + `ts` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) DEFAULT CHARSET=utf8; + +INSERT INTO t1 (id, c) VALUES (1, 'manually'); + +# We create the event so that it inserts exactly 1 row in the table +# A recuring event is used so that we can be sure the event will +# fire regardless of timing delays on the server. Otherwise, it is +# possible for the event to timeout before it has inserted a row. +--echo "Creating event test.justonce on the master" +CREATE EVENT test.justonce ON SCHEDULE EVERY 2 SECOND DO + INSERT IGNORE INTO t1 (id, c) VALUES (2, 'from justonce'); + +# Show the event is alive and present on master +--echo "Checking event is active on master" +SELECT db, name, status, originator FROM mysql.event WHERE db = 'test' AND name = 'justonce'; + +# Wait until event has fired. We know this because t1 will contain +# the row from the event. +let $wait_condition= + SELECT COUNT(*) = 1 FROM t1 WHERE c = 'from justonce'; +--source include/wait_condition.inc + +# check that table t1 contains something +--echo "Checking event data on the master" +let $events_done=`SELECT count(*) FROM t1 id`; +--disable_query_log +eval SELECT $events_done > 0 as ONE; +--enable_query_log + +sync_slave_with_master; + +--echo "Checking event data on the slave" +--disable_query_log +eval SELECT count(*) - $events_done as ZERO FROM t1 id; +--enable_query_log + +--echo "Checking event is inactive on slave" +SELECT db, name, status, originator FROM mysql.event WHERE db = 'test' AND name = 'justonce'; + +# Create an event on the slave and check to see what the originator is. +--echo "Dropping event test.slave_once on the slave" +--disable_warnings +DROP EVENT IF EXISTS test.slave_once; +--enable_warnings + +# Create an event on slave and check its state. An event shouldn't be executed +# so set start time in 1 hour. +CREATE EVENT test.slave_once ON SCHEDULE EVERY 5 MINUTE STARTS CURRENT_TIMESTAMP + INTERVAL 1 HOUR DO + INSERT IGNORE INTO t1(id, c) VALUES (3, 'from slave_once'); + +--echo "Checking event status on the slave for originator value = slave's server_id" +SELECT db, name, status, originator FROM mysql.event WHERE db = 'test' AND name = 'slave_once'; + +--echo "Dropping event test.slave_once on the slave" +--disable_warnings +DROP EVENT IF EXISTS test.slave_once; +--enable_warnings + +connection master; + +# BUG#20384 - disable events on slave +--echo "Dropping event test.justonce on the master" +--disable_warnings +DROP EVENT IF EXISTS test.justonce; +--enable_warnings + +# Create an event on master and check its state on slave. An event shouldn't be executed +# so set start time in 1 hour. Check that changes of event statement replicated to slave + +--echo "Creating event test.er on the master" +CREATE EVENT test.er ON SCHEDULE EVERY 3 SECOND STARTS CURRENT_TIMESTAMP + INTERVAL 1 HOUR DO + INSERT IGNORE INTO t1(id, c) VALUES (4, 'from er'); + +--echo "Checking event status on the master" +SELECT db, name, status, originator, body FROM mysql.event WHERE db = 'test' AND name = 'er'; + +sync_slave_with_master; + +--echo "Checking event status on the slave" +SELECT db, name, status, originator, body FROM mysql.event WHERE db = 'test' AND name = 'er'; + +connection master; +--echo "Altering event test.er on the master" +ALTER EVENT test.er ON SCHEDULE EVERY 5 SECOND STARTS CURRENT_TIMESTAMP + INTERVAL 1 HOUR DO + INSERT IGNORE INTO t1(id, c) VALUES (5, 'from alter er'); + +--echo "Checking event status on the master" +SELECT db, name, status, originator, body FROM mysql.event WHERE db = 'test' AND name = 'er'; + +sync_slave_with_master; + +--echo "Checking event status on the slave" +SELECT db, name, status, originator, body FROM mysql.event WHERE db = 'test' AND name = 'er'; + +connection master; +--echo "Dropping event test.er on the master" +DROP EVENT test.er; + +--echo "Checking event status on the master" +SELECT db, name, status, originator FROM mysql.event WHERE db = 'test'; + +--disable_info + +sync_slave_with_master; + +--echo "Checking event status on the slave" +SELECT db, name, status, originator FROM mysql.event WHERE db = 'test'; + +# test the DISABLE ON SLAVE for setting event SLAVESIDE_DISABLED as status +# on CREATE EVENT + +# Create an event on slave and check its status. An event shouldn't be executed +# so set start time in 1 hour. + +--echo "Creating event test.slave_terminate on the slave" +CREATE EVENT test.slave_terminate ON SCHEDULE EVERY 3 SECOND STARTS CURRENT_TIMESTAMP + INTERVAL 1 HOUR DO + INSERT IGNORE INTO t1(id, c) VALUES (6, 'from slave_terminate'); + +--echo "Checking event status on the slave" +SELECT db, name, status, originator FROM mysql.event WHERE db = 'test' AND name = 'slave_terminate'; + +--echo "Dropping event test.slave_terminate on the slave" +DROP EVENT test.slave_terminate; + +--echo "Creating event test.slave_terminate with DISABLE ON SLAVE on the slave" +CREATE EVENT test.slave_terminate ON SCHEDULE EVERY 3 SECOND DISABLE ON SLAVE DO + INSERT IGNORE INTO t1(c) VALUES (7, 'from slave_terminate'); + +--echo "Checking event status on the slave" +SELECT db, name, status, originator FROM mysql.event WHERE db = 'test' AND name = 'slave_terminate'; + +--echo "Dropping event test.slave_terminate on the slave" +DROP EVENT test.slave_terminate; + +--echo "Cleanup" + +connection master; +DROP TABLE t1; +sync_slave_with_master; +connection master; + +# +# Bug #28953 Using events in a replication let the slave crash. +# + +CREATE TABLE t28953 (a INT); + +DELIMITER |; +CREATE EVENT event1 ON SCHEDULE EVERY 1 YEAR +DO BEGIN + select * from t28953; +END;| +DELIMITER ;| + +ALTER EVENT event1 RENAME TO event2; + +sync_slave_with_master; + +connection master; + +DROP EVENT event2; + +# +# BUG#44331 +# This test verifies if the definer is consistent between master and slave, +# when the event is created without the DEFINER clause set explicitly or the +# DEFINER is set to CURRENT_USER +# +CREATE TABLE test.t1(details CHAR(30)); + +CREATE EVENT /*!50000 event44331_1 */ + ON SCHEDULE AT CURRENT_TIMESTAMP + ON COMPLETION PRESERVE DISABLE + DO INSERT INTO test.t1 VALUES('event event44331_1 fired - no definer'); + +CREATE DEFINER=CURRENT_USER /*!50000 EVENT event44331_2 */ + ON SCHEDULE AT CURRENT_TIMESTAMP + ON COMPLETION PRESERVE DISABLE + DO INSERT INTO test.t1 VALUES('event event44331_2 fired - DEFINER=CURRENT_USER'); + +CREATE DEFINER=CURRENT_USER() EVENT event44331_3 + ON SCHEDULE AT CURRENT_TIMESTAMP + ON COMPLETION PRESERVE DISABLE + DO INSERT INTO test.t1 VALUES('event event44331_3 fired - DEFINER=CURRENT_USER() function'); + +DELIMITER |; +CREATE /*!50000 DEFINER='user44331' */ EVENT event44331_4 + ON SCHEDULE AT CURRENT_TIMESTAMP + ON COMPLETION PRESERVE DISABLE + DO INSERT INTO test.t1 VALUES('event event44331_4 fired - DEFINER=user1'); +# Test for bug#50095 Multi-statement including CREATE EVENT causes rotten +# binlog entry + SELECT 'ABC'; + SELECT '123'| +DELIMITER ;| + +select EVENT_SCHEMA, EVENT_NAME, DEFINER from information_schema.events + where EVENT_NAME='event44331_1'; +select EVENT_SCHEMA, EVENT_NAME, DEFINER from information_schema.events + where EVENT_NAME='event44331_2'; +select EVENT_SCHEMA, EVENT_NAME, DEFINER from information_schema.events + where EVENT_NAME='event44331_3'; +select EVENT_SCHEMA, EVENT_NAME, DEFINER from information_schema.events + where EVENT_NAME='event44331_4'; + +sync_slave_with_master; +connection slave; +select EVENT_SCHEMA, EVENT_NAME, DEFINER from information_schema.events + where EVENT_NAME='event44331_1'; +select EVENT_SCHEMA, EVENT_NAME, DEFINER from information_schema.events + where EVENT_NAME='event44331_2'; +select EVENT_SCHEMA, EVENT_NAME, DEFINER from information_schema.events + where EVENT_NAME='event44331_3'; +select EVENT_SCHEMA, EVENT_NAME, DEFINER from information_schema.events + where EVENT_NAME='event44331_4'; + +connection master; +SET @@global.event_scheduler= @old_event_scheduler; +DROP TABLE t28953; +DROP TABLE t1; +DROP EVENT event44331_1; +DROP EVENT event44331_2; +DROP EVENT event44331_3; +DROP EVENT event44331_4; +sync_slave_with_master; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_extra_col_master_innodb.test b/mysql-test/suite/rpl/t/rpl_extra_col_master_innodb.test new file mode 100644 index 00000000..63ae0fce --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_extra_col_master_innodb.test @@ -0,0 +1,11 @@ +############################################################# +# Purpose: To test having extra columns on the master WL#3915 +############################################################# +-- source include/have_binlog_format_row.inc +-- source include/have_innodb.inc +-- source include/master-slave.inc + +let $engine_type = 'InnoDB'; +--source include/rpl_extra_col_master.test + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_extra_col_master_myisam.test b/mysql-test/suite/rpl/t/rpl_extra_col_master_myisam.test new file mode 100644 index 00000000..72a35992 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_extra_col_master_myisam.test @@ -0,0 +1,10 @@ +############################################################# +# Purpose: To test having extra columns on the master WL#3915 +############################################################# +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + +let $engine_type = 'MyISAM'; +--source include/rpl_extra_col_master.test + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_extra_col_slave_innodb.test b/mysql-test/suite/rpl/t/rpl_extra_col_slave_innodb.test new file mode 100644 index 00000000..e16e1dba --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_extra_col_slave_innodb.test @@ -0,0 +1,7 @@ +-- source include/have_binlog_format_row.inc +-- source include/have_innodb.inc +-- source include/master-slave.inc + +let $engine_type = 'InnoDB'; +-- source include/rpl_extra_col_slave.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_extra_col_slave_myisam.test b/mysql-test/suite/rpl/t/rpl_extra_col_slave_myisam.test new file mode 100644 index 00000000..f1e9fa24 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_extra_col_slave_myisam.test @@ -0,0 +1,6 @@ +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + +let $engine_type = 'MyISAM'; +-- source include/rpl_extra_col_slave.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_fail_register.test b/mysql-test/suite/rpl/t/rpl_fail_register.test new file mode 100644 index 00000000..d95a5c5f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_fail_register.test @@ -0,0 +1,33 @@ +source include/have_debug.inc; +source include/have_binlog_format_mixed.inc; +source include/master-slave.inc; + +connection slave; + +set @old_dbug=@@global.debug_dbug; +set global debug_dbug='d,fail_com_register_slave'; + +stop slave; +reset slave; +source include/wait_for_slave_to_stop.inc; +start slave; +stop slave; +source include/wait_for_slave_to_stop.inc; +set global debug_dbug=@old_dbug; + +connection master; + +let $id=`SELECT id from information_schema.processlist where command='Binlog Dump'`; + +if ($id) { + replace_result $id DUMP_THREAD; + eval kill $id; + let $wait_condition= SELECT count(*)=0 from information_schema.processlist where command='Killed'; + source include/wait_condition.inc; +} + +show slave hosts; + +connection slave; +start slave; +source include/rpl_end.inc; diff --git a/mysql-test/suite/rpl/t/rpl_failed_drop_tbl_binlog.opt b/mysql-test/suite/rpl/t/rpl_failed_drop_tbl_binlog.opt new file mode 100644 index 00000000..14fe8f7b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_failed_drop_tbl_binlog.opt @@ -0,0 +1 @@ +--loose-innodb-adaptive-hash-index diff --git a/mysql-test/suite/rpl/t/rpl_failed_optimize.test b/mysql-test/suite/rpl/t/rpl_failed_optimize.test new file mode 100644 index 00000000..a65c19cb --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_failed_optimize.test @@ -0,0 +1,3 @@ +-- source include/have_innodb.inc +let $engine_type=InnoDB; +-- source include/rpl_failed_optimize.test diff --git a/mysql-test/suite/rpl/t/rpl_filter_dbs_dynamic.test b/mysql-test/suite/rpl/t/rpl_filter_dbs_dynamic.test new file mode 100644 index 00000000..05590a0a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_filter_dbs_dynamic.test @@ -0,0 +1,63 @@ +# +# Test if dynamic replication database filter rules are properly evaluated. +# + +source include/have_binlog_format_statement.inc; +source include/master-slave.inc; + +connection slave; +--error ER_SLAVE_MUST_STOP +SET @@GLOBAL.replicate_do_db="db1"; +--error ER_SLAVE_MUST_STOP +SET @@GLOBAL.replicate_ignore_db="db2"; + +connection slave; +source include/stop_slave.inc; +SET @@GLOBAL.replicate_do_db="db1"; +SET @@GLOBAL.replicate_ignore_db="db2"; +source include/start_slave.inc; +connection master; + +CREATE DATABASE db1; +CREATE DATABASE db2; +CREATE DATABASE db3; + +# db is mentioned in do-db rules +USE db1; +CREATE TABLE t1 (a INT); + +# db is mentioned in ignore-db rules +USE db2; +CREATE TABLE t2 (a INT); + +# db is not mentioned in do-db or ignore-db rules +USE db3; +CREATE TABLE t3 (a INT); + +USE db1; +INSERT INTO t1 VALUES (1); + +USE db2; +INSERT INTO t2 VALUES (2); + +USE db3; +INSERT INTO t3 VALUES (3); + +# Only db1 should be replicated to slave +sync_slave_with_master; +echo [on slave]; +SHOW DATABASES LIKE 'db%'; +SHOW TABLES IN db1 LIKE 't%'; + +connection master; + +# Clean up +connection master; +DROP DATABASE IF EXISTS db1; +DROP DATABASE IF EXISTS db2; +DROP DATABASE IF EXISTS db3; +--source include/rpl_end.inc + +connection slave; +SET @@GLOBAL.replicate_do_db=""; +SET @@GLOBAL.replicate_ignore_db=""; diff --git a/mysql-test/suite/rpl/t/rpl_filter_revoke_missing_user.test b/mysql-test/suite/rpl/t/rpl_filter_revoke_missing_user.test new file mode 100644 index 00000000..ca2c18d3 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_filter_revoke_missing_user.test @@ -0,0 +1,92 @@ +# +# Purpose: +# This test ensures that a binlogged Query_log_event which failed on the +# primary server does not break replication if it is ignored by Grant_tables +# on the replica. The bug reported by MDEV-28530 shows this with +# REVOKE ALL PRIVILEGES.. using a non-existent user. The primary will binlog +# the REVOKE command with an error code, and the replica will think the command +# executed with success because the replication filter will ignore the command +# while accessing the Grant_tables classes. When the replica performs an error +# check, it sees the difference between the error codes, and replication +# breaks. +# +# Methodology: +# Using a replica configured with replicate_wild_ignore_table="schema.%", +# on the primary, execute REVOKE ALL PRVILEGES using a non-existent user and +# DROP USER using a list of users where not all users exist, and ensure that +# the replica acknowledges and ignores the events without erroring. +# +# References: +# MDEV-28530: Revoking privileges from a non-existing user on a master breaks +# replication on the slave in the presence of replication filters +# + +source include/master-slave.inc; +source include/have_binlog_format_statement.inc; + +--echo # +--echo # Set replica to ignore system tables +connection slave; +let $old_filter= query_get_value(SHOW SLAVE STATUS, Replicate_Wild_Ignore_Table, 1); +source include/stop_slave.inc; +SET @@GLOBAL.replicate_wild_ignore_table="mysql.%"; +source include/start_slave.inc; + + +--echo # +--echo # Trying to execute REVOKE ALL PRIVILEGES on a non-existent user and +--echo # DROP USER on a list of users where not all users exist should error +--echo # and be written into the binary log +--connection master + +--error 1269 +REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'nonexistentuser'@'%'; + +CREATE USER 'testuser'@'localhost' IDENTIFIED by ''; +--error 1396 +DROP USER 'testuser'@'localhost', 'nonexistentuser'@'%'; +--save_master_pos + + +--echo # +--echo # Ensure the events exist in the primary's binary log +--let $MYSQLD_DATADIR= `select @@datadir` +--let $binlog_file=query_get_value(SHOW MASTER STATUS, File, 1) +FLUSH BINARY LOGS; +--echo # MYSQL_BINLOG MYSQLD_DATADIR/binlog_file > MYSQL_TMP_DIR/mysqlbinlog_out.sql +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/$binlog_file > $MYSQL_TMP_DIR/mysqlbinlog_out.sql + +--echo # There should be three Query events: REVOKE, CREATE USER, and DROP USER +--let SEARCH_FILE= $MYSQL_TMP_DIR/mysqlbinlog_out.sql + +--let SEARCH_PATTERN= Query +--source include/search_pattern_in_file.inc + +--let SEARCH_PATTERN= REVOKE ALL PRIVILEGES +--source include/search_pattern_in_file.inc + +--let SEARCH_PATTERN= CREATE USER +--source include/search_pattern_in_file.inc + +--let SEARCH_PATTERN= DROP USER +--source include/search_pattern_in_file.inc + + +--echo # +--echo # Ensure that the replica receives the event without error +connection slave; +--sync_with_master +let $error= query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1); +--echo Last_SQL_Error = $error +let $errno= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1); +--echo Last_SQL_Errno = $errno + + +--echo # +--echo # Clean up +--connection slave +source include/stop_slave.inc; +--eval SET @@GLOBAL.replicate_wild_ignore_table="$old_filter" +source include/start_slave.inc; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_filter_set_var_missing_data.test b/mysql-test/suite/rpl/t/rpl_filter_set_var_missing_data.test new file mode 100644 index 00000000..25efb6ed --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_filter_set_var_missing_data.test @@ -0,0 +1,83 @@ +# +# Purpose: +# This test ensures that the SET DEFAULT ROLE and SET PASSWORD commands can +# be ignored by replica filter rules. MDEV-28294 exposed a bug in which +# SET DEFAULT ROLE would check for the existence of the given roles/user even +# when the targeted tables are ignored, resulting in errors if the targeted +# data does not exist. More specifically, when previously issued +# CREATE USER/ROLE commands are ignored by the replica because of the +# replication filtering rules, SET DEFAULT ROLE would result in an error +# because the targeted data does not exist. +# +# Methodology: +# Using a replica configured with replicate_wild_ignore_table="mysql.%", +# execute SET DEFAULT ROLE and SET PASSWORD on the primary and ensure that the +# replica neither errors nor executes the commands which the primary sends. +# +# References: +# MDEV-28294: set default role bypasses Replicate_Wild_Ignore_Table: mysql.% +# + +source include/master-slave.inc; +source include/have_binlog_format_mixed.inc; + +--echo # +--echo # Set replica to ignore system mysql tables +connection slave; +let $old_filter= query_get_value(SHOW SLAVE STATUS, Replicate_Wild_Ignore_Table, 1); +source include/stop_slave.inc; +SET @@GLOBAL.replicate_wild_ignore_table="mysql.%"; +source include/start_slave.inc; + +--echo # +--echo # Execute grant-based commands on primary which modify mysql system +--echo # tables +connection master; +CREATE ROLE journalist; +CREATE USER testuser@localhost IDENTIFIED by ''; +GRANT journalist to testuser@localhost; + +--echo # +--echo # Execute SET commands which use the previous user/role data +SET DEFAULT ROLE journalist for testuser@localhost; +SET PASSWORD for testuser@localhost= PASSWORD('123'); +--source include/save_master_gtid.inc + +--echo # +--echo # Verify primary's grant tables have the correct user/role data +select count(*)=1 from mysql.user where User='testuser'; +select count(*)=1 from mysql.roles_mapping where User='testuser'; + +--echo # +--echo # Ensure that the replica receives all of the primary's events without +--echo # error +connection slave; +--source include/sync_with_master_gtid.inc +let $error= query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1); +--echo Last_SQL_Error = $error +let $errno= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1); +--echo Last_SQL_Errno = $errno + +--echo # +--echo # Verify that the replica did not execute the master's commands +select count(*)=0 from mysql.user where User='testuser'; +select count(*)=0 from mysql.roles_mapping where User='testuser'; + +--echo # +--echo # Clean up + +# The master has to drop the role/user combination while the slave still has +# its filters active; otherwise, the slave would try to drop users/roles that +# were never replicated. +--connection master +DROP ROLE journalist; +DROP USER testuser@localhost; +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc +source include/stop_slave.inc; +--eval SET @@GLOBAL.replicate_wild_ignore_table="$old_filter" +source include/start_slave.inc; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_filter_tables_dynamic.test b/mysql-test/suite/rpl/t/rpl_filter_tables_dynamic.test new file mode 100644 index 00000000..529613b3 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_filter_tables_dynamic.test @@ -0,0 +1,217 @@ +# Test evaluation of replication table filter rules +# +# ==== Purpose ==== +# +# Test if dynamic replication table filter rules are properly evaluated +# when some of the tables referenced by the multiple-table update do not +# exist on slave. +# +# ==== Method ==== +# +# Master creates tables t1, t2, t3, t4, t5, t6, t7, t8, t9 and the +# slave is started with the following replication table filter rules: +# +# SET @@GLOBAL.replicate_do_table="test.t1,test.t2,test.t3"; +# +# and +# +# SET @@GLOBAL.replicate_ignore_table="test.t4,test.t5,test.t6"; +# +# So the slave only replicate changes to tables t1, t2 and t3 and only +# these tables exist on slave. +# +# From now on, tables t1, t2, and t3 are referenced as do tables, +# tables t4, t5, t6 are referenced as ignore tables, and tables t7, +# t8, t9 are referenced as other tables. +# +# All multi-table update tests reference tables that are not do +# tables, which do not exist on slave. And the following situations +# of multi-table update will be tested: +# +# 1. Do tables are not referenced at all +# 2. Do tables are not referenced for update +# 3. Ignore tables are referenced for update before do tables +# 4. Only do tables are referenced for update +# 5. Do tables and other tables are referenced for update +# 6. Do tables are referenced for update before ignore tables +# +# For 1, 2 and 3, the statement should be ignored by slave, for 4, 5 +# and 6 the statement should be accepted by slave and cause an error +# because of non-exist tables. +# + +source include/have_binlog_format_statement.inc; +source include/master-slave.inc; + +connection slave; +--error ER_SLAVE_MUST_STOP +SET @@GLOBAL.replicate_do_table="test.t1,test.t2,test.t3"; +--error ER_SLAVE_MUST_STOP +SET @@GLOBAL.replicate_ignore_table="test.t4,test.t5,test.t6"; + +connection slave; +source include/stop_slave.inc; +SET @@GLOBAL.replicate_do_table=""; +SET @@GLOBAL.replicate_ignore_table=""; +SET @@GLOBAL.replicate_do_table="test.t1,test.t2,test.t3"; +SET @@GLOBAL.replicate_ignore_table="test.t4,test.t5,test.t6"; +source include/start_slave.inc; +connection master; + +# These tables are mentioned in do-table rules +CREATE TABLE t1 (id int, a int); +CREATE TABLE t2 (id int, b int); +CREATE TABLE t3 (id int, c int); + +# These tables are mentioned in ignore-table rules +CREATE TABLE t4 (id int, d int); +CREATE TABLE t5 (id int, e int); +CREATE TABLE t6 (id int, f int); + +# These tables are not mentioned in do-table or ignore-table rules +CREATE TABLE t7 (id int, g int); +CREATE TABLE t8 (id int, h int); +CREATE TABLE t9 (id int, i int); + +INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3); +INSERT INTO t2 VALUES (1, 1), (2, 2), (3, 3); +INSERT INTO t3 VALUES (1, 1), (2, 2), (3, 3); + +INSERT INTO t4 VALUES (1, 1), (2, 2), (3, 3); +INSERT INTO t5 VALUES (1, 1), (2, 2), (3, 3); +INSERT INTO t6 VALUES (1, 1), (2, 2), (3, 3); + +INSERT INTO t7 VALUES (1, 1), (2, 2), (3, 3); +INSERT INTO t8 VALUES (1, 1), (2, 2), (3, 3); +INSERT INTO t9 VALUES (1, 1), (2, 2), (3, 3); + +# Only t1, t2, t3 should be replicated to slave +sync_slave_with_master; +SHOW TABLES LIKE 't%'; + +connection master; + +# +# Do tables are not referenced, these statements should be ignored by +# slave. +# +UPDATE t7 LEFT JOIN t4 ON (t4.id=t7.id) SET d=0, g=0 where t7.id=1; +UPDATE t7 LEFT JOIN (t4, t5, t6) ON (t7.id=t4.id and t7.id=t5.id and t7.id=t6.id) SET d=0, e=0, f=0, g=0 where t7.id=1; +UPDATE t4 LEFT JOIN (t7, t8, t9) ON (t4.id=t7.id and t4.id=t8.id and t4.id=t9.id) SET d=0, g=0, h=0, i=0 where t4.id=1; +UPDATE t7 LEFT JOIN (t8, t9) ON (t7.id=t8.id and t7.id=t9.id) SET g=0, h=0, i=0 where t7.id=1; + +# +# Do tables are not referenced for update, these statements should be +# ignored by slave. +# +UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET d=0 where t1.id=1; +UPDATE t1 LEFT JOIN t7 ON (t1.id=t7.id) SET g=0 where t1.id=1; +UPDATE t1 LEFT JOIN (t4, t5, t6) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t6.id) SET d=0, e=0, f=0 where t1.id=1; +UPDATE t1 LEFT JOIN (t4, t5, t8) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t8.id) SET d=0, e=0, h=0 where t1.id=1; +UPDATE t1 LEFT JOIN (t7, t8, t5) ON (t1.id=t7.id and t1.id=t8.id and t1.id=t5.id) SET g=0, h=0, e=0 where t1.id=1; +UPDATE t1 LEFT JOIN (t2, t3, t5) ON (t1.id=t2.id and t1.id=t3.id and t1.id=t5.id) SET e=0 where t1.id=1; + +# +# Ignore tables are referenced for update before do tables, these +# statements should be ignore by slave. +# +UPDATE t4 LEFT JOIN t1 ON (t1.id=t4.id) SET a=0, d=0 where t4.id=1; +UPDATE t4 LEFT JOIN (t1, t7) ON (t4.id=t1.id and t7.id=t4.id) SET a = 0, d=0, g=0 where t4.id=1; +UPDATE t4 LEFT JOIN (t1, t2, t3) ON (t1.id=t4.id and t2.id=t4.id and t3.id=t4.id) SET a=0, b=0, c=0, d=0 where t4.id=1; +UPDATE t4 LEFT JOIN (t1, t2, t5) ON (t1.id=t4.id and t2.id=t4.id and t5.id=t4.id) SET a=0, b=0, e=0, d=0 where t4.id=1; +UPDATE t4 LEFT JOIN (t1, t6, t7) ON (t4.id=t1.id and t4.id=t6.id and t4.id=t7.id) SET a=0, d=0, f=0, g=0 where t4.id=1; +UPDATE t7 LEFT JOIN (t4, t1, t2) ON (t7.id=t4.id and t7.id=t1.id and t7.id=t2.id) SET a=0, b=0, d=0, g=0 where t7.id=1; +UPDATE t7 LEFT JOIN (t8, t4, t1) ON (t7.id=t8.id and t7.id=t4.id and t7.id=t1.id) SET a=0, d=0, g=0, h=0 where t7.id=1; + +# Sync slave to make sure all above statements are correctly ignored, +# if any of the above statement are not ignored, it would cause error +# and stop slave sql thread. +sync_slave_with_master; +connection slave; +call mtr.add_suppression("Slave SQL.*Error .Table .test.t[47]. doesn.t exist. on query.* error.* 1146"); +connection master; + +# Parameters for include/wait_for_slave_sql_error_and_skip.inc: +# Ask it to show SQL error message. +let $show_slave_sql_error= 1; +# The expected error will always be 1146 (ER_NO_SUCH_TABLE). +let $slave_sql_errno= 1146; + +# +# Only do tables are referenced for update, these statements should +# cause error on slave +# +UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET a=0 where t1.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t1 LEFT JOIN (t4, t7) ON (t1.id=t4.id and t1.id=t7.id) SET a=0 where t1.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t1 LEFT JOIN (t2, t4, t7) ON (t1.id=t2.id and t1.id=t4.id and t1.id=t7.id) SET a=0, b=0 where t1.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t1 LEFT JOIN (t2, t3, t7) ON (t1.id=t2.id and t1.id=t3.id and t1.id=t7.id) SET a=0, b=0, c=0 where t1.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +# +# Do tables and other tables are referenced for update, these +# statements should cause error on slave +# +UPDATE t1 LEFT JOIN t7 ON (t1.id=t7.id) SET a=0, g=0 where t1.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t7 LEFT JOIN t1 ON (t1.id=t7.id) SET a=0, g=0 where t7.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t1 LEFT JOIN (t4, t5, t7) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t7.id) SET a=0, g=0 where t1.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t1 LEFT JOIN (t4, t7, t8) ON (t1.id=t4.id and t1.id=t7.id and t1.id=t8.id) SET a=0, g=0 where t1.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t1 LEFT JOIN (t7, t8, t9) ON (t1.id=t7.id and t1.id=t8.id and t1.id=t9.id) SET a=0, g=0, h=0, i=0 where t1.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t7 LEFT JOIN (t1, t2, t3) ON (t7.id=t1.id and t7.id=t2.id and t7.id=t3.id) SET g=0, a=0, b=0, c=0 where t7.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t7 LEFT JOIN (t4, t5, t3) ON (t7.id=t4.id and t7.id=t5.id and t7.id=t3.id) SET g=0, c=0 where t7.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t7 LEFT JOIN (t8, t9, t3) ON (t7.id=t8.id and t7.id=t9.id and t7.id=t3.id) SET g=0, h=0, i=0, c=0 where t7.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +# +# Do tables are referenced for update before ignore tables +# +UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET a=0, d=0 where t1.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t1 LEFT JOIN (t4, t5, t6) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t6.id) SET a=0, d=0, e=0, f=0 where t1.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t4 LEFT JOIN (t1, t5, t6) ON (t4.id=t1.id and t4.id=t5.id and t4.id=t6.id) SET a=0, e=0, f=0 where t4.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t7 LEFT JOIN (t1, t4, t2) ON (t7.id=t1.id and t7.id=t4.id and t7.id=t2.id) SET a=0, b=0, d=0, g=0 where t7.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +sync_slave_with_master; +echo [on slave]; + +# We should only have tables t1, t2, t3 on slave +show tables like 't%'; + +# The rows in these tables should remain untouched +SELECT * FROM t1; +SELECT * FROM t2; +SELECT * FROM t3; + +# Clean up +connection master; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +--source include/rpl_end.inc + +connection slave; +SET @@GLOBAL.replicate_do_table=""; +SET @@GLOBAL.replicate_ignore_table=""; diff --git a/mysql-test/suite/rpl/t/rpl_filter_tables_not_exist-slave.opt b/mysql-test/suite/rpl/t/rpl_filter_tables_not_exist-slave.opt new file mode 100644 index 00000000..42acd3ea --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_filter_tables_not_exist-slave.opt @@ -0,0 +1 @@ +--replicate-do-table=test.t1 --replicate-do-table=test.t2 --replicate-do-table=test.t3 --replicate-ignore-table=test.t4 --replicate-ignore-table=test.t5 --replicate-ignore-table=test.t6 diff --git a/mysql-test/suite/rpl/t/rpl_filter_tables_not_exist.test b/mysql-test/suite/rpl/t/rpl_filter_tables_not_exist.test new file mode 100644 index 00000000..ee6daac7 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_filter_tables_not_exist.test @@ -0,0 +1,267 @@ +# Test evaluation of replication table filter rules +# +# ==== Purpose ==== +# +# Test if replication table filter rules are properly evaluated when +# some of the tables referenced by the multiple-table update do not +# exist on slave. +# +# ==== Method ==== +# +# Master creates tables t1, t2, t3, t4, t5, t6, t7, t8, t9 and the +# slave is started with the following replication table filter rules: +# +# --replicate-do-table=t1 +# --replicate-do-table=t2 +# --replicate-do-table=t3 +# +# and +# +# --replicate-ignore-table=t4 +# --replicate-ignore-table=t5 +# --replicate-ignore-table=t6 +# +# So the slave only replicate changes to tables t1, t2 and t3 and only +# these tables exist on slave. +# +# From now on, tables t1, t2, and t3 are referenced as do tables, +# tables t4, t5, t6 are referenced as ignore tables, and tables t7, +# t8, t9 are referenced as other tables. +# +# All multi-table update tests reference tables that are not do +# tables, which do not exist on slave. And the following situations +# of multi-table update will be tested: +# +# 1. Do tables are not referenced at all +# 2. Do tables are not referenced for update +# 3. Ignore tables are referenced for update before do tables +# 4. Only do tables are referenced for update +# 5. Do tables and other tables are referenced for update +# 6. Do tables are referenced for update before ignore tables +# +# For 1, 2 and 3, the statement should be ignored by slave, for 4, 5 +# and 6 the statement should be accepted by slave and cause an error +# because of non-exist tables. +# +# ==== Related bugs ==== +# +# BUG#37051 Replication rules not evaluated correctly + + +source include/have_binlog_format_statement.inc; +source include/master-slave.inc; + +# These tables are mentioned in do-table rules +CREATE TABLE t1 (id int, a int); +CREATE TABLE t2 (id int, b int); +CREATE TABLE t3 (id int, c int); + +# These tables are mentioned in ignore-table rules +CREATE TABLE t4 (id int, d int); +CREATE TABLE t5 (id int, e int); +CREATE TABLE t6 (id int, f int); + +# These tables are not mentioned in do-table or ignore-table rules +CREATE TABLE t7 (id int, g int); +CREATE TABLE t8 (id int, h int); +CREATE TABLE t9 (id int, i int); + +INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3); +INSERT INTO t2 VALUES (1, 1), (2, 2), (3, 3); +INSERT INTO t3 VALUES (1, 1), (2, 2), (3, 3); + +INSERT INTO t4 VALUES (1, 1), (2, 2), (3, 3); +INSERT INTO t5 VALUES (1, 1), (2, 2), (3, 3); +INSERT INTO t6 VALUES (1, 1), (2, 2), (3, 3); + +INSERT INTO t7 VALUES (1, 1), (2, 2), (3, 3); +INSERT INTO t8 VALUES (1, 1), (2, 2), (3, 3); +INSERT INTO t9 VALUES (1, 1), (2, 2), (3, 3); + +# Only t1, t2, t3 should be replicated to slave +sync_slave_with_master; +SHOW TABLES LIKE 't%'; + +connection master; + +# +# Do tables are not referenced, these statements should be ignored by +# slave. +# +UPDATE t7 LEFT JOIN t4 ON (t4.id=t7.id) SET d=0, g=0 where t7.id=1; +UPDATE t7 LEFT JOIN (t4, t5, t6) ON (t7.id=t4.id and t7.id=t5.id and t7.id=t6.id) SET d=0, e=0, f=0, g=0 where t7.id=1; +UPDATE t4 LEFT JOIN (t7, t8, t9) ON (t4.id=t7.id and t4.id=t8.id and t4.id=t9.id) SET d=0, g=0, h=0, i=0 where t4.id=1; +UPDATE t7 LEFT JOIN (t8, t9) ON (t7.id=t8.id and t7.id=t9.id) SET g=0, h=0, i=0 where t7.id=1; + +# +# Do tables are not referenced for update, these statements should be +# ignored by slave. +# +UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET d=0 where t1.id=1; +UPDATE t1 LEFT JOIN t7 ON (t1.id=t7.id) SET g=0 where t1.id=1; +UPDATE t1 LEFT JOIN (t4, t5, t6) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t6.id) SET d=0, e=0, f=0 where t1.id=1; +UPDATE t1 LEFT JOIN (t4, t5, t8) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t8.id) SET d=0, e=0, h=0 where t1.id=1; +UPDATE t1 LEFT JOIN (t7, t8, t5) ON (t1.id=t7.id and t1.id=t8.id and t1.id=t5.id) SET g=0, h=0, e=0 where t1.id=1; +UPDATE t1 LEFT JOIN (t2, t3, t5) ON (t1.id=t2.id and t1.id=t3.id and t1.id=t5.id) SET e=0 where t1.id=1; + +# +# Ignore tables are referenced for update before do tables, these +# statements should be ignore by slave. +# +UPDATE t4 LEFT JOIN t1 ON (t1.id=t4.id) SET a=0, d=0 where t4.id=1; +UPDATE t4 LEFT JOIN (t1, t7) ON (t4.id=t1.id and t7.id=t4.id) SET a = 0, d=0, g=0 where t4.id=1; +UPDATE t4 LEFT JOIN (t1, t2, t3) ON (t1.id=t4.id and t2.id=t4.id and t3.id=t4.id) SET a=0, b=0, c=0, d=0 where t4.id=1; +UPDATE t4 LEFT JOIN (t1, t2, t5) ON (t1.id=t4.id and t2.id=t4.id and t5.id=t4.id) SET a=0, b=0, e=0, d=0 where t4.id=1; +UPDATE t4 LEFT JOIN (t1, t6, t7) ON (t4.id=t1.id and t4.id=t6.id and t4.id=t7.id) SET a=0, d=0, f=0, g=0 where t4.id=1; +UPDATE t7 LEFT JOIN (t4, t1, t2) ON (t7.id=t4.id and t7.id=t1.id and t7.id=t2.id) SET a=0, b=0, d=0, g=0 where t7.id=1; +UPDATE t7 LEFT JOIN (t8, t4, t1) ON (t7.id=t8.id and t7.id=t4.id and t7.id=t1.id) SET a=0, d=0, g=0, h=0 where t7.id=1; + +# Sync slave to make sure all above statements are correctly ignored, +# if any of the above statement are not ignored, it would cause error +# and stop slave sql thread. +sync_slave_with_master; +connection slave; +call mtr.add_suppression("Slave SQL.*Error .Table .test.t[47]. doesn.t exist. on query.* error.* 1146"); +connection master; + +# Parameters for include/wait_for_slave_sql_error_and_skip.inc: +# Ask it to show SQL error message. +let $show_slave_sql_error= 1; +# The expected error will always be 1146 (ER_NO_SUCH_TABLE). +let $slave_sql_errno= 1146; + +# +# Only do tables are referenced for update, these statements should +# cause error on slave +# +UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET a=0 where t1.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t1 LEFT JOIN (t4, t7) ON (t1.id=t4.id and t1.id=t7.id) SET a=0 where t1.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t1 LEFT JOIN (t2, t4, t7) ON (t1.id=t2.id and t1.id=t4.id and t1.id=t7.id) SET a=0, b=0 where t1.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t1 LEFT JOIN (t2, t3, t7) ON (t1.id=t2.id and t1.id=t3.id and t1.id=t7.id) SET a=0, b=0, c=0 where t1.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +# +# Do tables and other tables are referenced for update, these +# statements should cause error on slave +# +UPDATE t1 LEFT JOIN t7 ON (t1.id=t7.id) SET a=0, g=0 where t1.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t7 LEFT JOIN t1 ON (t1.id=t7.id) SET a=0, g=0 where t7.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t1 LEFT JOIN (t4, t5, t7) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t7.id) SET a=0, g=0 where t1.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t1 LEFT JOIN (t4, t7, t8) ON (t1.id=t4.id and t1.id=t7.id and t1.id=t8.id) SET a=0, g=0 where t1.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t1 LEFT JOIN (t7, t8, t9) ON (t1.id=t7.id and t1.id=t8.id and t1.id=t9.id) SET a=0, g=0, h=0, i=0 where t1.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t7 LEFT JOIN (t1, t2, t3) ON (t7.id=t1.id and t7.id=t2.id and t7.id=t3.id) SET g=0, a=0, b=0, c=0 where t7.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t7 LEFT JOIN (t4, t5, t3) ON (t7.id=t4.id and t7.id=t5.id and t7.id=t3.id) SET g=0, c=0 where t7.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t7 LEFT JOIN (t8, t9, t3) ON (t7.id=t8.id and t7.id=t9.id and t7.id=t3.id) SET g=0, h=0, i=0, c=0 where t7.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +# +# Do tables are referenced for update before ignore tables +# +UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET a=0, d=0 where t1.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t1 LEFT JOIN (t4, t5, t6) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t6.id) SET a=0, d=0, e=0, f=0 where t1.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t4 LEFT JOIN (t1, t5, t6) ON (t4.id=t1.id and t4.id=t5.id and t4.id=t6.id) SET a=0, e=0, f=0 where t4.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +UPDATE t7 LEFT JOIN (t1, t4, t2) ON (t7.id=t1.id and t7.id=t4.id and t7.id=t2.id) SET a=0, b=0, d=0, g=0 where t7.id=1; +source include/wait_for_slave_sql_error_and_skip.inc; + +sync_slave_with_master; +echo [on slave]; + +# We should only have tables t1, t2, t3 on slave +show tables like 't%'; + +# The rows in these tables should remain untouched +SELECT * FROM t1; +SELECT * FROM t2; +SELECT * FROM t3; + +# Clean up +connection master; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; + +--sync_slave_with_master + +# +# BUG#11754117 - 45670: INTVAR_EVENTS FOR FILTERED-OUT QUERY_LOG_EVENTS ARE EXECUTED +# Int-, Rand- and User- var events accompaning a filtered out Query-log-event should +# be filtered as well. +# +connection master; +# Although RAND() is from 0 to 1.0, DECIMAL(M,D), requires that M must be >= D. +CREATE TABLE test.t5 (a INT AUTO_INCREMENT PRIMARY KEY, b DECIMAL(20,20), c INT); # ignored on slave +CREATE TABLE test.t1 (a INT); # accepted on slave +INSERT INTO test.t1 VALUES(1); + +--sync_slave_with_master +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); +# Although RAND() is from 0 to 1.0, DECIMAL(M,D), requires that M must be >= D. +CREATE TABLE test.t_slave (a INT AUTO_INCREMENT PRIMARY KEY, b DECIMAL(20,20), c INT); +CREATE TRIGGER t1_update AFTER UPDATE ON test.t1 FOR EACH ROW + INSERT INTO test.t_slave VALUES(NULL, RAND(), @c); + +connection master; +SET INSERT_ID=2; +SET @c=2; +SET @@rand_seed1=10000000, @@rand_seed2=1000000; +INSERT INTO t5 VALUES (NULL, RAND(), @c); # to be ignored +SELECT b into @b FROM test.t5; +--let $b_master=`select @b` +UPDATE test.t1 SET a=2; # to run trigger on slave + +--sync_slave_with_master + +# The proof: +SELECT a AS 'ONE' into @a FROM test.t_slave; +SELECT c AS 'NULL' into @c FROM test.t_slave; + +let $count= 1; +let $table= test.t_slave; +source include/wait_until_rows_count.inc; + +if (`SELECT @a != 2 and @c != NULL`) +{ + SELECT * FROM test.t_slave; + --die Intvar or user var from replication events unexpetedly escaped out to screw a following query applying context. +} + +SELECT b into @b FROM test.t_slave; +--let $b_slave=`select @b` + +--let $assert_text= Random values from master and slave must be different +--let $assert_cond= $b_master != $b_slave +--source include/assert.inc + +# cleanup BUG#11754117 +connection master; +drop table test.t5; +drop table test.t1; + +--sync_slave_with_master +drop table test.t_slave; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_filter_wild_tables_dynamic.test b/mysql-test/suite/rpl/t/rpl_filter_wild_tables_dynamic.test new file mode 100644 index 00000000..657a95ce --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_filter_wild_tables_dynamic.test @@ -0,0 +1,49 @@ +# +# Test if dynamic replication wild table filter rules are properly evaluated. +# + +source include/have_binlog_format_statement.inc; +source include/master-slave.inc; + +connection slave; +--error ER_SLAVE_MUST_STOP +SET @@GLOBAL.replicate_wild_do_table="test.a%"; +--error ER_SLAVE_MUST_STOP +SET @@GLOBAL.replicate_wild_ignore_table="test.b%"; + +connection slave; +source include/stop_slave.inc; +SET @@GLOBAL.replicate_wild_do_table=""; +SET @@GLOBAL.replicate_wild_ignore_table=""; +SET @@GLOBAL.replicate_wild_do_table="test.a%"; +SET @@GLOBAL.replicate_wild_ignore_table="test.b%"; +source include/start_slave.inc; +connection master; + +# Table is mentioned in wild-do-table rules +CREATE TABLE a1 (a INT); + +# Table is mentioned in wild-ignore-table rules +CREATE TABLE b1 (a INT); + +# Table is not mentioned in wild-do-table or wild-ignore-table rules +CREATE TABLE c1 (a INT); + +INSERT INTO a1 VALUES (1); +INSERT INTO b1 VALUES (2); +INSERT INTO c1 VALUES (3); + +# Only a1 should be replicated to slave +sync_slave_with_master; +SHOW TABLES LIKE '%1'; + +connection master; + +# Clean up +connection master; +DROP TABLE IF EXISTS a1,b1,c1; +--source include/rpl_end.inc + +connection slave; +SET @@GLOBAL.replicate_wild_do_table=""; +SET @@GLOBAL.replicate_wild_ignore_table=""; diff --git a/mysql-test/suite/rpl/t/rpl_flush_logs-master.opt b/mysql-test/suite/rpl/t/rpl_flush_logs-master.opt new file mode 100644 index 00000000..36eab1d6 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_flush_logs-master.opt @@ -0,0 +1 @@ +--log-error=$MYSQLTEST_VARDIR/tmp/master_log.err diff --git a/mysql-test/suite/rpl/t/rpl_flush_logs.test b/mysql-test/suite/rpl/t/rpl_flush_logs.test new file mode 100644 index 00000000..6dad588f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_flush_logs.test @@ -0,0 +1,141 @@ +# +# WL#5124 +# This test verifies if the 'flush individual logs' statement +# works fine. +# + +--source include/have_binlog_format_statement.inc +--source include/master-slave.inc +connection master; + +# Test 'flush error logs' statement. + +--echo # Test if support 'flush error logs' statement. +flush error logs; + +file_exists $MYSQLTEST_VARDIR/tmp/master_log.err; + +--echo # Make sure binary logs was not be flushed +--echo # after execute 'flush error logs' statement. +--error 1 +file_exists $MYSQLTEST_VARDIR/mysqld.1/data/master-bin.000002; + +sync_slave_with_master; +--echo # Make sure relay logs was not be flushed +--echo # after execute 'flush error logs' statement. +--error 1 +file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000003; + +connection master; +--echo # Test if support 'flush relay logs' statement. +flush relay logs; + +sync_slave_with_master; +--echo # Check the 'slave-relay-bin.000003' file is not created +--echo # after executed 'flush relay logs' statement. +--error 1 +file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000003; + +connection master; +--echo # Make sure binary logs was not be flushed +--echo # after execute 'flush relay logs' statement. +--error 1 +file_exists $MYSQLTEST_VARDIR/mysqld.1/data/master-bin.000002; + + +# Test 'flush slow logs' statement. +--echo # Test if support 'flush slow logs' statement. +flush slow logs; + +--echo # Make sure binary logs was not be flushed +--echo # after execute 'flush slow logs' statement. +--error 1 +file_exists $MYSQLTEST_VARDIR/mysqld.1/data/master-bin.000002; + + +# Test 'flush general logs' statement. +--echo # Test if support 'flush general logs' statement. +flush general logs; + +--echo # Make sure binary logs was not be flushed +--echo # after execute 'flush general logs' statement. +--error 1 +file_exists $MYSQLTEST_VARDIR/mysqld.1/data/master-bin.000002; + + +# Test 'flush engine logs' statement. +--echo # Test if support 'flush engine logs' statement. +flush engine logs; + +--echo # Make sure binary logs was not be flushed +--echo # after execute 'flush engine logs' statement. +--error 1 +file_exists $MYSQLTEST_VARDIR/mysqld.1/data/master-bin.000002; + + +# Test 'flush binary logs' statement. +--echo # Make sure the 'master-bin.000002' file does not +--echo # exist before execute 'flush binary logs' statement. +--error 1 +file_exists $MYSQLTEST_VARDIR/mysqld.1/data/master-bin.000002; + +--echo # Test if support 'flush binary logs' statement. +flush binary logs; + +--echo # Check the 'master-bin.000002' file is created +--echo # after executed 'flush binary logs' statement. +file_exists $MYSQLTEST_VARDIR/mysqld.1/data/master-bin.000002; +file_exists $MYSQLTEST_VARDIR/mysqld.1/data/master-bin.000001; + + +# Test 'flush error logs, relay logs' statement +sync_slave_with_master; +--echo # Make sure the 'slave-relay-bin.000005' file does not exist +--echo # exist before execute 'flush error logs, relay logs' statement. +--error 1 +file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000005; + +connection master; + +--echo # Test if support to combine all kinds of logs into one statement. +flush error logs, relay logs; + +file_exists $MYSQLTEST_VARDIR/tmp/master_log.err; + +--echo # Make sure binary logs was not be flushed +--echo # after execute 'flush error logs, relay logs' statement. +--error 1 +file_exists $MYSQLTEST_VARDIR/mysqld.1/data/master-bin.000003; + +sync_slave_with_master; +--echo # Check the 'slave-relay-bin.000004' file is created after +--echo # execute 'flush error logs, relay logs' statement. +file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000004; + +# Test 'flush logs' statement +--echo # Make sure the 'slave-relay-bin.000005' and 'slave-relay-bin.000006' +--echo # files do not exist before execute 'flush error logs, relay logs' +--echo # statement. +--error 1 +file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000005; +--error 1 +file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000006; + +connection master; + +--echo # Test if 'flush logs' statement works fine and flush all the logs. +flush logs; + +file_exists $MYSQLTEST_VARDIR/tmp/master_log.err; + +--echo # Check 'master-bin.000003' is created +--echo # after execute 'flush logs' statement. +file_exists $MYSQLTEST_VARDIR/mysqld.1/data/master-bin.000003; + +sync_slave_with_master; +--echo # Check the 'slave-relay-bin.000005' and 'slave-relay-bin.000006' +--echo # files are created after execute 'flush logs' statement. +file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000005; +file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000006; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_flushlog_loop-master.opt b/mysql-test/suite/rpl/t/rpl_flushlog_loop-master.opt new file mode 100644 index 00000000..3b5d41d4 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_flushlog_loop-master.opt @@ -0,0 +1 @@ +--max_binlog_size=1M diff --git a/mysql-test/suite/rpl/t/rpl_flushlog_loop-slave.opt b/mysql-test/suite/rpl/t/rpl_flushlog_loop-slave.opt new file mode 100644 index 00000000..3b5d41d4 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_flushlog_loop-slave.opt @@ -0,0 +1 @@ +--max_binlog_size=1M diff --git a/mysql-test/suite/rpl/t/rpl_flushlog_loop.test b/mysql-test/suite/rpl/t/rpl_flushlog_loop.test new file mode 100644 index 00000000..d5d362ba --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_flushlog_loop.test @@ -0,0 +1,46 @@ +# Testing if "flush logs" command bouncing resulting in logs created in a loop +# in case of bi-directional replication +--let $rpl_topology= 1->2->1 +--source include/rpl_init.inc + +let $MYSQLD_DATADIR= `select @@datadir`; +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR/ +show variables like 'relay_log%'; + +# +# Flush logs of slave +# +# Create full loop by following way: +# 1. Insert into t1 on master (1st). +# 2. Insert into t1 on slave (2nd) when the event (1st) for t1 replicated. +# 3. Master waits until the event (2nd) for t1 will be replicated. + +CREATE TABLE t1 (a INT KEY) ENGINE= MyISAM; +let $wait_binlog_event= CREATE TABLE t1; +--source include/wait_for_binlog_event.inc +sync_slave_with_master server_2; + +connection server_1; +INSERT INTO t1 VALUE(1); +FLUSH LOGS; +sync_slave_with_master server_2; + +INSERT INTO t1 VALUE(2); +let $slave_param_value= query_get_value(SHOW MASTER STATUS, Position, 1); +sync_slave_with_master server_1; + +# +# Check that the master server's slave threads are still running and show +# Relay_Log_File +# +--source include/check_slave_is_running.inc +--let status_items= Relay_Log_File +--source include/show_slave_status.inc + +--disable_query_log +connection server_1; +DROP TABLE t1; +sync_slave_with_master server_2; +--enable_query_log + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_foreign_key_innodb.test b/mysql-test/suite/rpl/t/rpl_foreign_key_innodb.test new file mode 100644 index 00000000..2c4af75e --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_foreign_key_innodb.test @@ -0,0 +1,78 @@ +-- source include/have_innodb.inc + +# Check the replication of the FOREIGN_KEY_CHECKS variable. + +-- source include/master-slave.inc + +CREATE TABLE t1 (a INT AUTO_INCREMENT KEY) ENGINE=INNODB; +CREATE TABLE t2 (b INT AUTO_INCREMENT KEY, c INT, FOREIGN KEY(b) REFERENCES t1(a)) ENGINE=INNODB; + +SET FOREIGN_KEY_CHECKS=0; +INSERT INTO t1 VALUES (10); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL); +INSERT INTO t2 VALUES (5,0); +INSERT INTO t2 VALUES (NULL,LAST_INSERT_ID()); +SET FOREIGN_KEY_CHECKS=1; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY b; +sync_slave_with_master; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY b; + +connection master; +SET TIMESTAMP=1000000000; +CREATE TABLE t3 ( a INT UNIQUE ); +SET FOREIGN_KEY_CHECKS=0; +--error ER_DUP_ENTRY +INSERT INTO t3 VALUES (1),(1); +sync_slave_with_master; + +connection master; +SET FOREIGN_KEY_CHECKS=0; +DROP TABLE IF EXISTS t1,t2,t3; +SET FOREIGN_KEY_CHECKS=1; +sync_slave_with_master; + +# +# Bug #32468 delete rows event on a table with foreign key constraint fails +# + +connection master; + +create table t1 (b int primary key) engine = INNODB; +create table t2 (a int primary key, b int, foreign key (b) references t1(b)) engine = INNODB; + +insert into t1 set b=1; +insert into t2 set a=1, b=1; + +set foreign_key_checks=0; +delete from t1; + +--echo must sync w/o a problem (could not with the buggy code) +sync_slave_with_master; +select count(*) from t1 /* must be zero */; + + +# cleanup for bug#32468 + +connection master; +drop table t2,t1; +set foreign_key_checks=1; + +--echo # +--echo # MDEV-25530 Error 1451 on slave: Cannot delete or update a parent row: a foreign key constraint fails +--echo # + +create table t1 (id int primary key)engine=innodb; +create table t2 (id int not null primary key auto_increment, + id2 int default null, key f1 (id2), + constraint f1 foreign key (id2) references t1 (id) on delete cascade) engine=innodb; +error ER_ROW_IS_REFERENCED_2; +drop table t1,t2; +sync_slave_with_master; +show tables; +connection master; +drop table t1; +sync_slave_with_master; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_free_items-slave.opt b/mysql-test/suite/rpl/t/rpl_free_items-slave.opt new file mode 100644 index 00000000..b828d03f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_free_items-slave.opt @@ -0,0 +1 @@ +--replicate-wild-ignore-table=test.% diff --git a/mysql-test/suite/rpl/t/rpl_free_items.test b/mysql-test/suite/rpl/t/rpl_free_items.test new file mode 100644 index 00000000..581409cf --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_free_items.test @@ -0,0 +1,23 @@ +source include/master-slave.inc; +create table t1 (a int); +create table t2 (a int); +disable_query_log; +SET @query="INSERT INTO t2 SELECT * FROM t1 WHERE a REGEXP \"0\""; +let $1 = 2000; +while ($1) +{ + eval SET @query=concat(@query, " OR a REGEXP '$1'"); + dec $1; +} +let $1=`select @query`; +eval $1; +enable_query_log; +# I have seen the slave crash either now or at shutdown +sync_slave_with_master; +connection master; +drop table t1; +drop table t2; +sync_slave_with_master; + +# End of 4.1 tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_function_defaults.test b/mysql-test/suite/rpl/t/rpl_function_defaults.test new file mode 100644 index 00000000..f2413299 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_function_defaults.test @@ -0,0 +1,86 @@ +--echo # +--echo # Test of function defaults on replicated tables. +--echo # + +source include/master-slave.inc; + +connection master; +SET TIME_ZONE="+10:30"; +SET TIMESTAMP=123456.789123; +SELECT CURRENT_TIMESTAMP; + +connection slave; +SET TIME_ZONE="+00:00"; +SET TIMESTAMP=987654321.123456; +SELECT CURRENT_TIMESTAMP; + +connection master; +CREATE TABLE t1 ( + a TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + b TIMESTAMP(1) NOT NULL DEFAULT CURRENT_TIMESTAMP(1), + c TIMESTAMP(2) NOT NULL DEFAULT CURRENT_TIMESTAMP(2), + d TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + e TIMESTAMP(4) NOT NULL DEFAULT CURRENT_TIMESTAMP(4), + f TIMESTAMP(5) NOT NULL DEFAULT CURRENT_TIMESTAMP(5), + g TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), + h DATETIME DEFAULT CURRENT_TIMESTAMP, + i DATETIME(1) DEFAULT CURRENT_TIMESTAMP(1), + j DATETIME(2) DEFAULT CURRENT_TIMESTAMP(2), + k DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3), + l DATETIME(4) DEFAULT CURRENT_TIMESTAMP(4), + m DATETIME(5) DEFAULT CURRENT_TIMESTAMP(5), + n DATETIME(6) DEFAULT CURRENT_TIMESTAMP(6), + o INT +); + +INSERT INTO t1 ( o ) VALUES ( 1 ); + +CREATE TABLE t2 ( + a TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP, + b TIMESTAMP(1) NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP(1), + c TIMESTAMP(2) NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP(2), + d TIMESTAMP(3) NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP(3), + e TIMESTAMP(4) NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP(4), + f TIMESTAMP(5) NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP(5), + g TIMESTAMP(6) NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP(6), + h DATETIME ON UPDATE CURRENT_TIMESTAMP, + i DATETIME(1) ON UPDATE CURRENT_TIMESTAMP(1), + j DATETIME(2) ON UPDATE CURRENT_TIMESTAMP(2), + k DATETIME(3) ON UPDATE CURRENT_TIMESTAMP(3), + l DATETIME(4) ON UPDATE CURRENT_TIMESTAMP(4), + m DATETIME(5) ON UPDATE CURRENT_TIMESTAMP(5), + n DATETIME(6) ON UPDATE CURRENT_TIMESTAMP(6), + o INT +); + +INSERT INTO t2 ( o ) VALUES ( 1 ); + +--echo sync_slave_with_master +sync_slave_with_master; + +connection slave; + +query_vertical SELECT * FROM t1; +query_vertical SELECT * FROM t2; + +connection master; + +SET TIMESTAMP=1234567890.123456; +SELECT CURRENT_TIMESTAMP; + +UPDATE t1 SET o = 2; +UPDATE t2 SET o = 2; + +--echo sync_slave_with_master +sync_slave_with_master; + +connection slave; + +query_vertical SELECT * FROM t1; +query_vertical SELECT * FROM t2; + +connection master; + +DROP TABLE t1, t2; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_geometry.test b/mysql-test/suite/rpl/t/rpl_geometry.test new file mode 100644 index 00000000..415732a0 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_geometry.test @@ -0,0 +1,26 @@ +source include/have_binlog_format_row.inc; +source include/master-slave.inc; + +# +# Bug#48776, Bug#43784 +# +create table t1(a varchar(100), + b multipoint not null, + c varchar(256)); + +insert into t1 set + a='hello', + b=geomfromtext('multipoint(1 1)'), + c='geometry'; + +create table t2 (a int(11) not null auto_increment primary key, + b geometrycollection default null, + c decimal(10,0)); + +insert into t2(c) values (null); + +sync_slave_with_master; + +connection master; +drop table t1, t2; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_get_lock.test b/mysql-test/suite/rpl/t/rpl_get_lock.test new file mode 100644 index 00000000..b5c08858 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_get_lock.test @@ -0,0 +1,47 @@ +source include/master-slave.inc; + +CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); + +create table t1(n int); +# Use of get_lock gives a warning for unsafeness if binlog_format=statement +--disable_warnings +insert into t1 values(get_lock("lock",2)); +--enable_warnings +dirty_close master; +connection master1; +select get_lock("lock",2); + +select release_lock("lock"); +#ignore +disable_query_log; +let $1=2000; +while ($1) +{ + do get_lock("lock",2); + do release_lock("lock"); + dec $1; +} +enable_query_log; +sync_slave_with_master; +select get_lock("lock",3); +select * from t1; +# There is no point in testing REPLICATIION of the IS_*_LOCK +# functions; slave does not run with the same concurrency context as +# master (generally in slave we can't know that on master this lock +# was already held by another connection and so that the the +# get_lock() we're replicating timed out on master hence returned 0, +# or that the is_free_lock() we're playing returned 0 etc. +# But here all we do is test these functions outside of replication. +select is_free_lock("lock"), is_used_lock("lock") = connection_id(); +explain extended select is_free_lock("lock"), is_used_lock("lock"); +# Check lock functions +select is_free_lock("lock2"); +select is_free_lock(NULL); +connection master1; +drop table t1; +sync_slave_with_master; + + +--source include/rpl_end.inc + +# End of 4.1 tests diff --git a/mysql-test/suite/rpl/t/rpl_get_master_version_and_clock-slave.opt b/mysql-test/suite/rpl/t/rpl_get_master_version_and_clock-slave.opt new file mode 100644 index 00000000..f9aa8c03 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_get_master_version_and_clock-slave.opt @@ -0,0 +1 @@ +--master-retry-count=60 diff --git a/mysql-test/suite/rpl/t/rpl_get_master_version_and_clock.test b/mysql-test/suite/rpl/t/rpl_get_master_version_and_clock.test new file mode 100644 index 00000000..e3d049f0 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_get_master_version_and_clock.test @@ -0,0 +1,52 @@ +# +# BUG#45214 +# This test verifies if the slave I/O tread tries to reconnect to +# master when it tries to get the values of the UNIX_TIMESTAMP, SERVER_ID, +# COLLATION_SERVER and TIME_ZONE from master under network disconnection. +# The COLLATION_SERVER and TIME_ZONE are got only on master server version 4. +# So they can't be verified by test case here. +# Finish the following tests by calling its common test script: +# include/rpl_get_master_version_and_clock.test. + +source include/not_valgrind.inc; +source include/have_debug.inc; +source include/have_debug_sync.inc; +source include/master-slave.inc; + +# +# The test is not supposed to have any binglog affairs. +# Hence it's enough it to run only with one binlog format +# +source include/have_binlog_format_mixed.inc; + +connection slave; + +call mtr.add_suppression("Slave I/O: Master command COM_REGISTER_SLAVE failed: .*"); +call mtr.add_suppression("Slave I/O: .* failed with error: Lost connection to server at 'reading initial communication packet'"); +call mtr.add_suppression("Fatal error: The slave I/O thread stops because +master and slave have equal MariaDB server ids; .*"); +call mtr.add_suppression("Slave I/O thread .* register on master"); + +#Test case 1: Try to get the value of the UNIX_TIMESTAMP from master under network disconnection +SET @saved_dbug = @@GLOBAL.debug_dbug; + +# set up two parameters to pass into include/rpl_get_master_version_and_clock +let $dbug_sync_point= 'debug_lock.before_get_UNIX_TIMESTAMP'; +let $debug_sync_action= 'now SIGNAL signal.get_unix_timestamp'; +source include/rpl_get_master_version_and_clock.test; + +#Test case 2: Try to get the value of the SERVER_ID from master under network disconnection +connection slave; + +let $dbug_sync_point= 'debug_lock.before_get_SERVER_ID'; +let $debug_sync_action= 'now SIGNAL signal.get_server_id'; +source include/rpl_get_master_version_and_clock.test; + + +# cleanup +SET @@GLOBAL.debug_dbug = @saved_dbug; +# is not really necessary but avoids mtr post-run env check warnings +SET DEBUG_SYNC= 'RESET'; + +# End of tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_grant.test b/mysql-test/suite/rpl/t/rpl_grant.test new file mode 100644 index 00000000..02206453 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_grant.test @@ -0,0 +1,37 @@ +# Tests of grants and users + +source include/not_embedded.inc; +source include/master-slave.inc; + +connection master; + +CREATE USER dummy@localhost; +CREATE USER dummy1@localhost, dummy2@localhost; + +SELECT user, host FROM mysql.user WHERE user like 'dummy%'; +SELECT COUNT(*) FROM mysql.user WHERE user like 'dummy%'; +sync_slave_with_master; +--echo **** On Slave **** +SELECT user,host FROM mysql.user WHERE user like 'dummy%'; +SELECT COUNT(*) FROM mysql.user WHERE user like 'dummy%'; + +connection master; + +# No user exists +error ER_CANNOT_USER; +DROP USER nonexisting@localhost; + +# At least one user exists, but not all +error ER_CANNOT_USER; +DROP USER nonexisting@localhost, dummy@localhost; + +# All users exist +DROP USER dummy1@localhost, dummy2@localhost; + +SELECT user, host FROM mysql.user WHERE user like 'dummy%'; +SELECT COUNT(*) FROM mysql.user WHERE user like 'dummy%'; +sync_slave_with_master; +SELECT user,host FROM mysql.user WHERE user like 'dummy%'; +SELECT COUNT(*) FROM mysql.user WHERE user like 'dummy%'; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_basic.cnf b/mysql-test/suite/rpl/t/rpl_gtid_basic.cnf new file mode 100644 index 00000000..3ff94e45 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_basic.cnf @@ -0,0 +1,24 @@ +!include ../my.cnf + +[mysqld.1] +log-slave-updates +loose-innodb + +[mysqld.2] +log-slave-updates +loose-innodb + +[mysqld.3] +log-slave-updates +loose-innodb + +[mysqld.4] +log-slave-updates +loose-innodb + +[ENV] +SERVER_MYPORT_3= @mysqld.3.port +SERVER_MYSOCK_3= @mysqld.3.socket + +SERVER_MYPORT_4= @mysqld.4.port +SERVER_MYSOCK_4= @mysqld.4.socket diff --git a/mysql-test/suite/rpl/t/rpl_gtid_basic.test b/mysql-test/suite/rpl/t/rpl_gtid_basic.test new file mode 100644 index 00000000..70bd0087 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_basic.test @@ -0,0 +1,652 @@ +# +# This include file is used by more than one test suite +# (currently rpl and binlog_encryption). +# Please check all dependent tests after modifying it +# + +--source include/have_innodb.inc +--let $rpl_topology=1->2->3->4 +--source include/rpl_init.inc + +# Set up a 4-deep replication topology, then test various fail-overs +# using GTID. +# +# A -> B -> C -> D + +connection server_1; +--source include/wait_for_binlog_checkpoint.inc +--let $binlog_file = query_get_value(SHOW MASTER STATUS,File,1) +--let $binlog_pos = query_get_value(SHOW MASTER STATUS,Position,1) +--echo *** GTID position should be empty here *** +--replace_result $binlog_file <BINLOG_FILE> $binlog_pos <BINLOG_POS> +eval SELECT BINLOG_GTID_POS('$binlog_file',$binlog_pos); + +CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(10)) ENGINE=MyISAM; +CREATE TABLE t2 (a INT PRIMARY KEY, b VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, "m1"); +INSERT INTO t1 VALUES (2, "m2"), (3, "m3"), (4, "m4"); +INSERT INTO t2 VALUES (1, "i1"); +BEGIN; +INSERT INTO t2 VALUES (2, "i2"), (3, "i3"); +INSERT INTO t2 VALUES (4, "i4"); +COMMIT; +save_master_pos; +source include/wait_for_binlog_checkpoint.inc; +--let $binlog_file = query_get_value(SHOW MASTER STATUS,File,1) +--let $binlog_pos = query_get_value(SHOW MASTER STATUS,Position,1) +--let $gtid_pos_server_1 = `SELECT @@gtid_binlog_pos` +--echo *** GTID position should be non-empty here *** +--replace_result $binlog_file <BINLOG_FILE> $binlog_pos <BINLOG_POS> $gtid_pos_server_1 <GTID_POS_SERVER_1> +eval SELECT BINLOG_GTID_POS('$binlog_file',$binlog_pos); + +connection server_2; +sync_with_master; +source include/wait_for_binlog_checkpoint.inc; +--let $binlog_file = query_get_value(SHOW MASTER STATUS,File,1) +--let $binlog_pos = query_get_value(SHOW MASTER STATUS,Position,1) +--echo *** GTID position should be the same as on server_1 *** +--replace_result $binlog_file <BINLOG_FILE> $binlog_pos <BINLOG_POS> $gtid_pos_server_1 <GTID_POS_SERVER_1> +eval SELECT BINLOG_GTID_POS('$binlog_file',$binlog_pos); +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +save_master_pos; + +connection server_3; +sync_with_master; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +save_master_pos; + +connection server_4; +sync_with_master; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + + +--echo *** Now take out D, let it fall behind a bit, and then test re-attaching it to A *** +connection server_4; +--source include/stop_slave.inc + +connection server_1; +INSERT INTO t1 VALUES (5, "m1a"); +INSERT INTO t2 VALUES (5, "i1a"); +save_master_pos; + +connection server_4; +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $MASTER_MYPORT, + MASTER_USE_GTID=CURRENT_POS; +--source include/start_slave.inc +sync_with_master; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +--echo *** Now move B to D (C is still replicating from B) *** +connection server_2; +--source include/stop_slave.inc +--replace_result $SERVER_MYPORT_4 SERVER_MYPORT_4 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_4, + MASTER_USE_GTID=CURRENT_POS; +--source include/start_slave.inc + +connection server_4; +UPDATE t2 SET b="j1a" WHERE a=5; +save_master_pos; + +connection server_2; +sync_with_master; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +--echo *** Now move C to D, after letting it fall a little behind *** +connection server_3; +--source include/stop_slave.inc + +connection server_1; +INSERT INTO t2 VALUES (6, "i6b"); +INSERT INTO t2 VALUES (7, "i7b"); +--source include/save_master_gtid.inc + +connection server_3; +--replace_result $SERVER_MYPORT_4 SERVER_MYPORT_4 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_4, + MASTER_USE_GTID=CURRENT_POS; +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t2 ORDER BY a; + +--echo *** Now change everything back to what it was, to make rpl_end.inc happy +# Also check that MASTER_USE_GTID=CURRENT_POS is still enabled. +connection server_2; +# We need to sync up server_2 before switching. If it happened to have reached +# the point 'UPDATE t2 SET b="j1a" WHERE a=5' it will fail to connect to +# server_1, which is (deliberately) missing that transaction. +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc +--replace_result $MASTER_MYPORT MASTER_MYPORT +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $MASTER_MYPORT; +--source include/start_slave.inc +--source include/wait_for_slave_to_start.inc + +connection server_3; +--source include/stop_slave.inc +--replace_result $SLAVE_MYPORT SLAVE_MYPORT +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SLAVE_MYPORT; +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + +connection server_4; +--source include/stop_slave.inc +--replace_result $SERVER_MYPORT_3 SERVER_MYPORT_3 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_3; +--source include/start_slave.inc + +connection server_1; +DROP TABLE t1,t2; +--source include/save_master_gtid.inc + +--echo *** A few more checks for BINLOG_GTID_POS function *** +--let $valid_binlog_name = query_get_value(SHOW BINARY LOGS,Log_name,1) +--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT +SELECT BINLOG_GTID_POS(); +--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT +SELECT BINLOG_GTID_POS('a'); +--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT +SELECT BINLOG_GTID_POS('a',1,NULL); +SELECT BINLOG_GTID_POS(1,'a'); +SELECT BINLOG_GTID_POS(NULL,NULL); +SELECT BINLOG_GTID_POS('',1); +SELECT BINLOG_GTID_POS('a',1); +eval SELECT BINLOG_GTID_POS('$valid_binlog_name',-1); +eval SELECT BINLOG_GTID_POS('$valid_binlog_name',0); +eval SELECT BINLOG_GTID_POS('$valid_binlog_name',18446744073709551615); +eval SELECT BINLOG_GTID_POS('$valid_binlog_name',18446744073709551616); + + +--echo *** Some tests of @@GLOBAL.gtid_binlog_state *** +--connection server_2 +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc + +--connection server_1 +SET @old_state= @@GLOBAL.gtid_binlog_state; + +--error ER_BINLOG_MUST_BE_EMPTY +SET GLOBAL gtid_binlog_state = ''; +RESET MASTER; +SET GLOBAL gtid_binlog_state = ''; +FLUSH LOGS; +--source include/show_binary_logs.inc +SET GLOBAL gtid_binlog_state = '0-1-10,1-2-20,0-3-30'; +--source include/show_binary_logs.inc +--let $binlog_file= master-bin.000001 +--let $binlog_start= 4 +--source include/show_binlog_events.inc +#SELECT @@GLOBAL.gtid_binlog_pos; +#SELECT @@GLOBAL.gtid_binlog_state; +--error ER_BINLOG_MUST_BE_EMPTY +SET GLOBAL gtid_binlog_state = @old_state; +RESET MASTER; +SET GLOBAL gtid_binlog_state = @old_state; + +# Check that slave can reconnect again, despite the RESET MASTER, as we +# restored the state. + +CREATE TABLE t1 (a INT PRIMARY KEY); +SET gtid_seq_no=100; +INSERT INTO t1 VALUES (1); +--source include/save_master_gtid.inc + +--connection server_2 +--source include/start_slave.inc +# 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. +--source include/sync_with_master_gtid.inc + +SELECT * FROM t1; +# Check that the IO gtid position in SHOW SLAVE STATUS is also correct. +--let $status_items= Gtid_IO_Pos +--source include/show_slave_status.inc + +--echo *** Test @@LAST_GTID and MASTER_GTID_WAIT() *** + +--disable_ps2_protocol +--connection server_1 +DROP TABLE t1; +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; +--save_master_pos + +--connection server_2 +--sync_with_master +--source include/stop_slave.inc + +--connect (m1,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +SELECT @@last_gtid; +SET gtid_seq_no=110; +SELECT @@last_gtid; +BEGIN; +SELECT @@last_gtid; +INSERT INTO t1 VALUES (2); +SELECT @@last_gtid; +COMMIT; +SELECT @@last_gtid; +--let $pos= `SELECT @@gtid_binlog_pos` + +--connect (s1,127.0.0.1,root,,test,$SERVER_MYPORT_2,) +eval SET @pos= '$pos'; +# Check NULL argument. +SELECT master_gtid_wait(NULL); +# Check empty argument returns immediately. +SELECT master_gtid_wait('', NULL); +# Check this gets counted +SHOW STATUS LIKE 'Master_gtid_wait_count'; +SHOW STATUS LIKE 'Master_gtid_wait_timeouts'; +SHOW STATUS LIKE 'Master_gtid_wait_time'; +# Let's check that we get a timeout +SELECT master_gtid_wait(@pos, 0.5); +SELECT * FROM t1 ORDER BY a; +# Now actually wait until the slave reaches the position +send SELECT master_gtid_wait(@pos); + +--connection server_2 +--source include/start_slave.inc + +--connection s1 +reap; +SELECT * FROM t1 ORDER BY a; + +# Test waiting on a domain that does not exist yet. +--source include/stop_slave.inc + +--connection server_1 +SET gtid_domain_id= 1; +INSERT INTO t1 VALUES (3); +--let $pos= `SELECT @@gtid_binlog_pos` + +--connection s1 +--replace_result $pos POS +eval SET @pos= '$pos'; +SELECT master_gtid_wait(@pos, 0); +SELECT * FROM t1 WHERE a >= 3; +send SELECT master_gtid_wait(@pos, -1); + +--connection server_2 +--source include/start_slave.inc + +--connection s1 +reap; +SELECT * FROM t1 WHERE a >= 3; +# Waiting for only part of the position. +SELECT master_gtid_wait('1-1-1', 0); + +# Now test a lot of parallel master_gtid_wait() calls, completing in different +# order, and some of which time out or get killed on the way. + +--connection s1 +send SELECT master_gtid_wait('2-1-1,1-1-4,0-1-110'); + +--connect (s2,127.0.0.1,root,,test,$SERVER_MYPORT_2,) +# This will time out. No event 0-1-1000 exists +send SELECT master_gtid_wait('0-1-1000', 0.5); + +--connect (s3,127.0.0.1,root,,test,$SERVER_MYPORT_2,) +# This one we will kill +--let $kill1_id= `SELECT connection_id()` +send SELECT master_gtid_wait('0-1-2000'); + +--connect (s4,127.0.0.1,root,,test,$SERVER_MYPORT_2,) +send SELECT master_gtid_wait('2-1-10'); + +--connect (s5,127.0.0.1,root,,test,$SERVER_MYPORT_2,) +send SELECT master_gtid_wait('2-1-6', 1); + +# This one we will kill also. +--connect (s6,127.0.0.1,root,,test,$SERVER_MYPORT_2,) +--let $kill2_id= `SELECT connection_id()` +send SELECT master_gtid_wait('2-1-5'); + +--connect (s7,127.0.0.1,root,,test,$SERVER_MYPORT_2,) +send SELECT master_gtid_wait('2-1-10'); + +--connect (s8,127.0.0.1,root,,test,$SERVER_MYPORT_2,) +send SELECT master_gtid_wait('2-1-5,1-1-4,0-1-110'); + +--connect (s9,127.0.0.1,root,,test,$SERVER_MYPORT_2,) +send SELECT master_gtid_wait('2-1-2'); + +--connection server_2 +# This one completes immediately. +SHOW STATUS LIKE 'Master_gtid_wait_timeouts'; +SHOW STATUS LIKE 'Master_gtid_wait_count'; +SELECT master_gtid_wait('1-1-1'); +SHOW STATUS LIKE 'Master_gtid_wait_timeouts'; +SHOW STATUS LIKE 'Master_gtid_wait_count'; +let $wait_time = query_get_value(SHOW STATUS LIKE 'Master_gtid_wait_time', Value, 1); +--replace_result $wait_time MASTER_GTID_WAIT_TIME +eval SET @a= $wait_time; +SELECT IF(@a <= 100*1000*1000, "OK", CONCAT("Error: wait time ", @a, " is larger than expected")) + AS Master_gtid_wait_time_as_expected; + + +--connect (s10,127.0.0.1,root,,test,$SERVER_MYPORT_2,) +send SELECT master_gtid_wait('0-1-109'); + +--connection server_2 +# This one should time out. +SHOW STATUS LIKE 'Master_gtid_wait_timeouts'; +SHOW STATUS LIKE 'Master_gtid_wait_count'; +SELECT master_gtid_wait('2-1-2', 0.5); +SHOW STATUS LIKE 'Master_gtid_wait_timeouts'; +SHOW STATUS LIKE 'Master_gtid_wait_count'; +let $wait_time = query_get_value(SHOW STATUS LIKE 'Master_gtid_wait_time', Value, 1); +--replace_result $wait_time MASTER_GTID_WAIT_TIME +eval SET @a= $wait_time; +# We expect a wait time of just a bit over 0.5 seconds. But thread scheduling +# and timer inaccuracies could introduce significant jitter. So allow a +# generous interval. +SELECT IF(@a BETWEEN 0.4*1000*1000 AND 100*1000*1000, "OK", CONCAT("Error: wait time ", @a, " not as expected")) AS Master_gtid_wait_time_as_expected; + +--replace_result $kill1_id KILL_ID +eval KILL QUERY $kill1_id; +--connection s3 +--error ER_QUERY_INTERRUPTED +reap; + +--connection server_1 +SET gtid_domain_id=2; +SET gtid_seq_no=2; +INSERT INTO t1 VALUES (4); + +--connection s9 +reap; + +--connection server_2 +--replace_result $kill2_id KILL_ID +eval KILL CONNECTION $kill2_id; + +--connection s6 +--error 2013,ER_CONNECTION_KILLED +reap; + +--connection server_1 +SET gtid_domain_id=1; +SET gtid_seq_no=4; +INSERT INTO t1 VALUES (5); +SET gtid_domain_id=2; +SET gtid_seq_no=5; +INSERT INTO t1 VALUES (6); + +--connection s8 +reap; +--connection s1 +reap; +--connection s2 +reap; +--connection s5 +reap; +--connection s10 +reap; + +--connection server_1 +SET gtid_domain_id=2; +SET gtid_seq_no=10; +INSERT INTO t1 VALUES (7); + +--connection s4 +reap; +--connection s7 +reap; +--enable_ps2_protocol + +--echo *** Test gtid_slave_pos when used with GTID *** + +--connection server_2 +--source include/stop_slave.inc + +--connection server_1 +SET gtid_domain_id=2; +SET gtid_seq_no=1000; +INSERT INTO t1 VALUES (10); +INSERT INTO t1 VALUES (11); +--save_master_pos + +--connection server_2 +SET sql_slave_skip_counter= 1; +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 WHERE a >= 10 ORDER BY a; +SELECT IF(LOCATE("2-1-1001", @@GLOBAL.gtid_slave_pos)>0, "Ok", CONCAT("ERROR! expected GTID 2-1-1001 not found in gtid_slave_pos: ", @@GLOBAL.gtid_slave_pos)) AS status; + +--source include/stop_slave.inc + +--connection server_1 +SET gtid_domain_id=2; +SET gtid_seq_no=1010; +INSERT INTO t1 VALUES (12); +INSERT INTO t1 VALUES (13); +--save_master_pos + +--connection server_2 +SET sql_slave_skip_counter= 2; +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 WHERE a >= 10 ORDER BY a; +SELECT IF(LOCATE("2-1-1011", @@GLOBAL.gtid_slave_pos)>0, "Ok", CONCAT("ERROR! expected GTID 2-1-1011 not found in gtid_slave_pos: ", @@GLOBAL.gtid_slave_pos)) AS status; + +--source include/stop_slave.inc + +--connection server_1 +SET gtid_domain_id=2; +SET gtid_seq_no=1020; +INSERT INTO t1 VALUES (14); +INSERT INTO t1 VALUES (15); +INSERT INTO t1 VALUES (16); +--save_master_pos + +--connection server_2 +SET sql_slave_skip_counter= 3; +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 WHERE a >= 10 ORDER BY a; +SELECT IF(LOCATE("2-1-1022", @@GLOBAL.gtid_slave_pos)>0, "Ok", CONCAT("ERROR! expected GTID 2-1-1022 not found in gtid_slave_pos: ", @@GLOBAL.gtid_slave_pos)) AS status; + +--source include/stop_slave.inc + +--connection server_1 +SET gtid_domain_id=2; +SET gtid_seq_no=1030; +# Disable logging Annotate_rows events to preserve events count. +let $binlog_annotate_row_events_saved= `SELECT @@binlog_annotate_row_events`; +SET @@binlog_annotate_row_events= 0; +INSERT INTO t1 VALUES (17); +INSERT INTO t1 VALUES (18); +INSERT INTO t1 VALUES (19); +eval SET @@binlog_annotate_row_events= $binlog_annotate_row_events_saved; +--save_master_pos + +--connection server_2 +SET sql_slave_skip_counter= 5; +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 WHERE a >= 10 ORDER BY a; +SELECT IF(LOCATE("2-1-1032", @@GLOBAL.gtid_slave_pos)>0, "Ok", CONCAT("ERROR! expected GTID 2-1-1032 not found in gtid_slave_pos: ", @@GLOBAL.gtid_slave_pos)) AS status; + + +--source include/stop_slave.inc + +--connection server_1 +SET gtid_domain_id=3; +SET gtid_seq_no=100; +CREATE TABLE t2 (a INT PRIMARY KEY); +DROP TABLE t2; +SET gtid_domain_id=2; +SET gtid_seq_no=1040; +INSERT INTO t1 VALUES (20); +--save_master_pos + +--connection server_2 +SET @saved_mode= @@GLOBAL.slave_ddl_exec_mode; +SET GLOBAL slave_ddl_exec_mode=STRICT; +SET sql_slave_skip_counter=1; +START SLAVE UNTIL master_gtid_pos="3-1-100"; +--let $master_pos=3-1-100 +--source include/sync_with_master_gtid.inc +--source include/wait_for_slave_to_stop.inc +--error ER_NO_SUCH_TABLE +SELECT * FROM t2; +SELECT IF(LOCATE("3-1-100", @@GLOBAL.gtid_slave_pos)>0, "Ok", CONCAT("ERROR! expected GTID 3-1-100 not found in gtid_slave_pos: ", @@GLOBAL.gtid_slave_pos)) AS status; + +# Start the slave again, it should fail on the DROP TABLE as the table is not there. +SET sql_log_bin=0; +CALL mtr.add_suppression("Slave: Unknown table 'test\\.t2' Error_code: 1051"); +SET sql_log_bin=1; +START SLAVE; +--let $slave_sql_errno=1051 +--source include/wait_for_slave_sql_error.inc +SELECT IF(LOCATE("3-1-100", @@GLOBAL.gtid_slave_pos)>0, "Ok", CONCAT("ERROR! expected GTID 3-1-100 not found in gtid_slave_pos: ", @@GLOBAL.gtid_slave_pos)) AS status; + +STOP SLAVE IO_THREAD; +SET sql_slave_skip_counter=2; +--source include/start_slave.inc +--sync_with_master + +SELECT * FROM t1 WHERE a >= 20 ORDER BY a; +SELECT IF(LOCATE("3-1-101", @@GLOBAL.gtid_slave_pos)>0, "Ok", CONCAT("ERROR! expected GTID 3-1-101 not found in gtid_slave_pos: ", @@GLOBAL.gtid_slave_pos)) AS status; +SELECT IF(LOCATE("2-1-1040", @@GLOBAL.gtid_slave_pos)>0, "Ok", CONCAT("ERROR! expected GTID 2-1-1040 not found in gtid_slave_pos: ", @@GLOBAL.gtid_slave_pos)) AS status; + +SET GLOBAL slave_ddl_exec_mode= @saved_mode; + + +--echo *** Test GTID-connecting to a master with out-of-order sequence numbers in the binlog. *** + +# Create an out-of-order binlog on server 2. +# Let server 3 replicate to an out-of-order point, stop it, restart it, +# and check that it replicates correctly despite the out-of-order. + +--connection server_1 +SET gtid_domain_id= @@GLOBAL.gtid_domain_id; +INSERT INTO t1 VALUES (31); +--save_master_pos + +--connection server_2 +--sync_with_master +SET gtid_domain_id= @@GLOBAL.gtid_domain_id; +INSERT INTO t1 VALUES (32); + +--connection server_1 +INSERT INTO t1 VALUES (33); +--save_master_pos + +--connection server_2 +--sync_with_master +--save_master_pos + +--connection server_3 +--sync_with_master +--source include/stop_slave.inc + +--connection server_1 +INSERT INTO t1 VALUES (34); +--save_master_pos + +--connection server_2 +--sync_with_master +--save_master_pos + +--connection server_3 +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 WHERE a >= 30 ORDER BY a; +--save_master_pos + +--connection server_4 +--sync_with_master +SELECT * FROM t1 WHERE a >= 30 ORDER BY a; + + +--echo *** MDEV-31723: Crash on SET SESSION gtid_seq_no= DEFAULT +--connection server_1 + +# Setting gtid_seq_no forces the GTID logged, but only once. +SET SESSION gtid_seq_no= 2000; +SELECT @@SESSION.gtid_seq_no; +INSERT INTO t1 VALUES (40); +SELECT @@SESSION.gtid_seq_no; +SELECT REGEXP_REPLACE(@@gtid_binlog_pos, ".*\\b(0-1-[0-9]+)\\b.*", "\\1") AS dom0_pos; +INSERT INTO t1 VALUES (41); +SELECT REGEXP_REPLACE(@@gtid_binlog_pos, ".*\\b(0-1-[0-9]+)\\b.*", "\\1") AS dom0_pos; + +# Setting to 0 has no effect. +SET SESSION gtid_seq_no= 2010; +INSERT INTO t1 VALUES (42); +SELECT REGEXP_REPLACE(@@gtid_binlog_pos, ".*\\b(0-1-[0-9]+)\\b.*", "\\1") AS dom0_pos; +SET @old_strict= @@GLOBAL.gtid_strict_mode; +SET GLOBAL gtid_strict_mode= 1; +SET SESSION gtid_seq_no= 0; +INSERT INTO t1 VALUES (43); +SELECT REGEXP_REPLACE(@@gtid_binlog_pos, ".*\\b(0-1-[0-9]+)\\b.*", "\\1") AS dom0_pos; +SET GLOBAL gtid_strict_mode= @old_strict; +INSERT INTO t1 VALUES (44); +SELECT REGEXP_REPLACE(@@gtid_binlog_pos, ".*\\b(0-1-[0-9]+)\\b.*", "\\1") AS dom0_pos; + +# Setting gtid_seq_no multiple times. +SET SESSION gtid_seq_no= 2020; +SET SESSION gtid_seq_no= 2030; +INSERT INTO t1 VALUES (45); +SELECT REGEXP_REPLACE(@@gtid_binlog_pos, ".*\\b(0-1-[0-9]+)\\b.*", "\\1") AS dom0_pos; + +# Setting to DEFAULT or 0 disables prior setting. +SET SESSION gtid_seq_no= 2040; +SET SESSION gtid_seq_no= DEFAULT; +INSERT INTO t1 VALUES (46); +SELECT REGEXP_REPLACE(@@gtid_binlog_pos, ".*\\b(0-1-[0-9]+)\\b.*", "\\1") AS dom0_pos; +INSERT INTO t1 VALUES (47); +SELECT REGEXP_REPLACE(@@gtid_binlog_pos, ".*\\b(0-1-[0-9]+)\\b.*", "\\1") AS dom0_pos; +SET SESSION gtid_seq_no= 2050; +SET SESSION gtid_seq_no= 0; +INSERT INTO t1 VALUES (48); +SELECT REGEXP_REPLACE(@@gtid_binlog_pos, ".*\\b(0-1-[0-9]+)\\b.*", "\\1") AS dom0_pos; + + +# Clean up. +--connection server_1 +DROP TABLE t1; + + +--source include/rpl_end.inc + +--echo # +--echo # Start of 10.2 tests +--echo # + +--echo # +--echo # MDEV-10134 Add full support for DEFAULT +--echo # + +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED +CREATE TABLE t1 (a VARCHAR(100) DEFAULT BINLOG_GTID_POS("master-bin.000001", 600)); + +--echo # +--echo # End of 10.2 tests +--echo # + + +--echo # +--echo # Start of 10.3 tests +--echo # + +--echo # +--echo # MDEV-13967 Parameter data type control for Item_long_func +--echo # + +--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION +SELECT MASTER_GTID_WAIT(ROW(1,1),'str'); + +--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION +SELECT MASTER_GTID_WAIT('str',ROW(1,1)); + + +--echo # +--echo # End of 10.3 tests +--echo # diff --git a/mysql-test/suite/rpl/t/rpl_gtid_crash-master.opt b/mysql-test/suite/rpl/t/rpl_gtid_crash-master.opt new file mode 100644 index 00000000..590d44a6 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_crash-master.opt @@ -0,0 +1 @@ +--loose-skip-stack-trace --skip-core-file diff --git a/mysql-test/suite/rpl/t/rpl_gtid_crash-slave.opt b/mysql-test/suite/rpl/t/rpl_gtid_crash-slave.opt new file mode 100644 index 00000000..69c1a64e --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_crash-slave.opt @@ -0,0 +1 @@ +--master-retry-count=100 diff --git a/mysql-test/suite/rpl/t/rpl_gtid_crash.test b/mysql-test/suite/rpl/t/rpl_gtid_crash.test new file mode 100644 index 00000000..28329831 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_crash.test @@ -0,0 +1,668 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +# Valgrind does not work well with test that crashes the server +--source include/not_valgrind.inc + +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +--echo *** Test crashing master, causing slave IO thread to reconnect while SQL thread is running *** + +--connection server_1 +call mtr.add_suppression("Checking table:"); +call mtr.add_suppression("client is using or hasn't closed the table properly"); +call mtr.add_suppression("Table .* is marked as crashed and should be repaired"); +flush tables; + +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, 0); +--save_master_pos + +--connection server_2 +--sync_with_master +SET sql_log_bin=0; +call mtr.add_suppression('Master command COM_REGISTER_SLAVE failed: failed registering on master, reconnecting to try again'); +SET sql_log_bin=1; +--source include/stop_slave.inc +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $MASTER_MYPORT, + MASTER_USE_GTID=SLAVE_POS; + +--connection server_1 +INSERT INTO t1 VALUES (2,1); +INSERT INTO t1 VALUES (3,1); + +--connection server_2 +--source include/start_slave.inc + +--connection server_1 + +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait-rpl_gtid_crash.test +EOF + +let $1=200; +--disable_query_log +while ($1) +{ + eval INSERT INTO t1 VALUES ($1 + 10, 2); + dec $1; +} +--enable_query_log +--source include/save_master_gtid.inc + +SET SESSION debug_dbug="+d,crash_dispatch_command_before"; +--error 2006,2013 +SELECT 1; +--source include/wait_until_disconnected.inc + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart-rpl_gtid_crash.test +EOF + +--enable_reconnect +--source include/wait_until_connected_again.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc + +--connection server_1 +INSERT INTO t1 VALUES (1000, 3); +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc + +--connection server_1 +DROP TABLE t1; +--save_master_pos + +--echo *** Test crashing the master mysqld and check that binlog state is recovered. *** +--connection server_2 +--sync_with_master +--source include/stop_slave.inc +RESET MASTER; +SET GLOBAL gtid_slave_pos=''; + +--connection server_1 +RESET MASTER; +--replace_column 2 # 4 # 5 # +SHOW BINLOG EVENTS IN 'master-bin.000001' LIMIT 1,1; +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; + +--connection server_2 +--source include/start_slave.inc + +--connection server_1 +SET gtid_domain_id= 1; +INSERT INTO t1 VALUES (1); +INSERT INTO t1 VALUES (2); +FLUSH LOGS; +SET gtid_domain_id= 2; +INSERT INTO t1 VALUES (3); +FLUSH LOGS; +--source include/show_binary_logs.inc +--replace_column 2 # 4 # 5 # 6 # +SHOW BINLOG EVENTS IN 'master-bin.000003' LIMIT 1,1; + +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait +EOF + +SET SESSION debug_dbug="+d,crash_dispatch_command_before"; +--error 2006,2013 +SELECT 1; +--source include/wait_until_disconnected.inc + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart +EOF + +--enable_reconnect +--source include/wait_until_connected_again.inc + +--source include/show_binary_logs.inc +--replace_column 2 # 4 # 5 # 6 # +SHOW BINLOG EVENTS IN 'master-bin.000004' LIMIT 1,1; +--save_master_pos + +--connection server_2 +--sync_with_master +SELECT * FROM t1 ORDER BY a; + + +--echo *** Test crashing slave at various points and check that it recovers crash-safe. *** + +# Crash the slave just before updating mysql.gtid_slave_pos table. +--source include/stop_slave.inc +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF +# We do not have to save @@GLOBAL.debug_dbug, it is reset when slave crashes. +SET GLOBAL debug_dbug="+d,inject_crash_before_write_rpl_slave_state"; +START SLAVE; + +--connection server_1 +INSERT INTO t1 VALUES (4); +--source include/save_master_gtid.inc + +--connection server_2 +--source include/wait_until_disconnected.inc + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +restart: --skip-slave-start=0 +EOF + +--enable_reconnect +--source include/wait_until_connected_again.inc + +--source include/sync_with_master_gtid.inc + +# Crash the slave just before committing. +--source include/stop_slave.inc +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF +START SLAVE; +--error 0,2006,2013 +SET GLOBAL debug_dbug="+d,crash_commit_before"; + +--connection server_1 +INSERT INTO t1 VALUES (5); +--source include/save_master_gtid.inc + +--connection server_2 +--source include/wait_until_disconnected.inc + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +restart: --skip-slave-start=0 +EOF + +--enable_reconnect +--source include/wait_until_connected_again.inc + +--source include/sync_with_master_gtid.inc + +# Crash the slave just after committing. +--source include/stop_slave.inc +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF +START SLAVE; +--error 0,2006,2013 +SET GLOBAL debug_dbug="+d,crash_commit_after"; + +--connection server_1 +INSERT INTO t1 VALUES (6); +--source include/save_master_gtid.inc + +--connection server_2 +--source include/wait_until_disconnected.inc + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +restart: --skip-slave-start=0 +EOF + +--enable_reconnect +--source include/wait_until_connected_again.inc + +--source include/sync_with_master_gtid.inc + +# Crash the slave just before updating relay-log.info +--source include/stop_slave.inc +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF +SET GLOBAL debug_dbug="+d,inject_crash_before_flush_rli"; +--error 0,2006,2013 +START SLAVE; + +--connection server_1 +INSERT INTO t1 VALUES (7); +--source include/save_master_gtid.inc + +--connection server_2 +--source include/wait_until_disconnected.inc + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +restart: --skip-slave-start=0 +EOF + +--enable_reconnect +--source include/wait_until_connected_again.inc + +--source include/sync_with_master_gtid.inc + +# Crash the slave just after updating relay-log.info +--source include/stop_slave.inc +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF +SET GLOBAL debug_dbug="+d,inject_crash_after_flush_rli"; +--error 0,2006,2013 +START SLAVE; + +--connection server_1 +INSERT INTO t1 VALUES (8); +--source include/save_master_gtid.inc + +--connection server_2 +--source include/wait_until_disconnected.inc + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +restart: --skip-slave-start=0 +EOF + +--enable_reconnect +--source include/wait_until_connected_again.inc + +--source include/sync_with_master_gtid.inc + + +# Check that everything was replicated correctly. +SELECT * FROM t1 ORDER BY a; + + +--echo *** MDEV-4725: Incorrect recovery when crash in the middle of writing an event group *** + +--connection server_2 +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF + +--let $old_gtid_strict= `SELECT @@gtid_strict_mode` +SET GLOBAL debug_dbug="+d,crash_before_writing_xid"; + +--connection server_1 +INSERT INTO t1 VALUES (9), (10); +--let $saved_gtid=`SELECT @@last_gtid` +--save_master_pos + +--connection server_2 +--source include/wait_until_disconnected.inc + +# The bug was that during crash recovery we would update the binlog state +# with the GTID of the half-written event group at the end of the slaves +# binlog, even though this event group was not committed. +# We restart the server with gtid_strict_mode; this way, we get an error +# about duplicate gtid when the slave re-executes the event group, if the +# binlog crash recovery is incorrect. +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +restart: --gtid_strict_mode=1 +EOF + +--enable_reconnect +--source include/wait_until_connected_again.inc + +SHOW VARIABLES like 'gtid_strict_mode'; +--source include/start_slave.inc +--sync_with_master +--disable_query_log +eval SET GLOBAL gtid_strict_mode= $old_gtid_strict; +--enable_query_log + + +--echo *** MDEV-6462: Incorrect recovery on a slave reconnecting to crashed master *** + +--connection server_1 +set sql_log_bin= 0; +call mtr.add_suppression("Error writing file 'master-bin'"); +set sql_log_bin= 1; +--connection server_2 +set sql_log_bin= 0; +call mtr.add_suppression("The server_id of master server changed in the middle of GTID"); +call mtr.add_suppression("Unexpected change of master binlog file name in the middle of GTID"); +set sql_log_bin= 1; + +--connection server_1 +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait +EOF + +SET GLOBAL debug_dbug="+d,inject_error_writing_xid"; +BEGIN; +INSERT INTO t1 VALUES (11); +--error ER_ERROR_ON_WRITE +COMMIT; +SET GLOBAL debug_dbug="+d,crash_dispatch_command_before"; +--error 2006,2013 +COMMIT; + +--source include/wait_until_disconnected.inc + +# Simulate that we reconnect to a different server (new server_id). +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart: --server-id=3 +EOF + +--enable_reconnect +--source include/wait_until_connected_again.inc + +SELECT @@GLOBAL.server_id; +SELECT * from t1 WHERE a > 10 ORDER BY a; +--disable_query_log +eval SELECT IF(INSTR(@@gtid_binlog_pos, '$saved_gtid'), "Binlog pos ok", CONCAT("Unexpected binlog pos: ", @@gtid_binlog_pos, "; does not contain the GTID $saved_gtid.")) AS gtid_check; +--enable_query_log + +--echo # Wait 60 seconds for SQL thread to catch up with IO thread +--connection server_2 +--let $wait_timeout= 600 +while ($wait_timeout != 0) +{ + --let $read_log_pos= query_get_value('SHOW SLAVE STATUS', Read_Master_Log_Pos, 1) + --let $exec_log_pos= query_get_value('SHOW SLAVE STATUS', Exec_Master_Log_Pos, 1) + if ($read_log_pos == $exec_log_pos) + { + --let $wait_timeout= 0 + } + if ($read_log_pos != $exec_log_pos) + { + --sleep 0.1 + --dec $wait_timeout + } +} +if ($read_log_pos != $exec_log_pos) +{ + --die Timeout wait for SQL thread to catch up with IO thread +} + +SELECT * from t1 WHERE a > 10 ORDER BY a; +--disable_query_log +eval SELECT IF(INSTR(@@gtid_binlog_pos, '$saved_gtid'), "Binlog pos ok", CONCAT("Unexpected binlog pos: ", @@gtid_binlog_pos, "; does not contain the GTID $saved_gtid.")) AS gtid_check; +eval SELECT IF(INSTR(@@gtid_slave_pos, '$saved_gtid'), "Slave pos ok", CONCAT("Unexpected slave pos: ", @@gtid_slave_pos, "; does not contain the GTID $saved_gtid.")) AS gtid_check; +eval SELECT IF(INSTR(@@gtid_current_pos, '$saved_gtid'), "Current pos ok", CONCAT("Unexpected current pos: ", @@gtid_current_pos, "; does not contain the GTID $saved_gtid.")) AS gtid_check; +--enable_query_log + +--echo # Repeat this with additional transactions on the master + +--connection server_1 +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait +EOF + +SET GLOBAL debug_dbug="+d,inject_error_writing_xid"; +BEGIN; +INSERT INTO t1 VALUES (12); +--error ER_ERROR_ON_WRITE +COMMIT; +SET GLOBAL debug_dbug="+d,crash_dispatch_command_before"; +--error 2006,2013 +COMMIT; + +--source include/wait_until_disconnected.inc + +# Simulate that we reconnect to a different server (new server_id). +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart: --server-id=1 +EOF + +--enable_reconnect +--source include/wait_until_connected_again.inc + +SELECT @@GLOBAL.server_id; +INSERT INTO t1 VALUES (13); +INSERT INTO t1 VALUES (14); +--let $saved_gtid=`SELECT @@last_gtid` +SELECT * from t1 WHERE a > 10 ORDER BY a; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc +SELECT * from t1 WHERE a > 10 ORDER BY a; + +--connection server_1 +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait +EOF + +SET GLOBAL debug_dbug="+d,inject_error_writing_xid"; +BEGIN; +INSERT INTO t1 VALUES (21); +--error ER_ERROR_ON_WRITE +COMMIT; +SET GLOBAL debug_dbug="+d,crash_dispatch_command_before"; +--error 2006,2013 +COMMIT; + +--source include/wait_until_disconnected.inc + +# Simulate that we reconnect to the same server (same server_id). +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart +EOF + +--enable_reconnect +--source include/wait_until_connected_again.inc + +SELECT @@GLOBAL.server_id; +SELECT * from t1 WHERE a > 10 ORDER BY a; +--disable_query_log +eval SELECT IF(INSTR(@@gtid_binlog_pos, '$saved_gtid'), "Binlog pos ok", CONCAT("Unexpected binlog pos: ", @@gtid_binlog_pos, "; does not contain the GTID $saved_gtid.")) AS gtid_check; +eval SELECT IF(INSTR(@@gtid_current_pos, '$saved_gtid'), "Current pos ok", CONCAT("Unexpected current pos: ", @@gtid_current_pos, "; does not contain the GTID $saved_gtid.")) AS gtid_check; +--enable_query_log + +--echo # Wait 60 seconds for SQL thread to catch up with IO thread +--connection server_2 +--let $wait_timeout= 600 +while ($wait_timeout != 0) +{ + --let $read_log_pos= query_get_value('SHOW SLAVE STATUS', Read_Master_Log_Pos, 1) + --let $exec_log_pos= query_get_value('SHOW SLAVE STATUS', Exec_Master_Log_Pos, 1) + if ($read_log_pos == $exec_log_pos) + { + --let $wait_timeout= 0 + } + if ($read_log_pos != $exec_log_pos) + { + --sleep 0.1 + --dec $wait_timeout + } +} +if ($read_log_pos != $exec_log_pos) +{ + --die Timeout wait for SQL thread to catch up with IO thread +} + +SELECT * from t1 WHERE a > 10 ORDER BY a; +--disable_query_log +eval SELECT IF(INSTR(@@gtid_binlog_pos, '$saved_gtid'), "Binlog pos ok", CONCAT("Unexpected binlog pos: ", @@gtid_binlog_pos, "; does not contain the GTID $saved_gtid.")) AS gtid_check; +eval SELECT IF(INSTR(@@gtid_slave_pos, '$saved_gtid'), "Slave pos ok", CONCAT("Unexpected slave pos: ", @@gtid_slave_pos, "; does not contain the GTID $saved_gtid.")) AS gtid_check; +eval SELECT IF(INSTR(@@gtid_current_pos, '$saved_gtid'), "Current pos ok", CONCAT("Unexpected current pos: ", @@gtid_current_pos, "; does not contain the GTID $saved_gtid.")) AS gtid_check; +--enable_query_log + +--echo # Repeat this with additional transactions on the master + +--connection server_1 +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait +EOF + +SET GLOBAL debug_dbug="+d,inject_error_writing_xid"; +BEGIN; +INSERT INTO t1 VALUES (22); +--error ER_ERROR_ON_WRITE +COMMIT; +SET GLOBAL debug_dbug="+d,crash_dispatch_command_before"; +--error 2006,2013 +COMMIT; + +--source include/wait_until_disconnected.inc + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart +EOF + +--enable_reconnect +--source include/wait_until_connected_again.inc + +INSERT INTO t1 VALUES (23); +INSERT INTO t1 VALUES (24); +--let $saved_gtid=`SELECT @@last_gtid` +SELECT * from t1 WHERE a > 10 ORDER BY a; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc +SELECT * from t1 WHERE a > 10 ORDER BY a; + +--echo # Repeat this with slave restart + +--connection server_1 +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait +EOF + +SET GLOBAL debug_dbug="+d,inject_error_writing_xid"; +BEGIN; +INSERT INTO t1 VALUES (25); +--error ER_ERROR_ON_WRITE +COMMIT; +SET GLOBAL debug_dbug="+d,crash_dispatch_command_before"; +--error 2006,2013 +COMMIT; + +--source include/wait_until_disconnected.inc + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart +EOF + +--connection server_1 +--enable_reconnect +--source include/wait_until_connected_again.inc + +--connection server_2 +--echo # Wait 60 seconds for IO thread to connect and SQL thread to catch up +--echo # with IO thread. +--let $wait_timeout= 600 +while ($wait_timeout != 0) +{ + --let $connected=`SELECT COUNT(*) > 0 FROM information_schema.processlist WHERE State = 'Waiting for master to send event'` + if ($connected) + { + --let $read_log_pos= query_get_value('SHOW SLAVE STATUS', Read_Master_Log_Pos, 1) + --let $exec_log_pos= query_get_value('SHOW SLAVE STATUS', Exec_Master_Log_Pos, 1) + if ($read_log_pos == $exec_log_pos) + { + --let $wait_timeout= 0 + } + if ($read_log_pos != $exec_log_pos) + { + --sleep 0.1 + --dec $wait_timeout + } + } + if (!$connected) + { + --sleep 0.1 + --dec $wait_timeout + } +} +if (`SELECT NOT $connected OR $read_log_pos != $exec_log_pos`) +{ + --die Timeout wait for IO thread to connect and SQL thread to catch up with IO thread +} + +--source include/stop_slave.inc + +--connection server_1 +--disable_query_log +eval SELECT IF(INSTR(@@gtid_binlog_pos, '$saved_gtid'), "Binlog pos ok", CONCAT("Unexpected binlog pos: ", @@gtid_binlog_pos, "; does not contain the GTID $saved_gtid.")) AS gtid_check; +eval SELECT IF(INSTR(@@gtid_current_pos, '$saved_gtid'), "Current pos ok", CONCAT("Unexpected current pos: ", @@gtid_current_pos, "; does not contain the GTID $saved_gtid.")) AS gtid_check; +--enable_query_log +INSERT INTO t1 VALUES (26); +INSERT INTO t1 VALUES (27); +SELECT * from t1 WHERE a > 10 ORDER BY a; +--source include/save_master_gtid.inc + +--connection server_2 +--disable_query_log +eval SELECT IF(INSTR(@@gtid_binlog_pos, '$saved_gtid'), "Binlog pos ok", CONCAT("Unexpected binlog pos: ", @@gtid_binlog_pos, "; does not contain the GTID $saved_gtid.")) AS gtid_check; +eval SELECT IF(INSTR(@@gtid_slave_pos, '$saved_gtid'), "Slave pos ok", CONCAT("Unexpected slave pos: ", @@gtid_slave_pos, "; does not contain the GTID $saved_gtid.")) AS gtid_check; +eval SELECT IF(INSTR(@@gtid_current_pos, '$saved_gtid'), "Current pos ok", CONCAT("Unexpected current pos: ", @@gtid_current_pos, "; does not contain the GTID $saved_gtid.")) AS gtid_check; +--enable_query_log +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * from t1 WHERE a > 10 ORDER BY a; + + +--echo *** MDEV-6391: GTID binlog state not recovered if mariadb-bin.state is removed *** + +--connection server_2 +--source include/stop_slave.inc + +# Do some misc. transactions, stop the master, drop the master-bin.state file. +# Start the master back up, check that binlog state is correct. + +--connection server_1 + +INSERT INTO t1 VALUES (30); +SET @old_server_id= @@server_id; +SET @old_domain_id= @@gtid_domain_id; + +SET SESSION server_id= 10; +INSERT INTO t1 VALUES (31); +INSERT INTO t1 VALUES (32); +SET SESSION gtid_domain_id= 1; +SET SESSION server_id=11; +INSERT INTO t1 VALUES (33); +SET SESSION gtid_domain_id= 2; +INSERT INTO t1 VALUES (34); +SET SESSION server_id= 10; +INSERT INTO t1 VALUES (35); +INSERT INTO t1 VALUES (36); +SET SESSION gtid_domain_id= 0; +SET SESSION server_id= 12; +INSERT INTO t1 VALUES (37); +SET SESSION gtid_domain_id= @old_domain_id; +SET SESSION server_id= @old_server_id; +INSERT INTO t1 VALUES (38); +INSERT INTO t1 VALUES (39); +SELECT * FROM t1 WHERE a >= 30 ORDER BY a; +--source include/save_master_gtid.inc + +--let OLD_STATE= `SELECT @@gtid_binlog_state` + +--let $datadir= `SELECT @@datadir` + +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait +EOF +shutdown_server; +--source include/wait_until_disconnected.inc + +--remove_file $datadir/master-bin.state + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart +EOF +--enable_reconnect +--source include/wait_until_connected_again.inc + +--let NEW_STATE= `SELECT @@gtid_binlog_state` + +--perl +my $old= $ENV{'OLD_STATE'}; +my $new= $ENV{'NEW_STATE'}; +# Make them order-independent, for easy comparison. +$old= join(",", sort(split(",", $old))); +$new= join(",", sort(split(",", $new))); +die "ERROR: new binlog state '$new' differs from old '$old'\n" + unless $old eq $new; +EOF + +--connection server_2 +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 WHERE a >= 30 ORDER BY a; + + +--connection server_1 +DROP TABLE t1; + +--connection default +--enable_reconnect +--source include/wait_until_connected_again.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_crash_myisam-master.opt b/mysql-test/suite/rpl/t/rpl_gtid_crash_myisam-master.opt new file mode 100644 index 00000000..16d8af5b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_crash_myisam-master.opt @@ -0,0 +1 @@ +--loose-skip-stack-trace --skip-core-file --skip-innodb diff --git a/mysql-test/suite/rpl/t/rpl_gtid_crash_myisam.test b/mysql-test/suite/rpl/t/rpl_gtid_crash_myisam.test new file mode 100644 index 00000000..faf388f5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_crash_myisam.test @@ -0,0 +1,64 @@ +--source include/have_debug.inc +# Valgrind does not work well with test that crashes the server +--source include/not_valgrind.inc + +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +--echo *** Test crashing master with InnoDB disabled, the binlog gtid state should still be correctly recovered. *** + +--connection server_1 +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=MyISAM; +--save_master_pos + +--connection server_2 +--sync_with_master +--source include/stop_slave.inc +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_1 +INSERT INTO t1 VALUES (1); +INSERT INTO t1 VALUES (2); +--save_master_pos + +--connection server_2 +--sync_with_master +SELECT * FROM t1 ORDER BY a; + +--connection server_1 + +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait +EOF + +FLUSH TABLES; +SET SESSION debug_dbug="+d,crash_dispatch_command_before"; +--error 2006,2013 +SELECT 1; + +--source include/wait_until_disconnected.inc + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart-rpl_gtid_crash.test +EOF + +--connection server_1 +--enable_reconnect +--source include/wait_until_connected_again.inc + +INSERT INTO t1 VALUES (3); +--save_master_pos + +--connection server_2 +--sync_with_master +SELECT * FROM t1 ORDER BY a; + +--connection server_1 +DROP TABLE t1; + +--connection default +--enable_reconnect +--source include/wait_until_connected_again.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_delete_domain.test b/mysql-test/suite/rpl/t/rpl_gtid_delete_domain.test new file mode 100644 index 00000000..5537b6fb --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_delete_domain.test @@ -0,0 +1,101 @@ +# In case master's gtid binlog state is divergent from the slave's gtid_slave_pos +# slave may not be able to connect. +# For instance when slave is more updated in some of domains, see +# MDEV-12012 as example, the master's state may require adjustment. +# In a specific case of an "old" divergent domain, that is there +# won't be no more event groups from it generated, the states can be +# made compatible with wiping the problematic domain away. After that slave +# becomes connectable. +# +# Notice that the slave applied gtid state is not really required to +# be similarly cleaned in order for replication to flow. +# However this could lead to an expected error when the master +# resumes binlogging of such domain which the test demonstrate. + +--source include/master-slave.inc + +--connection master +# enforce the default domain_id binlogging explicitly +SET @@SESSION.gtid_domain_id=0; +CREATE TABLE t (a INT); +--sync_slave_with_master + +--connection slave +call mtr.add_suppression("connecting slave requested to start from.*which is not in the master's binlog"); + +--source include/stop_slave.inc +CHANGE MASTER TO master_use_gtid=slave_pos; + +--connection master +# create extra gtid domains for binlog state +--let $extra_domain_id=11 +--let $extra_domain_server_id=111 +--let $extra_gtid_seq_no=1 +--eval SET @@SESSION.gtid_domain_id=$extra_domain_id +--eval SET @@SESSION.server_id=$extra_domain_server_id +--eval SET @@SESSION.gtid_seq_no=$extra_gtid_seq_no +INSERT INTO t SET a=1; + +# +# Set up the slave replication state as if slave knows more events from the extra +# domain. +# +--connection slave +SET @save.gtid_slave_pos=@@global.gtid_slave_pos; +--eval SET @@global.gtid_slave_pos=concat(@@global.gtid_slave_pos, ",", $extra_domain_id, "-", $extra_domain_server_id, "-", $extra_gtid_seq_no + 1) + +# unsuccessful attempt to start slave +START SLAVE IO_THREAD; +--let $slave_io_errno=1236 +--source include/wait_for_slave_io_error.inc + +--connection master +# adjust the master binlog state +FLUSH BINARY LOGS; +--let $purge_to_binlog= query_get_value(SHOW MASTER STATUS, File, 1) +--let $purge_binlogs_to=$purge_to_binlog +--source include/wait_for_purge.inc + +# with final removal of the extra domain +--eval FLUSH BINARY LOGS DELETE_DOMAIN_ID=($extra_domain_id) +SELECT @@global.gtid_binlog_pos, @@global.gtid_binlog_state; + +--connection slave +SELECT @@global.gtid_slave_pos; +# start the slave sucessfully +--let rpl_debug=1 +--source include/start_slave.inc +--let rpl_debug=0 + +--connection master +# but the following gtid from the *extra* domain will break replication +INSERT INTO t SET a=1; + +# take note of the slave io thread error due to being dismissed +# extra domain at connection to master which tried becoming active; +# slave is to stop. +--connection slave +--let $errno=1236 +--source include/wait_for_slave_io_error.inc + +# let's apply the very same medicine +--connection master +FLUSH BINARY LOGS; +--let $purge_to_binlog= query_get_value(SHOW MASTER STATUS, File, 1) +--eval PURGE BINARY LOGS TO '$purge_to_binlog'; +# with final removal of the extra domain +--eval FLUSH BINARY LOGS DELETE_DOMAIN_ID=($extra_domain_id) + +--connection slave +--source include/start_slave.inc + +# +# cleanup +# +--connection master +SET @@SESSION.gtid_domain_id=0; +DROP TABLE t; + +sync_slave_with_master; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_errorhandling.test b/mysql-test/suite/rpl/t/rpl_gtid_errorhandling.test new file mode 100644 index 00000000..412489b3 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_errorhandling.test @@ -0,0 +1,291 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/master-slave.inc + +--echo *** Test that we check against incorrect table definition for mysql.gtid_slave_pos *** +--connection master +CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB; +call mtr.add_suppression("Incorrect definition of table mysql.gtid_slave_pos:.*"); +--sync_slave_with_master + +--connection slave +--source include/stop_slave.inc +ALTER TABLE mysql.gtid_slave_pos CHANGE seq_no seq_no VARCHAR(20); +START SLAVE; + +--connection master +INSERT INTO t1 VALUES (1); + +--connection slave +CALL mtr.add_suppression("Slave: Failed to open mysql.gtid_slave_pos"); +--let $slave_sql_errno=1944 +--source include/wait_for_slave_sql_error.inc + +--source include/stop_slave.inc +ALTER TABLE mysql.gtid_slave_pos CHANGE seq_no seq_no BIGINT UNSIGNED NOT NULL; +ALTER TABLE mysql.gtid_slave_pos DROP PRIMARY KEY; +ALTER TABLE mysql.gtid_slave_pos ADD PRIMARY KEY (sub_id, domain_id); +START SLAVE; +--let $slave_sql_errno=1944 +--source include/wait_for_slave_sql_error.inc + +--source include/stop_slave.inc +ALTER TABLE mysql.gtid_slave_pos DROP PRIMARY KEY; +START SLAVE; +--let $slave_sql_errno=1944 +--source include/wait_for_slave_sql_error.inc + +--source include/stop_slave.inc +ALTER TABLE mysql.gtid_slave_pos ADD PRIMARY KEY (sub_id); +START SLAVE; +--let $slave_sql_errno=1944 +--source include/wait_for_slave_sql_error.inc + +--source include/stop_slave.inc +ALTER TABLE mysql.gtid_slave_pos DROP PRIMARY KEY; +ALTER TABLE mysql.gtid_slave_pos ADD PRIMARY KEY (domain_id, sub_id); +--source include/start_slave.inc + +--connection master +--sync_slave_with_master + +--connection slave +SELECT * FROM t1; + + +--echo *** Test that setting @@gtid_domain_id or @@gtid_seq_no is not allowed inside a transaction. *** +BEGIN; +INSERT INTO t1 VALUES (100); +--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_GTID_DOMAIN_ID_SEQ_NO +SET SESSION gtid_domain_id= 100; +--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_GTID_DOMAIN_ID_SEQ_NO +SET SESSION gtid_seq_no= 100; +SET @old_domain= @@GLOBAL.gtid_domain_id; +SET GLOBAL gtid_domain_id= 100; +SELECT @@SESSION.gtid_domain_id; +SET GLOBAL gtid_domain_id= @old_domain; +INSERT INTO t1 VALUES (101); +SELECT * FROM t1 ORDER BY a; +ROLLBACK; +SELECT * FROM t1 ORDER BY a; + + +--echo *** Test requesting an explicit GTID position that conflicts with newer GTIDs of our own in the binlog. *** +--connection slave +--source include/stop_slave.inc + +--connection master +RESET MASTER; +# This insert will be GTID 0-1-1 +INSERT INTO t1 VALUES (2); +# And this will be GTID 0-1-2 +INSERT INTO t1 VALUES (4); +--source include/save_master_gtid.inc + +--connection slave +SET sql_log_bin = 0; +INSERT INTO t1 VALUES (2); +SET sql_log_bin = 1; +INSERT INTO t1 VALUES (3); + +CHANGE MASTER TO master_use_gtid=current_pos; +# Most not change @@GLOBAL.gtid_slave_pos in the middle of a transaction. +BEGIN; +--error ER_CANT_DO_THIS_DURING_AN_TRANSACTION +SET GLOBAL gtid_slave_pos = "100-100-100"; +INSERT INTO t1 VALUES (100); +--error ER_CANT_DO_THIS_DURING_AN_TRANSACTION +SET GLOBAL gtid_slave_pos = "100-100-100"; +ROLLBACK; + +# In gtid non-strict mode, we get warnings for setting @@gtid_slave_pos back +# to earlier than what is in the binlog. In strict mode, we get an error. +SET GLOBAL gtid_strict_mode= 1; +--error ER_MASTER_GTID_POS_CONFLICTS_WITH_BINLOG +SET GLOBAL gtid_slave_pos = "0-1-1"; +--error ER_MASTER_GTID_POS_MISSING_DOMAIN +SET GLOBAL gtid_slave_pos = ""; +SET GLOBAL gtid_strict_mode= 0; +SET GLOBAL gtid_slave_pos = "0-1-1"; +SET GLOBAL gtid_slave_pos = ""; +RESET MASTER; +SET GLOBAL gtid_slave_pos = "0-1-1"; + +START SLAVE; +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; + +--echo *** MDEV-4688: Empty value of @@GLOBAL.gtid_slave_pos *** +# The problem was that record_gtid() deleted too much of the in-memory state, +# leaving the state empty until after commit when we add the newly committed +# GTID. Test this by forcing an error after the delete of the old data but +# before the add of new data. + +--source include/stop_slave.inc + +--connection master +# This will be GTID 0-1-3 +INSERT INTO t1 VALUES (5); +--source include/save_master_gtid.inc + +--connection slave +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,dummy_disable_default_dbug_output"; +SET GLOBAL debug_dbug="+d,gtid_fail_after_record_gtid"; +SET sql_log_bin=0; +CALL mtr.add_suppression('Got error 131 "Command not supported by the engine" during COMMIT'); +SET sql_log_bin=1; +START SLAVE; +--let $slave_sql_errno= 1180 +--source include/wait_for_slave_sql_error.inc +# The bug was that @@GLOBAL.gtid_slave_pos was empty here. +SELECT @@GLOBAL.gtid_slave_pos; +SELECT * FROM t1 ORDER BY a; +SET GLOBAL debug_dbug= @old_dbug; +START SLAVE SQL_THREAD; +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; + + +--echo *** Test slave requesting a GTID that is not present in the master's binlog *** +--source include/stop_slave.inc +SET GLOBAL gtid_slave_pos = "0-1-4"; +START SLAVE; + +SET sql_log_bin=0; +CALL mtr.add_suppression("Got fatal error .* from master when reading data from binary log: 'Error: connecting slave requested to start from GTID .*, which is not in the master's binlog'"); +SET sql_log_bin=1; +--let $slave_io_errno= 1236 +--source include/wait_for_slave_io_error.inc +--let $status_items= Slave_IO_State, Last_IO_Errno, Last_IO_Error, Using_Gtid +--source include/show_slave_status.inc + +--let $rpl_only_running_threads= 1 +--source include/stop_slave.inc +SET GLOBAL gtid_slave_pos = "0-1-3"; +START SLAVE; +--source include/wait_for_slave_to_start.inc + +--connection master +INSERT INTO t1 VALUES (6); +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; + + +--echo *** MDEV-4278: Slave does not detect that master is not GTID-aware *** + +--connection slave +--source include/stop_slave.inc + +--connection master +SET @old_dbug= @@global.DEBUG_DBUG; +SET GLOBAL debug_dbug="+d,simulate_non_gtid_aware_master"; + +--connection slave +START SLAVE; +--let $slave_io_errno= 1233 +--source include/wait_for_slave_io_error.inc + +--connection master +SET GLOBAL debug_dbug= @old_dbug; +INSERT INTO t1 VALUES (7); +--save_master_pos + +--connection slave +START SLAVE; +--sync_with_master +SET sql_log_bin=0; +CALL mtr.add_suppression("The slave I/O thread stops because master does not support MariaDB global transaction id"); +SET sql_log_bin=1; + + +--echo *** Test error during record_gtid() (non-xid cases) *** + +--connection slave +--source include/stop_slave.inc + +--connection master +CREATE TABLE t2 (a INT) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1); +--save_master_pos + +--connection slave +SET @old_dbug= @@global.DEBUG_DBUG; +SET GLOBAL debug_dbug="+d,gtid_inject_record_gtid"; + +START SLAVE; +--let $slave_sql_errno= 1942 +--source include/wait_for_slave_sql_error.inc + +SET GLOBAL debug_dbug= @old_dbug; + +START SLAVE SQL_THREAD; +--sync_with_master + +SELECT * FROM t2; +SET sql_log_bin=0; +CALL mtr.add_suppression("Slave: Could not update replication slave gtid state"); +SET sql_log_bin=1; + + +--echo *** MDEV-4906: When event apply fails, next SQL thread start erroneously commits the failing GTID to gtid_slave_pos *** + +--connection slave +--source include/stop_slave.inc +SET sql_log_bin=0; +DELETE FROM t2; +SET sql_log_bin=1; +SET @old_format=@@binlog_format; +SET GLOBAL binlog_format='row'; +--source include/start_slave.inc + +--connection master +SET @old_format=@@binlog_format; +SET binlog_format='row'; +--let $gtid_pos1=`SELECT @@GLOBAL.gtid_binlog_pos` +DELETE FROM t2; +SET binlog_format=@old_format; +--save_master_pos + +--connection slave +--let $slave_sql_errno= 1032 +--source include/wait_for_slave_sql_error.inc +# Disable query to avoid result file update if precise GTID value changes. +--disable_query_log +SET @x=@@GLOBAL.gtid_slave_pos; +eval SELECT IF(@x='$gtid_pos1', "OK", CONCAT("ERROR: expected $gtid_pos1 got ", @x)) AS result; +--enable_query_log + +# The bug was that upon restarting the SQL thread, the GTID for the +# failing event group was not cleared, so we would update it in the +# gtid_slave_pos as part of the first rotate event, corrupting the +# replication. +STOP SLAVE IO_THREAD; +START SLAVE; +--let $slave_sql_errno= 1032 +--source include/wait_for_slave_sql_error.inc +# Disable query to avoid result file update if precise GTID value changes. +--disable_query_log +SET @x=@@GLOBAL.gtid_slave_pos; +eval SELECT IF(@x='$gtid_pos1', "OK", CONCAT("ERROR: expected $gtid_pos1 got ", @x)) AS result; +--enable_query_log + +STOP SLAVE IO_THREAD; +SET sql_log_bin=0; +INSERT INTO t2 VALUES (1); +CALL mtr.add_suppression("Slave: Can't find record in 't2' Error_code: 1032"); +SET sql_log_bin=1; +--source include/start_slave.inc +--sync_with_master +SET GLOBAL binlog_format=@old_format; + +--connection master +DROP TABLE t1; +DROP TABLE t2; + +call mtr.add_suppression("Can't find record in 't2'"); + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_errorlog.test b/mysql-test/suite/rpl/t/rpl_gtid_errorlog.test new file mode 100644 index 00000000..ea321062 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_errorlog.test @@ -0,0 +1,85 @@ +--source include/have_debug.inc +--source include/master-slave.inc + +connection master; +SET GLOBAL BINLOG_CHECKSUM=NONE; +connection slave; +SET GLOBAL BINLOG_CHECKSUM=NONE; + +--echo *** Test MDEV-6120, output of current GTID when a replication error is logged to the errorlog *** +--connection master +CREATE TABLE t1(a INT PRIMARY KEY); +--sync_slave_with_master + +--connection slave +--source include/stop_slave.inc +CHANGE MASTER TO master_use_gtid=slave_pos; + +--connection master +INSERT INTO t1 VALUES (1); +SET gtid_seq_no=100; +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (3); +INSERT INTO t1 VALUES (4); +--save_master_pos + +--connection slave +SET sql_log_bin=0; +INSERT INTO t1 VALUES (2); +SET sql_log_bin=1; + +START SLAVE; +--let $slave_sql_errno=1062 +--source include/wait_for_slave_sql_error.inc + +--source include/stop_slave.inc +# Skip the problem event from the master. +SET GLOBAL gtid_slave_pos= "0-1-100"; +--source include/start_slave.inc +--sync_with_master + +SELECT * FROM t1 ORDER BY a; + +--connection master + +SET @dbug_save= @@debug_dbug; +SET debug_dbug= '+d,incident_database_resync_on_replace'; +REPLACE INTO t1 VALUES (5); +SET debug_dbug= @dbug_save; +--save_master_pos + +--connection slave +--let $slave_sql_errno=1590 +--source include/wait_for_slave_sql_error.inc +--source include/stop_slave.inc +SET sql_slave_skip_counter=1; +--source include/start_slave.inc +--sync_with_master + +SELECT * FROM t1 ORDER BY a; + + +# Check error log for correct messages. +let $log_error_= `SELECT @@GLOBAL.log_error`; +if(!$log_error_) +{ + # MySQL Server on windows is started with --console and thus + # does not know the location of its .err log, use default location + let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.2.err; +} +--let SEARCH_FILE=$log_error_ +--let SEARCH_PATTERN=Slave SQL: Error 'Duplicate entry .* on query\. .*Query: '.*', Gtid 0-1-100, Internal MariaDB error code:|Slave SQL: Could not execute Write_rows.*table test.t1; Duplicate entry.*, Gtid 0-1-100, Internal MariaDB error +--source include/search_pattern_in_file.inc +--let SEARCH_PATTERN=Slave SQL: The incident LOST_EVENTS occurred on the master\. Message: <none>, Internal MariaDB error code: 1590 +--source include/search_pattern_in_file.inc + + +--connection master +DROP TABLE t1; + +connection master; +SET GLOBAL BINLOG_CHECKSUM=default; +connection slave; +SET GLOBAL BINLOG_CHECKSUM=default; +connection master; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_excess_initial_delay.test b/mysql-test/suite/rpl/t/rpl_gtid_excess_initial_delay.test new file mode 100644 index 00000000..6b1eec19 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_excess_initial_delay.test @@ -0,0 +1,58 @@ +# ==== Purpose ==== +# +# Test verifies that when "Master_Delay" is specified on slave with GTIDS there +# will not be any extra delay initially. +# +# ==== Implementation ==== +# +# Steps: +# 0 - Stop the slave and execute CHANGE MASTER command with +# master_delay= 10 +# 1 - On slave introduce a sleep of 15 seconds and check that the +# Seconds_Behind_Master is within specified master_delay limit. It should +# not be more that "10" seconds. +# +# ==== References ==== +# +# MDEV-13895: GTID and Master_Delay causes excessive initial delay + +--source include/have_binlog_format_mixed.inc +--source include/master-slave.inc + +CREATE TABLE t1 (i INT); +--sync_slave_with_master + +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_DELAY= 10; +--source include/start_slave.inc + +--connection master +INSERT INTO t1 VALUES (1); +--source include/sync_slave_io_with_master.inc + +--connection slave +--let $actual_delay= query_get_value(SHOW SLAVE STATUS, SQL_Delay, 1) +--let $sleep_time= `SELECT 5 + $actual_delay` +--echo "Sleeping for $sleep_time" +--sleep $sleep_time + +--let $assert_cond= [SHOW SLAVE STATUS, Seconds_Behind_Master, 1] <= 10 +--let $assert_text= Seconds_Behind_Master should be less than MASTER_DELAY +--source include/rpl_assert.inc + +# The row should be available in table after master_delay=20 seconds. +--let $assert_text= One row shoule be found in table t1. +--let $assert_cond= COUNT(*) = 1 FROM t1 +--source include/rpl_assert.inc + +--echo "======= Clean up ========" +STOP SLAVE; +CHANGE MASTER TO MASTER_DELAY=0; +START SLAVE; + +--connection master +DROP TABLE t1; +--sync_slave_with_master + +--connection master +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_glle_no_terminate.test b/mysql-test/suite/rpl/t/rpl_gtid_glle_no_terminate.test new file mode 100644 index 00000000..f0f38a31 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_glle_no_terminate.test @@ -0,0 +1,72 @@ +# +# Purpose: +# If a fake Glle event follows a Gtid event, we need to ensure the rest of +# the group should not terminate at the Glle event. MDEV-28550 revealed that +# a Glle would terminate the event and upon reconnect, the DDL would be lost. +# +# Methodology: +# Force the primary to send a fake GLLE event after a GTID on a "reconnect" +# and ensure that both 1) the replica does not error, and 2) the original +# command within the GTID is executed. +# +# References: +# MDEV-28550: improper handling of replication event group that contains Gtid_log_list_event + +--source include/master-slave.inc + +# Independent of binlog format +--source include/have_binlog_format_statement.inc + +--connection slave +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=slave_pos; + +--echo # +--echo # Initialize test data +--connection master +create table t1 (a int); +SET @@session.server_id= 3; +create table t2 (a int); +--source include/save_master_gtid.inc + +--echo # +--echo # Have the replica "reconnect" and the primary will send Gtid, Glle, DDL +--connection slave +eval set global gtid_slave_pos="0-3-1"; +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + +--echo # +--echo # Ensure that the replica did not error +connection slave; +--source include/sync_with_master_gtid.inc +let $error= query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1); +--echo Last_SQL_Error = $error +let $errno= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1); +--echo Last_SQL_Errno = $errno + +--echo # +--echo # Ensure that the primary sent a Glle after a Gtid event +let $binlog_file= query_get_value(SHOW SLAVE STATUS, Relay_Log_File, 1); +let $binlog_start= $relaylog_start; +let $binlog_limit=0,10; +--source include/show_relaylog_events.inc + +--echo # +--echo # Ensure the DDL was executed on the replica +if (!`SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'test' AND table_name = 't2'`) +{ + die "t2 should exist on slave"; +} + +--echo # +--echo # Cleanup + +--echo # t1 does not make it to the replica +--connection master +set sql_log_bin=0; +DROP TABLE t1; +set sql_log_bin=1; +DROP TABLE t2; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_grouping.test b/mysql-test/suite/rpl/t/rpl_gtid_grouping.test new file mode 100644 index 00000000..66448c4f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_grouping.test @@ -0,0 +1,97 @@ +# ==== Purpose ==== +# +# Test verifies that replicated transaction boundaries are set properly +# at receiving from master time. +# +# ==== Implementation ==== +# +# A. Simulate an unnoticeable loss of Xid event to observe a slave error, +# then restart slave to recover from the failure. +# B. Do the same to GTID event. +# +# ==== References ==== +# +# MDEV-27697 slave must recognize incomplete replication event group +# +--source include/have_binlog_format_mixed.inc +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/master-slave.inc + +--connection slave +call mtr.add_suppression("Unexpected break of being relay-logged GTID 0-27697-1000"); +call mtr.add_suppression("Relay log write failure: could not queue event from master"); +call mtr.add_suppression("The current group of events starts with a non-GTID"); + +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc + +--connection master +CREATE TABLE t (a INT) ENGINE=innodb; +INSERT INTO t VALUES(1); +save_master_pos; + +--echo ### A. Simulate an unnoticeable loss of Xid event +--sync_slave_with_master +SET @@global.debug_dbug="+d,slave_discard_xid_for_gtid_0_x_1000"; + +--connection master +SET @@gtid_seq_no=1000; +set @@server_id=27697; +INSERT INTO t VALUES(1000); +set @@server_id=default; +INSERT INTO t VALUES(1001); + +--echo ## Prove the error occurs. +--connection slave +# ER_SLAVE_RELAY_LOG_WRITE_FAILURE +--let $slave_io_errno = 1595 +--source include/wait_for_slave_io_error.inc +## EOP + +--echo ## Prove the slave recovers after the simulation condtion is lifted. +SET @@global.debug_dbug=default; +--source include/start_slave.inc + +--echo ### B. Do the same to GTID event. +--connection slave +SET @@global.debug_dbug="+d,slave_discard_gtid_0_x_1002"; + +--connection master +SET @@gtid_seq_no=1002; +set @@server_id=27697; +INSERT INTO t VALUES(1002); +set @@server_id=default; +INSERT INTO t VALUES(1003); + +--echo ## Prove the error occurs. +--connection slave +# ER_SLAVE_RELAY_LOG_WRITE_FAILURE +--let $slave_io_errno = 1595 +--source include/wait_for_slave_io_error.inc +## EOP + +--echo ## Prove the slave recovers after the simulation condtion is lifted. +SET @@global.debug_dbug=default; +--source include/start_slave.inc + +--connection master +save_master_pos; + +--sync_slave_with_master +## EOP + +--let $diff_tables=master:t,slave:t +--source include/diff_tables.inc + +--echo "===== Clean up =====" +--connection slave +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=no; +--source include/start_slave.inc + +--connection master +DROP TABLE t; +SET GLOBAL LOG_WARNINGS=default; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_ignored.test b/mysql-test/suite/rpl/t/rpl_gtid_ignored.test new file mode 100644 index 00000000..3c1324b2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_ignored.test @@ -0,0 +1,141 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc + +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; + +SET @old_gtid_strict_mode= @@GLOBAL.gtid_strict_mode; +SET GLOBAL gtid_strict_mode= 1; + +--connection server_2 +--source include/stop_slave.inc +SET @old_gtid_strict_mode= @@GLOBAL.gtid_strict_mode; +SET GLOBAL gtid_strict_mode=1; +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_1 +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +--save_master_pos + +--connection server_2 +--sync_with_master + +--echo **** MDEV-4488: GTID position should be updated for events that are ignored due to server id *** +--source include/stop_slave.inc +CHANGE MASTER TO ignore_server_ids=(1); +--source include/start_slave.inc + +--connection server_1 +# These inserts should be ignored (not applied) on the slave, but the +# gtid_slave_pos should still be updated. +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (3); +--save_master_pos +--let gtid_pos=`SELECT @@GLOBAL.gtid_binlog_pos` + +--connection server_2 +--sync_with_master +--let $wait_condition= SELECT @@GLOBAL.gtid_slave_pos = '$gtid_pos' +--source include/wait_condition.inc +--disable_query_log +eval SELECT IF(@@GLOBAL.gtid_slave_pos = '$gtid_pos', 'OK', CONCAT("ERROR: Expected $gtid_pos got ", @@GLOBAL.gtid_slave_pos)) AS RESULT; +--enable_query_log + +SELECT * FROM t1 ORDER BY a; + +--source include/stop_slave.inc +CHANGE MASTER TO ignore_server_ids=(); +--source include/start_slave.inc +--sync_with_master +--disable_query_log +eval SELECT IF(@@GLOBAL.gtid_slave_pos = '$gtid_pos', 'OK', CONCAT("ERROR: Expected $gtid_pos got ", @@GLOBAL.gtid_slave_pos)) AS RESULT; +--enable_query_log + +SELECT * FROM t1 ORDER BY a; + +--connection server_1 +INSERT INTO t1 VALUES (4); +INSERT INTO t1 VALUES (5); +--let gtid_pos=`SELECT @@GLOBAL.gtid_binlog_pos` +--save_master_pos + +--connection server_2 +--sync_with_master +--disable_query_log +eval SELECT IF(@@GLOBAL.gtid_slave_pos = '$gtid_pos', 'OK', CONCAT("ERROR: Expected $gtid_pos got ", @@GLOBAL.gtid_slave_pos)) AS RESULT; +SELECT * FROM t1 ORDER BY a; +--enable_query_log + + +--echo *** Test the same thing when IO thread exits before SQL thread reaches end of log. *** +--connection server_2 +--source include/stop_slave.inc +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug= "+d,inject_slave_sql_before_apply_event"; +CHANGE MASTER TO ignore_server_ids=(1); +--source include/start_slave.inc + +--connection server_1 +INSERT INTO t1 VALUES (6); +INSERT INTO t1 VALUES (7); +--let $master_pos= query_get_value(SHOW MASTER STATUS, Position, 1) +--let gtid_pos=`SELECT @@GLOBAL.gtid_binlog_pos` +--save_master_pos + +--connection server_2 +# Wait for IO thread to have read all events from master, and for SQL thread to +# sit in the debug_sync point. + +--let $slave_param= Read_Master_Log_Pos +--let $slave_param_value= $master_pos +--source include/wait_for_slave_param.inc + +# Now stop the IO thread, and let the SQL thread continue. The IO thread +# should write a Gtid_list event that the SQL thread can use to update the +# gtid_slave_pos with the GTIDs of the skipped events. +STOP SLAVE IO_THREAD; +SET debug_sync = "now SIGNAL continue"; + +--sync_with_master +--let $wait_condition= SELECT @@GLOBAL.gtid_slave_pos = '$gtid_pos' +--source include/wait_condition.inc +--disable_query_log +eval SELECT IF(@@GLOBAL.gtid_slave_pos = '$gtid_pos', 'OK', CONCAT("ERROR: Expected $gtid_pos got ", @@GLOBAL.gtid_slave_pos)) AS RESULT; +--let $slave_pos= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1) +eval SELECT IF('$slave_pos' = '$master_pos', 'OK', "ERROR: Expected $master_pos got $slave_pos") AS RESULT; +--enable_query_log + + +--source include/stop_slave.inc +CHANGE MASTER TO ignore_server_ids=(); +SET GLOBAL debug_dbug= @old_dbug; +--source include/start_slave.inc + +--connection server_1 +INSERT INTO t1 VALUES (8); +INSERT INTO t1 VALUES (9); +--save_master_pos + +--connection server_2 +--sync_with_master +SELECT * FROM t1 ORDER BY a; + +# Clean up. +--connection server_1 +DROP TABLE t1; +ALTER TABLE mysql.gtid_slave_pos ENGINE=Aria; +SET GLOBAL gtid_strict_mode= @old_gtid_strict_mode; +SET debug_sync = "reset"; + +--connection server_2 +SET GLOBAL gtid_strict_mode= @old_gtid_strict_mode; +SET debug_sync = "reset"; + +--source include/rpl_end.inc + diff --git a/mysql-test/suite/rpl/t/rpl_gtid_master_promote.cnf b/mysql-test/suite/rpl/t/rpl_gtid_master_promote.cnf new file mode 100644 index 00000000..4eafa897 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_master_promote.cnf @@ -0,0 +1,35 @@ +!include ../my.cnf + +[mysqld.1] +log-slave-updates +loose-innodb + +[mysqld.2] +log-slave-updates +skip-slave-start +loose-innodb + +[mysqld.3] +log-slave-updates +skip-slave-start +loose-innodb + +[mysqld.4] +log-slave-updates +skip-slave-start +loose-innodb + +[mysqld.5] +log-slave-updates +skip-slave-start +loose-innodb + +[ENV] +SERVER_MYPORT_3= @mysqld.3.port +SERVER_MYSOCK_3= @mysqld.3.socket + +SERVER_MYPORT_4= @mysqld.4.port +SERVER_MYSOCK_4= @mysqld.4.socket + +SERVER_MYPORT_5= @mysqld.5.port +SERVER_MYSOCK_5= @mysqld.5.socket diff --git a/mysql-test/suite/rpl/t/rpl_gtid_master_promote.test b/mysql-test/suite/rpl/t/rpl_gtid_master_promote.test new file mode 100644 index 00000000..064c70b1 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_master_promote.test @@ -0,0 +1,266 @@ +--source include/have_innodb.inc +--let $rpl_topology=1->2, 1->3, 1->4, 1->5 +--source include/rpl_init.inc + +# Set up a topology with one master and 4 slaves. +# +# Replicate some events leaving the four slaves at different points +# in different domains. +# +# Then promote one slave as new master, bringing it ahead of all others +# using START SLAVE UNTIL master_gtid_pos. + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t4 (a INT, b INT, PRIMARY KEY (a,b)) Engine=InnoDB; + +# Function to extract one GTID from a list. +delimiter |; +CREATE FUNCTION extract_gtid(d VARCHAR(100), s VARCHAR(100)) + RETURNS VARCHAR(100) DETERMINISTIC +BEGIN + SET s= CONCAT(",", s, ","); + SET s= SUBSTR(s FROM LOCATE(CONCAT(",", d, "-"), s) + 1); + SET s= SUBSTR(s FROM 1 FOR LOCATE(",", s) - 1); + RETURN s; +END| +delimiter ;| + +--save_master_pos + +--connection server_2 +--sync_with_master +--source include/stop_slave.inc + +--connection server_3 +--sync_with_master +--source include/stop_slave.inc + +--connection server_4 +--sync_with_master +--source include/stop_slave.inc + +--connection server_5 +--sync_with_master +--source include/stop_slave.inc + + +# Create three separate replication streams on master server_1. +# +# Then use START SLAVE UNTIL to get the different streams interleaved +# differently spread over multiple binlogs on the different slaves, to +# test that new master promotion is able to deal with this. + +--connection server_1 + +SET gtid_domain_id= 1; +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; +--let $d1_begin= `SELECT extract_gtid("1", @@GLOBAL.gtid_binlog_pos)` +INSERT INTO t1 VALUES (1); +INSERT INTO t1 VALUES (2); +INSERT INTO t4 VALUES (1, 1); +--let $d1_mid= `SELECT extract_gtid("1", @@GLOBAL.gtid_binlog_pos)` +INSERT INTO t1 VALUES (3); +INSERT INTO t1 VALUES (4); +INSERT INTO t4 VALUES (1, 3); +--let $d1_end= `SELECT extract_gtid("1", @@GLOBAL.gtid_binlog_pos)` + +SET gtid_domain_id= 2; +CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB; +--let $d2_begin= `SELECT extract_gtid("2", @@GLOBAL.gtid_binlog_pos)` +INSERT INTO t2 VALUES (1); +INSERT INTO t2 VALUES (2); +INSERT INTO t4 VALUES (2, 1); +--let $d2_mid= `SELECT extract_gtid("2", @@GLOBAL.gtid_binlog_pos)` +INSERT INTO t2 VALUES (3); +INSERT INTO t2 VALUES (4); +INSERT INTO t4 VALUES (2, 3); +--let $d2_end= `SELECT extract_gtid("2", @@GLOBAL.gtid_binlog_pos)` + +SET gtid_domain_id= 3; +CREATE TABLE t3 (a INT PRIMARY KEY) ENGINE=InnoDB; +--let $d3_begin= `SELECT extract_gtid("3", @@GLOBAL.gtid_binlog_pos)` +INSERT INTO t3 VALUES (1); +INSERT INTO t3 VALUES (2); +INSERT INTO t4 VALUES (3, 1); +--let $d3_mid= `SELECT extract_gtid("3", @@GLOBAL.gtid_binlog_pos)` +INSERT INTO t3 VALUES (3); +INSERT INTO t3 VALUES (4); +INSERT INTO t4 VALUES (3, 3); +--let $d3_end= `SELECT extract_gtid("3", @@GLOBAL.gtid_binlog_pos)` + + +# Slave server_2 (that will be promoted to master) is in the middle +# of each stream. +--connection server_2 +eval START SLAVE UNTIL master_gtid_pos= "$d1_mid,$d2_mid,$d3_mid"; + +# The remaining slaves sit at different points each in different domains. +--connection server_3 +eval START SLAVE UNTIL master_gtid_pos= "$d1_begin,$d2_mid,$d3_end"; +--connection server_4 +eval START SLAVE UNTIL master_gtid_pos= "$d2_begin,$d3_mid,$d1_end"; +--connection server_5 +eval START SLAVE UNTIL master_gtid_pos= "$d3_begin,$d1_mid,$d2_end"; +--connection server_2 +--source include/wait_for_slave_to_stop.inc +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; +SELECT * FROM t4 ORDER BY a,b; +--connection server_3 +--source include/wait_for_slave_to_stop.inc +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; +SELECT * FROM t4 ORDER BY a,b; +--connection server_4 +--source include/wait_for_slave_to_stop.inc +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; +SELECT * FROM t4 ORDER BY a,b; +--connection server_5 +--source include/wait_for_slave_to_stop.inc +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; +SELECT * FROM t4 ORDER BY a,b; + + +--echo *** Now replicate all extra changes from 3,4,5 to 2, in preparation for making 2 the new master. *** + +--connection server_3 +--let $server3_pos= `SELECT @@GLOBAL.gtid_slave_pos` +--connection server_2 +--replace_result $SERVER_MYPORT_3 SERVER_MYPORT_3 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_3; +--replace_result $server3_pos SERVER3_POS +eval START SLAVE UNTIL master_gtid_pos = "$server3_pos"; +--source include/wait_for_slave_to_stop.inc +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; +SELECT * FROM t4 ORDER BY a,b; + +--connection server_4 +--let $server4_pos= `SELECT @@GLOBAL.gtid_slave_pos` +--connection server_2 +--replace_result $SERVER_MYPORT_4 SERVER_MYPORT_4 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_4; +--replace_result $server4_pos SERVER4_POS +eval START SLAVE UNTIL master_gtid_pos = "$server4_pos"; +--source include/wait_for_slave_to_stop.inc +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; +SELECT * FROM t4 ORDER BY a,b; + +--connection server_5 +--let $server5_pos= `SELECT @@GLOBAL.gtid_slave_pos` +--connection server_2 +--replace_result $SERVER_MYPORT_5 SERVER_MYPORT_5 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_5; +--replace_result $server5_pos SERVER5_POS +eval START SLAVE UNTIL master_gtid_pos = "$server5_pos"; +--source include/wait_for_slave_to_stop.inc +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; +SELECT * FROM t4 ORDER BY a,b; + +--echo *** Now make 2 master and point 3,4,5 to the new master 2 +--connection server_2 +SET gtid_domain_id= 1; +INSERT INTO t1 values (5); +INSERT INTO t4 values (1,5); +SET gtid_domain_id= 2; +INSERT INTO t2 values (5); +INSERT INTO t4 values (2,5); +SET gtid_domain_id= 3; +INSERT INTO t3 values (5); +INSERT INTO t4 values (3,5); + +--connection server_3 +--replace_result $SERVER_MYPORT_2 SERVER_MYPORT_2 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_2; +--source include/start_slave.inc +--connection server_4 +--replace_result $SERVER_MYPORT_2 SERVER_MYPORT_2 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_2; +--source include/start_slave.inc +--connection server_5 +--replace_result $SERVER_MYPORT_2 SERVER_MYPORT_2 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_2; +--source include/start_slave.inc + +--connection server_2 +--save_master_pos + +--connection server_3 +--sync_with_master +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; +SELECT * FROM t4 ORDER BY a,b; +--connection server_5 +--sync_with_master +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; +SELECT * FROM t4 ORDER BY a,b; +--connection server_5 +--sync_with_master +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; +SELECT * FROM t4 ORDER BY a,b; + + +--echo *** Now let the old master join up as slave. *** +--connection server_1 +--replace_result $SERVER_MYPORT_2 SERVER_MYPORT_2 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_2, + master_user = "root", master_use_gtid = slave_pos, master_demote_to_slave=1; +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; +SELECT * FROM t4 ORDER BY a,b; + + +--echo *** Finally move things back and clean up. *** +--connection server_1 +--source include/stop_slave.inc +RESET SLAVE ALL; + +--connection server_2 +--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_1; +--source include/start_slave.inc +--connection server_3 +--source include/stop_slave.inc +--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_1; +--source include/start_slave.inc +--connection server_4 +--source include/stop_slave.inc +--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_1; +--source include/start_slave.inc +--connection server_5 +--source include/stop_slave.inc +--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_1; +--source include/start_slave.inc + +--connection server_1 +SET gtid_domain_id = 0; +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; +DROP FUNCTION extract_gtid; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_mdev4473.cnf b/mysql-test/suite/rpl/t/rpl_gtid_mdev4473.cnf new file mode 100644 index 00000000..4fe90e6a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_mdev4473.cnf @@ -0,0 +1,18 @@ +!include ../my.cnf + +[mysqld.1] +log-slave-updates +loose-innodb + +[mysqld.2] +log-slave-updates +loose-innodb + +[mysqld.3] +log-slave-updates +loose-innodb + +[ENV] +SERVER_MYPORT_3= @mysqld.3.port +SERVER_MYSOCK_3= @mysqld.3.socket + diff --git a/mysql-test/suite/rpl/t/rpl_gtid_mdev4473.test b/mysql-test/suite/rpl/t/rpl_gtid_mdev4473.test new file mode 100644 index 00000000..f52e51c2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_mdev4473.test @@ -0,0 +1,72 @@ +--source include/have_innodb.inc +--source include/have_binlog_format_mixed.inc + +--let $rpl_topology=1->2,1->3 +--source include/rpl_init.inc + +connection server_1; +create table t1 (n int); +insert into t1 values (1); +insert into t1 values (2); +save_master_pos; + +connection server_3; +sync_with_master; +source include/stop_slave.inc; +source include/wait_for_slave_to_stop.inc; + +connection server_2; +sync_with_master; +source include/stop_slave.inc; +source include/wait_for_slave_to_stop.inc; +reset slave all; + +connection server_1; +--replace_result $SERVER_MYPORT_2 SERVER_MYPORT_2 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_2, + master_user='root', MASTER_USE_GTID=SLAVE_POS, master_demote_to_slave=1; +source include/start_slave.inc; +source include/wait_for_slave_to_start.inc; + +connection server_2; +flush logs; +insert into t1 values (3); +insert into t1 values (4); +flush logs; +save_master_pos; + +connection server_3; +--replace_result $SERVER_MYPORT_2 SERVER_MYPORT_2 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_2, + MASTER_USE_GTID=SLAVE_POS; +source include/start_slave.inc; +sync_with_master; + +select * from t1 order by n; +source include/show_binary_logs.inc; +let $binlog_file=LAST; +source include/show_binlog_events.inc; + +connection server_1; +--sync_with_master +source include/stop_slave.inc; +source include/wait_for_slave_to_stop.inc; +reset slave all; + +connection server_2; +--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_1, + master_user = 'root', MASTER_USE_GTID=SLAVE_POS, master_demote_to_slave=1; +source include/start_slave.inc; + +connection server_3; +source include/stop_slave.inc; +--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_1, + MASTER_USE_GTID=SLAVE_POS; +source include/start_slave.inc; + +connection server_1; +drop table t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_mdev4474.cnf b/mysql-test/suite/rpl/t/rpl_gtid_mdev4474.cnf new file mode 100644 index 00000000..2b9e70c5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_mdev4474.cnf @@ -0,0 +1,11 @@ +!include suite/rpl/rpl_1slave_base.cnf +!include include/default_client.cnf + + +[mysqld.1] +log-slave-updates +loose-innodb + +[mysqld.2] +log-slave-updates +loose-innodb diff --git a/mysql-test/suite/rpl/t/rpl_gtid_mdev4474.test b/mysql-test/suite/rpl/t/rpl_gtid_mdev4474.test new file mode 100644 index 00000000..064f7b8a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_mdev4474.test @@ -0,0 +1,72 @@ +--source include/have_innodb.inc +--source include/have_binlog_format_mixed_or_statement.inc +--let $rpl_topology=1->2->1 +--source include/rpl_init.inc + +--echo # +--echo # For now we'll only have 1->2 running + +--echo # +--echo # Server 1 +--echo # Stop replication 2->1 +--connection server_1 +--source include/stop_slave.inc + +--echo # +--echo # Server 2 +--echo # Use GTID for replication 1->2 +--connection server_2 +--source include/stop_slave.inc +change master to master_use_gtid=slave_pos; +--source include/start_slave.inc + +--echo # +--echo # Create some 0-1-* and 0-2-* events in binlog of server 2 + +--connection server_1 +create table t1 (i int) engine=InnoDB; +insert into t1 values (1); +--save_master_pos + +--connection server_2 +--sync_with_master +create table t2 (i int) engine=InnoDB; +--save_master_pos + +--connection server_1 +insert into t1 values (2); +--save_master_pos + +--connection server_2 +--sync_with_master +insert into t2 values (1); +--save_master_pos + +--echo # +--echo # All events are present in the binlog of server 2 + +--source include/show_binlog_events.inc + +--echo # +--echo # Server 1 +--echo # Start replication 2->1 using GTID, + +--connection server_1 +change master to master_use_gtid=slave_pos; +--source include/start_slave.inc +--sync_with_master + +select * from t1 order by i; +select * from t2 order by i; + +--connection server_2 +select * from t1 order by i; +select * from t2 order by i; + +--connection server_1 +drop table t1; + +--connection server_2 +drop table t2; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_mdev4484.test b/mysql-test/suite/rpl/t/rpl_gtid_mdev4484.test new file mode 100644 index 00000000..5c17653d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_mdev4484.test @@ -0,0 +1,106 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/master-slave.inc + +--connection slave +--source include/stop_slave.inc +# Since we inject an error updating mysql.gtid_slave_pos, we will get different +# output depending on whether it is InnoDB or MyISAM (roll back or no roll +# back). So fix it to make sure we are consistent, in case an earlier test case +# left it as InnoDB. +SET sql_log_bin=0; +ALTER TABLE mysql.gtid_slave_pos ENGINE=Aria; +SET sql_log_bin=1; +--source include/start_slave.inc + +--connection master +CREATE TABLE t1 (i int) ENGINE=InnoDB; + +--sync_slave_with_master + +--echo *** MDEV-4484, incorrect error handling when entries in gtid_slave_pos not found. *** +TRUNCATE TABLE mysql.gtid_slave_pos; + +--connection master +INSERT INTO t1 VALUES (1); +--sync_slave_with_master + +# Inject an artificial error deleting entries, and check that the error handling code works. +--connection slave +--source include/stop_slave.inc +SET @old_gtid_cleanup_batch_size= @@GLOBAL.gtid_cleanup_batch_size; +SET GLOBAL gtid_cleanup_batch_size= 2; +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,gtid_slave_pos_simulate_failed_delete"; +SET sql_log_bin= 0; +CALL mtr.add_suppression("<DEBUG> Error deleting old GTID row"); +SET sql_log_bin= 1; +--source include/start_slave.inc + +--connection master +--disable_query_log +let $i = 20; +while ($i) { + eval INSERT INTO t1 VALUES ($i+10); + dec $i; +} +--enable_query_log +--save_master_pos + +--connection slave +--sync_with_master + +# Now wait for the slave background thread to try to delete old rows and +# hit the error injection. +--let _TEST_MYSQLD_ERROR_LOG=$MYSQLTEST_VARDIR/log/mysqld.2.err +--perl + open F, '<', $ENV{'_TEST_MYSQLD_ERROR_LOG'} or die; + outer: while (1) { + inner: while (<F>) { + last outer if /<DEBUG> Error deleting old GTID row/; + } + # Easy way to do sub-second sleep without extra modules. + select(undef, undef, undef, 0.1); + } +EOF + +# Since we injected error in the cleanup code, the rows should remain in +# mysql.gtid_slave_pos. Check that we have at least 20 (more robust against +# non-deterministic cleanup and future changes than checking for exact number). +SELECT COUNT(*), MAX(seq_no) INTO @pre_count, @pre_max_seq_no + FROM mysql.gtid_slave_pos; +SELECT IF(@pre_count >= 20, "OK", CONCAT("Error: too few rows seen while errors injected: ", @pre_count)); +SET GLOBAL debug_dbug= @old_dbug; + +--connection master +--disable_query_log +let $i = 20; +while ($i) { + eval INSERT INTO t1 VALUES ($i+40); + dec $i; +} +--enable_query_log +--sync_slave_with_master + +--connection slave +# Now check that 1) rows are being deleted again after removing error +# injection, and 2) old rows are left that failed their delete while errors +# where injected (again compensating for non-deterministic deletion). +# Deletion is async and slightly non-deterministic, so we wait for at +# least 10 of the 20 new rows to be deleted. +let $wait_condition= + SELECT COUNT(*) <= 20-10 + FROM mysql.gtid_slave_pos + WHERE seq_no > @pre_max_seq_no; +--source include/wait_condition.inc +SELECT IF(COUNT(*) >= 1, "OK", CONCAT("Error: too few rows seen after errors no longer injected: ", COUNT(*))) + FROM mysql.gtid_slave_pos + WHERE seq_no <= @pre_max_seq_no; + +# Clean up +--connection master +DROP TABLE t1; +--connection slave +SET GLOBAL gtid_cleanup_batch_size= @old_gtid_cleanup_batch_size; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_mdev4485.cnf b/mysql-test/suite/rpl/t/rpl_gtid_mdev4485.cnf new file mode 100644 index 00000000..fccef215 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_mdev4485.cnf @@ -0,0 +1,18 @@ +!include suite/rpl/rpl_1slave_base.cnf +!include include/default_client.cnf + +[mysqld.1] +log-slave-updates +gtid-domain-id=1 + +[mysqld.2] +log-slave-updates +gtid-domain-id=2 + +[mysqld.3] +log-slave-updates +gtid-domain-id=3 + +[ENV] +SERVER_MYPORT_3= @mysqld.3.port +SERVER_MYSOCK_3= @mysqld.3.socket diff --git a/mysql-test/suite/rpl/t/rpl_gtid_mdev4485.test b/mysql-test/suite/rpl/t/rpl_gtid_mdev4485.test new file mode 100644 index 00000000..6c37ceaf --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_mdev4485.test @@ -0,0 +1,41 @@ +--let $rpl_topology= 1->3 +--source include/rpl_init.inc + +--echo *** MDEV-4485. Master did not allow slave to connect from the very start (empty GTID pos) if GTIDs from other multi_source master was present *** + +--connection server_1 +create table t1 (i int); + +--connection server_2 +create table t2 (i int); + +--connection server_3 + +set default_master_connection = 'm2'; +--replace_result $SERVER_MYPORT_2 SERVER_MYPORT_2 +eval change master to master_host='127.0.0.1', master_port=$SERVER_MYPORT_2, master_user='root', master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_2 +insert into t2 values (1); +--save_master_pos + +--connection server_3 +--sync_with_master 0,'m2' + +--connection server_1 +drop table t1; + +--connection server_2 +drop table t2; +--save_master_pos + +--connection server_3 +--sync_with_master 0,'m2' +set default_master_connection = 'm2'; +--source include/stop_slave.inc +RESET SLAVE ALL; +set default_master_connection = ''; + +--connection server_1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_mdev4820.test b/mysql-test/suite/rpl/t/rpl_gtid_mdev4820.test new file mode 100644 index 00000000..7f4d851f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_mdev4820.test @@ -0,0 +1,118 @@ +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +--connection server_2 +--source include/stop_slave.inc +SET @slave_old_strict= @@GLOBAL.gtid_strict_mode; +SET GLOBAL gtid_strict_mode= 1; +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_1 +SET @master_old_strict= @@GLOBAL.gtid_strict_mode; +SET GLOBAL gtid_strict_mode= 1; +CREATE TABLE t1 (a INT PRIMARY KEY); +INSERT INTO t1 VALUES (1); +--save_master_pos + +--connection server_2 +--sync_with_master +SELECT * FROM t1 ORDER BY a; + +--source include/stop_slave.inc + +--connection server_1 +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (3); +--let $old_gtid_pos= `SELECT @@GLOBAL.gtid_current_pos` +RESET MASTER; +--replace_result $old_gtid_pos OLD_GTID_POS +eval SET GLOBAL gtid_slave_pos= '$old_gtid_pos'; + +--connection server_2 +--source include/start_slave.inc + +--connection server_1 +INSERT INTO t1 VALUES (4); +--source include/save_master_gtid.inc + +--connection server_2 +SET sql_log_bin= 0; +CALL mtr.add_suppression("The binlog on the master is missing the GTID"); +SET sql_log_bin= 1; +--let $slave_io_errno=1236 +--source include/wait_for_slave_io_error.inc + +STOP SLAVE SQL_THREAD; +--replace_result $old_gtid_pos OLD_GTID_POS +eval SET GLOBAL gtid_slave_pos= '$old_gtid_pos'; + +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; + +--source include/stop_slave.inc +RESET SLAVE ALL; +RESET MASTER; +SET GLOBAL gtid_slave_pos= '0-2-10'; + +--connection server_1 +--replace_result $SERVER_MYPORT_2 SERVER_MYPORT_2 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_2, + master_user= 'root', master_use_gtid=CURRENT_POS; +START SLAVE; + +--connection server_2 +INSERT INTO t1 VALUES (11); +--save_master_pos + +--connection server_1 +SET sql_log_bin= 0; +CALL mtr.add_suppression("which is not in the master's binlog. Since the master's binlog contains GTIDs with higher sequence numbers, it probably means that the slave has diverged"); +SET sql_log_bin= 1; +--let $slave_io_errno=1236 +--source include/wait_for_slave_io_error.inc + +--connection server_1 +STOP SLAVE SQL_THREAD; +SET GLOBAL gtid_slave_pos= '0-2-10'; +SET GLOBAL gtid_strict_mode= 0; +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 ORDER BY a; + +--source include/stop_slave.inc +RESET SLAVE ALL; +--let $old_gtid_pos= `SELECT @@GLOBAL.gtid_current_pos` +INSERT INTO t1 VALUES (12); +--save_master_pos + +--connection server_2 +INSERT INTO t1 VALUES (22); +--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_1, + master_user= 'root', master_use_gtid=CURRENT_POS; +START SLAVE; +SET sql_log_bin= 0; +CALL mtr.add_suppression("which is not in the master's binlog. Since the master's binlog contains GTIDs with higher sequence numbers, it probably means that the slave has diverged"); +SET sql_log_bin= 1; +--let $slave_io_errno=1236 +--source include/wait_for_slave_io_error.inc +STOP SLAVE SQL_THREAD; +SET GLOBAL gtid_strict_mode= 0; +CHANGE MASTER TO master_use_gtid=SLAVE_POS; +--replace_result $old_gtid_pos OLD_GTID_POS +eval SET GLOBAL gtid_slave_pos= '$old_gtid_pos'; +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 ORDER BY a; + +# Clean up. +--connection server_2 +SET GLOBAL gtid_strict_mode= @slave_old_strict; + +--connection server_1 +DROP TABLE t1; +SET GLOBAL gtid_strict_mode= @master_old_strict; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_mdev9033.cnf b/mysql-test/suite/rpl/t/rpl_gtid_mdev9033.cnf new file mode 100644 index 00000000..80b66498 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_mdev9033.cnf @@ -0,0 +1,20 @@ +!include ../my.cnf + +[mysqld.1] +log-slave-updates +loose-innodb +gtid_domain_id=1 + +[mysqld.2] +log-slave-updates +loose-innodb +gtid_domain_id=2 + +[mysqld.3] +log-slave-updates +loose-innodb +gtid_domain_id=3 + +[ENV] +SERVER_MYPORT_3= @mysqld.3.port +SERVER_MYSOCK_3= @mysqld.3.socket diff --git a/mysql-test/suite/rpl/t/rpl_gtid_mdev9033.test b/mysql-test/suite/rpl/t/rpl_gtid_mdev9033.test new file mode 100644 index 00000000..76723e1d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_mdev9033.test @@ -0,0 +1,72 @@ +--source include/have_innodb.inc +--let $rpl_topology=1->2->3 +--source include/rpl_init.inc + +--connection server_2 +--source include/stop_slave.inc +eval CHANGE MASTER TO + MASTER_USE_GTID = SLAVE_POS, IGNORE_DOMAIN_IDS = (2,3); +START SLAVE; + +--connection server_3 +--source include/stop_slave.inc +eval CHANGE MASTER TO + MASTER_USE_GTID = SLAVE_POS, IGNORE_DOMAIN_IDS = (2,3); +START SLAVE; + +connection server_1; + +CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, "m1"); +INSERT INTO t1 VALUES (2, "m2"), (3, "m3"), (4, "m4"); + +SET @@session.gtid_domain_id=2; +--echo # The following should get filetered on slave. +CREATE TABLE t2 (a INT PRIMARY KEY, b VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t2 VALUES (1, "m1"); +INSERT INTO t2 VALUES (2, "m2"), (3, "m3"), (4, "m4"); + +--source include/save_master_gtid.inc + +connection server_2; +--source include/sync_with_master_gtid.inc + +SELECT * FROM t1 ORDER BY a; +--echo # Only 't1' should have replicated to slaves. +SHOW TABLES; + +--source include/save_master_gtid.inc + +connection server_3; +--source include/sync_with_master_gtid.inc + +SELECT * FROM t1 ORDER BY a; +--echo # Only 't1' should have replicated to slaves. +SHOW TABLES; + +--echo # Cleanup +--connection server_1 +SET @@session.gtid_domain_id=1; +DROP TABLE t1; +SET @@session.gtid_domain_id=2; +DROP TABLE t2; + +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc + +--source include/save_master_gtid.inc + +--connection server_3 +--source include/sync_with_master_gtid.inc + +--connection server_2 +STOP SLAVE; +CHANGE MASTER TO IGNORE_DOMAIN_IDS = (); + +--connection server_3 +STOP SLAVE; +CHANGE MASTER TO IGNORE_DOMAIN_IDS = (); + +--echo # End of test. diff --git a/mysql-test/suite/rpl/t/rpl_gtid_misc.test b/mysql-test/suite/rpl/t/rpl_gtid_misc.test new file mode 100644 index 00000000..a78b7471 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_misc.test @@ -0,0 +1,49 @@ +--source include/master-slave.inc + +--echo *** MDEV-6403: Temporary tables lost at STOP SLAVE in GTID mode if master has not rotated binlog since restart *** + +--connection master +CREATE TABLE t1 (a INT PRIMARY KEY); +--sync_slave_with_master + +--connection slave +--source include/stop_slave.inc +# Inject a duplicate key error that will make the slave stop in the middle of +# a sequence of transactions that use a temporary table. +SET sql_log_bin= 0; +INSERT INTO t1 VALUES (1); +SET sql_log_bin= 1; + +--connection master + +# Make some queries that use a temporary table. +CREATE TEMPORARY TABLE t2 LIKE t1; +INSERT INTO t2 VALUE (1); +INSERT INTO t1 SELECT * FROM t2; +DROP TEMPORARY TABLE t2; +--save_master_pos + +--connection slave +START SLAVE; +--let $slave_sql_errno=1062 +--source include/wait_for_slave_sql_error.inc + +# Restart the slave. +# The bug was that the IO thread would receive again the restart +# format_description event at the start of the master's binlog, and this +# event would cause the SQL thread to discard all active temporary tables. + +STOP SLAVE IO_THREAD; + +SET sql_log_bin= 0; +DELETE FROM t1 WHERE a=1; +SET sql_log_bin= 1; + +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 ORDER BY a; + +--connection master +DROP TABLE t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_nobinlog.cnf b/mysql-test/suite/rpl/t/rpl_gtid_nobinlog.cnf new file mode 100644 index 00000000..0ea0d951 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_nobinlog.cnf @@ -0,0 +1,9 @@ +!include ../my.cnf + +[mysqld.1] +log-slave-updates=0 +loose-innodb + +[mysqld.2] +log-slave-updates=0 +loose-innodb diff --git a/mysql-test/suite/rpl/t/rpl_gtid_nobinlog.test b/mysql-test/suite/rpl/t/rpl_gtid_nobinlog.test new file mode 100644 index 00000000..e140f335 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_nobinlog.test @@ -0,0 +1,65 @@ +--let $rpl_topology=1->2 +--source include/rpl_init.inc +--source include/have_binlog_format_statement.inc + +--connection server_1 +SET @old_strict= @@GLOBAL.gtid_strict_mode; +SET GLOBAL gtid_strict_mode= 1; +select @@global.log_slave_updates; + +CREATE TABLE t1 (a INT PRIMARY KEY, b INT); +INSERT INTO t1 VALUES (1, 1); +INSERT INTO t1 VALUES (2, 1); +--save_master_pos + +--connection server_2 +SET @old_strict= @@GLOBAL.gtid_strict_mode; +SET GLOBAL gtid_strict_mode= 1; +select @@global.log_slave_updates; + +--sync_with_master +SELECT * FROM t1 ORDER BY a; + +--source include/stop_slave.inc + +--connection server_1 +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SLAVE_MYPORT, + master_user = 'root'; +START SLAVE; +--source include/wait_for_slave_to_start.inc + +--connection server_2 +INSERT INTO t1 VALUES (3, 2); +INSERT INTO t1 VALUES (4, 2); +--source include/save_master_gtid.inc + +--source include/show_binlog_events.inc + +--connection server_1 +--source include/sync_with_master_gtid.inc + +SELECT * FROM t1 ORDER BY a; + +--source include/stop_slave.inc +RESET SLAVE; +INSERT INTO t1 VALUES (5, 1); +INSERT INTO t1 VALUES (6, 1); +--source include/save_master_gtid.inc + +--connection server_2 +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $MASTER_MYPORT; +START SLAVE; +--source include/sync_with_master_gtid.inc + +SELECT * FROM t1 ORDER BY a; + +# Cleanup. +SET GLOBAL gtid_strict_mode= @old_strict; + +--connection server_1 +SET GLOBAL gtid_strict_mode= @old_strict; +DROP TABLE t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_reconnect.test b/mysql-test/suite/rpl/t/rpl_gtid_reconnect.test new file mode 100644 index 00000000..1452d6b0 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_reconnect.test @@ -0,0 +1,201 @@ +--let $rpl_topology=1->2 +--source include/rpl_init.inc +--source include/have_innodb.inc +--source include/have_debug.inc + + +--connection server_1 +CREATE TABLE t1 (a INT); +FLUSH LOGS; +--save_master_pos + +--connection server_2 +--sync_with_master + + +# Prepare a string of events and have the slave replicate all of it. +--connection server_1 +SET gtid_domain_id=10; +INSERT INTO t1 VALUES (1); +INSERT INTO t1 VALUES (2); +SET gtid_seq_no=100; +INSERT INTO t1 VALUES (3); +INSERT INTO t1 VALUES (4); +INSERT INTO t1 VALUES (5); +--save_master_pos + +--connection server_2 +--sync_with_master +--source include/stop_slave.inc +SELECT * FROM t1 ORDER BY a; + +# Now start the slave again, but force a reconnect. There was a bug that this +# reconnect would cause duplicate events. + +--connection server_1 +# Make sure to get rid of any old binlog dump thread so it does not +# interfere with our DBUG error injection. +--source include/kill_binlog_dump_threads.inc +INSERT INTO t1 VALUES (10); +SET @old_debug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,dummy_disable_default_dbug_output"; +SET GLOBAL debug_dbug="+d,gtid_force_reconnect_at_10_1_100"; +--save_master_pos + +--connection server_2 +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 ORDER BY a; + +--source include/stop_slave.inc +TRUNCATE t1; +RESET MASTER; +SET GLOBAL gtid_slave_pos= ""; + +--connection server_1 +SET GLOBAL debug_dbug= @old_debug; +TRUNCATE t1; +RESET MASTER; + +# A1 B1 A2 B2 A3 B3, slave reached A1 and B3 and stopped. Slave starts, +# reconnects at A2. There was a bug that B2 would be duplicated. + +SET gtid_domain_id=10; +SET gtid_seq_no=50; +INSERT INTO t1 VALUES (1); +SET gtid_domain_id=11; +INSERT INTO t1 VALUES (11); +SET gtid_domain_id=10; +SET gtid_seq_no=100; +INSERT INTO t1 VALUES (2); +SET gtid_domain_id=11; +INSERT INTO t1 VALUES (12); +SET gtid_domain_id=10; +INSERT INTO t1 VALUES (3); +SET gtid_domain_id=11; +SET gtid_seq_no=200; +INSERT INTO t1 VALUES (13); + +--connection server_2 +START SLAVE UNTIL master_gtid_pos="10-1-50,11-1-200"; +--source include/wait_for_slave_to_stop.inc +SELECT * FROM t1 ORDER BY a; + +--connection server_1 +--source include/kill_binlog_dump_threads.inc +INSERT INTO t1 VALUES (20); +SET GLOBAL debug_dbug="+d,dummy_disable_default_dbug_output"; +SET GLOBAL debug_dbug="+d,gtid_force_reconnect_at_10_1_100"; +--save_master_pos + +--connection server_2 +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 ORDER BY a; + +--source include/stop_slave.inc +TRUNCATE t1; +RESET MASTER; +SET GLOBAL gtid_slave_pos= ""; + +--connection server_1 +SET GLOBAL debug_dbug= @old_debug; +TRUNCATE t1; +RESET MASTER; + +# A1 B1 A2 B2 A3 B3. START SLAVE UNTIL A1,B3, gets reconnect at B2. +# There was a bug that the UNTIL would be ignored, and A2 would be lost. + +--source include/kill_binlog_dump_threads.inc +SET gtid_domain_id= 9; +SET gtid_seq_no= 50; +INSERT INTO t1 VALUES (1); +SET gtid_domain_id= 10; +INSERT INTO t1 VALUES (11); +SET gtid_domain_id= 9; +INSERT INTO t1 VALUES (2); +SET gtid_domain_id= 10; +SET gtid_seq_no= 100; +INSERT INTO t1 VALUES (12); +SET gtid_domain_id= 9; +INSERT INTO t1 VALUES (3); +SET gtid_domain_id= 10; +SET gtid_seq_no= 200; +INSERT INTO t1 VALUES (13); +SET gtid_domain_id= 10; + +SET GLOBAL debug_dbug="+d,dummy_disable_default_dbug_output"; +SET GLOBAL debug_dbug="+d,gtid_force_reconnect_at_10_1_100"; + +--connection server_2 +START SLAVE UNTIL master_gtid_pos="9-1-50,10-1-200"; +--source include/wait_for_slave_to_stop.inc +SELECT * FROM t1 ORDER BY a; + +--connection server_1 +SET GLOBAL debug_dbug= @old_debug; +INSERT INTO t1 VALUES (20); +--save_master_pos + +--connection server_2 +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 ORDER BY a; + + +--echo *** Test when slave IO thread needs to reconnect in the middle of an event group. *** +--connection server_2 +--source include/stop_slave.inc + +TRUNCATE t1; +RESET MASTER; +SET GLOBAL gtid_slave_pos= ""; + +--connection server_1 +SET GLOBAL debug_dbug= @old_debug; +TRUNCATE t1; +RESET MASTER; + +--source include/kill_binlog_dump_threads.inc +SET GLOBAL debug_dbug="+d,dummy_disable_default_dbug_output"; +SET GLOBAL debug_dbug="+d,binlog_force_reconnect_after_22_events"; + +# 4 events for FD, fake rotate, gtid list, binlog checkpoint. +# 2 events for GTID, create table +CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB; +# 3 events for BEGIN/query/COMMIT +INSERT INTO t2 VALUES (1); +# 4 events for BEGIN/query/query/COMMIT +BEGIN; +INSERT INTO t2 VALUES (10); +INSERT INTO t2 VALUES (11); +COMMIT; +# So this event group starts after 4+2+4+3=13 events. Or 16 in row-based. +BEGIN; +INSERT INTO t2 VALUES (20); +INSERT INTO t2 VALUES (21); +INSERT INTO t2 VALUES (22); +INSERT INTO t2 VALUES (23); +INSERT INTO t2 VALUES (24); +INSERT INTO t2 VALUES (25); +INSERT INTO t2 VALUES (26); +INSERT INTO t2 VALUES (27); +INSERT INTO t2 VALUES (28); +INSERT INTO t2 VALUES (29); +COMMIT; +--save_master_pos + +--connection server_2 +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t2 ORDER BY a; + +--connection server_1 +SET GLOBAL debug_dbug= @old_debug; + + +# Clean up. +--connection server_1 +DROP TABLE t1, t2; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_sort.test b/mysql-test/suite/rpl/t/rpl_gtid_sort.test new file mode 100644 index 00000000..c31ba877 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_sort.test @@ -0,0 +1,77 @@ +--source include/have_innodb.inc +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +--echo *** Test connecting with empty GTID state to start from very beginning of binlog *** +--connection server_2 +--source include/stop_slave.inc +RESET MASTER; +RESET SLAVE; +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +SHOW VARIABLES LIKE 'gtid_current_pos'; +SHOW VARIABLES LIKE 'gtid_slave_pos'; +SHOW VARIABLES LIKE 'gtid_binlog_state'; + +--connection server_1 +RESET MASTER; +FLUSH LOGS; +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; +SET @@SESSION.gtid_domain_id=1; +INSERT INTO t1 VALUES(1); + +SET @@SESSION.gtid_domain_id=99999; +INSERT INTO t1 VALUES(3); + +SET @@SESSION.gtid_domain_id=10; +INSERT INTO t1 VALUES(4); + +SET @@SESSION.gtid_domain_id=100; +INSERT INTO t1 VALUES(5); + +SET @@SESSION.gtid_domain_id=2147483648; # 0x80000000 +INSERT INTO t1 VALUES(6); + +SET @@SESSION.gtid_domain_id=4294967295; # 0xFFFFFFFF +INSERT INTO t1 VALUES(7); + +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +SHOW VARIABLES LIKE 'gtid_current_pos'; +SHOW VARIABLES LIKE 'gtid_slave_pos'; +SHOW VARIABLES LIKE 'gtid_binlog_state'; +--save_master_pos + +--connection server_2 +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +SHOW VARIABLES LIKE 'gtid_current_pos'; +SHOW VARIABLES LIKE 'gtid_slave_pos'; +SHOW VARIABLES LIKE 'gtid_binlog_state'; +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $MASTER_MYPORT, + MASTER_USE_GTID=SLAVE_POS; +--source include/start_slave.inc +--sync_with_master +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +SHOW VARIABLES LIKE 'gtid_current_pos'; +SHOW VARIABLES LIKE 'gtid_slave_pos'; +SHOW VARIABLES LIKE 'gtid_binlog_state'; +SELECT * FROM t1; + +SET @@SESSION.gtid_domain_id=1000; +INSERT INTO t1 VALUES(8); + +SET @@SESSION.gtid_domain_id=89; +INSERT INTO t1 VALUES(9); + +SET @@SESSION.gtid_domain_id=10100000; +INSERT INTO t1 VALUES(10); + +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +SHOW VARIABLES LIKE 'gtid_current_pos'; +SHOW VARIABLES LIKE 'gtid_slave_pos'; +SHOW VARIABLES LIKE 'gtid_binlog_state'; + +# Clean up. +--connection server_1 +DROP TABLE t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_startpos.test b/mysql-test/suite/rpl/t/rpl_gtid_startpos.test new file mode 100644 index 00000000..c7bcc1bb --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_startpos.test @@ -0,0 +1,360 @@ +--source include/have_innodb.inc +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +--echo *** Test connecting with empty GTID state to start from very beginning of binlog *** +--connection server_2 +--source include/stop_slave.inc +RESET MASTER; +RESET SLAVE; + +--connection server_1 +RESET MASTER; +# Create an empty binlog file, to check that empty binlog state is handled correctly. +FLUSH LOGS; +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; +--save_master_pos + +--connection server_2 +SET GLOBAL gtid_slave_pos=""; +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $MASTER_MYPORT, + MASTER_USE_GTID=SLAVE_POS; +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1; + +--connection server_1 +INSERT INTO t1 VALUES (1); +--save_master_pos + +--connection server_2 +--sync_with_master +SELECT * FROM t1; +--source include/stop_slave.inc + +--echo *** Test that master gives error when slave asks for empty gtid pos and binlog files have been purged. *** +--connection server_1 +FLUSH LOGS; +INSERT INTO t1 VALUES (2); +--save_master_pos +--let $purge_binlogs_to=master-bin.000003 +--source include/wait_for_purge.inc +--source include/show_binary_logs.inc + +--connection server_2 +SET GLOBAL gtid_slave_pos=""; +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $MASTER_MYPORT, + MASTER_USE_GTID=SLAVE_POS; +START SLAVE; +--let $slave_io_errno= 1236 +--source include/wait_for_slave_io_error.inc +--source include/stop_slave.inc + +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $MASTER_MYPORT, + MASTER_LOG_FILE="master-bin.000003", MASTER_LOG_POS=4, MASTER_USE_GTID=NO; +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 ORDER BY a; +SET sql_log_bin=0; +call mtr.add_suppression('Could not find GTID state requested by slave in any binlog files'); +SET sql_log_bin=1; + +--echo *** Test that we give warning when explict @@gtid_slave_pos=xxx that conflicts with what is in our binary log *** +--source include/stop_slave.inc + +--connection server_1 +INSERT INTO t1 VALUES(3); +--source include/save_master_gtid.inc + +--connection server_2 +SET GLOBAL gtid_slave_pos='0-1-3'; +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $MASTER_MYPORT, + MASTER_USE_GTID=SLAVE_POS; +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER by a; +--source include/stop_slave.inc + +--connection server_1 +INSERT INTO t1 VALUES (4); +--source include/save_master_gtid.inc + +--connection server_2 +# Now add some local transactions that conflict with the GTID position +# being set for @@gtid_slave_pos. +INSERT INTO t1 VALUES (10); +DELETE FROM t1 WHERE a=10; +SET GLOBAL gtid_slave_pos='0-1-4'; + +# Try again after RESET MASTER to remove the conflicting binlog. +RESET MASTER; +SET GLOBAL gtid_slave_pos='0-1-4'; +START SLAVE; +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER by a; + +--connection server_1 +DROP TABLE t1; +--save_master_pos + +--connection server_2 +--sync_with_master + + +--echo *** MDEV-4275: I/O thread restart duplicates events in relay log *** + +--connection server_2 +--source include/stop_slave.inc +RESET SLAVE ALL; +RESET MASTER; + +--connection server_1 +RESET MASTER; + +--connection server_2 +SET GLOBAL gtid_slave_pos=''; +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO master_host='127.0.0.1', master_port=$MASTER_MYPORT, master_user='root', master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_1 +CREATE TABLE t1 (a INT PRIMARY KEY); +INSERT INTO t1 VALUES (1); +--save_master_pos + +--connection server_2 +--sync_with_master +SELECT * FROM t1; + +--source include/stop_slave_io.inc +START SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_start.inc + +--connection server_1 +INSERT INTO t1 VALUES (2); +--save_master_pos + +--connection server_2 +--sync_with_master + +SELECT * FROM t1 ORDER BY a; + + +--echo *** MDEV-4329: GTID_SLAVE_POS='' is not checked for conflicts with binlog *** + +# Test starting the slave completely from scratch, deleting all tables and +# replicating from the start of the master's binlog. This requires RESET +# MASTER is run on the slave to avoid old junk in the binlog. The bug was +# that the code did not catch the error of missing RESET MASTER when an +# empty GTID_SLAVE_POS='' was specified. + +--connection server_2 +--source include/stop_slave.inc +DROP TABLE t1; +RESET SLAVE; +SET GLOBAL gtid_slave_pos=""; +RESET MASTER; +SET GLOBAL gtid_slave_pos=""; + +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 ORDER BY a; + + +# Same thing, but this time using SQL_LOG_BIN=0 to avoid polluting the +# slave binlog. + +--connection server_2 +--source include/stop_slave.inc +SET SQL_LOG_BIN=0; +DROP TABLE t1; +SET SQL_LOG_BIN=1; +RESET SLAVE; +SET GLOBAL gtid_slave_pos=""; +# Ensure that the slave fails because of missing table to be dropped +SET @save_slave_ddl_exec_mode=@@global.slave_ddl_exec_mode; +SET GLOBAL slave_ddl_exec_mode=STRICT; + +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 ORDER BY a; + +--echo *** Test that RESET SLAVE clears the Using_Gtid flag. *** +--source include/stop_slave.inc +--let $master_use_gtid_option= No +--source include/reset_slave.inc +--let $status_items= Using_Gtid +--source include/show_slave_status.inc + +# Starting the slave now reverts to old-style position which defaults to +# the first non-purged binlog file on the master. +# This should give error due to table already existing. +START SLAVE; +--let $slave_sql_errno= 1050 +--source include/wait_for_slave_sql_error.inc + +# Going back to using GTID should fix things. +STOP SLAVE IO_THREAD; +CHANGE MASTER TO MASTER_USE_GTID=SLAVE_POS; +--source include/start_slave.inc + +--connection server_1 +INSERT INTO t1 VALUES(3); +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; +SET SQL_LOG_BIN=0; +call mtr.add_suppression("Slave: Table 't1' already exists error.* 1050"); +SET SQL_LOG_BIN=1; + + +--echo *** Test reconnecting slave with GTID after purge logs on master. *** + +--connection server_1 +FLUSH LOGS; +INSERT INTO t1 VALUES (4); +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc + +--connection server_1 +FLUSH LOGS; +FLUSH LOGS; +--let $purge_binlogs_to=master-bin.000004 +--source include/wait_for_purge.inc +--source include/show_binary_logs.inc +INSERT INTO t1 VALUES (5); +--source include/save_master_gtid.inc + +--connection server_2 +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $MASTER_MYPORT; +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; + + +--echo *** Test modifying binlog on slave and the effect on GTID state. *** + +--connection server_2 +--source include/stop_slave.inc +RESET MASTER; +SET GLOBAL gtid_slave_pos=""; + +--connection server_1 +RESET MASTER; +TRUNCATE TABLE t1; +INSERT INTO t1 VALUES (10); # Will be GTID 0-1-2 +--source include/save_master_gtid.inc + +--connection server_2 +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + +SELECT * FROM t1; +--let $value= query_get_value(SHOW SLAVE STATUS, "Using_Gtid", 1) +eval SELECT '$value' AS Using_Gtid; +--let $value= query_get_value(SHOW ALL SLAVES STATUS, "Gtid_Slave_Pos", 1) +eval SELECT '$value' AS Gtid_Slave_Pos; + +UPDATE t1 SET a=9 WHERE a=10; +UPDATE t1 SET a=10 WHERE a=9; + +--let $value= query_get_value(SHOW ALL SLAVES STATUS, "Gtid_Slave_Pos", 1) +eval SELECT '$value' AS Gtid_Slave_Pos; + +--source include/stop_slave.inc +SET GLOBAL gtid_slave_pos='0-1-2'; +RESET MASTER; +--let $value= query_get_value(SHOW ALL SLAVES STATUS, "Gtid_Slave_Pos", 1) +eval SELECT '$value' AS Gtid_Slave_Pos; +SET GLOBAL gtid_slave_pos='0-1-2'; +--source include/start_slave.inc +--let $value= query_get_value(SHOW ALL SLAVES STATUS, "Gtid_Slave_Pos", 1) +eval SELECT '$value' AS Gtid_Slave_Pos; + + +--echo *** MDEV-4483: Slave loses traditional master coordinates immediately on CHANGE MASTER TO MASTER_USE_GTID = 1 *** +--connection server_2 +--source include/stop_slave.inc +DROP TABLE t1; +RESET SLAVE ALL; +CHANGE MASTER TO MASTER_USE_GTID=NO; +RESET MASTER; +SET GLOBAL gtid_slave_pos= ""; + +# Set up old-style replication. The bug was that CHANGE MASTER would clear +# out the old-style binlog/relaylog coordinates when it should not. + +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO master_host='127.0.0.1', master_port=$MASTER_MYPORT, master_user='root', master_use_gtid=no, master_log_file="", master_log_pos= 4; + +--connection server_1 +DROP TABLE t1; +RESET MASTER; + +CREATE TABLE t1 (a INT PRIMARY KEY); +--save_master_pos + +--connection server_2 +--source include/start_slave.inc +--sync_with_master + +--source include/stop_slave.inc + +--connection server_1 +INSERT INTO t1 VALUES (1); +--let $log_file1= query_get_value(SHOW MASTER STATUS, "File", 1) +--let $log_pos1= query_get_value(SHOW MASTER STATUS, "Position", 1) +INSERT INTO t1 VALUES (2); +--let $log_file2= query_get_value(SHOW MASTER STATUS, "File", 1) +--let $log_pos2= query_get_value(SHOW MASTER STATUS, "Position", 1) +--save_master_pos + +--connection server_2 +# Get the slave to a point where the IO thread has fetched one event ahead +# of the SQL thread (we want to test that CHANGE MASTER does not mess with +# existing relay logs). +--replace_result $log_file1 LOG_FILE1 $log_pos1 LOG_POS1 +eval START SLAVE UNTIL master_log_file='$log_file1', master_log_pos=$log_pos1; +--source include/wait_for_slave_sql_to_stop.inc +SELECT * FROM t1; +--let $slave_param= Read_Master_Log_Pos +--let $slave_param_value= $log_pos2 +--source include/wait_for_slave_param.inc +--source include/stop_slave_io.inc + +# Test that we can change to GTID and back without loosing our +# old-style slave position. +CHANGE MASTER TO master_use_gtid=slave_pos; +# Unknown GTID, so slave will fail to connect. +SET GLOBAL gtid_slave_pos="0-42-42"; +SET sql_log_bin=0; +call mtr.add_suppression("Error: connecting slave requested to start from GTID"); +SET sql_log_bin=1; +START SLAVE; +--let $slave_io_errno= 1236 +--source include/wait_for_slave_io_error.inc +STOP SLAVE SQL_THREAD; +--source include/wait_for_slave_sql_to_stop.inc +CHANGE MASTER TO master_use_gtid=no; + +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 ORDER BY a; + +# Clean up. +--connection server_1 +DROP TABLE t1; +--connection server_2 +set @@global.slave_ddl_exec_mode=@save_slave_ddl_exec_mode; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_stop_start.cnf b/mysql-test/suite/rpl/t/rpl_gtid_stop_start.cnf new file mode 100644 index 00000000..c7247a80 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_stop_start.cnf @@ -0,0 +1,5 @@ +!include ../my.cnf + +[mysqld.2] +# Needed because depending on load on test machine the master restart can take long. +master_retry_count = 120 diff --git a/mysql-test/suite/rpl/t/rpl_gtid_stop_start.test b/mysql-test/suite/rpl/t/rpl_gtid_stop_start.test new file mode 100644 index 00000000..9760d4df --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_stop_start.test @@ -0,0 +1,355 @@ +if (`SELECT $PS_PROTOCOL != 0`) +{ + --skip Test temporarily disabled for ps-protocol +} +--source include/no_valgrind_without_big.inc +--let $rpl_topology=1->2 +--source include/rpl_init.inc +--source include/have_innodb.inc + +--echo *** Test normal shutdown/restart of slave server configured as a GTID slave. *** + +--connection server_1 +CREATE TABLE t1 (a INT PRIMARY KEY); +INSERT INTO t1 VALUES (1); +--save_master_pos + +--connection server_2 +--sync_with_master +--source include/stop_slave.inc + +--let $status_items= Master_Log_File,Using_Gtid +--source include/show_slave_status.inc + + +# Now try to restart the slave mysqld server without starting the slave first +# threads after the CHANGE MASTER. +# When the slave restarts, it should reconnect using GTID. +# We test that it really uses GTID by purging on the master the +# old binlog the slave would need if connecting with old style +# file name/offset. + +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF +FLUSH LOGS; +--shutdown_server +--source include/wait_until_disconnected.inc + +--connection server_1 +FLUSH LOGS; +--let $purge_binlogs_to=master-bin.000002 +--source include/wait_for_purge.inc +--source include/show_binary_logs.inc +INSERT INTO t1 VALUES (2); +FLUSH LOGS; +INSERT INTO t1 VALUES (3); +--source include/save_master_gtid.inc +--source include/show_binary_logs.inc + +# Let the slave mysqld server start again. +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +restart: --skip-slave-start=0 +EOF + +--connection server_2 +--enable_reconnect +--source include/wait_until_connected_again.inc + +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; + + +--echo *** Test normal shutdown/restart of master server, check binlog state is preserved. *** + +--connection server_1 +SET SESSION gtid_domain_id= 1; +INSERT INTO t1 VALUES (4); +--replace_column 2 # 4 # 5 # +SHOW BINLOG EVENTS IN 'master-bin.000003' LIMIT 1,1; +FLUSH LOGS; +--replace_column 2 # 4 # 5 # 6 # +SHOW BINLOG EVENTS IN 'master-bin.000004' LIMIT 1,1; + +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait +EOF +--shutdown_server +--source include/wait_until_disconnected.inc + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart +EOF + +--connection default +--enable_reconnect +--source include/wait_until_connected_again.inc +--connection server_1 +--enable_reconnect +--source include/wait_until_connected_again.inc + +--replace_column 2 # 4 # 5 # 6 # +SHOW BINLOG EVENTS IN 'master-bin.000005' LIMIT 1,1; +--source include/show_binary_logs.inc + +INSERT INTO t1 VALUES(5); +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc +FLUSH NO_WRITE_TO_BINLOG TABLES; +SELECT * FROM t1 ORDER BY a; + +--echo *** Test that @@gtid_slave_pos and @@gtid_current_pos are correctly loaded even if slave threads have not started. *** +--let $slave_pos1= `SELECT @@GLOBAL.gtid_slave_pos` +--let $current_pos1= `SELECT @@GLOBAL.gtid_current_pos` + +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF +--shutdown_server +--source include/wait_until_disconnected.inc + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +restart: --skip-slave-start=1 --skip-log-bin +EOF +--enable_reconnect +--source include/wait_until_connected_again.inc +--disable_query_log +eval SET @slave_pos1= "$slave_pos1"; +eval SET @current_pos1= "$current_pos1"; +--enable_query_log +SET @slave_pos2= @@GLOBAL.gtid_slave_pos; +SET @current_pos2= @@GLOBAL.gtid_current_pos; +SELECT IF(@slave_pos1=@slave_pos2, "OK", CONCAT(@slave_pos1, " != ", @slave_pos2)); +SELECT IF(@current_pos1=@current_pos2, "OK", CONCAT(@current_pos1, " != ", @current_pos2)); + +--connection server_1 +INSERT INTO t1 VALUES (6); +--save_master_pos + +--connection server_2 +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 ORDER BY a; + + +--echo *** MDEV-4490: Old-style master position points at the last GTID event after slave restart *** + +--connection server_1 +INSERT INTO t1 VALUES (7); +--save_master_pos + +--connection server_2 +--sync_with_master +FLUSH NO_WRITE_TO_BINLOG TABLES; +SELECT * FROM t1 ORDER BY a; + +# Now we restart the slave server. When it restarts, there is nothing new +# to replicate. Check that the position is nevertheless updated and +# MASTER_POS_WAIT() works correctly and detects that we are up-to-date. + +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF +--shutdown_server +--source include/wait_until_disconnected.inc + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +restart: --skip-slave-start=0 +EOF +--enable_reconnect +--source include/wait_until_connected_again.inc + +--source include/wait_for_slave_to_start.inc + +--connection server_1 +--save_master_pos + +--connection server_2 +--sync_with_master +SELECT * FROM t1 ORDER BY a; + + +--echo *** MDEV-4486: Allow to start old-style replication even if mysql.gtid_slave_pos is unavailable + +--connection server_2 +--source include/stop_slave.inc +CHANGE MASTER TO master_use_gtid= no; +--source include/start_slave.inc + +--connection server_1 +INSERT INTO t1 VALUES (8); +--save_master_pos + +--connection server_2 +--sync_with_master +FLUSH NO_WRITE_TO_BINLOG TABLES; +SELECT * FROM t1 ORDER BY a; +--source include/stop_slave.inc + +SET sql_log_bin= 0; +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +SET sql_log_bin= 1; + +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF +--shutdown_server +--source include/wait_until_disconnected.inc + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +restart: --skip-slave-start=1 --skip-innodb +EOF +--enable_reconnect +--source include/wait_until_connected_again.inc + +--error ER_UNKNOWN_STORAGE_ENGINE +SELECT * FROM mysql.gtid_slave_pos; +SET sql_log_bin=0; +call mtr.add_suppression("Failed to load slave replication state from table"); +call mtr.add_suppression("Unable to load replication GTID slave state"); +SET sql_log_bin=1; + +--source include/start_slave.inc +--connection server_1 +INSERT INTO t1 VALUES (9); +--save_master_pos + +--connection server_2 +--sync_with_master +FLUSH NO_WRITE_TO_BINLOG TABLES; +SELECT * FROM t1 ORDER BY a; + +# Put things back as they were. +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF +--shutdown_server +--source include/wait_until_disconnected.inc + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +restart: +EOF +--enable_reconnect +--source include/wait_until_connected_again.inc +SET sql_log_bin= 0; +ALTER TABLE mysql.gtid_slave_pos ENGINE=Aria; +SET sql_log_bin= 1; +# Do a second restart to get the mysql.gtid_slave_pos table loaded with +# the right engine. +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF +--shutdown_server +--source include/wait_until_disconnected.inc + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +restart: +EOF +--enable_reconnect +--source include/wait_until_connected_again.inc + +--source include/start_slave.inc + +--connection server_1 +INSERT INTO t1 VALUES (10); +--save_master_pos + +--connection server_2 +--sync_with_master +--source include/stop_slave.inc +CHANGE MASTER TO master_use_gtid= slave_pos; +--source include/start_slave.inc + +--echo *** MDEV-4692: mysql.gtid_slave_pos accumulates values for a domain *** +SELECT domain_id, COUNT(*) FROM mysql.gtid_slave_pos GROUP BY domain_id; + +--connection server_1 +INSERT INTO t1 VALUES (11); +--save_master_pos + +--connection server_2 +--sync_with_master +FLUSH NO_WRITE_TO_BINLOG TABLES; +SELECT domain_id, COUNT(*) FROM mysql.gtid_slave_pos GROUP BY domain_id; + +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF +--shutdown_server +--source include/wait_until_disconnected.inc + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +restart: +EOF +--enable_reconnect +--source include/wait_until_connected_again.inc +--source include/start_slave.inc + +--connection server_1 +INSERT INTO t1 VALUES (12); +INSERT INTO t1 VALUES (13); +--save_master_pos + +--connection server_2 +--sync_with_master +FLUSH NO_WRITE_TO_BINLOG TABLES; +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.old_gtid_slave_pos; +SET sql_log_bin=1; + +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF +--shutdown_server +--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.old_gtid_slave_pos 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; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_strict.test b/mysql-test/suite/rpl/t/rpl_gtid_strict.test new file mode 100644 index 00000000..56ebba82 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_strict.test @@ -0,0 +1,179 @@ +--source include/have_debug.inc +--source include/have_innodb.inc +--source include/have_binlog_format_statement.inc +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +SET sql_log_bin= 0; +call mtr.add_suppression("Error writing file .*errno: 1950"); + +SET sql_log_bin= 1; + +SET @old_gtid_strict_mode= @@GLOBAL.gtid_strict_mode; +SET GLOBAL gtid_strict_mode= 1; +--connection server_2 +--source include/stop_slave.inc +SET @old_gtid_strict_mode= @@GLOBAL.gtid_strict_mode; +SET GLOBAL gtid_strict_mode=1; +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_1 +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); + +--source include/show_binlog_events.inc + +SET server_id= 3; +--error ER_GTID_STRICT_OUT_OF_ORDER +SET gtid_seq_no= 3; +SET @old_dbug = @@session.debug_dbug; +SET SESSION debug_dbug="d,ignore_set_gtid_seq_no_check"; +SET gtid_seq_no= 3; +SET SESSION debug_dbug=@old_dbug; +--error ER_GTID_STRICT_OUT_OF_ORDER +INSERT INTO t1 VALUES (2); + +--error ER_GTID_STRICT_OUT_OF_ORDER +SET gtid_seq_no= 2; +SET SESSION debug_dbug="d,ignore_set_gtid_seq_no_check"; +SET gtid_seq_no= 2; +SET SESSION debug_dbug=@old_dbug; +--error ER_GTID_STRICT_OUT_OF_ORDER +INSERT INTO t1 VALUES (3); +SET server_id= 1; +SET gtid_seq_no= 4; +INSERT INTO t1 VALUES (4); +SELECT * FROM t1 ORDER BY 1; +--source include/show_binlog_events.inc + +--echo *** Test non-transactional GTID error (cannot be rolled back). *** +SET server_id= 3; +--error ER_GTID_STRICT_OUT_OF_ORDER +SET gtid_seq_no= 1; +SET SESSION debug_dbug="d,ignore_set_gtid_seq_no_check"; +SET gtid_seq_no= 1; +SET SESSION debug_dbug=@old_dbug; +--error ER_GTID_STRICT_OUT_OF_ORDER +CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=MyISAM; +# The table is still created, DDL cannot be rolled back. +# Fix it up for replication. +SET sql_log_bin= 0; +DROP TABLE t2; +SET sql_log_bin= 1; +CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=MyISAM; + +--error ER_GTID_STRICT_OUT_OF_ORDER +SET gtid_seq_no= 1; +SET SESSION debug_dbug="d,ignore_set_gtid_seq_no_check"; +SET gtid_seq_no= 1; +SET SESSION debug_dbug=@old_dbug; +--error ER_GTID_STRICT_OUT_OF_ORDER +INSERT INTO t2 VALUES (1); +# The value is still inserted, cannot be rolled back. +SET server_id= 1; +SET gtid_seq_no= 6; +INSERT INTO t2 VALUES (2); +SELECT * FROM t2 ORDER BY a; +--source include/show_binlog_events.inc + + +--echo *** Test that slave stops if it tries to apply a GTID that would create out-of-order binlog GTID sequence numbers. *** + +--save_master_pos +--connection server_2 +--sync_with_master + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SET sql_log_bin= 0; +call mtr.add_suppression("An attempt was made to binlog GTID .* which would create an out-of-order sequence number with existing GTID .*, and gtid strict mode is enabled"); +call mtr.add_suppression("The binlog on the master is missing the GTID [-0-9]+ requested by the slave"); +SET sql_log_bin= 1; + +# Create some out-of-order stuff on slave. +INSERT INTO t1 VALUES (5); + +--connection server_1 +INSERT INTO t1 VALUES (6); +--save_master_pos + +--connection server_2 +--let $slave_sql_errno=1950 +--source include/wait_for_slave_sql_error.inc +STOP SLAVE IO_THREAD; +SET GLOBAL gtid_strict_mode=0; +--source include/start_slave.inc +--sync_with_master +SET GLOBAL gtid_strict_mode=1; +SELECT * FROM t1 ORDER BY a; + +INSERT INTO t1 VALUES (7); +--connection server_1 +CREATE TABLE t3 (a INT PRIMARY KEY); +--save_master_pos + +--connection server_2 +--let $slave_sql_errno=1950 +--source include/wait_for_slave_sql_error.inc +--error ER_NO_SUCH_TABLE +--query_vertical SHOW CREATE TABLE t3 +STOP SLAVE IO_THREAD; +SET GLOBAL gtid_strict_mode=0; +--source include/start_slave.inc +--sync_with_master +SET GLOBAL gtid_strict_mode=1; +--query_vertical SHOW CREATE TABLE t3 + +INSERT INTO t1 VALUES (8); +--connection server_1 +INSERT INTO t2 VALUES (3); +--save_master_pos + +--connection server_2 +--let $slave_sql_errno=1950 +--source include/wait_for_slave_sql_error.inc +SELECT * FROM t2 ORDER BY a; +STOP SLAVE IO_THREAD; +SET GLOBAL gtid_strict_mode=0; +--source include/start_slave.inc +--sync_with_master +SET GLOBAL gtid_strict_mode=1; +SELECT * FROM t2 ORDER BY a; + + +--echo *** Check slave requests starting from a hole on the master. *** +--connection server_2 +--source include/stop_slave.inc + +--connection server_1 +INSERT INTO t1 VALUES (10); +SET gtid_seq_no= 100; +INSERT INTO t1 VALUES (11); +INSERT INTO t1 VALUES (12); +--save_master_pos + +--connection server_2 +SET GLOBAL gtid_slave_pos= "0-1-50"; +START SLAVE; +--let $slave_io_errno=1236 +--source include/wait_for_slave_io_error.inc +STOP SLAVE SQL_THREAD; +SET GLOBAL gtid_strict_mode= 0; +--source include/start_slave.inc +--sync_with_master + +SELECT * FROM t1 ORDER BY a; +SET GLOBAL gtid_strict_mode= 1; + + +# Clean up. +--connection server_1 +DROP TABLE t1, t2, t3; +SET GLOBAL gtid_strict_mode= @old_gtid_strict_mode; +--connection server_2 +SET GLOBAL gtid_strict_mode= @old_gtid_strict_mode; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_until.test b/mysql-test/suite/rpl/t/rpl_gtid_until.test new file mode 100644 index 00000000..c89cea23 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_gtid_until.test @@ -0,0 +1,253 @@ +--source include/have_innodb.inc +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +--connection server_2 +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=NO; +--source include/start_slave.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +# Function to extract one GTID from a list. +delimiter |; +CREATE FUNCTION extract_gtid(d VARCHAR(100), s VARCHAR(100)) + RETURNS VARCHAR(100) DETERMINISTIC +BEGIN + SET s= CONCAT(",", s, ","); + SET s= SUBSTR(s FROM LOCATE(CONCAT(",", d, "-"), s) + 1); + SET s= SUBSTR(s FROM 1 FOR LOCATE(",", s) - 1); + RETURN s; +END| +delimiter ;| +--save_master_pos + +--connection server_2 +--sync_with_master +# Restart SQL thread to pick up ALTER TABLE of mysql.gtid_slave_pos. +--source include/stop_slave.inc +--source include/start_slave.inc + +# Both replication threads must be stopped for UNTIL master_gtid_pos. +--error ER_SLAVE_WAS_RUNNING +START SLAVE UNTIL master_gtid_pos = ""; +--source include/stop_slave_io.inc +--error ER_SLAVE_WAS_RUNNING +START SLAVE UNTIL master_gtid_pos = ""; +START SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_start.inc +--source include/stop_slave_sql.inc +--error ER_SLAVE_WAS_RUNNING +START SLAVE UNTIL master_gtid_pos = ""; +--source include/stop_slave_io.inc +# UNTIL master_gtid_pos only valid if GTID is used. + +--error ER_UNTIL_REQUIRES_USING_GTID +START SLAVE UNTIL master_gtid_pos = ""; + +CHANGE MASTER TO master_use_gtid=slave_pos; + +--connection server_1 +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES(1); +--let $gtid_pos=`SELECT @@GLOBAL.gtid_binlog_pos` +INSERT INTO t1 VALUES(2); + +--connection server_2 + +# Test various incorrect syntax for UNTIL master_gtid_pos. +--error ER_DUPLICATE_GTID_DOMAIN +START SLAVE UNTIL master_gtid_pos = "0-1-100,1-1-100,2-2-200,1-3-100,4-4-400"; +--error ER_PARSE_ERROR +START SLAVE UNTIL master_log_file = "master-bin.000001", master_log_pos = 4, master_gtid_pos = ""; +--error ER_BAD_SLAVE_UNTIL_COND +START SLAVE IO_THREAD UNTIL master_gtid_pos = ""; +--error ER_BAD_SLAVE_UNTIL_COND +START SLAVE SQL_THREAD UNTIL master_gtid_pos = ""; + +eval START SLAVE UNTIL master_gtid_pos = '$gtid_pos'; + +--source include/wait_for_slave_to_stop.inc +SELECT * FROM t1; + +--source include/start_slave.inc + +--connection server_1 +--save_master_pos + +--connection server_2 +--sync_with_master +SELECT * FROM t1 ORDER BY a; + +# Test showing the UNTIL condition in SHOW SLAVE STATUS. +--source include/stop_slave.inc +START SLAVE UNTIL master_gtid_pos = "1-10-100,2-20-200,0-1-300"; +--source include/wait_for_slave_to_start.inc +--let $status_items= Using_Gtid,Until_Condition +--source include/show_slave_status.inc + +# Clear the UNTIL condition. +# Note that we need to wait for a transaction to get through from the master. +# Otherwise the IO thread may still be in get_master_version_and_clock() +# (wait_for_slave_to_start.inc returns as soon as the IO thread is connected), +# and we can get test failures from warnings in the log about IO thread being +# killed in the middle of setting @@gtid_strict_mode or similar (MDEV-7940). +--connection server_1 +INSERT INTO t1 VALUES (3); +DELETE FROM t1 WHERE a=3; +--save_master_pos + +--connection server_2 +--sync_with_master +--source include/stop_slave.inc + + +--echo *** Test UNTIL condition in an earlier binlog than the start GTID. *** +--connection server_2 + +--connection server_1 +SET gtid_domain_id = 1; +INSERT INTO t1 VALUES (3); +SET gtid_domain_id = 2; +CREATE TABLE t2 (a INT); +INSERT INTO t2 VALUES (3); +--let $d1_point1= `SELECT extract_gtid("1", @@GLOBAL.gtid_binlog_pos)` +--let $d2_point1= `SELECT extract_gtid("2", @@GLOBAL.gtid_binlog_pos)` +FLUSH LOGS; +SET gtid_domain_id = 1; +INSERT INTO t1 VALUES (4); +SET gtid_domain_id = 2; +INSERT INTO t2 VALUES (4); +FLUSH LOGS; +SET gtid_domain_id = 1; +INSERT INTO t1 VALUES (5); +--let $d1_point2= `SELECT extract_gtid("1", @@GLOBAL.gtid_binlog_pos)` +--let $d2_point2= `SELECT extract_gtid("2", @@GLOBAL.gtid_binlog_pos)` +SET gtid_domain_id = 2; +INSERT INTO t2 VALUES (5); +FLUSH LOGS; +SET gtid_domain_id = 1; +INSERT INTO t1 VALUES (6); +--let $d1_point3= `SELECT extract_gtid("1", @@GLOBAL.gtid_binlog_pos)` +--let $d2_point3= `SELECT extract_gtid("2", @@GLOBAL.gtid_binlog_pos)` +SET gtid_domain_id = 2; +INSERT INTO t2 VALUES (6); +SET gtid_domain_id = 0; +--source include/show_binary_logs.inc +--save_master_pos + +--connection server_2 +# Let the slave reach an middle point in domain 1 and a late point in domain 2. +eval START SLAVE UNTIL master_gtid_pos='$d1_point2,$d2_point3'; +--source include/wait_for_slave_to_stop.inc +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +# Now test starting at a middle point in the binlogs when the stop position in +# one domain (domain 2) is early. +eval START SLAVE UNTIL master_gtid_pos='$d1_point3,$d2_point1'; +--source include/wait_for_slave_to_stop.inc +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +# Test that one UNTIL domain empty means stop that domain immediately. +eval START SLAVE UNTIL master_gtid_pos='$d1_point2'; +--source include/wait_for_slave_to_stop.inc +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +--echo *** Test when the UNTIL position is right at the end of the binlog file prior to the starting position *** + +--connection server_2 +--source include/stop_slave.inc + +--connection server_1 +FLUSH LOGS; +SET gtid_domain_id = 1; +INSERT INTO t1 VALUES (7); +SET gtid_domain_id = 0; +--save_master_pos + +--connection server_2 +eval START SLAVE UNTIL master_gtid_pos='$d1_point3'; +--source include/wait_for_slave_to_stop.inc +# This should not show row 7, as we requested stop just before it. +SELECT * FROM t1 ORDER BY a; +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 ORDER BY a; + + +--echo *** Test when UNTIL condition is after a stand-alone event (not a transaction). *** + +--connection server_2 +--source include/stop_slave.inc + +--connection server_1 +CREATE TABLE t3 (a INT); +--let $until_condition=`SELECT @@GLOBAL.gtid_binlog_pos` +DROP TABLE t3; +--save_master_pos + +--connection server_2 +--replace_result $until_condition UNTIL_CONDITION +eval START SLAVE UNTIL master_gtid_pos='$until_condition'; +--source include/wait_for_slave_to_stop.inc +SHOW CREATE TABLE t3; +--source include/start_slave.inc +--sync_with_master + +--echo *** Test UNTIL condition that has not yet been logged. *** + +--connection server_2 +--source include/stop_slave.inc +RESET SLAVE ALL; +RESET MASTER; +SET GLOBAL gtid_slave_pos=''; + +--connection server_1 +# Do it once to compute the right GTID, then throw it away and do it again +# for the actual test. +RESET MASTER; +INSERT INTO t1 VALUES (10); +INSERT INTO t1 VALUES (11); +--let $until_condition=`SELECT @@GLOBAL.gtid_binlog_pos` +INSERT INTO t1 VALUES (12); +DELETE FROM t1 WHERE a >= 10; + +RESET MASTER; +INSERT INTO t1 VALUES (10); + +--connection server_2 +--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1 +eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $SERVER_MYPORT_1, + master_user = "root", master_use_gtid = slave_pos; +eval START SLAVE UNTIL master_gtid_pos = '$until_condition'; +--source include/wait_for_slave_to_start.inc + +--connection server_1 +INSERT INTO t1 VALUES (11); +INSERT INTO t1 VALUES (12); +--save_master_pos + +--connection server_2 +# This then should wait until it gets the row (11) and then stop, not +# yet having the row (12). +--source include/wait_for_slave_to_stop.inc +SELECT * FROM t1 ORDER BY a; +--source include/start_slave.inc +--sync_with_master +# And now the row (12) should be there. +SELECT * FROM t1 ORDER BY a; + + +# Clean up. +--connection server_1 +DROP TABLE t1; +DROP TABLE t2; +DROP FUNCTION extract_gtid; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_heartbeat.test b/mysql-test/suite/rpl/t/rpl_heartbeat.test new file mode 100644 index 00000000..e4753b7b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_heartbeat.test @@ -0,0 +1,175 @@ +# Testing master to slave heartbeat protocol +# +# Including: +# - user interface, grammar, checking the range and warnings about +# unreasonable values for the heartbeat period; +# - no rotation of relay log if heartbeat is less that slave_net_timeout +# - SHOW STATUS like 'Slave_received_heartbeats' action +# - SHOW STATUS like 'Slave_heartbeat_period' report + +-- source include/have_log_bin.inc + +connect (master,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK); +connect (slave,localhost,root,,test,$SLAVE_MYPORT,$SLAVE_MYSOCK); + +connection master; +reset master; + +connection slave; +set @restore_slave_net_timeout= @@global.slave_net_timeout; +--disable_warnings +set @@global.slave_net_timeout= 10; +--enable_warnings + +--enable_prepare_warnings +### +### Checking the range +### + +# +# default period slave_net_timeout/2 +# +--replace_result $MASTER_MYPORT MASTER_PORT +eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root'; +--query_vertical show status like 'Slave_heartbeat_period'; + +# +# the max for the period is ULONG_MAX/1000; an attempt to exceed it is denied +# +--replace_result $MASTER_MYPORT MASTER_PORT +--error ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE +eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 4294968; +--query_vertical show status like 'Slave_heartbeat_period'; + +# +# the min value for the period is 1 millisecond an attempt to assign a +# lesser will be warned with treating the value as zero +# +connection slave; +--replace_result $MASTER_MYPORT MASTER_PORT +### 5.1 mtr does not have --warning ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE +eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 0.0009999; +--query_vertical show status like 'Slave_heartbeat_period'; + +# +# the actual max and min must be accepted +# +--replace_result $MASTER_MYPORT MASTER_PORT +eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 4294967; +--query_vertical show status like 'Slave_heartbeat_period'; + +--replace_result $MASTER_MYPORT MASTER_PORT +eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 0.001; +--query_vertical show status like 'Slave_heartbeat_period'; + +reset slave; + +# +# A warning if period greater than slave_net_timeout +# +set @@global.slave_net_timeout= 5; +--replace_result $MASTER_MYPORT MASTER_PORT +eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 5.001; +--query_vertical show status like 'Slave_heartbeat_period'; + +reset slave; + +# +# A warning if slave_net_timeout is set to less than the current HB period +# +set @@global.slave_net_timeout= 5; +--replace_result $MASTER_MYPORT MASTER_PORT +eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 4; +--query_vertical show status like 'Slave_heartbeat_period'; +set @@global.slave_net_timeout= 3 /* must be a warning */; + +reset slave; + + +### +### checking no rotation +### + +connection master; +--disable_warnings +drop table if exists t1; +--enable_warnings +# +# Even though master_heartbeat_period= 0.5 is 20 times less than +# @@global.slave_net_timeout= 10 in some circumstances master will +# not be able to send any heartbeat during the slave's net timeout +# and slave's relay log will rotate. +# The probability for such a scenario is pretty small so the following +# part is almost deterministic. +# + +connection slave; +set @@global.slave_net_timeout= 10; +--replace_result $MASTER_MYPORT MASTER_PORT +# no error this time but rather a warning +eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 0.5; +--query_vertical show status like 'Slave_heartbeat_period'; + +start slave; + +connection master; +create table t1 (f1 int); + +#connection slave; +sync_slave_with_master; +let $slave_param= Relay_Log_File; +let $slave_param_value= query_get_value(SHOW SLAVE STATUS, Relay_Log_File, 1); + +# there is an explicit sleep lasting longer than slave_net_timeout +# to ensure that nothing will come to slave from master for that period. +# That would cause reconnecting and relaylog rotation w/o the fix i.e +# without a heartbeat received. + +real_sleep 15; + +# check (compare with the previous show's results) that no rotation happened +source include/check_slave_param.inc; + +### +### SHOW STATUS like 'Slave_heartbeat_period' and 'Slave_received_heartbeats' +### + +--query_vertical show status like 'Slave_heartbeat_period'; + +# +# proof that there has been received at least one heartbeat; +# The exact number of received heartbeat is an indeterministic value +# and therefore it's not recorded into results. +# + +let $slave_wait_param_counter= 300; +let $slave_value= query_get_value("SHOW STATUS like 'Slave_received_heartbeats'", Value, 1); +# Checking the fact that at least one heartbeat is received +while (!$slave_value) +{ + dec $slave_wait_param_counter; + if (!$slave_wait_param_counter) + { + --echo ERROR: failed while waiting for slave parameter $slave_param: $slave_param_value + query_vertical show slave status; + SHOW STATUS like 'Slave_received_heartbeats'; + exit; + } + sleep 0.1; + let $slave_value= query_get_value("SHOW STATUS like 'Slave_received_heartbeats'", Value, 1); +} +--echo A heartbeat has been received by the slave +# cleanup + +connection master; +drop table t1; + +#connection slave; +sync_slave_with_master; +set @@global.slave_net_timeout= @restore_slave_net_timeout; + +--disable_prepare_warnings + +--source include/stop_slave.inc + +--echo End of tests diff --git a/mysql-test/suite/rpl/t/rpl_heartbeat_2slaves.cnf b/mysql-test/suite/rpl/t/rpl_heartbeat_2slaves.cnf new file mode 100644 index 00000000..f24de9ab --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_heartbeat_2slaves.cnf @@ -0,0 +1,12 @@ +!include ../my.cnf + +[mysqld.1] +log-slave-updates + +[mysqld.2] +log-slave-updates + +[mysqld.3] + +[ENV] +SERVER_MYPORT_3= @mysqld.3.port diff --git a/mysql-test/suite/rpl/t/rpl_heartbeat_2slaves.test b/mysql-test/suite/rpl/t/rpl_heartbeat_2slaves.test new file mode 100644 index 00000000..e0fdf668 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_heartbeat_2slaves.test @@ -0,0 +1,124 @@ +############################################################# +# Author: Serge Kozlov <Serge.Kozlov@Sun.COM> +# Date: 02/19/2009 +# Purpose: Testing heartbeat for schema +# 1 master and 2 slaves +############################################################# +--let $rpl_topology= 1->2,1->3 +--source include/rpl_init.inc + +--let $rpl_connection_name= master +--let $rpl_server_number= 1 +--source include/rpl_connect.inc + +--let $rpl_connection_name= slave_1 +--let $rpl_server_number= 2 +--source include/rpl_connect.inc + +--let $rpl_connection_name= slave_2 +--let $rpl_server_number= 3 +--source include/rpl_connect.inc + +# +# Set different heartbeat periods for slaves +# +--connection slave_1 +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_HEARTBEAT_PERIOD = 0.1; +--source include/start_slave.inc +--connection slave_2 +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_HEARTBEAT_PERIOD = 1; +--source include/start_slave.inc + +# +# Testing heartbeat for one master and two slaves +# + +# Check that heartbeat events sent to both slaves with correct periods +--connection slave_1 +let $status_var= slave_received_heartbeats; +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $status_var_comparsion= >; +--source include/wait_for_status_var.inc +--echo Slave has received heartbeat event +--connection slave_2 +let $status_var= slave_received_heartbeats; +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $status_var_comparsion= >; +--source include/wait_for_status_var.inc +--let $assert_cond= [slave_1:SHOW STATUS LIKE "slave_received_heartbeats", Value, 1] > [slave_2:SHOW STATUS LIKE "slave_received_heartbeats", Value, 1] +--let $assert_text= slave_1 should have received more heartbeats than slave_2 +--source include/assert.inc +--echo + +# Create topology master->slave_2->slave_1 and check that slave_1 +# receives heartbeat while slave_2 gets data. + +# slave_2 was started w/o --log-slave-updates because slave_2 should +# not send data from master to slave_1 + +--source include/rpl_stop_slaves.inc +--let $rpl_topology= 1->3->2 +--source include/rpl_change_topology.inc +--source include/rpl_start_slaves.inc +--connection slave_1 +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_HEARTBEAT_PERIOD=0.1; +--source include/start_slave.inc + +# Check heartbeat for new replication channel slave_2->slave +let $status_var= slave_received_heartbeats; +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $status_var_comparsion= >; +--source include/wait_for_status_var.inc +--echo slave_1 has received heartbeat event +--connection master +CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(10), c LONGTEXT); +INSERT INTO t1 VALUES (1, 'on master', ''); +SHOW TABLES; +--sync_slave_with_master slave_2 +SHOW TABLES; +let $slave_2_pos_before= query_get_value(SHOW SLAVE STATUS, Read_Master_Log_Pos, 1); +--sync_slave_with_master slave_1 +SHOW TABLES; +--connection master +--echo creating updates on master and send to slave_2 during 5 second +# Generate events on master and send to slave_2 during 5 second +let $i= 1; +let $j= 1; +let $k= 1; +--disable_query_log +while ($i) { + eval SET @c_text=REPEAT('1234567890', $j); + eval UPDATE t1 SET a=$j, c=@c_text; + --connection slave_2 + let $slave_2_pos= query_get_value(SHOW SLAVE STATUS, Read_Master_Log_Pos, 1); + if (`SELECT ($k*($slave_2_pos - $slave_2_pos_before)) > 0`) { + --connection slave_1 + let $slave_1_rcvd_heartbeats_before= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); + let $k= 0; + let $time_before = `SELECT NOW()`; + } + if (`SELECT ((1-$k)*TIMESTAMPDIFF(SECOND,'$time_before',NOW())) > 5`) { + let $i= 0; + } + --connection master + inc $j; + sleep 0.1; +} +--enable_query_log +--connection slave_1 +--let $assert_cond= [SHOW STATUS LIKE "slave_received_heartbeats", Value, 1] > $slave_1_rcvd_heartbeats_before +--let $assert_text= slave_1 should have received heartbeats +--source include/assert.inc +--echo + +# +# Clean up +# +--echo *** Clean up *** +--connection master +DROP TABLE t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_heartbeat_basic.cnf b/mysql-test/suite/rpl/t/rpl_heartbeat_basic.cnf new file mode 100644 index 00000000..a4a291bc --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_heartbeat_basic.cnf @@ -0,0 +1,7 @@ +!include ../my.cnf + +[mysqld.1] +log-slave-updates + +[mysqld.2] +log-slave-updates diff --git a/mysql-test/suite/rpl/t/rpl_heartbeat_basic.test b/mysql-test/suite/rpl/t/rpl_heartbeat_basic.test new file mode 100644 index 00000000..d6d14e02 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_heartbeat_basic.test @@ -0,0 +1,575 @@ +############################################################# +# Author: Serge Kozlov <Serge.Kozlov@Sun.COM> +# Date: 02/19/2009 +# Purpose: Testing basic functionality of heartbeat. +# Description: +# * Testing different values for slave_heartbeat_period. +# * How to affect various statements to slave_heartbeat_period +# * Various states of slave and heartbeat +# * Various states of master and heartbeat +# * Circular replication +############################################################# +--source include/master-slave.inc +# +# The test runs long and does not have any specifics to +# binlog_format. It is chosen therefore to run with MIXED mode +# in order to not slow down much `make test'. +# +--source include/have_binlog_format_mixed.inc +--echo + +--enable_prepare_warnings + +# Set number of retries to connect to master +let $connect_retry= 20; + +--echo *** Preparing *** +--connection slave +--source include/stop_slave.inc +RESET SLAVE; +SET @restore_slave_net_timeout=@@global.slave_net_timeout; +let $slave_heartbeat_timeout= query_get_value(SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period', Value, 1); +--disable_query_log +eval SET @restore_slave_heartbeat_timeout=$slave_heartbeat_timeout; +--enable_query_log + +--connection master +RESET MASTER; +SET @restore_slave_net_timeout=@@global.slave_net_timeout; +--echo + +# +# Test slave_heartbeat_period +# + +--connection slave + +# Default value of slave_heartbeat_timeout = slave_net_timeout/2 +--echo *** Default value *** +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root'; +let $slave_net_timeout= query_get_value(SHOW VARIABLES LIKE 'slave_net_timeout', Value, 1); +let $slave_heartbeat_timeout= query_get_value(SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period', Value, 1); +let $result= query_get_value(SELECT $slave_net_timeout/$slave_heartbeat_timeout AS Result, Result, 1); +--echo slave_net_timeout/slave_heartbeat_timeout=$result +--source include/reset_slave.inc +--echo + +# Reset slave set slave_heartbeat_timeout = slave_net_timeout/2 +--echo *** Reset slave affect *** +--disable_warnings +SET @@global.slave_net_timeout=30; +--enable_warnings +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=5; +--source include/reset_slave.inc +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +--echo + +# Check default value of slave_heartbeat_timeout if slave_net_timeout is changed +--echo *** Default value if slave_net_timeout changed *** +--disable_warnings +SET @@global.slave_net_timeout=50; +--enable_warnings +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +SET @@global.slave_net_timeout=@restore_slave_net_timeout; +--source include/reset_slave.inc +--echo + +# Set slave_net_timeout less than current value of slave_heartbeat_period +--echo *** Warning if updated slave_net_timeout < slave_heartbeat_timeout *** +let $slave_heartbeat_timeout= query_get_value(SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period', Value, 1); +--replace_result $slave_heartbeat_timeout SLAVE_HEARTBEAT_TIMEOUT +eval SET @@global.slave_net_timeout=FLOOR($slave_heartbeat_timeout)-1; +SET @@global.slave_net_timeout=@restore_slave_net_timeout; +RESET SLAVE; +--echo + +# Set value of slave_heartbeat_period greater than slave_net_timeout +--echo *** Warning if updated slave_heartbeat_timeout > slave_net_timeout *** +let $slave_net_timeout= query_get_value(SHOW VARIABLES LIKE 'slave_net_timeout', Value, 1); +inc $slave_net_timeout; +--replace_result $MASTER_MYPORT MASTER_PORT $slave_net_timeout SLAVE_NET_TIMEOUT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=$slave_net_timeout; +RESET SLAVE; +--echo + +# Changing of slave_net_timeout shouldn't affect to current value of slave_heartbeat_period +--echo *** CHANGE MASTER statement only updates slave_heartbeat_period *** +--disable_warnings +SET @@global.slave_net_timeout=20; +--enable_warnings +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=5; +SHOW VARIABLES LIKE 'slave_net_timeout'; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +SET @@global.slave_net_timeout=2*@@global.slave_net_timeout; +SHOW VARIABLES LIKE 'slave_net_timeout'; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +SET @@global.slave_net_timeout=@restore_slave_net_timeout; +RESET SLAVE; +--echo + +# Master value of slave_net_timeout shouldn't affect to slave's slave_heartbeat_period +--echo *** Update slave_net_timeout on master *** +--connection master +--disable_warnings +SET @@global.slave_net_timeout=500; +--enable_warnings +--connection slave +SET @@global.slave_net_timeout=200; +RESET SLAVE; +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry; +--source include/start_slave.inc +--connection master +--sync_slave_with_master +SHOW VARIABLES LIKE 'slave_net_timeout'; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +SET @@global.slave_net_timeout=@restore_slave_net_timeout; +--source include/stop_slave.inc +RESET SLAVE; +--connection master +SET @@global.slave_net_timeout=@restore_slave_net_timeout; +--echo + +# Start/stop slave shouldn't change slave_heartbeat_period +--echo *** Start/stop slave *** +--connection slave +--disable_warnings +SET @@global.slave_net_timeout=100; +--enable_warnings +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=20; +--source include/start_slave.inc +--connection master +--sync_slave_with_master +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +--source include/stop_slave.inc +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +--echo + +# Reload slave shouldn't change slave_heartbeat_period +--echo *** Reload slave *** +--connection slave +--disable_warnings +SET @@global.slave_net_timeout=50; +--enable_warnings +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=30; +--let $rpl_server_number= 2 +--source include/rpl_restart_server.inc +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +SET @restore_slave_net_timeout=@@global.slave_net_timeout; +--echo + +# Disable heartbeat +--echo *** Disable heartbeat *** +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=0; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +SHOW STATUS LIKE 'slave_received_heartbeats'; +--source include/start_slave.inc +--connection master +--sync_slave_with_master +--sleep 2 +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +SHOW STATUS LIKE 'slave_received_heartbeats'; +--source include/stop_slave.inc +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +SHOW STATUS LIKE 'slave_received_heartbeats'; +RESET SLAVE; +let $slave_heartbeat_timeout= query_get_value(SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period', Value, 1); +--replace_result $slave_heartbeat_timeout SLAVE_HEARTBEAT_TIMEOUT +--eval SELECT $slave_heartbeat_timeout = 0 AS Result +--echo + +# +# Check limits for slave_heartbeat_timeout +# + +--echo *** Min slave_heartbeat_timeout *** +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=0.001; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +RESET SLAVE; +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=0.0009; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +RESET SLAVE; +--echo + +--echo *** Max slave_heartbeat_timeout *** +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=4294967; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +RESET SLAVE; +--replace_result $MASTER_MYPORT MASTER_PORT +--error ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=4294968; +RESET SLAVE; +# Check double size of max allowed value for master_heartbeat_period +--replace_result $MASTER_MYPORT MASTER_PORT +--error ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=8589935; +RESET SLAVE; +# Check 2^32 +--replace_result $MASTER_MYPORT MASTER_PORT +--error ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=4294967296; +RESET SLAVE; +--echo + +--echo *** Misc incorrect values *** +--replace_result $MASTER_MYPORT MASTER_PORT +--error ER_PARSE_ERROR +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD='-1'; +RESET SLAVE; +--replace_result $MASTER_MYPORT MASTER_PORT +--error ER_PARSE_ERROR +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD='123abc'; +RESET SLAVE; +--replace_result $MASTER_MYPORT MASTER_PORT +--error ER_PARSE_ERROR +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=''; +RESET SLAVE; +--echo + +# +# Testing heartbeat +# + +# Check received heartbeat events for running slave +--echo *** Running slave *** +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=0.1; +--source include/start_slave.inc +--connection master +--sync_slave_with_master +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $status_var= slave_received_heartbeats; +let $status_var_comparsion= >; +--source include/wait_for_status_var.inc +--echo Heartbeat event received +--echo + +# Check received heartbeat events for stopped slave +--echo *** Stopped slave *** +--source include/stop_slave.inc +let $rcvd_heartbeats_before= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +sleep 2; +let $rcvd_heartbeats_after= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $result= query_get_value(SELECT ($rcvd_heartbeats_after - $rcvd_heartbeats_before) AS Result, Result, 1); +--echo Number of received heartbeat events while slave stopped: $result +--echo + +# Check received heartbeat events for started slave +--echo *** Started slave *** +--source include/start_slave.inc +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +--source include/wait_for_status_var.inc +--echo Heartbeat event received +--echo + +# Check received heartbeat events for stopped IO thread +--echo *** Stopped IO thread *** +--source include/stop_slave_io.inc +let $rcvd_heartbeats_before= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +sleep 2; +let $rcvd_heartbeats_after= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $result= query_get_value(SELECT ($rcvd_heartbeats_after - $rcvd_heartbeats_before) AS Result, Result, 1); +--echo Number of received heartbeat events while io thread stopped: $result +--echo + +# Check received heartbeat events for started IO thread +--echo *** Started IO thread *** +START SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_start.inc +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +--source include/wait_for_status_var.inc +--echo Heartbeat event received +--echo + +# Check received heartbeat events for stopped SQL thread +--echo *** Stopped SQL thread *** +--source include/stop_slave_sql.inc +let $rcvd_heartbeats_before= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +sleep 2; +let $rcvd_heartbeats_after= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $result= query_get_value(SELECT ($rcvd_heartbeats_after - $rcvd_heartbeats_before) > 0 AS Result, Result, 1); +--echo Heartbeat events are received while sql thread stopped (1 means 'yes'): $result +--echo + +# Check received heartbeat events for started SQL thread +--echo *** Started SQL thread *** +START SLAVE SQL_THREAD; +--source include/wait_for_slave_sql_to_start.inc +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +--source include/wait_for_status_var.inc +--echo Heartbeat event received +--echo + +# Check received heartbeat event for stopped SQL thread by error +--echo *** Stopped SQL thread by error *** +--connection master +CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(10), c LONGTEXT); +--sync_slave_with_master +INSERT INTO t1 VALUES (1, 'on slave', NULL); +--connection master +INSERT INTO t1 VALUES (1, 'on master', NULL); +--connection slave +set sql_log_bin= 0; +call mtr.add_suppression("Slave SQL.*Duplicate entry .1. for key .PRIMARY.. on query.* error.* 1062"); +call mtr.add_suppression("Slave SQL.*Request to stop slave SQL Thread received while applying a group that has non-transactional changes; waiting for completion of the group"); +set sql_log_bin= 1; +let $slave_errno= ER_DUP_ENTRY +--source include/wait_for_slave_sql_error.inc +let $rcvd_heartbeats_before= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +sleep 4; +let $rcvd_heartbeats_after= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $result= query_get_value(SELECT ($rcvd_heartbeats_after - $rcvd_heartbeats_before) > 0 AS Result, Result, 1); +--echo Heartbeat events are received while sql thread stopped (1 means 'yes'): $result +--source include/stop_slave.inc +set sql_log_bin= 0; +DROP TABLE t1; +set sql_log_bin= 1; +--echo + +# Check received heartbeat events while master send events to slave +--echo *** Master send to slave *** +--connection master +# Create the event that will update table t1 every second +DELIMITER |; +CREATE EVENT e1 + ON SCHEDULE EVERY 1 SECOND + DO + BEGIN + UPDATE test.t1 SET a = a + 1 WHERE a < 10; + END| +DELIMITER ;| +--connection slave +--source include/reset_slave.inc +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=5; +--source include/start_slave.inc +--connection master +# Enable scheduler +SET @@global.event_scheduler=1; + +--sync_slave_with_master +let $rcvd_heartbeats_before= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); + +--connection master + +# Whether or not to send a heartbeat is decided on the master, based on +# whether the binlog was updated during the period or not. +# Even with the 1-second event, we cannot make the master to write binary +# logs (or execute SQL) in a timely manner. We can only check that they +# were executed in a timely manner, and if they were not, neutralize the +# heartbeat check on the slave. +# We will wait for 5 events, and keep checking 'Binlog_commits' on master. +# Time interval between consequent events will be measured. +# We can only expect that no heartbeats have been sent if the interval +# between events never exceeded MASTER_HEARTBEAT_PERIOD. +# If it has exceeded the value at least once, the slave can legitimately +# receive a heartbeat (but we cannot require it, because the delay +# could have occurred somewhere else, e.g. upon checking the status). +# So, if the delay is detected, we will signal slave to ignore possible +# heartbeats. + +let $possible_heartbeats= 0; +let $commits_to_wait= 5; +while ($commits_to_wait) +{ + let $tm= `SELECT UNIX_TIMESTAMP(NOW(3))`; + let $binlog_commits= query_get_value(SHOW STATUS LIKE 'Binlog_commits', Value, 1); + let $wait_condition= SELECT VARIABLE_VALUE > $binlog_commits FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME= 'BINLOG_COMMITS'; + --source include/wait_condition.inc + dec $commits_to_wait; + if (`SELECT UNIX_TIMESTAMP(NOW(3)) > $tm + 5`) + { + let $possible_heartbeats= 1; + let $commits_to_wait= 0; + } +} + +--connection slave +let $rcvd_heartbeats_after= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $result= `SELECT CASE WHEN $possible_heartbeats THEN 'TRUE' WHEN $rcvd_heartbeats_after - $rcvd_heartbeats_before > 0 THEN 'FALSE' ELSE 'TRUE' END`; +--echo Received heartbeats meet expectations: $result +--connection master +DELETE FROM t1; +DROP EVENT e1; +--sync_slave_with_master +--echo + +# Check received heartbeat events while logs flushed on slave +--echo *** Flush logs on slave *** +STOP SLAVE; +--source include/reset_slave.inc +set sql_log_bin= 0; +DROP TABLE t1; +set sql_log_bin= 1; +--connection master +DROP TABLE t1; +RESET MASTER; +--connection slave +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=0.5; +let $slave_param_comparison= =; +--source include/start_slave.inc +let $rcvd_heartbeats_before= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +# Flush logs every 0.1 second during 5 sec +--disable_query_log +let $i=100; +while ($i) { + FLUSH LOGS; + dec $i; + sleep 0.1; +} +--enable_query_log +let $rcvd_heartbeats_after= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $result= query_get_value(SELECT ($rcvd_heartbeats_after - $rcvd_heartbeats_before) > 0 AS Result, Result, 1); +--echo Heartbeat events are received while rotation of relay logs (1 means 'yes'): $result +--echo + +# Use compressed protocol between master and slave +--echo *** Compressed protocol *** +--connection master +SET @@global.slave_compressed_protocol=1; +--connection slave +--source include/stop_slave.inc +--source include/reset_slave.inc +SET @@global.slave_compressed_protocol=1; +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=0.1; +--source include/start_slave.inc +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $status_var= slave_received_heartbeats; +let $status_var_comparsion= >; +--source include/wait_for_status_var.inc +--echo Heartbeat event received +SET @@global.slave_compressed_protocol=0; +--connection master +SET @@global.slave_compressed_protocol=0; +--echo + + +# Check received heartbeat events after reset of master +--echo *** Reset master *** +--connection slave +STOP SLAVE; +--source include/reset_slave.inc +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=0.1; +--source include/start_slave.inc +let $rcvd_heartbeats_before= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +--connection master +RESET MASTER; +--enable_query_log +--sync_slave_with_master +--sleep 2 +let $rcvd_heartbeats_after= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $result= query_get_value(SELECT ($rcvd_heartbeats_after - $rcvd_heartbeats_before) > 0 AS Result, Result, 1); +--echo Heartbeat events are received after reset of master (1 means 'yes'): $result +--echo + +# Reloaded master should restore heartbeat +--echo *** Reload master *** +--connection slave +STOP SLAVE; +--source include/reset_slave.inc +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=0.1; +--source include/start_slave.inc +# Wait until slave_received_heartbeats will be incremented +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $status_var= slave_received_heartbeats; +let $status_var_comparsion= >; +--source include/wait_for_status_var.inc +--echo Heartbeat event received +--let $rpl_server_number= 1 +--source include/rpl_restart_server.inc +# make sure IO thread has re-connected +# due to slow valgrind env the following wait_for_status may time out +--let $rpl_allow_error= 1 +--source include/wait_for_slave_io_to_start.inc +# Wait until slave_received_heartbeats will be incremented +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $status_var= slave_received_heartbeats; +let $status_var_comparsion= >; +--source include/wait_for_status_var.inc +--echo Heartbeat event received +--echo + +# Circular replication: demonstrating bidirectional hearbeat flow +--echo *** Circular replication *** +# Configure circular replication +--source include/rpl_reset.inc +--source include/stop_slave.inc +--let $rpl_topology= 1->2->1 +--source include/rpl_change_topology.inc + +#--connection slave +#--source include/stop_slave.inc +#let $slave_binlog= query_get_value(SHOW MASTER STATUS, File, 1); +--connection master +#--replace_result $SLAVE_MYPORT SLAVE_PORT $slave_binlog SLAVE_BINLOG +#eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$SLAVE_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=1, MASTER_LOG_FILE='$slave_binlog'; + +# BUG#12403008 RPL_HEARTBEAT_BASIC FAILS SPORADICALLY ON PUSHBUILD +# MASTER_HEARTBEAT_PERIOD had the default value (slave_net_timeout/2) +# so wait on "Heartbeat event received on master", that only waits for +# 1 minute, sometimes timeout before heartbeat arrives. +CHANGE MASTER TO MASTER_HEARTBEAT_PERIOD=1; +--source include/start_slave.inc + +# Insert data on master and on slave and make sure that it replicated for both directions +CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(10)); +INSERT INTO t1 VALUES(1, 'on master'); +--save_master_pos +--connection slave +## set slave period 1/10 of master's +CHANGE MASTER TO MASTER_HEARTBEAT_PERIOD=0.1; +--source include/start_slave.inc +--sync_with_master +INSERT INTO t1 VALUES(2, 'on slave'); +--sync_slave_with_master master +SELECT * FROM t1 ORDER BY a; +let $master_rcvd_heartbeats_before= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +--connection slave +SELECT * FROM t1 ORDER BY a; + +# Wait for heartbeat event on master +--connection master +let $status_var= slave_received_heartbeats; +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $status_var_comparsion= >; +--source include/wait_for_status_var.inc +--echo Heartbeat event received on master + +# Wait heartbeat events on slave +--connection slave +let $status_var= slave_received_heartbeats; +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $status_var_comparsion= >; +--source include/wait_for_status_var.inc +--echo Heartbeat event received on slave +let $slave_rcvd_heartbeats= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); + +# +# Clean up and restore system variables +# +--echo *** Clean up *** +--connection master +#--source include/stop_slave.inc +DROP TABLE t1; +--sync_slave_with_master +SET @@global.slave_net_timeout=@restore_slave_net_timeout; + +--disable_prepare_warnings + +#--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_heartbeat_debug.test b/mysql-test/suite/rpl/t/rpl_heartbeat_debug.test new file mode 100644 index 00000000..bd66a249 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_heartbeat_debug.test @@ -0,0 +1,52 @@ +# Testing master to slave heartbeat protocol, test cases that need debug build. + +--source include/have_debug.inc +--source include/master-slave.inc + +connection slave; +--source include/stop_slave.inc +set @restore_slave_net_timeout= @@global.slave_net_timeout; +--disable_warnings +set @@global.slave_net_timeout= 10; +--enable_warnings + +### +### Checking the range +### + +# +# default period slave_net_timeout/2 +# +--query_vertical show status like 'Slave_heartbeat_period'; +SET @saved_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,simulate_slave_heartbeat_network_error"; +CALL mtr.add_suppression('SET @master_heartbeat_period to master failed with error'); +CALL mtr.add_suppression('Master command COM_REGISTER_SLAVE failed: failed registering on master, reconnecting to try again'); +--source include/start_slave.inc + + +connection master; +--disable_warnings +drop table if exists t1; +--enable_warnings + +CREATE TABLE t1 (a INT PRIMARY KEY); +INSERT INTO t1 VALUES (1); + +sync_slave_with_master; + +--connection slave +SELECT * FROM t1; + +connection master; +drop table t1; + +connection slave; +--source include/stop_slave.inc +--disable_warnings +SET GLOBAL debug_dbug=@saved_dbug; +set @@global.slave_net_timeout= @restore_slave_net_timeout; +--enable_warnings +--source include/start_slave.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_heartbeat_ssl.test b/mysql-test/suite/rpl/t/rpl_heartbeat_ssl.test new file mode 100644 index 00000000..2c41fdee --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_heartbeat_ssl.test @@ -0,0 +1,57 @@ +############################################################# +# Author: Serge Kozlov <Serge.Kozlov@Sun.COM> +# Date: 02/19/2009 +# Purpose: Testing basic functionality of heartbeat over SSL +############################################################# +--source include/have_ssl_communication.inc +--source include/master-slave.inc +--echo + +# +# Testing heartbeat over SSL +# + +# Heartbeat over SSL +--echo *** Heartbeat over SSL *** +--connection master +let $master_binlog= query_get_value(SHOW MASTER STATUS, File, 1); +--connection slave +--source include/stop_slave.inc +RESET SLAVE; +# Connect to master with SSL +--replace_result $MASTER_MYPORT MASTER_PORT $MYSQL_TEST_DIR MYSQL_TEST_DIR $master_binlog MASTER_BINLOG +eval CHANGE MASTER TO + MASTER_HOST='127.0.0.1', + MASTER_PORT=$MASTER_MYPORT, + MASTER_USER='root', + MASTER_HEARTBEAT_PERIOD=0.1, + MASTER_LOG_FILE='$master_binlog', + MASTER_SSL=1, + MASTER_SSL_CA='$MYSQL_TEST_DIR/std_data/cacert.pem', + MASTER_SSL_CERT='$MYSQL_TEST_DIR/std_data/client-cert.pem', + MASTER_SSL_KEY='$MYSQL_TEST_DIR/std_data/client-key.pem', + MASTER_USE_GTID=NO; +--source include/start_slave.inc +# Check SSL state of slave +let $slave_ssl_status= query_get_value(SHOW SLAVE STATUS, Master_SSL_Allowed, 1); +--echo Master_SSL_Allowed: $slave_ssl_status +# Wait until hearbeat event will received +let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); +let $status_var= slave_received_heartbeats; +let $status_var_comparsion= >; +--source include/wait_for_status_var.inc +--echo Heartbeat event has received +--echo + +# +# Clean up +# +--echo *** Clean up *** +--source include/stop_slave.inc +CHANGE MASTER TO + MASTER_SSL=0, + MASTER_SSL_CA='', + MASTER_SSL_CERT='', + MASTER_SSL_KEY=''; +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_hrtime.test b/mysql-test/suite/rpl/t/rpl_hrtime.test new file mode 100644 index 00000000..98b08abe --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_hrtime.test @@ -0,0 +1,7 @@ +--source include/have_binlog_format_mixed_or_statement.inc + +--source suite/rpl/include/hrtime.inc + +let $MYSQLD_DATADIR= `select @@datadir`; +--exec $MYSQL_BINLOG --short-form $MYSQLD_DATADIR/master-bin.000001 + diff --git a/mysql-test/suite/rpl/t/rpl_hrtime_row.test b/mysql-test/suite/rpl/t/rpl_hrtime_row.test new file mode 100644 index 00000000..e1d49f53 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_hrtime_row.test @@ -0,0 +1,3 @@ +--source include/have_binlog_format_row.inc +--source suite/rpl/include/hrtime.inc + diff --git a/mysql-test/suite/rpl/t/rpl_idempotency.test b/mysql-test/suite/rpl/t/rpl_idempotency.test new file mode 100644 index 00000000..12dec236 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_idempotency.test @@ -0,0 +1,107 @@ +# Testing various forms of idempotency for replication that should +# work the same way under statement based as under row based. + +source include/master-slave.inc; + +# Add suppression for expected warning(s) in slaves error log +call mtr.add_suppression("Slave SQL.*Can.t find record in .t[12].* error.* 1032"); +call mtr.add_suppression("Slave SQL.*Cannot delete or update a parent row: a foreign key constraint fails .* error.* 1451"); +call mtr.add_suppression("Slave SQL.*Cannot add or update a child row: a foreign key constraint fails .* error.* 1452"); +call mtr.add_suppression("Slave SQL.*Could not execute Write_rows event on table test.* Duplicate entry .1. for key .PRIMARY.* error.* 1062"); +call mtr.add_suppression("Can't find record in 't1'"); +call mtr.add_suppression("Can't find record in 't2'"); + +connection master; +CREATE TABLE t1 (a INT PRIMARY KEY); +CREATE TABLE t2 (a INT); +INSERT INTO t1 VALUES (-1),(-2),(-3); +INSERT INTO t2 VALUES (-1),(-2),(-3); +sync_slave_with_master; + +SET @old_slave_exec_mode= @@global.slave_exec_mode; +SET @@global.slave_exec_mode= IDEMPOTENT; + +# A delete for a row that does not exist, the statement is +# deliberately written to be idempotent for statement-based +# replication as well. We test this towards both a table with a +# primary key and without a primary key. + +connection slave; +DELETE FROM t1 WHERE a = -2; +DELETE FROM t2 WHERE a = -2; +connection master; +DELETE FROM t1 WHERE a = -2; +DELETE FROM t2 WHERE a = -2; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +sync_slave_with_master; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +--source include/check_slave_no_error.inc + +# An insert of a row that already exists. Since we are replacing the +# row if it already exists, the most apropriate representation is +# INSERT IGNORE. We only test this towards a table with a primary key, +# since the other case does not make sense. + +INSERT IGNORE INTO t1 VALUES (-2); +connection master; +INSERT IGNORE INTO t1 VALUES (-2); +SELECT * FROM t1 ORDER BY a; +sync_slave_with_master; +SELECT * FROM t1 ORDER BY a; +--source include/check_slave_no_error.inc + + +# BUG#19958: RBR idempotency issue for UPDATE and DELETE + +# Statement-based and row-based replication have different behaviour +# when updating a row with an explicit WHERE-clause that matches +# exactly one row (or no row at all). For statement-based replication, +# the statement is idempotent since the first time it is executed, it +# will update exactly one row, and the second time it will not update +# any row at all. This was not the case for row-based replication, so +# we test under both row-based and statement-based replication both +# for tables with and without primary keys. + +connection slave; +UPDATE t1 SET a = 1 WHERE a = -1; +UPDATE t2 SET a = 1 WHERE a = -1; +connection master; +UPDATE t1 SET a = 1 WHERE a = -1; +UPDATE t2 SET a = 1 WHERE a = -1; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +sync_slave_with_master; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +--source include/check_slave_no_error.inc + +connection slave; +drop table t1, t2; + +connection master; +DROP TABLE t1, t2; +sync_slave_with_master; +--source include/check_slave_no_error.inc +create database d; +create database e; + +connection master; +create database d; +create database if not exists e; + +sync_slave_with_master; +--source include/check_slave_no_error.inc +drop database d; +drop database e; + +connection master; +drop database d; +drop database if exists e; +sync_slave_with_master; +--source include/check_slave_no_error.inc + +SET @@global.slave_exec_mode= @old_slave_exec_mode; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_ignore_grant-slave.opt b/mysql-test/suite/rpl/t/rpl_ignore_grant-slave.opt new file mode 100644 index 00000000..e931bfbd --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_ignore_grant-slave.opt @@ -0,0 +1 @@ +--replicate-wild-ignore-table=mysql.% diff --git a/mysql-test/suite/rpl/t/rpl_ignore_grant.test b/mysql-test/suite/rpl/t/rpl_ignore_grant.test new file mode 100644 index 00000000..58457c14 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_ignore_grant.test @@ -0,0 +1,55 @@ +# Test that GRANT is not replicated to the slave +# when --replicate-wild-ignore-table=mysql.% +# In BUG#980, this test would _randomly_ fail. + +source include/master-slave.inc; + +# do not be influenced by other tests. +connection master; +set sql_mode=""; +delete from mysql.user where user=_binary'rpl_ignore_grant'; +delete from mysql.db where user=_binary'rpl_ignore_grant'; +flush privileges; +--sync_slave_with_master +set sql_mode=""; +# as these DELETE were not replicated, we need to do them manually on the +# slave. +delete from mysql.user where user=_binary'rpl_ignore_grant'; +delete from mysql.db where user=_binary'rpl_ignore_grant'; +flush privileges; + +# test non-replication of GRANT +connection master; +grant select on *.* to rpl_ignore_grant@localhost; +grant drop on test.* to rpl_ignore_grant@localhost; +show grants for rpl_ignore_grant@localhost; +--sync_slave_with_master +--error 1141 #("no such grant for user") +show grants for rpl_ignore_grant@localhost; +# check it another way +select count(*) from mysql.user where user=_binary'rpl_ignore_grant'; +select count(*) from mysql.db where user=_binary'rpl_ignore_grant'; + +# test non-replication of SET PASSWORD +# first force creation of the user on slave (because as the user does not exist +# on slave, the SET PASSWORD may be replicated but silently do nothing; this is +# not what we want; we want it to be not-replicated). +grant select on *.* to rpl_ignore_grant@localhost; +connection master; +set password for rpl_ignore_grant@localhost=password("does it work?"); +--sync_slave_with_master +select password<>_binary'' from mysql.user where user=_binary'rpl_ignore_grant'; + +# clear what we have done, to not influence other tests. +connection master; +delete from mysql.user where user=_binary'rpl_ignore_grant'; +delete from mysql.db where user=_binary'rpl_ignore_grant'; +flush privileges; +--sync_slave_with_master +delete from mysql.user where user=_binary'rpl_ignore_grant'; +delete from mysql.db where user=_binary'rpl_ignore_grant'; +flush privileges; + +connection master; +# End of 4.1 tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_ignore_revoke-slave.opt b/mysql-test/suite/rpl/t/rpl_ignore_revoke-slave.opt new file mode 100644 index 00000000..e931bfbd --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_ignore_revoke-slave.opt @@ -0,0 +1 @@ +--replicate-wild-ignore-table=mysql.% diff --git a/mysql-test/suite/rpl/t/rpl_ignore_revoke.test b/mysql-test/suite/rpl/t/rpl_ignore_revoke.test new file mode 100644 index 00000000..db20e807 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_ignore_revoke.test @@ -0,0 +1,52 @@ +# test verifies that REVOKE must not be replicated when +# slave server starts with --replicate-wild-ignore-table=mysql.% +# the option is set in rpl_ignore_revoke-slave.opt +# The first part of BUG#9483 for GRANT is checked by +# existed specific rpl_ignore_grant test case (BUG#980) + + +source include/master-slave.inc; + +### CLEAN-UP: create an account and manually duplicate it on the slave + +connection master; +grant select on *.* to 'user_foo'@'%' identified by 'user_foopass'; +revoke select on *.* from 'user_foo'@'%'; +select select_priv from mysql.user where user='user_foo' /* master:must be N */; + +sync_slave_with_master; +#connection slave; +grant select on *.* to 'user_foo'@'%' identified by 'user_foopass'; +revoke select on *.* from 'user_foo'@'%'; +select select_priv from mysql.user where user='user_foo' /* slave:must be N */; + + +### TEST + +#connection slave; +grant select on *.* to 'user_foo'@'%' identified by 'user_foopass'; +select select_priv from mysql.user where user='user_foo' /* slave:must be Y */; + +connection master; +revoke select on *.* from 'user_foo'; +select select_priv from mysql.user where user='user_foo' /* master:must be N */; + +sync_slave_with_master; +#connection slave; +select select_priv from mysql.user where user='user_foo' /* slave:must get Y */; + +### CLEAN-UP + +connection slave; +--disable_abort_on_error +revoke select on *.* FROM 'user_foo'; +--enable_abort_on_error + +connection master; +delete from mysql.user where user="user_foo"; +sync_slave_with_master; + +# Since changes to mysql.* are ignored, the revoke need to +# be done on slave as well +delete from mysql.user where user="user_foo"; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_ignore_table-slave.opt b/mysql-test/suite/rpl/t/rpl_ignore_table-slave.opt new file mode 100644 index 00000000..3aabbb2e --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_ignore_table-slave.opt @@ -0,0 +1 @@ +--replicate-ignore-table=test.t1 --replicate-ignore-table=test.t2 --replicate-ignore-table=test.t3 --replicate-wild-ignore-table=%.tmptbl% diff --git a/mysql-test/suite/rpl/t/rpl_ignore_table.test b/mysql-test/suite/rpl/t/rpl_ignore_table.test new file mode 100644 index 00000000..b78ad90a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_ignore_table.test @@ -0,0 +1,198 @@ +let collation=utf8mb3_unicode_ci; +source include/have_collation.inc; +source include/master-slave.inc; + +call mtr.add_suppression("Can't find record in 't.'"); +call mtr.add_suppression("Can't find record in 'global_priv'"); +call mtr.add_suppression("Can't find record in 'tables_priv'"); + +# +# BUG#16487 +# +# Requirement: +# Multi-updates on ignored tables should not fail even if the slave does +# not have the ignored tables. +# +# Note table t1, t2, and t3 are ignored in the option file to this test. +# + +--echo **** Test case for BUG#16487 **** +connection master; +CREATE TABLE test.t4 (a int); +CREATE TABLE test.t1 (a int); + +# Expect: The row must *not* by updated on slave, since t1 is ignored +UPDATE test.t4 NATURAL JOIN test.t1 SET t1.a=5; + +sync_slave_with_master; +SELECT * FROM t4; + +# Cleanup +connection master; +DROP TABLE t1; +DROP TABLE t4; + +sync_slave_with_master; + + +# +# Bug#25482 GRANT statements are not replicated if +# you use "replicate-ignore-table" +# + +--echo **** Test case for BUG#25482 **** +--echo **** Adding GRANTS on master **** + +connection master; +create table test.t1(a int); +create table test.t4(a int); + +set sql_mode=""; +# Simple user that should not replicate +GRANT SELECT ON test.t1 TO mysqltest1@localhost; + +# Partial replicate +GRANT INSERT ON test.t4 TO mysqltest2@localhost; +GRANT select, update, insert, references on t1 + to mysqltest2@localhost; + +# Partial replicate 2 +GRANT SELECT ON test.* TO mysqltest3@localhost; +GRANT INSERT ON test.t4 TO mysqltest3@localhost; +GRANT select(a), update(a), insert(a), references(a) on t4 + to mysqltest3@localhost; + +# Create another database and table +create database mysqltest2; +create table mysqltest2.t2 (id int); +# Create a grant that should replicate +GRANT SELECT ON mysqltest2.t2 TO mysqltest4@localhost IDENTIFIED BY 'pass'; + +# Create a grant manually +insert into mysql.global_priv (user, host) values ("mysqltest5", "somehost"); + +# Partial replicate 3 with *.* +GRANT SELECT ON *.* TO mysqltest6@localhost; +GRANT INSERT ON *.* TO mysqltest6@localhost; +GRANT INSERT ON test.* TO mysqltest6@localhost; +GRANT INSERT ON test.t1 TO mysqltest6@localhost; + +--sorted_result +show grants for mysqltest1@localhost; +--sorted_result +show grants for mysqltest2@localhost; +--sorted_result +show grants for mysqltest3@localhost; +--sorted_result +show grants for mysqltest4@localhost; +--sorted_result +show grants for mysqltest6@localhost; + +flush privileges; +show grants for mysqltest5@somehost; + +set sql_mode=""; +sync_slave_with_master; + +--echo **** Checking grants on slave **** + +# Check that grants are replicated to slave +--sorted_result +show grants for mysqltest2@localhost; +--sorted_result +show grants for mysqltest3@localhost; +--sorted_result +show grants for mysqltest4@localhost; +--sorted_result +show grants for mysqltest5@somehost; +--sorted_result +show grants for mysqltest6@localhost; + +# mysqltest1 should not be on slave +--error 1141 +show grants for mysqltest1@localhost; + +--echo **** Revoking grants on master **** +connection master; +REVOKE SELECT ON test.t1 FROM mysqltest1@localhost; +REVOKE SELECT ON mysqltest2.t2 FROM mysqltest4@localhost; +REVOKE select(a) on t4 + from mysqltest3@localhost; + +--sorted_result +show grants for mysqltest1@localhost; +--sorted_result +show grants for mysqltest3@localhost; +--sorted_result +show grants for mysqltest4@localhost; + +sync_slave_with_master; + +--echo **** Checking grants on slave **** + +# mysqltest1 should not be on slave +--error 1141 +show grants for mysqltest1@localhost; +show grants for mysqltest3@localhost; +show grants for mysqltest4@localhost; + +# Cleanup +# connection slave; +# BUG31552 changes idempotency is not default any longer +# In order the following `delete from mysql.user', +# where mysqltest1 does not exist on slave, +# to succeed on slave the mode is temporarily changed +set global slave_exec_mode='IDEMPOTENT'; +call mtr.add_suppression("Slave SQL.*Could not execute Delete_rows event on table mysql.* error.* 1032"); + +connection master; +drop table t1, mysqltest2.t2; +drop table t4; +drop database mysqltest2; +delete from mysql.user where user like "mysqltest%"; +delete from mysql.db where user like "mysqltest%"; +# +# BUG 27606 causes failure to replicate this statement +# move it to slave instead +#delete from mysql.tables_priv where user like "mysqltest%"; +delete from mysql.columns_priv where user like "mysqltest%"; + +sync_slave_with_master; +# bug#31552: do not restore the mode here but later in order +# to succeed with yet the following delete from mysql.tables_priv + +#BUG27606 +delete from mysql.tables_priv where user like "mysqltest%"; + +connection master; + +#BUG27606 +delete from mysql.tables_priv where user like "mysqltest%"; + +# +# bug#22877 replication character sets get out of sync +# using replicate-wild-ignore-table +# +connection master; +--disable_warnings +DROP TABLE IF EXISTS t5; +--enable_warnings +CREATE TABLE t5 ( + word varchar(50) collate utf8_unicode_ci NOT NULL default '' +) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +SET @@session.character_set_client=33,@@session.collation_connection=192; +CREATE TEMPORARY TABLE tmptbl504451f4258$1 (id INT NOT NULL) ENGINE=MEMORY; +INSERT INTO t5 (word) VALUES ('TEST’'); +SELECT HEX(word) FROM t5; +sync_slave_with_master; +set @@global.slave_exec_mode= default; # bug#31552 comments above +connection slave; +SELECT HEX(word) FROM t5; +--error 1146 +SELECT * FROM tmptbl504451f4258$1; +connection master; +DROP TABLE t5; +flush privileges; +sync_slave_with_master; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_ignore_table_update-slave.opt b/mysql-test/suite/rpl/t/rpl_ignore_table_update-slave.opt new file mode 100644 index 00000000..177f89e0 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_ignore_table_update-slave.opt @@ -0,0 +1 @@ +--replicate-ignore-table=test.mysqltest_foo diff --git a/mysql-test/suite/rpl/t/rpl_ignore_table_update.test b/mysql-test/suite/rpl/t/rpl_ignore_table_update.test new file mode 100644 index 00000000..6591dbbc --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_ignore_table_update.test @@ -0,0 +1,35 @@ +# This one assumes we are ignoring updates on table mysqltest_foo, but doing +# the ones on all other tables + +source include/master-slave.inc; +connection slave; + +# +# For this test we must be in the test database +# +use test; + +--disable_warnings +drop table if exists mysqltest_foo; +drop table if exists mysqltest_bar; +--enable_warnings + +create table mysqltest_foo (n int); +insert into mysqltest_foo values(4); +connection master; +use test; +create table mysqltest_foo (n int); +insert into mysqltest_foo values(5); +create table mysqltest_bar (m int); +insert into mysqltest_bar values(15); +create table t1 (k int); +insert into t1 values(55); +--sync_slave_with_master +select mysqltest_foo.n,mysqltest_bar.m,t1.k from mysqltest_foo,mysqltest_bar,t1; +connection master; +drop table mysqltest_foo,mysqltest_bar,t1; +--sync_slave_with_master +drop table mysqltest_foo,mysqltest_bar,t1; + +# End of 4.1 tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_incident.test b/mysql-test/suite/rpl/t/rpl_incident.test new file mode 100644 index 00000000..75d28d6a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_incident.test @@ -0,0 +1,61 @@ +# +# This include file is used by more than one test suite +# (currently rpl and binlog_encryption). +# Please check all dependent tests after modifying it +# + +--source include/have_debug.inc +--source include/master-slave.inc + +SET @old_binlog_checksum=@@binlog_checksum; +SET GLOBAL BINLOG_CHECKSUM=none; +connection slave; +SET @old_binlog_checksum=@@binlog_checksum; +SET GLOBAL BINLOG_CHECKSUM=none; +connection master; + +--echo **** On Master **** +CREATE TABLE t1 (a INT); + +INSERT INTO t1 VALUES (1),(2),(3); +SELECT * FROM t1; + +set @saved_dbug = @@global.debug_dbug; +SET GLOBAL debug_dbug= '+d,incident_database_resync_on_replace,*'; + +# This will generate an incident log event and store it in the binary +# log before the replace statement. +REPLACE INTO t1 VALUES (4); +--save_master_pos +SELECT * FROM t1; + +set @@global.debug_dbug = @saved_dbug; + +connection slave; +# Wait until SQL thread stops with error LOST_EVENT on master +call mtr.add_suppression("Slave SQL.*The incident LOST_EVENTS occurred on the master.* 1590"); +let $slave_sql_errno= 1590; +let $show_slave_sql_error= 1; +source include/wait_for_slave_sql_error.inc; + +# The 4 should not be inserted into the table, since the incident log +# event should have stop the slave. +--echo **** On Slave **** +SELECT * FROM t1; + +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +--sync_with_master + +# Now, we should have inserted the row into the table and the slave +# should be running. We should also have rotated to a new binary log. + +SELECT * FROM t1; +source include/check_slave_is_running.inc; + +connection master; +SET GLOBAL BINLOG_CHECKSUM=@old_binlog_checksum; +DROP TABLE t1; +--sync_slave_with_master +SET GLOBAL BINLOG_CHECKSUM=@old_binlog_checksum; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_incompatible_heartbeat.test b/mysql-test/suite/rpl/t/rpl_incompatible_heartbeat.test new file mode 100644 index 00000000..104debe7 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_incompatible_heartbeat.test @@ -0,0 +1,44 @@ +# ==== Purpose ==== +# +# Test verifies that slave IO thread can process heartbeat events with log_pos +# values higher than UINT32_MAX. +# +# ==== Implementation ==== +# +# Steps: +# 0 - Stop slave threads. Configure a small master_heartbeat_period. +# 1 - Using debug points, simulate a huge binlog offset higher than +# UINT32_MAX on master. +# 2 - Start the slave and observe that slave IO thread is able to process +# the offset received through heartbeat event. +# +# ==== References ==== +# +# MDEV-16146: MariaDB slave stops with incompatible heartbeat +# +--source include/have_debug.inc +--source include/have_innodb.inc +--source include/have_binlog_format_mixed.inc +# Test simulates binarylog offsets higher than UINT32_MAX +--source include/have_64bit.inc +--source include/master-slave.inc + +--connection master +SET @saved_dbug = @@GLOBAL.debug_dbug; +SET @@global.debug_dbug= 'd,simulate_pos_4G'; + +--connection slave +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_HEARTBEAT_PERIOD=0.001; +--source include/start_slave.inc + +--connection master +sleep 1; +SET @@GLOBAL.debug_dbug = @saved_dbug; +--sync_slave_with_master + +--connection master +CREATE TABLE t (f INT) ENGINE=INNODB; +INSERT INTO t VALUES (10); +DROP TABLE t; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_init_slave-slave.opt b/mysql-test/suite/rpl/t/rpl_init_slave-slave.opt new file mode 100644 index 00000000..337e8a60 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_init_slave-slave.opt @@ -0,0 +1 @@ +--init-slave="set global max_connections=500" diff --git a/mysql-test/suite/rpl/t/rpl_init_slave.test b/mysql-test/suite/rpl/t/rpl_init_slave.test new file mode 100644 index 00000000..1803b146 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_init_slave.test @@ -0,0 +1,34 @@ +source include/master-slave.inc; + +# +# Test of init_slave variable +# + +set global max_connections=151; + +connection slave; +source include/stop_slave.inc; +source include/start_slave.inc; + +connection master; +sync_slave_with_master; +show variables like 'init_slave'; +show variables like 'max_connections'; +reset master; +connection master; +show variables like 'init_slave'; +show variables like 'max_connections'; +sync_slave_with_master; +# Save variable value +set @my_global_init_connect= @@global.init_connect; +set global init_connect="set @c=1"; +show variables like 'init_connect'; +connection master; +sync_slave_with_master; + +# Restore changed global variable +set global init_connect= @my_global_init_connect; +set global max_connections= default; + +# End of 4.1 tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_init_slave_errors.test b/mysql-test/suite/rpl/t/rpl_init_slave_errors.test new file mode 100644 index 00000000..46673ea4 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_init_slave_errors.test @@ -0,0 +1,96 @@ +# +# This include file is used by more than one test suite +# (currently rpl and binlog_encryption). +# Please check all dependent tests after modifying it +# + +###################################################################### +# Some errors that cause the slave SQL thread to stop are not shown in +# the Slave_SQL_Error column of "SHOW SLAVE STATUS". Instead, the error +# is only in the server's error log. +# +# Two failures and their respective reporting are verified: +# +# 1 - Failures during slave thread initialization +# 2 - Failures while processing queries passed through the init_slave +# option. +# +# In order to check the first type of failure, we inject a fault in the +# SQL/IO Threads through SET GLOBAL debug. +# +# To check the second type, we set @@global.init_slave to an invalid +# command thus preventing the initialization of the SQL Thread. +# +# Obs: +# 1 - Note that testing failures while initializing the relay log position +# is hard as the same function is called before the code reaches the point +# that we want to test. +# +# 2 - This test does not target failures that are reported while applying +# events such as duplicate keys, errors while reading the relay-log.bin*, +# etc. Such errors are already checked on other tests. +###################################################################### + +###################################################################### +# Configuring the Environment +###################################################################### +source include/have_debug.inc; +source include/have_log_bin.inc; +source include/master-slave.inc; + +connection slave; + +--disable_warnings +stop slave; +--enable_warnings +reset slave; + +###################################################################### +# Injecting faults in the threads' initialization +###################################################################### +connection slave; + +# Set debug flags on slave to force errors to occur +set @saved_dbug = @@global.debug_dbug; +SET GLOBAL debug_dbug= "d,simulate_io_slave_error_on_init,simulate_sql_slave_error_on_init"; + +start slave; + +# +# slave is going to stop because of emulated failures +# but there won't be any crashes nor asserts hit. +# +# 1593 = ER_SLAVE_FATAL_ERROR +--let $slave_sql_errno= 1593 +--let $show_slave_sql_error= 1 +--source include/wait_for_slave_sql_error.inc + +call mtr.add_suppression("Failed during slave.* thread initialization"); + +set @@global.debug_dbug = @saved_dbug; + +###################################################################### +# Injecting faults in the init_slave option +###################################################################### +connection slave; + +reset slave; + +SET GLOBAL init_slave= "garbage"; + +start slave; +# 1064 = ER_PARSE_ERROR +--let $slave_sql_errno= 1064 +--let $show_slave_sql_error= 1 +--source include/wait_for_slave_sql_error.inc + +###################################################################### +# Clean up +###################################################################### +SET GLOBAL init_slave= ""; + +# Clean up Last_SQL_Error +--source include/stop_slave_io.inc +RESET SLAVE; +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_innodb-master.opt b/mysql-test/suite/rpl/t/rpl_innodb-master.opt new file mode 100644 index 00000000..e27ee9b2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_innodb-master.opt @@ -0,0 +1 @@ +--loose-innodb-autoinc-lock-mode=0 diff --git a/mysql-test/suite/rpl/t/rpl_innodb_bug28430-master.opt b/mysql-test/suite/rpl/t/rpl_innodb_bug28430-master.opt new file mode 100644 index 00000000..e27ee9b2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_innodb_bug28430-master.opt @@ -0,0 +1 @@ +--loose-innodb-autoinc-lock-mode=0 diff --git a/mysql-test/suite/rpl/t/rpl_innodb_bug28430-slave.opt b/mysql-test/suite/rpl/t/rpl_innodb_bug28430-slave.opt new file mode 100644 index 00000000..e27ee9b2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_innodb_bug28430-slave.opt @@ -0,0 +1 @@ +--loose-innodb-autoinc-lock-mode=0 diff --git a/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test b/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test new file mode 100644 index 00000000..0b8fb751 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test @@ -0,0 +1,163 @@ +--source include/big_test.inc +--source include/have_innodb.inc +--source include/have_partition.inc +--source include/have_binlog_format_mixed_or_row.inc +--source include/master-slave.inc + +# Set the default connection to 'master' +--enable_prepare_warnings +--vertical_results + +let $engine_type= 'innodb'; + +######## Creat Table Section ######### +use test; + +eval CREATE TABLE test.regular_tbl(id MEDIUMINT NOT NULL AUTO_INCREMENT, + dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON + UPDATE CURRENT_TIMESTAMP, user CHAR(255), uuidf LONGBLOB, + fkid MEDIUMINT, filler VARCHAR(255), + PRIMARY KEY(id)) ENGINE=$engine_type; + +eval CREATE TABLE test.bykey_tbl(id MEDIUMINT NOT NULL AUTO_INCREMENT, + dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE + CURRENT_TIMESTAMP, user CHAR(255), uuidf LONGBLOB, + fkid MEDIUMINT, filler VARCHAR(255), + PRIMARY KEY(id)) ENGINE=$engine_type + PARTITION BY KEY(id) partitions 5; + +eval CREATE TABLE test.byrange_tbl(id MEDIUMINT NOT NULL AUTO_INCREMENT, + dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE + CURRENT_TIMESTAMP, user CHAR(255), uuidf LONGBLOB, + fkid MEDIUMINT, filler VARCHAR(255), + PRIMARY KEY(id)) ENGINE=$engine_type + PARTITION BY RANGE(id) + SUBPARTITION BY hash(id) subpartitions 2 + (PARTITION pa1 values less than (10), + PARTITION pa2 values less than (20), + PARTITION pa3 values less than (30), + PARTITION pa4 values less than (40), + PARTITION pa5 values less than (50), + PARTITION pa6 values less than (60), + PARTITION pa7 values less than (70), + PARTITION pa8 values less than (80), + PARTITION pa9 values less than (90), + PARTITION pa10 values less than (100), + PARTITION pa11 values less than MAXVALUE); + +######## Create SPs, Functions, Views and Triggers Section ############## + +delimiter |; +CREATE PROCEDURE test.proc_norm() +BEGIN + DECLARE ins_count INT DEFAULT 1000; + DECLARE del_count INT; + DECLARE cur_user VARCHAR(255); + DECLARE local_uuid VARCHAR(255); + DECLARE local_time TIMESTAMP; + + SET local_time= NOW(); + SET cur_user= CURRENT_USER(); + SET local_uuid= UUID(); + + WHILE ins_count > 0 DO + INSERT INTO test.regular_tbl VALUES (NULL, NOW(), USER() , UUID(), + ins_count,'Going to test MBR for MySQL'); + SET ins_count = ins_count - 1; + END WHILE; + + SELECT MAX(id) FROM test.regular_tbl INTO del_count; + WHILE del_count > 0 DO + DELETE FROM test.regular_tbl WHERE id = del_count; + SET del_count = del_count - 2; + END WHILE; +END| + +CREATE PROCEDURE test.proc_bykey() +BEGIN + DECLARE ins_count INT DEFAULT 1000; + DECLARE del_count INT; + DECLARE cur_user VARCHAR(255); + DECLARE local_uuid VARCHAR(255); + DECLARE local_time TIMESTAMP; + + SET local_time= NOW(); + SET cur_user= CURRENT_USER(); + SET local_uuid= UUID(); + + WHILE ins_count > 0 DO + INSERT INTO test.bykey_tbl VALUES (NULL, NOW(), USER() , UUID(), + ins_count,'Going to test MBR for MySQL'); + SET ins_count = ins_count - 1; + END WHILE; + + SELECT MAX(id) FROM test.bykey_tbl INTO del_count; + WHILE del_count > 0 DO + DELETE FROM test.bykey_tbl WHERE id = del_count; + SET del_count = del_count - 2; + END WHILE; +END| + +CREATE PROCEDURE test.proc_byrange() +BEGIN + DECLARE ins_count INT DEFAULT 1000; + DECLARE del_count INT; + DECLARE cur_user VARCHAR(255); + DECLARE local_uuid VARCHAR(255); + DECLARE local_time TIMESTAMP; + + SET local_time= NOW(); + SET cur_user = CURRENT_USER(); + SET local_uuid=UUID(); + + WHILE ins_count > 0 DO + INSERT INTO test.byrange_tbl VALUES (NULL, NOW(), USER(), UUID(), + ins_count,'Going to test MBR for MySQL'); + SET ins_count = ins_count - 1; + END WHILE; + + SELECT MAX(id) FROM test.byrange_tbl INTO del_count; + WHILE del_count > 0 DO + DELETE FROM test.byrange_tbl WHERE id = del_count; + SET del_count = del_count - 2; + END WHILE; +END| + +delimiter ;| + +############ Finish Setup Section ################### + + +############ Test Section ################### + +begin; +CALL test.proc_norm(); +commit; +SELECT count(*) as "Master regular" FROM test.regular_tbl; +begin; +CALL test.proc_bykey(); +commit; +SELECT count(*) as "Master bykey" FROM test.bykey_tbl; +begin; +CALL test.proc_byrange(); +commit; +SELECT count(*) as "Master byrange" FROM test.byrange_tbl; + +--sync_slave_with_master +connection slave; +show create table test.byrange_tbl; +SELECT count(*) "Slave norm" FROM test.regular_tbl; +SELECT count(*) "Slave bykey" FROM test.bykey_tbl; +SELECT count(*) "Slave byrange" FROM test.byrange_tbl; + +###### CLEAN UP SECTION ############## +--disable_prepare_warnings +connection master; +DROP PROCEDURE test.proc_norm; +DROP PROCEDURE test.proc_bykey; +DROP PROCEDURE test.proc_byrange; +DROP TABLE test.regular_tbl; +DROP TABLE test.bykey_tbl; +DROP TABLE test.byrange_tbl; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_innodb_bug30888.opt b/mysql-test/suite/rpl/t/rpl_innodb_bug30888.opt new file mode 100644 index 00000000..e6685732 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_innodb_bug30888.opt @@ -0,0 +1 @@ +--innodb-flush-log-at-trx-commit=2 diff --git a/mysql-test/suite/rpl/t/rpl_innodb_bug30888.test b/mysql-test/suite/rpl/t/rpl_innodb_bug30888.test new file mode 100644 index 00000000..a18b0998 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_innodb_bug30888.test @@ -0,0 +1,67 @@ +--source include/have_innodb.inc +--source include/have_binlog_format_mixed_or_row.inc +--source include/master-slave.inc + +# Set the default connection to 'master' + +--vertical_results + +#let $engine_type= 'myisam'; +let $engine_type= 'innodb'; + +######## Creat Table Section ######### +use test; + +eval CREATE TABLE test.regular_tbl(id MEDIUMINT NOT NULL AUTO_INCREMENT, + dt TIMESTAMP, user CHAR(255), uuidf LONGBLOB, + fkid MEDIUMINT, filler VARCHAR(255), + PRIMARY KEY(id)) ENGINE=$engine_type; + +######## Create SPs, Functions, Views and Triggers Section ############## + +--enable_prepare_warnings +delimiter |; +CREATE PROCEDURE test.proc_norm() +BEGIN + DECLARE ins_count INT DEFAULT 1000; + DECLARE del_count INT; + DECLARE cur_user VARCHAR(255); + DECLARE local_uuid VARCHAR(255); + DECLARE local_time TIMESTAMP; + + SET local_time= NOW(); + SET cur_user= CURRENT_USER(); + SET local_uuid= UUID(); + + WHILE ins_count > 0 DO + INSERT INTO test.regular_tbl VALUES (NULL, NOW(), USER() , UUID(), + ins_count,'Going to test MBR for MySQL'); + SET ins_count = ins_count - 1; + END WHILE; + + SELECT MAX(id) FROM test.regular_tbl INTO del_count; + WHILE del_count > 0 DO + DELETE FROM test.regular_tbl WHERE id = del_count; + SET del_count = del_count - 2; + END WHILE; +END| + +delimiter ;| +--disable_prepare_warnings +############ Finish Setup Section ################### + + +############ Test Section ################### + +CALL test.proc_norm(); + +--sync_slave_with_master + +###### CLEAN UP SECTION ############## + +connection master; +DROP PROCEDURE test.proc_norm; +DROP TABLE test.regular_tbl; + +--source include/rpl_end.inc + diff --git a/mysql-test/suite/rpl/t/rpl_innodb_mixed_ddl.test b/mysql-test/suite/rpl/t/rpl_innodb_mixed_ddl.test new file mode 100644 index 00000000..5147e67c --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_innodb_mixed_ddl.test @@ -0,0 +1,9 @@ +######################################### +# Purpose: testing the replication in mixed mode +# Requirements: define binlog format for mysqld as in example below: +# ./mysql-test-run.pl --mysqld=--binlog-format=mixed +######################################### +--source include/have_binlog_format_mixed.inc +--source include/have_innodb.inc +let $engine_type= innodb; +--source suite/rpl/include/rpl_mixed_ddl.inc diff --git a/mysql-test/suite/rpl/t/rpl_innodb_mixed_dml.test b/mysql-test/suite/rpl/t/rpl_innodb_mixed_dml.test new file mode 100644 index 00000000..d04ced0f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_innodb_mixed_dml.test @@ -0,0 +1,9 @@ +######################################### +# Purpose: testing the replication in mixed mode +# Requirements: define binlog format for mysqld as in example below: +# ./mysql-test-run.pl --mysqld=--binlog-format=mixed +######################################### +--source include/have_binlog_format_mixed.inc +--source include/have_innodb.inc +let $engine_type= innodb; +--source suite/rpl/include/rpl_mixed_dml.inc diff --git a/mysql-test/suite/rpl/t/rpl_insert.test b/mysql-test/suite/rpl/t/rpl_insert.test new file mode 100644 index 00000000..48814508 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_insert.test @@ -0,0 +1,45 @@ +--echo # +--echo # Bug#20821: INSERT DELAYED fails to write some rows to binlog +--echo # + +--source include/not_embedded.inc +--source include/not_windows.inc +--source include/master-slave.inc + +disable_query_log; +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); +enable_query_log; + +--disable_warnings +CREATE SCHEMA IF NOT EXISTS mysqlslap; +USE mysqlslap; +--enable_warnings + +CREATE TABLE t1 (id INT, name VARCHAR(64)) ENGINE=MyISAM; + +sync_slave_with_master; +connection master; + +let $query = "INSERT DELAYED INTO t1 VALUES (1, 'Dr. No'), (2, 'From Russia With Love'), (3, 'Goldfinger'), (4, 'Thunderball'), (5, 'You Only Live Twice')"; +--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=200 --query=$query --delimiter=";" + +# Wait until all the 5000 inserts has been inserted into the table +let $wait_condition= SELECT COUNT(*) = 5000 FROM mysqlslap.t1; +source include/wait_condition.inc; +SELECT COUNT(*) FROM mysqlslap.t1; + +connection slave; +# Wait until all the 5000 inserts has been inserted into the table +let $wait_condition= SELECT COUNT(*) = 5000 FROM mysqlslap.t1; +source include/wait_condition.inc; +SELECT COUNT(*) FROM mysqlslap.t1; + +--echo # +--echo # Cleanup +--echo # + +connection master; +USE test; +DROP SCHEMA mysqlslap; +sync_slave_with_master; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_insert_delayed.test b/mysql-test/suite/rpl/t/rpl_insert_delayed.test new file mode 100644 index 00000000..6a88899f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_insert_delayed.test @@ -0,0 +1,5 @@ +--source include/not_embedded.inc +--source include/not_windows.inc +--source include/master-slave.inc +--source include/rpl_insert_delayed.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_insert_id.test b/mysql-test/suite/rpl/t/rpl_insert_id.test new file mode 100644 index 00000000..c9d84049 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_insert_id.test @@ -0,0 +1,6 @@ +################################# +# Wrapper for rpl_insert_id.test# +################################# +-- source include/have_innodb.inc +let $engine_type=myisam; +-- source include/rpl_insert_id.test diff --git a/mysql-test/suite/rpl/t/rpl_insert_id_pk.test b/mysql-test/suite/rpl/t/rpl_insert_id_pk.test new file mode 100644 index 00000000..d9ba2a2b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_insert_id_pk.test @@ -0,0 +1,6 @@ +################################# +# Wrapper for rpl_insert_id.test# +################################# +-- source include/have_innodb.inc +let $engine_type=innodb; +-- source include/rpl_insert_id_pk.test diff --git a/mysql-test/suite/rpl/t/rpl_insert_ignore.test b/mysql-test/suite/rpl/t/rpl_insert_ignore.test new file mode 100644 index 00000000..2940ad16 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_insert_ignore.test @@ -0,0 +1,15 @@ +##################################### +# Wrapper for rpl_insert_ignore.test# +##################################### +-- source include/have_innodb.inc +-- source include/master-slave.inc + +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); + +-- let $engine_type=innodb +-- source include/rpl_insert_ignore.test + +-- let $engine_type=myisam +-- source include/rpl_insert_ignore.test + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_invoked_features-master.opt b/mysql-test/suite/rpl/t/rpl_invoked_features-master.opt new file mode 100644 index 00000000..96f0ce3f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_invoked_features-master.opt @@ -0,0 +1 @@ +--default-storage-engine=MyISAM diff --git a/mysql-test/suite/rpl/t/rpl_invoked_features.test b/mysql-test/suite/rpl/t/rpl_invoked_features.test new file mode 100644 index 00000000..91391cf8 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_invoked_features.test @@ -0,0 +1,311 @@ +######################################### +# Author: Serge Kozlov skozlov@mysql.com +# Date: 04/25/2007 +# Purpose: Testing Invocation and Invoked +# Features for Replication. +######################################### + +--source include/have_innodb.inc +--source include/master-slave.inc + +disable_query_log; +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); +enable_query_log; + +# --disable_warnings/--enable_warnings added before/after query +# if one uses UUID() function because we need to avoid warnings +# for STATEMENT binlog format + +# Non-transactional engine +--let $engine_type= myisam + +# Transactional engine +--let $engine_type2= innodb + + +# +# Clean up +# + +USE test; +--disable_warnings +DROP VIEW IF EXISTS v1,v11; +DROP TABLE IF EXISTS t1,t2,t3,t11,t12,t13; +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p11; +DROP FUNCTION IF EXISTS f1; +DROP FUNCTION IF EXISTS f2; +DROP EVENT IF EXISTS e1; +DROP EVENT IF EXISTS e11; +--enable_warnings + + +# +# Prepare objects (tables etc) +# + +# Create tables + +--echo +eval CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b INT, c VARCHAR(64)) ENGINE=$engine_type; +INSERT INTO t1 VALUES (1,1,'1'); +--disable_warnings +INSERT INTO t1 VALUES (2,2,UUID()); +--enable_warnings +eval CREATE TABLE t2 (a INT UNIQUE, b INT, c VARCHAR(64)) ENGINE=$engine_type; +INSERT INTO t2 VALUES (1,1,'1'); +--disable_warnings +INSERT INTO t2 VALUES (2,2,UUID()); +--enable_warnings + +eval CREATE TABLE t11 (a INT NOT NULL PRIMARY KEY, b INT, c VARCHAR(64)) ENGINE=$engine_type2; +INSERT INTO t11 VALUES (1,1,'1'); +--disable_warnings +INSERT INTO t11 VALUES (2,2,UUID()); +--enable_warnings +eval CREATE TABLE t12 (a INT UNIQUE, b INT, c VARCHAR(64)) ENGINE=$engine_type2; +INSERT INTO t12 VALUES (1,1,'1'); +--disable_warnings +INSERT INTO t12 VALUES (2,2,UUID()); +--enable_warnings + +# Create invoked features +--echo +# Create view for tables t1,t11 +CREATE VIEW v1 AS SELECT * FROM t1; +CREATE VIEW v11 AS SELECT * FROM t11; + +# Create triggers for t1,t11 +DELIMITER |; + +CREATE TRIGGER t1_tr1 BEFORE INSERT ON t1 FOR EACH ROW +BEGIN + INSERT INTO t2 VALUES (NEW.a, NEW.b, NEW.c); + INSERT INTO t3 VALUES (NEW.a, NEW.b, NEW.c); +END| + +CREATE TRIGGER t1_tr2 BEFORE UPDATE ON t1 FOR EACH ROW +BEGIN + UPDATE t2 SET c = ''; + UPDATE t3 SET c = ''; +END| + +CREATE TRIGGER t11_tr1 BEFORE INSERT ON t11 FOR EACH ROW +BEGIN + INSERT INTO t12 VALUES (NEW.a, NEW.b, NEW.c); + INSERT INTO t13 VALUES (NEW.a, NEW.b, NEW.c); +END| + +CREATE TRIGGER t11_tr2 BEFORE UPDATE ON t11 FOR EACH ROW +BEGIN + UPDATE t12 SET c = ''; + UPDATE t13 SET c = ''; +END| + +# Create events which will run every 1 sec +CREATE EVENT e1 ON SCHEDULE EVERY 1 SECOND DISABLE DO +BEGIN + ALTER EVENT e1 DISABLE; + CALL p1(10, ''); +END| + +CREATE EVENT e11 ON SCHEDULE EVERY 1 SECOND DISABLE DO +BEGIN + ALTER EVENT e11 DISABLE; + CALL p11(10, ''); +END| + +# Create functions and procedures used for events +CREATE FUNCTION f1 (x INT) RETURNS VARCHAR(64) +BEGIN + IF x > 5 THEN + RETURN UUID(); + END IF; + RETURN ''; +END| + +CREATE FUNCTION f2 (x INT) RETURNS VARCHAR(64) +BEGIN + RETURN f1(x); +END| + +CREATE PROCEDURE p1 (IN x INT, IN y VARCHAR(64)) +BEGIN + INSERT IGNORE INTO t1 VALUES (x,x,y); +END| + +CREATE PROCEDURE p11 (IN x INT, IN y VARCHAR(64)) +BEGIN + INSERT IGNORE INTO t11 VALUES (x,x,y); +END| + +DELIMITER ;| + + +# +# Start test case +# + +# Do some actions for non-transactional tables +--echo +CREATE TABLE t3 SELECT * FROM v1; +INSERT INTO t1 VALUES (3,3,''); +UPDATE t1 SET c='2' WHERE a = 1; +--disable_warnings +INSERT INTO t1 VALUES(4,4,f1(4)); +--enable_warnings +INSERT INTO t1 VALUES (100,100,''); +--disable_warnings +CALL p1(5, UUID()); +--enable_warnings +INSERT INTO t1 VALUES (101,101,''); +--disable_warnings +INSERT INTO t1 VALUES(6,6,f1(6)); +--enable_warnings +INSERT INTO t1 VALUES (102,102,''); +--disable_warnings +INSERT INTO t1 VALUES(7,7,f2(7)); +--enable_warnings +INSERT INTO t1 VALUES (103,103,''); + +# Do some actions for transactional tables +--echo +--disable_warnings +CREATE TABLE t13 SELECT * FROM v11; +INSERT INTO t11 VALUES (3,3,''); +UPDATE t11 SET c='2' WHERE a = 1; +INSERT INTO t11 VALUES(4,4,f1(4)); +INSERT INTO t11 VALUES (100,100,''); +CALL p11(5, UUID()); +INSERT INTO t11 VALUES (101,101,''); +INSERT INTO t11 VALUES(6,6,f1(6)); +INSERT INTO t11 VALUES (102,102,''); +INSERT INTO t11 VALUES(7,7,f2(7)); +INSERT INTO t11 VALUES (103,103,''); +--enable_warnings + +# Scheduler is on +--echo +# Temporally events fire sequentally due Bug#29020. +SET GLOBAL EVENT_SCHEDULER = on; +# Wait while events will executed +ALTER EVENT e1 ENABLE; +let $wait_condition= SELECT COUNT(*) = 1 FROM t1 WHERE t1.a = 10; +--source include/wait_condition.inc +ALTER EVENT e11 ENABLE; +let $wait_condition= SELECT COUNT(*) = 1 FROM t11 WHERE t11.a = 10; +--source include/wait_condition.inc +SET GLOBAL EVENT_SCHEDULER = off; + +# Check original objects +--echo +--sorted_result +SHOW TABLES LIKE 't%'; +--sorted_result +SELECT table_name FROM information_schema.views WHERE table_schema='test'; +--sorted_result +SELECT trigger_name, event_manipulation, event_object_table FROM information_schema.triggers WHERE trigger_schema='test'; +--sorted_result +SELECT routine_type, routine_name FROM information_schema.routines WHERE routine_schema='test'; +--sorted_result +SELECT event_name, status FROM information_schema.events WHERE event_schema='test'; + +# Check original data +--echo +SELECT COUNT(*) FROM t1; +SELECT a,b FROM t1 ORDER BY a; +SELECT COUNT(*) FROM t2; +SELECT a,b FROM t2 ORDER BY a; +SELECT COUNT(*) FROM t3; +SELECT a,b FROM t3 ORDER BY a; +SELECT a,b FROM v1 ORDER BY a; +SELECT COUNT(*) FROM t11; +SELECT a,b FROM t11 ORDER BY a; +SELECT COUNT(*) FROM t12; +SELECT a,b FROM t12 ORDER BY a; +SELECT COUNT(*) FROM t13; +SELECT a,b FROM t13 ORDER BY a; +SELECT a,b FROM v11 ORDER BY a; + +--sync_slave_with_master slave + +# Check replicated objects +--echo +--sorted_result +SHOW TABLES LIKE 't%'; +--sorted_result +SELECT table_name FROM information_schema.views WHERE table_schema='test'; +--sorted_result +SELECT trigger_name, event_manipulation, event_object_table FROM information_schema.triggers WHERE trigger_schema='test'; +--sorted_result +SELECT routine_type, routine_name FROM information_schema.routines WHERE routine_schema='test'; +--sorted_result +SELECT event_name, status FROM information_schema.events WHERE event_schema='test'; + +# Check replicated data +--echo +SELECT COUNT(*) FROM t1; +SELECT a,b FROM t1 ORDER BY a; +SELECT COUNT(*) FROM t2; +SELECT a,b FROM t2 ORDER BY a; +SELECT COUNT(*) FROM t3; +SELECT a,b FROM t3 ORDER BY a; +SELECT a,b FROM v1 ORDER BY a; +SELECT COUNT(*) FROM t11; +SELECT a,b FROM t11 ORDER BY a; +SELECT COUNT(*) FROM t12; +SELECT a,b FROM t12 ORDER BY a; +SELECT COUNT(*) FROM t13; +SELECT a,b FROM t13 ORDER BY a; +SELECT a,b FROM v11 ORDER BY a; + +# Remove UUID() before comparing and sort tables + +--connection master +--echo +UPDATE t1 SET c=''; +UPDATE t2 SET c=''; +UPDATE t3 SET c=''; +--disable_warnings +UPDATE t11 SET c=''; +--enable_warnings +UPDATE t12 SET c=''; +UPDATE t13 SET c=''; + +ALTER TABLE t3 ORDER BY a; +ALTER TABLE t13 ORDER BY a; + +--sync_slave_with_master slave + +# Compare a data from master and slave +--echo +--exec $MYSQL_DUMP --compact --order-by-primary --skip-extended-insert --no-create-info test > $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_master.sql +--exec $MYSQL_DUMP_SLAVE --compact --order-by-primary --skip-extended-insert --no-create-info test > $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_slave.sql +--diff_files $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_master.sql $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_slave.sql + + +# +# Clean up +# + +# Remove dumps +--echo +--remove_file $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_master.sql +--remove_file $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_slave.sql + +# Remove tables,views,procedures,functions +--connection master +--echo +DROP VIEW IF EXISTS v1,v11; +DROP TABLE IF EXISTS t1,t2,t3,t11,t12,t13; +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p11; +DROP FUNCTION IF EXISTS f1; +DROP FUNCTION IF EXISTS f2; +DROP EVENT IF EXISTS e1; +DROP EVENT IF EXISTS e11; + +--sync_slave_with_master slave + +# End 5.1 test case +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_iodku.test b/mysql-test/suite/rpl/t/rpl_iodku.test new file mode 100644 index 00000000..815b927c --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_iodku.test @@ -0,0 +1,50 @@ +--source include/have_innodb.inc +--source include/master-slave.inc + +if (`select @@binlog_format = "statement"`) +{ + call mtr.add_suppression("Unsafe statement written to the binary log using statement"); +} + +## MDEV-28310 loss of binlog event for multi-record IODKU +# Check that the duplicate key error does not cause +# loss of replication event for IODKU that specifies values +# for at least two unique columns per record. +# "Implicit" NULL value of the auto-increment column also counts. + +CREATE TABLE t1 (id INT PRIMARY KEY AUTO_INCREMENT, a INT, b INT, c INT, + UNIQUE (a), UNIQUE (b)) ENGINE=innodb; +INSERT INTO t1 (`a`,`c`) VALUES (1,1), (2,1) ON DUPLICATE KEY UPDATE c = 1; +--echo # UNSAFE +# because of two keys involved: a UK and PK even though implicitly via auto-inc +INSERT INTO t1 (`a`,`c`) VALUES (3, 1),(2,1), (1,1) ON DUPLICATE KEY UPDATE c = a * 10 + VALUES(c); +SELECT * from t1; + +--sync_slave_with_master +--let $diff_tables = master:t1,slave:t1 +--source include/diff_tables.inc + +## MDEV-21810 MBR: Unexpected "Unsafe statement" warning for unsafe IODKU +# Unnecessary unsafe statement warning is not error-logged anymore. + + +--connection master +CREATE OR REPLACE TABLE t1 (a INT, b INT, c INT, UNIQUE (a), UNIQUE (b)) ENGINE=innodb; +INSERT INTO t1 VALUES (1,10,1); +--echo # eligable for the statement format run unsafe warning +INSERT INTO t1 VALUES (2,20,2) ON DUPLICATE KEY UPDATE c = 100; +--echo # not eligable: no warning in the statement format run +INSERT INTO t1 (`a`,`c`) VALUES (3, 1) ON DUPLICATE KEY UPDATE c = 99; +SELECT * from t1; + +--sync_slave_with_master +--let $diff_tables = master:t1,slave:t1 +--source include/diff_tables.inc + +# Cleanup +--connection master +DROP TABLE t1; +--sync_slave_with_master + + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_ip_mix.cnf b/mysql-test/suite/rpl/t/rpl_ip_mix.cnf new file mode 100644 index 00000000..00e2637d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_ip_mix.cnf @@ -0,0 +1,56 @@ +# Use default setting for mysqld processes +!include include/default_mysqld.cnf +!include include/default_client.cnf + +[mysqld.1] + +# Run the master.sh script before starting this process +#!run-master-sh + +log-bin= master-bin + +loose-innodb + +skip-name-resolve +bind-address= :: + + +[mysqld.2] +# Run the slave.sh script before starting this process +#!run-slave-sh + +# Append <testname>-slave.opt file to the list of argument used when +# starting the mysqld +#!use-slave-opt + +log-bin= slave-bin +relay-log= slave-relay-bin + +init-rpl-role= slave +log-slave-updates +master-retry-count= 10 + +# Values reported by slave when it connect to master +# and shows up in SHOW SLAVE STATUS; +report-host= localhost +report-port= @mysqld.2.port +report-user= root + +skip-slave-start +skip-name-resolve +bind-address= 0.0.0.0 + +# Directory where slaves find the dumps generated by "load data" +# on the server. The path need to have constant length otherwise +# test results will vary, thus a relative path is used. +slave-load-tmpdir= ../../tmp + +loose-innodb + +[ENV] +MASTER_MYPORT= @mysqld.1.port +MASTER_MYSOCK= @mysqld.1.socket + +SLAVE_MYPORT= @mysqld.2.port +SLAVE_MYSOCK= @mysqld.2.socket + diff --git a/mysql-test/suite/rpl/t/rpl_ip_mix.test b/mysql-test/suite/rpl/t/rpl_ip_mix.test new file mode 100644 index 00000000..63c5fa92 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_ip_mix.test @@ -0,0 +1,48 @@ +# Test of ipv6 format, especially "change master host=..." +# Options: --skip-name-resolve, master: --bind-address=::, slave: --bind-address=0.0.0.0 +# (see corresponding cnf file) +# +--source include/check_ipv6.inc +--source include/have_log_bin.inc + +let $IPv6= ::1; +--echo #################### IP: $IPv6 ########################### +--source include/rpl_ip_mix.inc + +let $IPv6= ::1/128; +#--echo #################### IP: $IPv6 ########################### +#--source include/rpl_ip_mix.inc + +let $IPv6= 0000:0000:0000:0000:0000:0000:0000:0001; +--echo #################### IP: $IPv6 ########################### +--source include/rpl_ip_mix.inc + +let $IPv6= 0:0:0:0:0:0:0:1; +--echo #################### IP: $IPv6 ########################### +--source include/rpl_ip_mix.inc + +let $IPv6= ::1; +--echo #################### IP: $IPv6 mix ####################### +connect (master,$IPv6,root,,test,$MASTER_MYPORT); +connect (slave,127.0.0.1,root,,test,$SLAVE_MYPORT); +connection master; +reset master; +source include/show_master_status.inc; +connection slave; +reset slave; +let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +--echo Master-Host: $master_host +eval change master to master_host='$IPv6'; +let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +--echo Master-Host: $master_host +eval change master to master_host='127.0.0.1'; +let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +--echo Master-Host: $master_host +eval change master to master_host='0:0:0:0:0:0:0:1'; +let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +--echo Master-Host: $master_host + +# clean up +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_USER='root'; +--connection slave +reset slave all; diff --git a/mysql-test/suite/rpl/t/rpl_ip_mix2.cnf b/mysql-test/suite/rpl/t/rpl_ip_mix2.cnf new file mode 100644 index 00000000..306df437 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_ip_mix2.cnf @@ -0,0 +1,56 @@ +# Use default setting for mysqld processes +!include include/default_mysqld.cnf +!include include/default_client.cnf + +[mysqld.1] + +# Run the master.sh script before starting this process +#!run-master-sh + +log-bin= master-bin + +loose-innodb + +skip-name-resolve +bind-address= 0.0.0.0 + + +[mysqld.2] +# Run the slave.sh script before starting this process +#!run-slave-sh + +# Append <testname>-slave.opt file to the list of argument used when +# starting the mysqld +#!use-slave-opt + +log-bin= slave-bin +relay-log= slave-relay-bin + +init-rpl-role= slave +log-slave-updates +master-retry-count= 10 + +# Values reported by slave when it connect to master +# and shows up in SHOW SLAVE STATUS; +report-host= localhost +report-port= @mysqld.2.port +report-user= root + +skip-slave-start +skip-name-resolve +bind-address= :: + +# Directory where slaves find the dumps generated by "load data" +# on the server. The path need to have constant length otherwise +# test results will vary, thus a relative path is used. +slave-load-tmpdir= ../../tmp + +loose-innodb + +[ENV] +MASTER_MYPORT= @mysqld.1.port +MASTER_MYSOCK= @mysqld.1.socket + +SLAVE_MYPORT= @mysqld.2.port +SLAVE_MYSOCK= @mysqld.2.socket + diff --git a/mysql-test/suite/rpl/t/rpl_ip_mix2.test b/mysql-test/suite/rpl/t/rpl_ip_mix2.test new file mode 100644 index 00000000..3fff54e5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_ip_mix2.test @@ -0,0 +1,49 @@ +# Test of ipv6 format, especially "change master host=..." +# Options: --skip-name-resolve, master: --bind-address=0.0.0.0, slave: --bind-address=:: +# (see corresponding cnf file) +# +--source include/check_ipv6.inc +--source include/have_log_bin.inc + +let $IPv6= ::1; +--echo #################### IP: $IPv6 ########################### +--source include/rpl_ip_mix2.inc + +let $IPv6= ::1/128; +#--echo #################### IP: $IPv6 ########################### +#--source include/rpl_ip_mix2.inc + +let $IPv6= 0000:0000:0000:0000:0000:0000:0000:0001; +--echo #################### IP: $IPv6 ########################### +--source include/rpl_ip_mix2.inc + +let $IPv6= 0:0:0:0:0:0:0:1; +--echo #################### IP: $IPv6 ########################### +--source include/rpl_ip_mix2.inc + +let $IPv6= ::1; +--echo #################### IP: $IPv6 mix ####################### +connect (master,127.0.0.1,root,,test,$MASTER_MYPORT); +connect (slave,$IPv6,root,,test,$SLAVE_MYPORT); +connection master; +reset master; +source include/show_master_status.inc; +save_master_pos; +connection slave; +reset slave; +let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +--echo Master-Host: $master_host +eval change master to master_host='$IPv6'; +let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +--echo Master-Host: $master_host +eval change master to master_host='127.0.0.1'; +let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +--echo Master-Host: $master_host +eval change master to master_host='0:0:0:0:0:0:0:1'; +let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +--echo Master-Host: $master_host + +# clean up +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_USER='root'; +connection slave; +reset slave all; diff --git a/mysql-test/suite/rpl/t/rpl_ipv4_as_ipv6.cnf b/mysql-test/suite/rpl/t/rpl_ipv4_as_ipv6.cnf new file mode 100644 index 00000000..b646a408 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_ipv4_as_ipv6.cnf @@ -0,0 +1,56 @@ +# Use default setting for mysqld processes +!include include/default_mysqld.cnf +!include include/default_client.cnf + +[mysqld.1] + +# Run the master.sh script before starting this process +#!run-master-sh + +log-bin= master-bin + +loose-innodb + +skip-name-resolve +bind-address= 0.0.0.0 + + +[mysqld.2] +# Run the slave.sh script before starting this process +#!run-slave-sh + +# Append <testname>-slave.opt file to the list of argument used when +# starting the mysqld +#!use-slave-opt + +log-bin= slave-bin +relay-log= slave-relay-bin + +init-rpl-role= slave +log-slave-updates +master-retry-count= 10 + +# Values reported by slave when it connect to master +# and shows up in SHOW SLAVE STATUS; +report-host= localhost +report-port= @mysqld.2.port +report-user= root + +skip-slave-start +skip-name-resolve +bind-address= 0.0.0.0 + +# Directory where slaves find the dumps generated by "load data" +# on the server. The path need to have constant length otherwise +# test results will vary, thus a relative path is used. +slave-load-tmpdir= ../../tmp + +loose-innodb + +[ENV] +MASTER_MYPORT= @mysqld.1.port +MASTER_MYSOCK= @mysqld.1.socket + +SLAVE_MYPORT= @mysqld.2.port +SLAVE_MYSOCK= @mysqld.2.socket + diff --git a/mysql-test/suite/rpl/t/rpl_ipv4_as_ipv6.test b/mysql-test/suite/rpl/t/rpl_ipv4_as_ipv6.test new file mode 100644 index 00000000..d17b32c3 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_ipv4_as_ipv6.test @@ -0,0 +1,63 @@ +# Test of ipv4 (127.0.0.1) in ipv6 format, especially "change master host=..." +# Options: --skip-name-resolve, --bind-address=0.0.0.0 (see corresponding cnf file) +# for master and slave +# +--source include/have_ipv4_mapped.inc +--source include/have_log_bin.inc + +let $IPv6= 127.0.0.1; +--echo #################### IP: $IPv6 ########################### +--source include/rpl_ipv6.inc + +let $IPv6= 0:0:0:0:0:FFFF:127.0.0.1; +--echo #################### IP: $IPv6 ########################### +--source include/rpl_ipv6.inc + +let $IPv6= 0000:0000:0000:0000:0000:FFFF:127.0.0.1; +--echo #################### IP: $IPv6 ########################### +--source include/rpl_ipv6.inc + +let $IPv6= 0:0000:0000:0:0000:FFFF:127.0.0.1; +--echo #################### IP: $IPv6 ########################### +--source include/rpl_ipv6.inc + +let $IPv6= 0::0000:FFFF:127.0.0.1; +--echo #################### IP: $IPv6 ########################### +--source include/rpl_ipv6.inc + +#let $IPv6= 0:0:0:0:0:FFFF:127.0.0.1/96; +#--echo #################### IP: $IPv6 ########################### +#--source include/rpl_ipv6.inc + +let $IPv6= ::FFFF:127.0.0.1; +--echo #################### IP: $IPv6 ########################### +--source include/rpl_ipv6.inc + +#let $IPv6= ::FFFF:127.0.0.1/96; +#--echo #################### IP: $IPv6 ########################### +#--source include/rpl_ipv6.inc + +let $IPv6= ::FFFF:127.0.0.1; +--echo #################### IP: $IPv6 ########################### +connect (master,127.0.0.1,root,,test,$MASTER_MYPORT); +connect (slave,127.0.0.1,root,,test,$SLAVE_MYPORT); +connection master; +reset master; +source include/show_master_status.inc; +save_master_pos; +connection slave; +reset slave; +let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +--echo Master-Host: $master_host +eval change master to master_host='$IPv6'; +let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +--echo Master-Host: $master_host +eval change master to master_host='127.0.0.1'; +let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +--echo Master-Host: $master_host +eval change master to master_host='0:0000:0000:0:0000:FFFF:127.0.0.1'; +let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +--echo Master-Host: $master_host + +# clean up +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_USER='root'; diff --git a/mysql-test/suite/rpl/t/rpl_ipv6.cnf b/mysql-test/suite/rpl/t/rpl_ipv6.cnf new file mode 100644 index 00000000..6bf97a94 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_ipv6.cnf @@ -0,0 +1,56 @@ +# Use default setting for mysqld processes +!include include/default_mysqld.cnf +!include include/default_client.cnf + +[mysqld.1] + +# Run the master.sh script before starting this process +#!run-master-sh + +log-bin= master-bin + +loose-innodb + +skip-name-resolve +bind-address= * + + +[mysqld.2] +# Run the slave.sh script before starting this process +#!run-slave-sh + +# Append <testname>-slave.opt file to the list of argument used when +# starting the mysqld +#!use-slave-opt + +log-bin= slave-bin +relay-log= slave-relay-bin + +init-rpl-role= slave +log-slave-updates +master-retry-count= 10 + +# Values reported by slave when it connect to master +# and shows up in SHOW SLAVE STATUS; +report-host= localhost +report-port= @mysqld.2.port +report-user= root + +skip-slave-start +skip-name-resolve +bind-address= * + +# Directory where slaves find the dumps generated by "load data" +# on the server. The path need to have constant length otherwise +# test results will vary, thus a relative path is used. +slave-load-tmpdir= ../../tmp + +loose-innodb + +[ENV] +MASTER_MYPORT= @mysqld.1.port +MASTER_MYSOCK= @mysqld.1.socket + +SLAVE_MYPORT= @mysqld.2.port +SLAVE_MYSOCK= @mysqld.2.socket + diff --git a/mysql-test/suite/rpl/t/rpl_ipv6.test b/mysql-test/suite/rpl/t/rpl_ipv6.test new file mode 100644 index 00000000..f3795832 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_ipv6.test @@ -0,0 +1,49 @@ +# Test of ipv6 format, especially "change master host=..." +# Options: --skip-name-resolve, --bind-address=:: (see corresponding cnf file) +# for master and slave. +# +--source include/check_ipv6.inc +# Can't be tested with windows due to mixed format like 0::0000:FFFF:127.0.0.1 +--source include/not_windows.inc +--source include/have_log_bin.inc + +let $IPv6= ::1; +--echo #################### IP: $IPv6 ########################### +--source include/rpl_ipv6.inc + +let $IPv6= ::1/128; +#--echo #################### IP: $IPv6 ########################### +#--source include/rpl_ipv6.inc + +let $IPv6= 0000:0000:0000:0000:0000:0000:0000:0001; +--echo #################### IP: $IPv6 ########################### +--source include/rpl_ipv6.inc + +let $IPv6= 0:0:0:0:0:0:0:1; +--echo #################### IP: $IPv6 ########################### +--source include/rpl_ipv6.inc + +let $IPv6= ::1; +--echo #################### IP: $IPv6 mix ####################### +connect (master,127.0.0.1,root,,test,$MASTER_MYPORT); +connect (slave,127.0.0.1,root,,test,$SLAVE_MYPORT); +connection master; +reset master; +source include/show_master_status.inc; +save_master_pos; +connection slave; +reset slave; +let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +--echo Master-Host: $master_host +eval change master to master_host='$IPv6'; +let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +--echo Master-Host: $master_host +eval change master to master_host='127.0.0.1'; +let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +--echo Master-Host: $master_host +eval change master to master_host='0:0:0:0:0:0:0:1'; +let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +--echo Master-Host: $master_host + +# clean up +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_USER='root'; diff --git a/mysql-test/suite/rpl/t/rpl_killed_ddl-master.opt b/mysql-test/suite/rpl/t/rpl_killed_ddl-master.opt new file mode 100644 index 00000000..dcc136e1 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_killed_ddl-master.opt @@ -0,0 +1 @@ +--loose-debug-dbug=d,debug_lock_before_query_log_event diff --git a/mysql-test/suite/rpl/t/rpl_killed_ddl.test b/mysql-test/suite/rpl/t/rpl_killed_ddl.test new file mode 100644 index 00000000..6415b3e8 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_killed_ddl.test @@ -0,0 +1,349 @@ +# ==== Purpose ==== +# +# This test check if DDL statements are correctly binlogged when the +# thread is killed +# +# ==== Method ==== +# +# Start a DDL query and kill it, check if the error code of the binlog +# event is correct. +# +# DDL statements tested: +# CREATE/ALTER/RENAME/DROP DATABASE +# CREATE/ALTER/DROP EVENT +# CREATE/ALTER/DROP FUNCTION +# CREATE/ALTER/DROP PROCEDURE +# CREATE/ALTER/DROP SERVER +# CREATE/ALTER/RENAME/DROP TABLE +# CREATE/DROP TRIGGER +# CREATE/ALTER/DROP VIEW +# +# ==== Bugs ===== +# +# BUG#37145 +# +# ==== TODO ==== +# +# There are some part of the test are temporarily disabled because of +# the following bugs, please enable then once they get fixed: +# - BUG#22473427 +# - Bug#22587377 + +# Temporarily disabled on Windows due to bug #47638 +--source include/not_windows.inc + +source include/have_debug.inc; +source include/master-slave.inc; + +# Use the DBUG_SYNC_POINT to make sure the thread running the DDL is +# waiting before creating the query log event + +let $debug_lock= "debug_lock.before_query_log_event"; + +######## INITIALIZATION ######## + +disable_warnings; +DROP DATABASE IF EXISTS d1; +DROP DATABASE IF EXISTS d2; +DROP DATABASE IF EXISTS d3; +DROP DATABASE IF EXISTS d4; +DROP EVENT IF EXISTS e1; +DROP EVENT IF EXISTS e2; +DROP EVENT IF EXISTS e3; +DROP EVENT IF EXISTS e4; +DROP FUNCTION IF EXISTS f1; +DROP FUNCTION IF EXISTS f2; +DROP FUNCTION IF EXISTS f3; +DROP FUNCTION IF EXISTS f4; +DROP SERVER IF EXISTS s1; +DROP SERVER IF EXISTS s2; +DROP SERVER IF EXISTS s3; +DROP SERVER IF EXISTS s4; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +DROP TABLE IF EXISTS t3; +DROP TABLE IF EXISTS t4; +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +DROP PROCEDURE IF EXISTS p3; +DROP PROCEDURE IF EXISTS p4; +DROP TRIGGER IF EXISTS tr1; +DROP TRIGGER IF EXISTS tr2; +DROP TRIGGER IF EXISTS tr3; +DROP TRIGGER IF EXISTS tr4; +enable_warnings; + +CREATE DATABASE d1; + +CREATE EVENT e1 + ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 DAY + DO INSERT INTO test.t1 VALUES (1); + +CREATE FUNCTION f1 () RETURNS INT DETERMINISTIC + RETURN 1; + +DELIMITER //; +CREATE PROCEDURE p1 (OUT rows_cnt INT) + BEGIN + SELECT COUNT(*) INTO rows_cnt FROM t1; + END; + // +DELIMITER ;// + +CREATE SERVER s1 +FOREIGN DATA WRAPPER mysql +OPTIONS (USER 'user1', HOST '192.168.1.106', DATABASE 'test'); + +CREATE TABLE t1 (a int); +CREATE TABLE t3 (a int); + +DELIMITER //; +CREATE TRIGGER tr1 BEFORE INSERT ON t1 + FOR EACH ROW BEGIN + DELETE FROM t4 WHERE a=NEW.a; + END; + // +DELIMITER ;// + +CREATE INDEX i1 ON t1 (a); + +CREATE VIEW v1 AS SELECT a FROM t1 WHERE a < 100; + +sync_slave_with_master; + +connection master1; +let $connection_name= master1; +let $connection_id= `SELECT CONNECTION_ID()`; + +connection master; + +# This will block the execution of a statement at the DBUG_SYNC_POINT +# with given lock name +if ($debug_lock) +{ + disable_query_log; + disable_result_log; + eval SELECT IS_FREE_LOCK($debug_lock); + eval SELECT GET_LOCK($debug_lock, 10); + eval SELECT IS_FREE_LOCK($debug_lock); + enable_query_log; + enable_result_log; +} + +######## START TEST ######## + +connection master1; + +disable_warnings; + +######## DATABASE ######## + +let $rpl_diff_statement= SELECT schema_name FROM information_schema.schemata + WHERE schema_name LIKE \'d%\' ORDER BY schema_name; + +send CREATE DATABASE d2; +source include/kill_query_and_diff_master_slave.inc; + +send ALTER DATABASE d1 + DEFAULT CHARACTER SET = 'utf8'; +source include/kill_query_and_diff_master_slave.inc; + +send DROP DATABASE d1; +source include/kill_query_and_diff_master_slave.inc; + +send DROP DATABASE IF EXISTS d2; +source include/kill_query_and_diff_master_slave.inc; + +######## EVENT ######## + +let $rpl_diff_statement= SELECT event_name, event_body, execute_at + FROM information_schema.events where event_name like \'e%\' + ORDER BY event_name; + +send CREATE EVENT e2 + ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 DAY + DO INSERT INTO test.t1 VALUES (2); +source include/kill_query_and_diff_master_slave.inc; + +# Temporarily disabled,see Bug#22587377-RPL.RPL_KILLED_DDL +# FAILS SPORADICALLY ON PB2 IN 5.5 AND 5.6 +#send ALTER EVENT e1 +# ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 2 DAY; +#source include/kill_query_and_diff_master_slave.inc; + +send DROP EVENT e1; +source include/kill_query_and_diff_master_slave.inc; + +send DROP EVENT IF EXISTS e2; +source include/kill_query_and_diff_master_slave.inc; + +######## FUNCTION ######## + +--let $rpl_diff_statement= SHOW FUNCTION STATUS LIKE \'f%\' + +send CREATE FUNCTION f2 () RETURNS INT DETERMINISTIC + RETURN 1; +source include/kill_query_and_diff_master_slave.inc; + +send ALTER FUNCTION f1 SQL SECURITY INVOKER; +source include/kill_query_and_diff_master_slave.inc; + +# function f1 probably does not exist because the ALTER query was +# killed +send DROP FUNCTION f1; +source include/kill_query_and_diff_master_slave.inc; + +# function f2 probably does not exist because the CREATE query was +# killed +send DROP FUNCTION IF EXISTS f2; +source include/kill_query_and_diff_master_slave.inc; + +######## PROCEDURE ######## + +--let $rpl_diff_statement= SHOW PROCEDURE STATUS LIKE \'p%\' + +DELIMITER //; +send CREATE PROCEDURE p2 (OUT rows_cnt INT) + BEGIN + SELECT COUNT(*) INTO rows_cnt FROM t2; + END; + // +DELIMITER ;// +source include/kill_query_and_diff_master_slave.inc; + +send ALTER PROCEDURE p1 SQL SECURITY INVOKER COMMENT 'return rows_cnt of table t1'; +source include/kill_query_and_diff_master_slave.inc; + +send DROP PROCEDURE p1; +source include/kill_query_and_diff_master_slave.inc; + +send DROP PROCEDURE IF EXISTS p2; +source include/kill_query_and_diff_master_slave.inc; + +######## TABLE ######## + +--let $rpl_diff_statement= SHOW TABLES LIKE \'t%\' + +send CREATE TABLE t2 (b int); +source include/kill_query_and_diff_master_slave.inc; + +send ALTER TABLE t1 ADD (d int); +source include/kill_query_and_diff_master_slave.inc; + +send RENAME TABLE t3 TO t4; +source include/kill_query_and_diff_master_slave.inc; + +######## INDEX ######## + +--let $rpl_diff_statement= SHOW INDEX FROM t1 + +send CREATE INDEX i2 on t1 (a); +source include/kill_query_and_diff_master_slave.inc; + +send DROP INDEX i1 on t1; +source include/kill_query_and_diff_master_slave.inc; + + +######## SERVER ######## + +# Temporarily disabled, see Bug #22473427 - DROP SERVER FAILS +# AFTER ALTER SERVER+KILL QUERY + +# --let $rpl_diff_statement= SELECT * FROM mysql.servers WHERE Server_name like \'s%\' + +# send CREATE SERVER s2 +# FOREIGN DATA WRAPPER mysql +# OPTIONS (USER 'user2', HOST '192.168.1.108', DATABASE 'test'); +# source include/kill_query_and_diff_master_slave.inc; + +# send ALTER SERVER s1 +# OPTIONS (DATABASE 'test1'); +# source include/kill_query_and_diff_master_slave.inc; + +# send DROP SERVER s1; +# source include/kill_query_and_diff_master_slave.inc; + +# send DROP SERVER IF EXIST s1; +# source include/kill_query_and_diff_master_slave.inc; + +######## TRIGGER ######## + +# Make sure table t4 exists +connection master; +CREATE TABLE IF NOT EXISTS t4 (a int); +connection master1; + +--let $rpl_diff_statement= SHOW TRIGGERS LIKE \'v%\' + +DELIMITER //; +send CREATE TRIGGER tr2 BEFORE INSERT ON t4 + FOR EACH ROW BEGIN + DELETE FROM t1 WHERE a=NEW.a; + END; + // +DELIMITER ;// +source include/kill_query_and_diff_master_slave.inc; + +send DROP TRIGGER tr1; +source include/kill_query_and_diff_master_slave.inc; + +send DROP TRIGGER IF EXISTS tr2; +source include/kill_query_and_diff_master_slave.inc; + +######## VIEW ######## + +--let $rpl_diff_statement= SHOW TABLES LIKE \'v%\' + +send CREATE VIEW v2 AS SELECT a FROM t1 WHERE a > 100; +source include/kill_query_and_diff_master_slave.inc; + +send DROP VIEW v1; +source include/kill_query_and_diff_master_slave.inc; + +send DROP VIEW IF EXISTS v2; +source include/kill_query_and_diff_master_slave.inc; + +######## DROP TABLE ######## + +--let $rpl_diff_statement= SHOW TABLES LIKE \'t%\' + +send DROP TABLE t1; +source include/kill_query_and_diff_master_slave.inc; + +send DROP TABLE IF EXISTS t2; +source include/kill_query_and_diff_master_slave.inc; + +######## CLEAN UP ######## + +connection master; + +# The DROP statements above are killed during the process, so they +# does not make sure the objects are dropped. + +disable_warnings; +DROP DATABASE IF EXISTS d1; +DROP DATABASE IF EXISTS d2; +DROP DATABASE IF EXISTS d3; +DROP DATABASE IF EXISTS d4; +DROP EVENT IF EXISTS e1; +DROP EVENT IF EXISTS e2; +DROP EVENT IF EXISTS e3; +DROP EVENT IF EXISTS e4; +DROP FUNCTION IF EXISTS f1; +DROP FUNCTION IF EXISTS f2; +DROP FUNCTION IF EXISTS f3; +DROP FUNCTION IF EXISTS f4; +DROP SERVER IF EXISTS s1; +DROP SERVER IF EXISTS s2; +DROP SERVER IF EXISTS s3; +DROP SERVER IF EXISTS s4; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +DROP TABLE IF EXISTS t3; +DROP TABLE IF EXISTS t4; +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +DROP PROCEDURE IF EXISTS p3; +DROP PROCEDURE IF EXISTS p4; +enable_warnings; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_known_bugs_detection-master.opt b/mysql-test/suite/rpl/t/rpl_known_bugs_detection-master.opt new file mode 100644 index 00000000..d4ba386a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_known_bugs_detection-master.opt @@ -0,0 +1 @@ +--loose-debug=d,pretend_version_50034_in_binlog diff --git a/mysql-test/suite/rpl/t/rpl_known_bugs_detection.test b/mysql-test/suite/rpl/t/rpl_known_bugs_detection.test new file mode 100644 index 00000000..5ea056d5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_known_bugs_detection.test @@ -0,0 +1,76 @@ +# Test to see if slave can detect certain known bugs present +# on the master, and appropriately decides to stop +# (assuming the bug is fixed in the slave, slave cannot of course +# imitate the bug, so it has to stop). + +call mtr.add_suppression("Unsafe statement written to the binary log using statement format"); + +source include/have_debug.inc; +# because of pretend_version_50034_in_binlog the test can't run with checksum +source include/have_binlog_checksum_off.inc; + +# Currently only statement-based-specific bugs are here +-- source include/have_binlog_format_statement.inc + +source include/master-slave.inc; + +# testcase with INSERT SELECT +connection master; +CREATE TABLE t1 ( + id bigint(20) unsigned NOT NULL auto_increment, + field_1 int(10) unsigned NOT NULL, + field_2 varchar(255) NOT NULL, + field_3 varchar(255) NOT NULL, + PRIMARY KEY (id), + UNIQUE KEY field_1 (field_1, field_2) +); +CREATE TABLE t2 ( + field_a int(10) unsigned NOT NULL, + field_b varchar(255) NOT NULL, + field_c varchar(255) NOT NULL +); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (1, 'a', '1a'); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (2, 'b', '2b'); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (3, 'c', '3c'); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (4, 'd', '4d'); +INSERT INTO t2 (field_a, field_b, field_c) VALUES (5, 'e', '5e'); +sync_slave_with_master; +connection master; +# Updating table t1 based on values from table t2 +INSERT INTO t1 (field_1, field_2, field_3) +SELECT t2.field_a, t2.field_b, t2.field_c +FROM t2 +ON DUPLICATE KEY UPDATE +t1.field_3 = t2.field_c; +# Inserting new record into t2 +INSERT INTO t2 (field_a, field_b, field_c) VALUES (6, 'f', '6f'); +# Updating t1 again +INSERT INTO t1 (field_1, field_2, field_3) +SELECT t2.field_a, t2.field_b, t2.field_c +FROM t2 +ON DUPLICATE KEY UPDATE +t1.field_3 = t2.field_c; +SELECT * FROM t1; +connection slave; + +# show the error message +#1105 = ER_UNKNOWN_ERROR +--let $slave_sql_errno= 1105 +--let $show_slave_sql_error= 1 +--source include/wait_for_slave_sql_error.inc + +# show that it was not replicated +SELECT * FROM t1; +connection master; + +# clean up +drop table t1, t2; +connection slave; +drop table t1, t2; +# clear error message in sql thread +--source include/stop_slave_io.inc +RESET SLAVE; + +# End of 5.0 tests +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_lcase_tblnames_rewrite_db-slave.opt b/mysql-test/suite/rpl/t/rpl_lcase_tblnames_rewrite_db-slave.opt new file mode 100644 index 00000000..0031a57a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_lcase_tblnames_rewrite_db-slave.opt @@ -0,0 +1 @@ +--lower-case-table-names=1 "--replicate-rewrite-db=b37656->bug37656" diff --git a/mysql-test/suite/rpl/t/rpl_lcase_tblnames_rewrite_db.test b/mysql-test/suite/rpl/t/rpl_lcase_tblnames_rewrite_db.test new file mode 100644 index 00000000..a27a50d0 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_lcase_tblnames_rewrite_db.test @@ -0,0 +1,60 @@ +# BUG#37656 +# +# DESCRIPTION +# +# +# This test case is tests whether replication works properly when +# slave is configured with --lower-case-table-names=1 and replication +# rewrite rules are in effect. +# +# It checks four issues: +# +# (i) master contains capitalized table name +# +# (ii) slave contains lowered case table name +# +# (iii) master and slave tables do not differ +# +-- source include/not_windows.inc +-- source include/master-slave.inc + +SET SQL_LOG_BIN=0; +CREATE DATABASE B37656; +SET SQL_LOG_BIN=1; + +-- connection slave +CREATE DATABASE BUG37656; + +-- echo ### action: show that database on slave is created in lowercase +SHOW DATABASES LIKE '%37656'; + +-- connection master +USE B37656; +CREATE TABLE T1 (a int); +INSERT INTO T1 VALUES (1); + +-- echo ### assertion: master contains capitalized case table +SHOW TABLES; + +-- sync_slave_with_master + +use bug37656; + +-- echo ### assertion: slave contains lowered case table +SHOW TABLES; + +-- echo ### assertion: master and slave tables do not differ +let $diff_tables= master:B37656.T1, slave:bug37656.t1; + +-- source include/diff_tables.inc + +-- connection master +SET SQL_LOG_BIN=0; +DROP DATABASE B37656; +SET SQL_LOG_BIN=1; +SHOW DATABASES LIKE '%37656'; + +-- connection slave +DROP DATABASE BUG37656; +SHOW DATABASES LIKE '%37656'; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_loaddata.test b/mysql-test/suite/rpl/t/rpl_loaddata.test new file mode 100644 index 00000000..9f0ba95a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_loaddata.test @@ -0,0 +1,4 @@ +-- source include/have_binlog_format_statement.inc + +let $engine_type=MyISAM; +-- source include/rpl_loaddata.test diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_charset.test b/mysql-test/suite/rpl/t/rpl_loaddata_charset.test new file mode 100644 index 00000000..bb87ee95 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_loaddata_charset.test @@ -0,0 +1,49 @@ +# +# Check LOAD DATA + character sets + replication +# +source include/master-slave.inc; + +# +# Bug#15126 character_set_database is not replicated +# (LOAD DATA INFILE need it) +# +connection master; +create table t1 (a varchar(10) character set utf8); +load data infile '../../std_data/loaddata6.dat' into table t1; +set @@character_set_database=koi8r; +load data infile '../../std_data/loaddata6.dat' into table t1; +set @@character_set_database=DEFAULT; +load data infile '../../std_data/loaddata6.dat' into table t1; +load data infile '../../std_data/loaddata6.dat' into table t1; +load data infile '../../std_data/loaddata6.dat' into table t1; +set @@character_set_database=koi8r; +load data infile '../../std_data/loaddata6.dat' into table t1; +set @@character_set_database=DEFAULT; +load data infile '../../std_data/loaddata6.dat' into table t1 character set koi8r; + +select hex(a) from t1; + +sync_slave_with_master; + +select hex(a) from t1; +connection master; +drop table t1; +sync_slave_with_master; + +# +# Bug#45516 +# When slave SQL thread executing LOAD DATA command, the +# thd->variables.collation_database was not set properly to the default +# database charset +# + +echo -------------test bug#45516------------------; + +# LOAD DATA INFILE +let $LOAD_LOCAL=1; +source include/rpl_loaddata_charset.inc; + +# LOAD DATA LOCAL INFILE +let $LOAD_LOCAL=0; +source include/rpl_loaddata_charset.inc; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_fatal-slave.opt b/mysql-test/suite/rpl/t/rpl_loaddata_fatal-slave.opt new file mode 100644 index 00000000..9c846c79 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_loaddata_fatal-slave.opt @@ -0,0 +1 @@ +--loose-debug=+d,LOAD_DATA_INFILE_has_fatal_error diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_fatal.test b/mysql-test/suite/rpl/t/rpl_loaddata_fatal.test new file mode 100644 index 00000000..4e87d6de --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_loaddata_fatal.test @@ -0,0 +1,27 @@ +source include/have_binlog_format_statement.inc; +source include/have_debug.inc; +source include/master-slave.inc; + +# We do this little stunt to make sure that the slave has started +# before we stop it again. +connection master; +CREATE TABLE t1 (a INT, b INT); +INSERT INTO t1 VALUES (1,10); +sync_slave_with_master; + +# Now we feed it a load data infile, which should make it stop with a +# fatal error. +connection master; +LOAD DATA INFILE '../../std_data/rpl_loaddata.dat' INTO TABLE t1; + +connection slave; +call mtr.add_suppression("Slave SQL.*Fatal error: Not enough memory, error.* 1593"); +let $slave_sql_errno= 1593; +let $show_slave_sql_error= 1; +source include/wait_for_slave_sql_error_and_skip.inc; + +connection master; +DROP TABLE t1; +sync_slave_with_master; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_local.test b/mysql-test/suite/rpl/t/rpl_loaddata_local.test new file mode 100644 index 00000000..01f5607b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_loaddata_local.test @@ -0,0 +1,244 @@ +# +# This include file is used by more than one test suite +# (currently rpl and binlog_encryption). +# Please check all dependent tests after modifying it +# + +# See if "LOAD DATA LOCAL INFILE" is well replicated +# (LOAD DATA LOCAL INFILE is not written to the binlog +# the same way as LOAD DATA INFILE : Append_blocks are smaller). +# In MySQL 4.0 <4.0.12 there were 2 bugs with LOAD DATA LOCAL INFILE : +# - the loaded file was not written entirely to the master's binlog, +# only the first 4KB, 8KB or 16KB usually. +# - the loaded file's first line was not written entirely to the +# master's binlog (1st char was absent) +source include/master-slave.inc; + +create table t1(a int); +let $1=10000; +disable_query_log; +set SQL_LOG_BIN=0; +while ($1) +{ + insert into t1 values(1); + dec $1; +} +set SQL_LOG_BIN=1; +enable_query_log; +let $MYSQLD_DATADIR= `select @@datadir`; +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +--disable_ps2_protocol +eval select * into outfile '$MYSQLD_DATADIR/rpl_loaddatalocal.select_outfile' from t1; +--enable_ps2_protocol +#This will generate a 20KB file, now test LOAD DATA LOCAL +truncate table t1; +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval load data local infile '$MYSQLD_DATADIR/rpl_loaddatalocal.select_outfile' into table t1; +--remove_file $MYSQLD_DATADIR/rpl_loaddatalocal.select_outfile +sync_slave_with_master; +select a,count(*) from t1 group by a; +connection master; +drop table t1; +sync_slave_with_master; + +# End of 4.1 tests + +# +# Now let us test how well we replicate LOAD DATA LOCAL in situation when +# we met duplicates in tables to which we are adding rows. +# (It supposed that LOAD DATA LOCAL ignores such errors) +# +connection master; +create table t1(a int); +insert into t1 values (1), (2), (2), (3); +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +--disable_ps2_protocol +eval select * into outfile '$MYSQLD_DATADIR/rpl_loaddatalocal.select_outfile' from t1; +--enable_ps2_protocol +drop table t1; +create table t1(a int primary key); +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval load data local infile '$MYSQLD_DATADIR/rpl_loaddatalocal.select_outfile' into table t1; +--remove_file $MYSQLD_DATADIR/rpl_loaddatalocal.select_outfile +SELECT * FROM t1 ORDER BY a; +save_master_pos; +connection slave; +sync_with_master; +SELECT * FROM t1 ORDER BY a; +connection master; +drop table t1; +save_master_pos; +connection slave; +sync_with_master; + + +# +# Bug22504 load data infile sql statement in replication architecture get error +# +--echo ==== Bug22504 Initialize ==== + +--connection master + +SET sql_mode='ignore_space'; +CREATE TABLE t1(a int); +insert into t1 values (1), (2), (3), (4); +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +--disable_ps2_protocol +eval select * into outfile '$MYSQLD_DATADIR/rpl_loaddatalocal.select_outfile' from t1; +--enable_ps2_protocol +truncate table t1; +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval load data local infile '$MYSQLD_DATADIR/rpl_loaddatalocal.select_outfile' into table t1; +--remove_file $MYSQLD_DATADIR/rpl_loaddatalocal.select_outfile +SELECT * FROM t1 ORDER BY a; + +sync_slave_with_master; +SELECT * FROM t1 ORDER BY a; + +--echo ==== Clean up ==== + +connection master; +DROP TABLE t1; + +sync_slave_with_master; + +--echo +--echo Bug #43746: +--echo "return wrong query string when parse 'load data infile' sql statement" +--echo + +connection master; +let $MYSQLD_DATADIR= `select @@datadir`; +SELECT @@SESSION.sql_mode INTO @old_mode; + +SET sql_mode='ignore_space'; + +CREATE TABLE t1(a int); +INSERT INTO t1 VALUES (1), (2), (3), (4); + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +--disable_ps2_protocol +eval SELECT * INTO OUTFILE '$MYSQLD_DATADIR/bug43746.sql' FROM t1; +--enable_ps2_protocol +TRUNCATE TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA LOCAL INFILE '$MYSQLD_DATADIR/bug43746.sql' INTO TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD/* look mum, with comments in weird places! */DATA/* oh hai */LOCAL INFILE '$MYSQLD_DATADIR/bug43746.sql'/* we are */INTO/* from the internets */TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA/*!10000 LOCAL */INFILE '$MYSQLD_DATADIR/bug43746.sql' INTO TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA LOCAL INFILE '$MYSQLD_DATADIR/bug43746.sql' /*!10000 INTO */ TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA LOCAL INFILE '$MYSQLD_DATADIR/bug43746.sql' /*!10000 INTO TABLE */ t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA /*!10000 LOCAL INFILE '$MYSQLD_DATADIR/bug43746.sql' INTO TABLE */ t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA/*!10000 LOCAL */INFILE '$MYSQLD_DATADIR/bug43746.sql'/*!10000 INTO*/TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA/*!10000 LOCAL */INFILE '$MYSQLD_DATADIR/bug43746.sql'/* empty */INTO TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA/*!10000 LOCAL */INFILE '$MYSQLD_DATADIR/bug43746.sql' INTO/* empty */TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD/*!999999 special comments that do not expand */DATA/*!999999 code from the future */LOCAL INFILE '$MYSQLD_DATADIR/bug43746.sql'/*!999999 have flux capacitor */INTO/*!999999 will travel */TABLE t1; + +SET sql_mode='PIPES_AS_CONCAT,ANSI_QUOTES,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER'; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA LOCAL INFILE '$MYSQLD_DATADIR/bug43746.sql' INTO TABLE t1; + +sync_slave_with_master; + +--echo +--echo Bug #59267: +--echo "LOAD DATA LOCAL INFILE not executed on slave with SBR" +--echo + +connection master; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +--disable_ps2_protocol +eval SELECT * INTO OUTFILE '$MYSQLD_DATADIR/bug59267.sql' FROM t1; +--enable_ps2_protocol +TRUNCATE TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA LOCAL INFILE '$MYSQLD_DATADIR/bug59267.sql' INTO TABLE t1; + +SELECT 'Master', COUNT(*) FROM t1; + +--sync_slave_with_master +SELECT 'Slave', COUNT(*) FROM t1; + +# cleanup +connection master; + +--remove_file $MYSQLD_DATADIR/bug43746.sql +--remove_file $MYSQLD_DATADIR/bug59267.sql + +DROP TABLE t1; +SET SESSION sql_mode=@old_mode; + +sync_slave_with_master; + +connection master; + +--echo +--echo Bug #60580/#11902767: +--echo "statement improperly replicated crashes slave sql thread" +--echo + +connection master; +let $MYSQLD_DATADIR= `select @@datadir`; + +CREATE TABLE t1(f1 INT, f2 INT); +CREATE TABLE t2(f1 INT, f2 TIMESTAMP); + +INSERT INTO t2 VALUES(1, '2011-03-22 21:01:28'); +INSERT INTO t2 VALUES(2, '2011-03-21 21:01:28'); +INSERT INTO t2 VALUES(3, '2011-03-20 21:01:28'); + +CREATE TABLE t3 AS SELECT * FROM t2; + +CREATE VIEW v1 AS SELECT * FROM t2 + WHERE f1 IN (SELECT f1 FROM t3 WHERE (t3.f2 IS NULL)); + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +--disable_ps2_protocol +eval SELECT 1 INTO OUTFILE '$MYSQLD_DATADIR/bug60580.csv' FROM DUAL; +--enable_ps2_protocol + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA LOCAL INFILE '$MYSQLD_DATADIR/bug60580.csv' INTO TABLE t1 (@f1) SET f2 = (SELECT f1 FROM v1 WHERE f1=@f1); + +SELECT * FROM t1; + +sleep 1; + +sync_slave_with_master; + +SELECT * FROM t1; + +--remove_file $MYSQLD_DATADIR/bug60580.csv + +connection master; + +DROP VIEW v1; +DROP TABLE t1, t2, t3; + +sync_slave_with_master; + +connection master; +--source include/rpl_end.inc + +--echo # End of 5.1 tests diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_m-master.opt b/mysql-test/suite/rpl/t/rpl_loaddata_m-master.opt new file mode 100644 index 00000000..9d4a8f0b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_loaddata_m-master.opt @@ -0,0 +1 @@ +--binlog_ignore_db=test diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_m.test b/mysql-test/suite/rpl/t/rpl_loaddata_m.test new file mode 100644 index 00000000..b9dffa3f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_loaddata_m.test @@ -0,0 +1,51 @@ +# See if the master logs LOAD DATA INFILE correctly when binlog_*_db rules +# exist. +# This is for BUG#1100 (LOAD DATA INFILE was half-logged). +###################################################### +# Change Author: JBM +# Change Date: 2005-12-22 +# Change: Test rewritten to remove show binlog events +# and to test the option better + Cleanup +###################################################### +-- source include/master-slave.inc + +--disable_warnings +drop database if exists mysqltest; +--enable_warnings + +connection master; +# 'test' database should be ignored by the slave +USE test; +CREATE TABLE t1(a INT, b INT, UNIQUE(b)); +LOAD DATA INFILE '../../std_data/rpl_loaddata.dat' INTO TABLE test.t1; +SELECT COUNT(*) FROM test.t1; + +# 'mysqltest' database should NOT be ignored by the slave +CREATE DATABASE mysqltest; +USE mysqltest; +CREATE TABLE t1(a INT, b INT, UNIQUE(b)); +LOAD DATA INFILE '../../std_data/rpl_loaddata.dat' INTO TABLE mysqltest.t1; +SELECT COUNT(*) FROM mysqltest.t1; + +# Now lets check the slave to see what we have :-) +sync_slave_with_master; + +SHOW DATABASES; + +USE test; +SHOW TABLES; + +USE mysqltest; +SHOW TABLES; +SELECT COUNT(*) FROM mysqltest.t1; + +#show binlog events; + +# Cleanup +connection master; +DROP DATABASE mysqltest; +DROP TABLE IF EXISTS test.t1; +sync_slave_with_master; + +# End of test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_map-master.opt b/mysql-test/suite/rpl/t/rpl_loaddata_map-master.opt new file mode 100644 index 00000000..5fdeb855 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_loaddata_map-master.opt @@ -0,0 +1 @@ +--read_buffer_size=12K --max_allowed_packet=8K --net-buffer-length=8K diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_map-slave.opt b/mysql-test/suite/rpl/t/rpl_loaddata_map-slave.opt new file mode 100644 index 00000000..7d404fae --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_loaddata_map-slave.opt @@ -0,0 +1 @@ +--max_allowed_packet=8K --net-buffer-length=8K diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_map.test b/mysql-test/suite/rpl/t/rpl_loaddata_map.test new file mode 100644 index 00000000..0df424aa --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_loaddata_map.test @@ -0,0 +1,74 @@ +# ==== Purpose ==== +# +# check replication of load data with the server parameters subjected to +# read_buffer_size > max_allowed_packet +# +# ==== Implementation ==== +# +# Insert many rows into t1, write t1 to file. +# Load the file into t2. +# See that t2 came out as expected on slave. +# +# ==== Related Bugs ==== +# +# BUG#30435 loading large LOAD DATA INFILE breaks slave with +# read_buffer_size set on master +# BUG#33413 show binlog events fails if binlog has event size of close +# to max_allowed_packet + +source include/have_binlog_format_statement.inc; +source include/master-slave.inc; + + +--echo ==== Create a big file ==== + +# We turn off binlogging to avoid too much noise in the binlog. t1 is +# just an auxiliary construction anyways, it is not needed on the +# slave. + +--disable_query_log +SET @@sql_log_bin= 0; + +let $rows= 5000; +create table t1 (id int not null primary key auto_increment); + +while($rows) +{ + eval insert into t1 values (null); + dec $rows; +} +--disable_ps2_protocol +eval select * into outfile '$MYSQLTEST_VARDIR/tmp/bug30435_5k.txt' from t1; +--enable_ps2_protocol + +DROP TABLE t1; +SET @@sql_log_bin= 1; +--enable_query_log + + +--echo ==== Load our big file into a table ==== +create table t2 (id int not null primary key auto_increment); + +select @@session.read_buffer_size - @@session.max_allowed_packet > 0 ; + +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +eval load data infile '$MYSQLTEST_VARDIR/tmp/bug30435_5k.txt' into table t2; +select count(*) from t2 /* 5 000 */; + +# the binlog will show fragmented Append_block events +source include/show_binlog_events.inc; + + +--echo ==== Verify results on slave ==== + +sync_slave_with_master; +select count(*) from t2 /* 5 000 */; + + +--echo ==== Clean up ==== + +connection master; +drop table t2; +sync_slave_with_master; +remove_file $MYSQLTEST_VARDIR/tmp/bug30435_5k.txt; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_s-slave.opt b/mysql-test/suite/rpl/t/rpl_loaddata_s-slave.opt new file mode 100644 index 00000000..9d4a8f0b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_loaddata_s-slave.opt @@ -0,0 +1 @@ +--binlog_ignore_db=test diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_s.test b/mysql-test/suite/rpl/t/rpl_loaddata_s.test new file mode 100644 index 00000000..21167968 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_loaddata_s.test @@ -0,0 +1,27 @@ +# See if the slave logs (in its own binlog, with --log-slave-updates) a +# replicated LOAD DATA INFILE correctly when it has binlog_*_db rules. +# This is for BUG#1100 (LOAD DATA INFILE was half-logged). + +-- source include/have_binlog_format_mixed_or_statement.inc +-- source include/master-slave.inc + +connection slave; +# Not sure why we connect to slave and then try to reset master, but I will leave it [JBM] +reset master; + +connection master; +# 'test' is the current database +create table test.t1(a int, b int, unique(b)); +load data infile '../../std_data/rpl_loaddata.dat' into table test.t1; + +# Test logging on slave; + +sync_slave_with_master; +select count(*) from test.t1; # check that LOAD was replicated +source include/show_binlog_events.inc; + +# Cleanup +connection master; +drop table test.t1; +sync_slave_with_master; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_simple.test b/mysql-test/suite/rpl/t/rpl_loaddata_simple.test new file mode 100644 index 00000000..a09d3fee --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_loaddata_simple.test @@ -0,0 +1,15 @@ +--source include/master-slave.inc + +CREATE TABLE t1 (word CHAR(20) NOT NULL); +LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE t1; +SELECT * FROM t1 ORDER BY word; +sync_slave_with_master; + +# Check +SELECT * FROM t1 ORDER BY word; + +# Cleanup +connection master; +drop table t1; +sync_slave_with_master; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_symlink-master.opt b/mysql-test/suite/rpl/t/rpl_loaddata_symlink-master.opt new file mode 100644 index 00000000..719832a2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_loaddata_symlink-master.opt @@ -0,0 +1 @@ +--secure-file-priv=$MYSQLTEST_VARDIR/std_data_master_link diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_symlink-master.sh b/mysql-test/suite/rpl/t/rpl_loaddata_symlink-master.sh new file mode 100644 index 00000000..e5bb3e61 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_loaddata_symlink-master.sh @@ -0,0 +1,2 @@ +rm -f $MYSQLTEST_VARDIR/std_data_master_link +ln -s $MYSQLTEST_VARDIR/std_data $MYSQLTEST_VARDIR/std_data_master_link diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_symlink-slave.opt b/mysql-test/suite/rpl/t/rpl_loaddata_symlink-slave.opt new file mode 100644 index 00000000..a112e81a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_loaddata_symlink-slave.opt @@ -0,0 +1 @@ +--slave-load-tmpdir=$MYSQLTEST_VARDIR/std_data_slave_link diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_symlink-slave.sh b/mysql-test/suite/rpl/t/rpl_loaddata_symlink-slave.sh new file mode 100644 index 00000000..7a0c0bb3 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_loaddata_symlink-slave.sh @@ -0,0 +1,2 @@ +rm -f $MYSQLTEST_VARDIR/std_data_slave_link +ln -s $MYSQLTEST_VARDIR/std_data $MYSQLTEST_VARDIR/std_data_slave_link diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_symlink.test b/mysql-test/suite/rpl/t/rpl_loaddata_symlink.test new file mode 100644 index 00000000..e5ee400d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_loaddata_symlink.test @@ -0,0 +1,22 @@ +# +# BUG#43913 +# This test verifies if loading data infile will work fine +# if the path of the load data file is a symbolic link. +# +--source include/not_windows.inc +--source include/have_binlog_format_statement.inc +--source include/master-slave.inc + +create table t1(a int not null auto_increment, b int, primary key(a) ); +load data infile '../../std_data/rpl_loaddata.dat' into table t1; +select * from t1; + +sync_slave_with_master; +connection slave; +select * from t1; + +connection master; +drop table t1; +sync_slave_with_master; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_loadfile.test b/mysql-test/suite/rpl/t/rpl_loadfile.test new file mode 100644 index 00000000..a49b3c30 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_loadfile.test @@ -0,0 +1,122 @@ +# +# This include file is used by more than one test suite +# (currently rpl and binlog_encryption). +# Please check all dependent tests after modifying it +# + +############################################################################# +# Original Author: JBM # +# Original Date: Aug/18/2005 # +############################################################################# +# TEST: To test the LOAD_FILE() in rbr # +############################################################################# +# Change Author: JBM +# Change Date: 2006-01-16 +########## + +# Includes +-- source include/have_binlog_format_mixed_or_row.inc +-- source include/master-slave.inc + +-- source suite/rpl/include/rpl_loadfile.test + +# BUG#39701: Mixed binlog format does not switch to row mode on LOAD_FILE +# +# DESCRIPTION +# +# Problem: when using load_file string function and mixed binlogging format +# there was no switch to row based binlogging format. This leads +# to scenarios on which the slave replicates the statement and it +# will try to load the file from local file system, which in most +# likely it will not exist. +# +# Solution: +# Marking this function as unsafe for statement format, makes the +# statement using it to be logged in row based format. As such, data +# replicated from the master, becomes the content of the loaded file. +# Consequently, the slave receives the necessary data to complete +# the load_file instruction correctly. +# +# IMPLEMENTATION +# +# The test is implemented as follows: +# +# On Master, +# i) write to file the desired content. +# ii) create table and stored procedure with load_file +# iii) stop slave +# iii) execute load_file +# iv) remove file +# +# On Slave, +# v) start slave +# vi) sync it with master so that it gets the updates from binlog (which +# should have bin logged in row format). +# +# If the the binlog format does not change to row, then the assertion +# done in the following step fails. This happens because tables differ +# since the file does not exist anymore, meaning that when slave +# attempts to execute LOAD_FILE statement it inserts NULL on table +# instead of the same contents that the master loaded when it executed +# the procedure (which was executed when file existed). +# +# vii) assert that the contents of master and slave +# table are the same + +--source include/rpl_reset.inc + +connection master; +let $file= $MYSQLTEST_VARDIR/tmp/bug_39701.data; + +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--disable_ps2_protocol +--eval SELECT repeat('x',20) INTO OUTFILE '$file' +--enable_ps2_protocol + +disable_warnings; +DROP TABLE IF EXISTS t1; +enable_warnings; + +CREATE TABLE t1 (t text); +DELIMITER |; +CREATE PROCEDURE p(file varchar(4096)) + BEGIN + INSERT INTO t1 VALUES (LOAD_FILE(file)); + END| +DELIMITER ;| + +# stop slave before issuing the load_file on master +connection slave; +source include/stop_slave.inc; + +connection master; + +# test: check that logging falls back to rbr. +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--eval CALL p('$file') + +# test: remove the file from the filesystem and assert that slave still +# gets the loaded file +remove_file $file; + +# now that the file is removed it is safe (regarding what we want to test) +# to start slave +connection slave; +source include/start_slave.inc; + +connection master; +sync_slave_with_master; + +# assertion: assert that the slave got the updates even +# if the file was removed before the slave started, +# meaning that contents were indeed transfered +# through binlog (in row format) +let $diff_tables= master:t1, slave:t1; +source include/diff_tables.inc; + +# CLEAN UP +--connection master +DROP TABLE t1; +DROP PROCEDURE p; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_locale.test b/mysql-test/suite/rpl/t/rpl_locale.test new file mode 100644 index 00000000..0d6692dd --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_locale.test @@ -0,0 +1,25 @@ +# Replication of locale variables + +source include/master-slave.inc; + +# +# Bug#22645 LC_TIME_NAMES: Statement not replicated +# +connection master; +create table t1 (s1 char(10)); +set lc_time_names= 'de_DE'; +insert into t1 values (date_format('2001-01-01','%W')); +set lc_time_names= 'en_US'; +insert into t1 values (date_format('2001-01-01','%W')); +select * from t1; +sync_slave_with_master; +connection slave; +select * from t1; +connection master; +drop table t1; +sync_slave_with_master; + +# End of 4.1 tests + + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_log_pos.test b/mysql-test/suite/rpl/t/rpl_log_pos.test new file mode 100644 index 00000000..1504cba0 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_log_pos.test @@ -0,0 +1,57 @@ +########## +# Change Author: JBM +# Change Date: 2006-01-16 +########## + +# +# Testing of setting slave to wrong log position with master_log_pos +# + +# Passes with rbr no problem, removed statement include [jbm] + +source include/master-slave.inc; + +# +# Add an event to get some information into the log we can try to parse +# +let $read_pos= query_get_value(SHOW MASTER STATUS, Position, 1); +create table if not exists t1 (n int); +drop table t1; + +call mtr.add_suppression ("Slave I/O: Got fatal error 1236 from master when reading data from binary"); +call mtr.add_suppression ("Error in Log_event::read_log_event"); +source include/show_master_status.inc; +sync_slave_with_master; +source include/stop_slave.inc; + +let $wrong_log_pos= `SELECT $read_pos+2`; +--replace_result $wrong_log_pos MASTER_LOG_POS +eval change master to master_log_pos=$wrong_log_pos, master_use_gtid=no; +start slave; +let $slave_io_errno= 1236; +--let $show_slave_io_error= 1 +# Mask line numbers +--let $slave_io_error_replace= / at [0-9]*/ at XXX/ +source include/wait_for_slave_io_error.inc; +source include/stop_slave_sql.inc; +--enable_warnings + +connection master; +source include/show_master_status.inc; +create table if not exists t1 (n int); +drop table if exists t1; +create table t1 (n int); +insert into t1 values (1),(2),(3); +save_master_pos; +connection slave; +--replace_result 4 MASTER_LOG_POS +change master to master_log_pos=4, master_use_gtid=no; +start slave; +sync_with_master; +select * from t1 ORDER BY n; +connection master; +drop table t1; +sync_slave_with_master; + +--echo End of 5.0 tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_lost_events_on_rotate.test b/mysql-test/suite/rpl/t/rpl_lost_events_on_rotate.test new file mode 100644 index 00000000..8c4baafe --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_lost_events_on_rotate.test @@ -0,0 +1,52 @@ +# +# Whenever the mysql_binlog_send method (dump thread) reaches the +# end of file when reading events from the binlog, before checking +# if it should wait for more events, there was a test to check if +# the file being read was still active, i.e, it was the last known +# binlog. However, it was possible that something was written to +# the binary log and then a rotation would happen, after EOF was +# detected and before the check for active was performed. In this +# case, the end of the binary log would not be read by the dump +# thread, and this would cause the slave to lose updates. +# +# This test verifies that the problem has been fixed. It waits +# during this window while forcing a rotation in the binlog. +# +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/master-slave.inc + +--connection master + +SET @debug_saved= @@GLOBAL.DEBUG_DBUG; + +CREATE TABLE t (i INT); + +# When reaching the EOF the dump thread will wait before deciding if +# it should move to a new binlong file. +SET GLOBAL DEBUG_DBUG= "d,wait_after_binlog_EOF"; + +INSERT INTO t VALUES (1); + +--sleep 1 + +# A insert and a rotate happens before the decision +INSERT INTO t VALUES (2); +FLUSH LOGS; + +SET DEBUG_SYNC= 'now SIGNAL signal.rotate_finished'; + +--sync_slave_with_master + +# All the rows should be sent to the slave. +--let $diff_tables=master:t,slave:t +--source include/diff_tables.inc + +##Clean up +--connection master + +SET @@GLOBAL.DEBUG_DBUG= @debug_saved; +SET DEBUG_SYNC= 'RESET'; + +DROP TABLE t; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_manual_change_index_file.test b/mysql-test/suite/rpl/t/rpl_manual_change_index_file.test new file mode 100644 index 00000000..a3da34ec --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_manual_change_index_file.test @@ -0,0 +1,114 @@ +source include/master-slave.inc; + +connection slave; +source include/stop_slave.inc; +CHANGE MASTER TO MASTER_USE_GTID=NO; +source include/start_slave.inc; +connection master; + +# +# BUG#28421 Infinite loop on slave relay logs +# +# That, manually deleteing one or more entries from 'master-bin.index', will +# cause master infinitely loop to send one binlog file. +# +# Manually changing index file is a illegal action, so when this happen, we +# send a fatal error to slave and close the dump session. + +FLUSH LOGS; +# Now, 2 entries in index file. +# ./master-bin.000001 +# ./master-bin.000002 + +CREATE TABLE t1(c1 INT); +# Now, the current dump file(master-bin.000002) is the second line of index +# file +sync_slave_with_master; +# Now, all events has been replicate to slave. As current dump file +# (master-bin.000002) is the last binlog file, so master is waiting for new +# events. + +connection master; +# Delete './master-bin.000001' from index file. +let $MYSQLD_DATADIR= `SELECT @@DATADIR`; +let TRUNCATE_FILE= $MYSQLD_DATADIR/master-bin.index; +source include/truncate_file.inc; + +if (`SELECT CONVERT(@@VERSION_COMPILE_OS USING latin1) NOT IN ('Win32', 'Win64', 'Windows')`) +{ +append_file $MYSQLD_DATADIR/master-bin.index; +./master-bin.000002 +EOF +sleep 0.00000001; +} + +if (`SELECT CONVERT(@@VERSION_COMPILE_OS USING latin1) IN ('Win32', 'Win64', 'Windows')`) +{ +append_file $MYSQLD_DATADIR/master-bin.index; +.\master-bin.000002 +EOF +sleep 0.00000001; +} + +# Now, only 1 entry in index file. ./master-bin.000002 + +# Generate master-bin.000003, but it is in the second line. +FLUSH LOGS; +# Now, 2 entries in index file. +# ./master-bin.000002 +# ./master-bin.000003 + +# Now, master know that new binlog file(master-bin.000003) has been generated. +# It expects that the new binlog file is in third line of index file, but +# there is no third line in index file. It is so strange that master sends an +# error to slave. +call mtr.add_suppression('Got fatal error 1236 from master when reading data from binary log: .*could not find next log'); +connection slave; +# 1236 = ER_MASTER_FATAL_ERROR_READING_BINLOG +--let $slave_io_errno= 1236 +--let $show_slave_io_error= 1 +# Mask line numbers +--let $slave_io_error_replace= / at [0-9]*/ at XXX/ /the first event '(\.|master-bin.000001)'/the first event 'FILE'/ +--source include/wait_for_slave_io_error.inc + +connection master; + +source include/truncate_file.inc; + +if (`SELECT CONVERT(@@VERSION_COMPILE_OS USING latin1) NOT IN ('Win32', 'Win64', 'Windows')`) +{ +append_file $MYSQLD_DATADIR/master-bin.index; +./master-bin.000001 +./master-bin.000002 +./master-bin.000003 +EOF +sleep 0.00000001; +} + +if (`SELECT CONVERT(@@VERSION_COMPILE_OS USING latin1) IN ('Win32', 'Win64', 'Windows')`) +{ +append_file $MYSQLD_DATADIR/master-bin.index; +.\master-bin.000001 +.\master-bin.000002 +.\master-bin.000003 +EOF +sleep 0.00000001; +} + +CREATE TABLE t2(c1 INT); +FLUSH LOGS; +CREATE TABLE t3(c1 INT); +FLUSH LOGS; +CREATE TABLE t4(c1 INT); + +connection slave; +START SLAVE IO_THREAD; +source include/wait_for_slave_io_to_start.inc; + +connection master; +sync_slave_with_master; +SHOW TABLES; + +connection master; +DROP TABLE t1, t2, t3, t4; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_many_optimize.test b/mysql-test/suite/rpl/t/rpl_many_optimize.test new file mode 100644 index 00000000..d5e9f69b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_many_optimize.test @@ -0,0 +1,23 @@ +# Test for BUG#7658 "optimize crashes slave thread (1 in 1000)]" + +source include/master-slave.inc; + +create table t1 (a int not null auto_increment primary key, b int, key(b)); +INSERT INTO t1 (a) VALUES (1),(2); +# Now many OPTIMIZE to test if we crash (BUG#7658) +let $1=300; +disable_query_log; +disable_result_log; +while ($1) +{ + eval OPTIMIZE TABLE t1; + dec $1; +} +enable_result_log; +enable_query_log; +drop table t1; +# Bug was that slave segfaulted after ~ a hundred of OPTIMIZE (or ANALYZE) +sync_slave_with_master; + +# End of 4.1 tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test b/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test new file mode 100644 index 00000000..d49851cc --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test @@ -0,0 +1,167 @@ +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/have_binlog_format_row.inc +--source include/have_innodb.inc +--source include/master-slave.inc + +connection master; +set @old_master_binlog_checksum= @@global.binlog_checksum; + +# MDEV-4475: Cannot replicate to old server when binlog contains +# empty Gtid_list event +# +# Test this by binlog rotation before we log any GTIDs. +connection slave; + +# Need to stop/start the master without GTID before setting debug_dbug +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=NO; +--source include/start_slave.inc + +--source include/stop_slave.inc +--echo # Test slave with no capability gets dummy event, which is ignored. +set @old_dbug= @@global.debug_dbug; +SET @@global.debug_dbug='+d,simulate_slave_capability_none'; +--source include/start_slave.inc + +connection master; +FLUSH LOGS; +CREATE TABLE t1 (a INT PRIMARY KEY); +INSERT INTO t1 VALUES (0); +sync_slave_with_master; + +connection master; +# Add a dummy event just to have something to sync_slave_with_master on. +# Otherwise we occasionally get different $relaylog_start, depending on +# whether Format_description_log_event was written to relay log or not +# at the time of SHOW SLAVE STATUS. +ALTER TABLE t1 ORDER BY a; +sync_slave_with_master; +connection slave; +let $relaylog_start= query_get_value(SHOW SLAVE STATUS, Relay_Log_Pos, 1); + +connection master; +SET SESSION binlog_annotate_row_events = ON; +let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1); +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +# A short event, to test when we need to use user_var_event for dummy event. +DELETE FROM t1; +INSERT INTO t1 /* A comment just to make the annotate event sufficiently long that the dummy event will need to get padded with spaces so that we can test that this works */ VALUES(1); +let $binlog_limit= 0, 10; +--source include/show_binlog_events.inc +sync_slave_with_master; +connection slave; + +SELECT * FROM t1; +let $binlog_file= query_get_value(SHOW SLAVE STATUS, Relay_Log_File, 1); +let $binlog_start= $relaylog_start; +let $binlog_limit=0,10; +--source include/show_relaylog_events.inc +set @@global.debug_dbug= @old_dbug; + +--echo # Test dummy event is checksummed correctly. + +connection master; +set @@global.binlog_checksum = CRC32; +--source include/wait_for_binlog_checkpoint.inc +TRUNCATE t1; +let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1); +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +INSERT INTO t1 VALUES(2); +let $binlog_limit= 0, 5; +--source include/show_binlog_events.inc +sync_slave_with_master; +connection slave; + +SELECT * FROM t1; +let $binlog_file= query_get_value(SHOW SLAVE STATUS, Relay_Log_File, 1); +let $binlog_start= 0; +let $binlog_limit=7,5; +--source include/show_relaylog_events.inc + + +--echo *** MDEV-5754: MySQL 5.5 slaves cannot replicate from MariaDB 10.0 *** + +# The problem was that for a group commit, we get commit id into the +# GTID event, and there was a bug in the code that replaces GTID with +# dummy that failed when commit id was present. +# +# So setup a group commit in InnoDB. + +--connection master +CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB; +# MDEV-515 takes X-lock on the table for the first insert. +# So concurrent insert won't happen on the table +INSERT INTO t2 VALUES(100); +let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1); +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); + +--connect (con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1'; +send INSERT INTO t2 VALUES (1); + +--connection master +SET debug_sync='now WAIT_FOR master_queued1'; + +--connect (con2,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2'; +send INSERT INTO t2 VALUES (2); + +--connection master +SET debug_sync='now WAIT_FOR master_queued2'; +SET debug_sync='now SIGNAL master_cont1'; + +--connection con1 +REAP; +SET debug_sync='RESET'; +--connection con2 +REAP; +SET debug_sync='RESET'; +--connection master +SET debug_sync='RESET'; +let $binlog_limit= 0, 10; +--source include/show_binlog_events.inc +--save_master_pos + +--connection slave +--sync_with_master +SELECT * FROM t2 ORDER BY a; + + +--echo # Test that slave which cannot tolerate holes in binlog stream but +--echo # knows the event does not get dummy event + +--source include/stop_slave.inc +SET @@global.debug_dbug='+d,simulate_slave_capability_old_53'; +--source include/start_slave.inc +connection master; +ALTER TABLE t1 ORDER BY a; +sync_slave_with_master; +connection slave; +let $relaylog_start= query_get_value(SHOW SLAVE STATUS, Relay_Log_Pos, 1); + +connection master; +let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1); +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +UPDATE t1 SET a = 3; +let $binlog_limit= 0, 5; +--source include/show_binlog_events.inc +sync_slave_with_master; +connection slave; + +SELECT * FROM t1; +let $binlog_file= query_get_value(SHOW SLAVE STATUS, Relay_Log_File, 1); +let $binlog_start= $relaylog_start; +let $binlog_limit=0,5; +--source include/show_relaylog_events.inc + +select @@global.log_slave_updates; +select @@global.replicate_annotate_row_events; + +--echo Clean up. +connection master; +set @@global.binlog_checksum = @old_master_binlog_checksum; +DROP TABLE t1, t2; +sync_slave_with_master; +set @@global.debug_dbug= @old_dbug; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mark_optimize_tbl_ddl.test b/mysql-test/suite/rpl/t/rpl_mark_optimize_tbl_ddl.test new file mode 100644 index 00000000..6d66e3fd --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mark_optimize_tbl_ddl.test @@ -0,0 +1,142 @@ +# ==== Purpose ==== +# +# Test verifies that there is no deadlock or assertion in +# slave_parallel_mode=optimistic configuration while applying admin command +# like 'OPTIMIZE TABLE', 'REPAIR TABLE' and 'ANALYZE TABLE'. +# +# ==== Implementation ==== +# +# Steps: +# 0 - Create a table, execute OPTIMIZE TABLE command on the table followed +# by some DMLS. +# 1 - No assert should happen on slave server. +# 2 - Assert that 'OPTIMIZE TABLE', 'REPAIR TABLE' and 'ANALYZE TABLE' are +# marked as 'DDL' in the binary log. +# +# ==== References ==== +# +# MDEV-17515: GTID Replication in optimistic mode deadlock +# +--source include/have_partition.inc +--source include/have_innodb.inc +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +--connection server_1 +FLUSH TABLES; +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; + +--connection server_2 +SET @save_slave_parallel_threads= @@GLOBAL.slave_parallel_threads; +SET @save_slave_parallel_mode= @@GLOBAL.slave_parallel_mode; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=2; +SET GLOBAL slave_parallel_mode=optimistic; +--source include/start_slave.inc + +--connection server_1 +CREATE TABLE t1(a INT) ENGINE=INNODB; +OPTIMIZE TABLE t1; +INSERT INTO t1 VALUES(1); +INSERT INTO t1 SELECT 1+a FROM t1; +INSERT INTO t1 SELECT 2+a FROM t1; +--save_master_pos + +--connection server_2 +--sync_with_master + +--echo # +--echo # Verify that following admin commands are marked as ddl +--echo # 'OPTIMIZE TABLE', 'REPAIR TABLE' and 'ANALYZE TABLE' +--echo # +--connection server_1 + +OPTIMIZE TABLE t1; +--let optimize_gtid= `SELECT @@GLOBAL.gtid_binlog_pos` + +REPAIR TABLE t1; +--let repair_gtid= `SELECT @@GLOBAL.gtid_binlog_pos` + +ANALYZE TABLE t1; +--let analyze_gtid= `SELECT @@GLOBAL.gtid_binlog_pos` + +let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1); +FLUSH LOGS; + +--let $MYSQLD_DATADIR= `select @@datadir` +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/$binlog_file > $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out + +--let SEARCH_PATTERN= GTID $optimize_gtid ddl +--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out +--source include/search_pattern_in_file.inc + +--let SEARCH_PATTERN= GTID $repair_gtid ddl +--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out +--source include/search_pattern_in_file.inc + +--let SEARCH_PATTERN= GTID $analyze_gtid ddl +--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out +--source include/search_pattern_in_file.inc + +--echo # +--echo # Clean up +--echo # +DROP TABLE t1; +--remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out +--save_master_pos + +--connection server_2 +--sync_with_master +FLUSH LOGS; + +--echo # +--echo # Check that ALTER TABLE commands with ANALYZE, OPTIMIZE and REPAIR on +--echo # partitions will be marked as DDL in binary log. +--echo # +--connection server_1 +CREATE TABLE t1(id INT) PARTITION BY RANGE (id) (PARTITION p0 VALUES LESS THAN (100), + PARTITION pmax VALUES LESS THAN (MAXVALUE)); +INSERT INTO t1 VALUES (1), (10), (100), (1000); + +ALTER TABLE t1 ANALYZE PARTITION p0; +--let analyze_gtid= `SELECT @@GLOBAL.gtid_binlog_pos` + +ALTER TABLE t1 OPTIMIZE PARTITION p0; +--let optimize_gtid= `SELECT @@GLOBAL.gtid_binlog_pos` + +ALTER TABLE t1 REPAIR PARTITION p0; +--let repair_gtid= `SELECT @@GLOBAL.gtid_binlog_pos` + +let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1); +FLUSH LOGS; + +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/$binlog_file > $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out + +--let SEARCH_PATTERN= GTID $analyze_gtid ddl +--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out +--source include/search_pattern_in_file.inc + +--let SEARCH_PATTERN= GTID $optimize_gtid ddl +--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out +--source include/search_pattern_in_file.inc + +--let SEARCH_PATTERN= GTID $repair_gtid ddl +--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out +--source include/search_pattern_in_file.inc + +--echo # +--echo # Clean up +--echo # +DROP TABLE t1; +--remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out +--save_master_pos + +--connection server_2 +--sync_with_master + +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads= @save_slave_parallel_threads; +SET GLOBAL slave_parallel_mode= @save_slave_parallel_mode; +--source include/start_slave.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_master_pos_wait.test b/mysql-test/suite/rpl/t/rpl_master_pos_wait.test new file mode 100644 index 00000000..437d8412 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_master_pos_wait.test @@ -0,0 +1,79 @@ +# See if master_pos_wait(,,timeout) +# Terminates with "timeout expired" (-1) +source include/master-slave.inc; +sync_slave_with_master; +# Ask for a master log that has certainly not been reached yet +# timeout= 2 seconds +select master_pos_wait('master-bin.999999',0,2); +explain extended select master_pos_wait('master-bin.999999',0,2); +# Testcase for bug 651 (master_pos_wait() hangs if slave idle and STOP SLAVE). +send select master_pos_wait('master-bin.999999',0); +connection slave1; +stop slave sql_thread; +--source include/wait_for_slave_sql_to_stop.inc +connection slave; +reap; + +# +# bug#26622 MASTER_POS_WAIT does not work as documented +# + +connection master; +echo "*** must be empty ***"; +query_vertical show slave status; + +echo "*** must be NULL ***"; +select master_pos_wait('foo', 98); + +# End of 4.1 tests + + +--echo *** MDEV-7130: MASTER_POS_WAIT(log_name,log_pos,timeout,"connection_name") hangs, does not respect the timeout *** + +--connection slave +--source include/stop_slave.inc +reset slave all; +--replace_result $MASTER_MYPORT MASTER_MYPORT +eval change master 'my_slave' to master_port=$MASTER_MYPORT, master_host='127.0.0.1', master_user='root'; +set default_master_connection = 'my_slave'; +--source include/start_slave.inc + +--echo # Call without connection name -- works (expected -1) +select master_pos_wait('master-bin.000001',1000000,1); + +set default_master_connection = ''; + +--echo # Call for non-existing anonymous connection -- works (expected NULL) +select master_pos_wait('master-bin.000001',1000000,1); + +--echo # Call with a valid connection name -- hangs before MDEV-7130 fix (expected -1) +select master_pos_wait('master-bin.000001',1000000,1,"my_slave"); + +STOP SLAVE 'my_slave'; +RESET SLAVE 'my_slave' ALL; + +--replace_result $MASTER_MYPORT MASTER_MYPORT +eval change master to master_port=$MASTER_MYPORT, master_host='127.0.0.1', master_user='root'; + +# End of 10.0 tests + +--echo # +--echo # Start of 10.3 tests +--echo # + +--echo # +--echo # MDEV-13965 Parameter data type control for Item_longlong_func +--echo # + +--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION +SELECT MASTER_POS_WAIT('x',1,ROW(1,1)); +--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION +SELECT MASTER_POS_WAIT('x',1,1,ROW(1,1)); + +--echo # +--echo # End of 10.3 tests +--echo # + + +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mdev-11092.opt b/mysql-test/suite/rpl/t/rpl_mdev-11092.opt new file mode 100644 index 00000000..7f1d270d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mdev-11092.opt @@ -0,0 +1 @@ +--binlog_checksum=1 --binlog-annotate-row-events=1 diff --git a/mysql-test/suite/rpl/t/rpl_mdev-11092.test b/mysql-test/suite/rpl/t/rpl_mdev-11092.test new file mode 100644 index 00000000..fa8a685b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mdev-11092.test @@ -0,0 +1,543 @@ +--source include/have_debug.inc +--source include/have_innodb.inc +--source include/not_embedded.inc +--source include/not_windows.inc +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +######################################################################################## +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); +call mtr.add_suppression("Slave SQL: The incident LOST_EVENTS occurred on the master. .*"); +call mtr.add_suppression("Write to binary log failed: Multi-row statements required more than .max_binlog_stmt_cache_size.* "); +call mtr.add_suppression("Write to binary log failed: Multi-statement transaction required more than .max_binlog_cache_size.* "); +call mtr.add_suppression("Incident event write to the binary log file failed"); +call mtr.add_suppression("handlerton rollback failed"); + +let $old_max_binlog_cache_size= query_get_value(SHOW VARIABLES LIKE "max_binlog_cache_size", Value, 1); +let $old_binlog_cache_size= query_get_value(SHOW VARIABLES LIKE "binlog_cache_size", Value, 1); +let $old_max_binlog_stmt_cache_size= query_get_value(SHOW VARIABLES LIKE "max_binlog_stmt_cache_size", Value, 1); +let $old_binlog_stmt_cache_size= query_get_value(SHOW VARIABLES LIKE "binlog_stmt_cache_size", Value, 1); + +--echo "*********** Annotate Event write failure **************" + +SET GLOBAL max_binlog_cache_size = 4096; +SET GLOBAL binlog_cache_size = 4096; +SET GLOBAL max_binlog_stmt_cache_size = 4096; +SET GLOBAL binlog_stmt_cache_size = 4096; +disconnect master; +connect (master,127.0.0.1,root,,test,$MASTER_MYPORT,); + +CREATE TABLE t1(a INT PRIMARY KEY, data VARCHAR(30000)) ENGINE=MYISAM; + +let $data = `select concat('"', repeat('a',2000), '"')`; + +connection master; + +# Insert a huge row into MyISAM table. The row will be inserted in engine and a +# request to write to binary log will be initiated. Since row annotations are +# enabled the size of the annotate event itself will exceed the +# "max_binlog_stmt_cache_size". This will result in ER_STMT_CACHE_FULL error +# and an incident event will be written to the binary log as row update in +# engine cannot be undone. + +--echo "#######################################################################" +--echo "# Test Case1: Annotate event write failure for MyISAM #" +--echo "#######################################################################" + +--disable_query_log +--let $old_gtid_binlog_pos= query_get_value(SHOW VARIABLES LIKE 'gtid_binlog_pos', Value, 1) +--error ER_STMT_CACHE_FULL +eval INSERT INTO t1 (a, data) VALUES (2, + CONCAT($data, $data, $data, $data, $data, $data)); +--enable_query_log + +--let $new_gtid_binlog_pos= query_get_value(SHOW VARIABLES LIKE 'gtid_binlog_pos', Value, 1) +--echo # Validating update was not binlogged.. +if(`SELECT strcmp("$old_gtid_binlog_pos","$new_gtid_binlog_pos") != 0`) +{ + --die Binlog GTID position should have been unchanged after failed update +} +--echo # ..success + +--echo # Validating that the inserted data was saved on the master.. +if(`SELECT COUNT(*)!=1 FROM t1`) +{ + --die The insertion should have saved on a non-transactional table +} +--echo # ..success + +--connection slave +# Incident event +# 1590=ER_SLAVE_INCIDENT +--let $slave_sql_errno= 1590 +--source include/wait_for_slave_sql_error_and_skip.inc + +--echo # Validating that the insert was not replicated to the slave.. +if(`SELECT COUNT(*) FROM t1`) +{ + --die The insertion should not have replicated to the slave +} +--echo # ..success + +# MDEV-21087 +# Insert two huge rows in to transaction cache. Have data such that first row +# fits inside the binary log cache. While writing the annotate event for the +# second row the binary log cache size will exceed "max_binlog_cache_size". +# Hence this statement cannot be written to binary log. As DMLs in Innodb can +# be safely rolled back only an error will be reported. Slave will continue to +# work. + +--echo "#######################################################################" +--echo "# Test Case2: Annotate event write failure for INNODB #" +--echo "#######################################################################" + +--connection master +CREATE TABLE t2(a INT PRIMARY KEY, data VARCHAR(30000)) ENGINE=INNODB; +--disable_query_log +--let $old_gtid_binlog_pos= query_get_value(SHOW VARIABLES LIKE 'gtid_binlog_pos', Value, 1) +BEGIN; +eval INSERT INTO t2 (a, data) VALUES (1, CONCAT($data, $data)); +--error ER_TRANS_CACHE_FULL +eval INSERT INTO t2 (a, data) VALUES (2, CONCAT($data, $data)); +COMMIT; +--enable_query_log + +--let $new_gtid_binlog_pos= query_get_value(SHOW VARIABLES LIKE 'gtid_binlog_pos', Value, 1) +--echo # Validating binlog GTID position progressed from first insert.. +if(`SELECT strcmp("$old_gtid_binlog_pos","$new_gtid_binlog_pos") = 0`) +{ + --die Binlog GTID position should have updated +} +--echo # ..success + +--echo # Validating that only the first insert into t2 saved.. +if(`SELECT COUNT(*)!=1 FROM t2`) +{ + --die Only one row should exist in t2 from the first insert, the second should have rolled back +} +--echo # ..success +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc +--echo # Validating the first insert into t2 replicated to slave.. +--let $diff_tables= master:test.t2,slave:test.t2 +--source include/diff_tables.inc +--echo # ..success + +# Testing mixed engine UPDATE statement scenario. In the following multi +# update query 'ha_update_row' will be invoked for t1 (myisam) table. This +# intern invokes binlog_write_table_map() function call. While writing a huge +# annotate event binary log cache size will exceed max_binlog_cache_size. +# Writing to binary log fails. Since non transactional changes cannot be +# rolled back incident event will be written to binary log. + +--echo "#######################################################################" +--echo "# Test Case3: Annotate event write failure for mixed engine UPDATE #" +--echo "#######################################################################" + +--connection master +let $new_data = `select concat('"', repeat('b',2000), '"')`; +--let $old_gtid_binlog_pos= query_get_value(SHOW VARIABLES LIKE 'gtid_binlog_pos', Value, 1) +--disable_query_log +--error ER_STMT_CACHE_FULL +eval UPDATE t1,t2 SET t1.data="Hello", t2.data=CONCAT($new_data,$new_data,$new_data,$new_data,$new_data); +--enable_query_log + +--let $new_gtid_binlog_pos= query_get_value(SHOW VARIABLES LIKE 'gtid_binlog_pos', Value, 1) +--echo # Validating update was not binlogged.. +if(`SELECT strcmp("$old_gtid_binlog_pos","$new_gtid_binlog_pos") != 0`) +{ + --die Binlog GTID position should have been unchanged after failed update +} +--echo # ..success + +--echo # Validating non-transactional part of update saved.. +if(`SELECT COUNT(*)!=1 from t1 where data="Hello"`) +{ + --die Non-transactional part of update should have saved +} +--echo # ..success + +--echo # Validating transactional part of update was rolled back.. +if(`SELECT COUNT(*) from t2 where data LIKE "b%"`) +{ + --die Transactional part of update should have been rolled back +} +--echo # ..success + +--source include/save_master_gtid.inc + +--connection slave + +# Incident event +# 1590=ER_SLAVE_INCIDENT +--let $slave_sql_errno= 1590 +--source include/wait_for_slave_sql_error_and_skip.inc + +--echo # Validating the rolled-back multi-engine update did not replicate to slave at all.. +if(`SELECT COUNT(*) from t1 where data="Hello"`) +{ + --die Non-transactional part of update should not have replicated +} +if(`SELECT COUNT(*) from t2 where data LIKE "b%"`) +{ + --die Transactional part of update should not have replicated +} +--echo # ..success + +--connection master + +--echo "****** Clean up *******" +--replace_result $old_max_binlog_cache_size ORIGINAL_VALUE +--eval SET GLOBAL max_binlog_cache_size= $old_max_binlog_cache_size +--replace_result $old_binlog_cache_size ORIGINAL_VALUE +--eval SET GLOBAL binlog_cache_size= $old_binlog_cache_size +--replace_result $old_max_binlog_stmt_cache_size ORIGINAL_VALUE +--eval SET GLOBAL max_binlog_stmt_cache_size= $old_max_binlog_stmt_cache_size +--replace_result $old_binlog_stmt_cache_size ORIGINAL_VALUE +--eval SET GLOBAL binlog_stmt_cache_size= $old_binlog_stmt_cache_size + +DROP TABLE t1,t2; + +--echo "*********** TABLE MAP Event write failure **************" + +--let $debug_save= `SELECT @@GLOBAL.debug_dbug` +CREATE TABLE tm (f INT) ENGINE=MYISAM; +CREATE TABLE ti (f INT) ENGINE=INNODB; +INSERT INTO tm VALUES (10); +INSERT INTO ti VALUES (20); +--sync_slave_with_master + +--echo "#######################################################################" +--echo "# Test Case4: Table_map event write failure for trans engine UPDATE #" +--echo "#######################################################################" +--echo # Transaction should be rolled back without writing incident event +--connection master +--let $old_gtid_binlog_pos= query_get_value(SHOW VARIABLES LIKE 'gtid_binlog_pos', Value, 1) +SET debug_dbug="+d,table_map_write_error"; +--error ER_TRANS_CACHE_FULL +UPDATE ti, tm set ti.f=30; + +--let $new_gtid_binlog_pos= query_get_value(SHOW VARIABLES LIKE 'gtid_binlog_pos', Value, 1) +--echo # Validating update was not binlogged.. +if(`SELECT strcmp("$old_gtid_binlog_pos","$new_gtid_binlog_pos") != 0`) +{ + --die Binlog GTID position should have been unchanged after failed update +} +--echo # ..success + +--echo # Validating update was rolled back from storage engines.. +if(`SELECT COUNT(*) FROM ti WHERE f=130`) +{ + --die Update for InnoDB table should not have saved +} +--echo # ..success + +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc + +--echo "#######################################################################" +--echo "# Test Case5: Table_map event write failure for mixed engine UPDATE #" +--echo "#######################################################################" +--connection master +--let $old_gtid_binlog_pos= query_get_value(SHOW VARIABLES LIKE 'gtid_binlog_pos', Value, 1) +--echo # In case of mixed engines if non trans table is updated write INCIDENT event +--error ER_TRANS_CACHE_FULL +UPDATE ti,tm SET tm.f=88, ti.f=120; + +--let $new_gtid_binlog_pos= query_get_value(SHOW VARIABLES LIKE 'gtid_binlog_pos', Value, 1) +--echo # Validating update was not binlogged.. +if(`SELECT strcmp("$old_gtid_binlog_pos","$new_gtid_binlog_pos") != 0`) +{ + --die Binlog GTID position should have been unchanged after failed update +} +--echo # ..success + +--echo # Validating that only the non-transactional update saved on master.. +if(`SELECT COUNT(*)!=1 FROM tm WHERE f=88`) +{ + --die Update for MyISAM table should have saved +} +if(`SELECT COUNT(*) FROM ti WHERE f=120`) +{ + --die Update for InnoDB table should not have saved +} +--echo # ..success + + +--connection slave +# Incident event +# 1590=ER_SLAVE_INCIDENT +--let $slave_sql_errno= 1590 +--source include/wait_for_slave_sql_error_and_skip.inc + +--echo # Validating that neither of the updates replicated to slave.. +if(`SELECT COUNT(*) FROM tm WHERE f=88`) +{ + --die Update for MyISAM table should not have replicated to slave +} +if(`SELECT COUNT(*) FROM ti WHERE f=120`) +{ + --die Update for InnoDB table should not have replicated to slave +} +--echo # ..success + +--echo "#######################################################################" +--echo "# Test Case6: Committing a transaction consisting of two updates: +--echo "# S1) Update transactional table +--echo "# S2) Update transactional table +--echo "# with a table_map event write failure on the second event should +--echo "# roll-back only the second update without incident +--echo "#######################################################################" +--connection master +--let $old_gtid_binlog_pos= query_get_value(SHOW VARIABLES LIKE 'gtid_binlog_pos', Value, 1) + +SET debug_dbug=""; +BEGIN; +# successful update +UPDATE ti, tm set ti.f=40; +SET debug_dbug="+d,table_map_write_error"; +--error ER_TRANS_CACHE_FULL +UPDATE ti, tm set ti.f=50; +COMMIT; + +--let $new_gtid_binlog_pos= query_get_value(SHOW VARIABLES LIKE 'gtid_binlog_pos', Value, 1) +--echo # Validating binlog GTID position progressed from first update.. +if(`SELECT strcmp("$old_gtid_binlog_pos","$new_gtid_binlog_pos") = 0`) +{ + --die Binlog GTID position should have updated +} +--echo # ..success + +--echo # Validating the first update saved.. +if(`SELECT COUNT(*)!=1 FROM ti WHERE f=40`) +{ + --die The first update should have saved because it was transactional +} +--echo # ..and that the second update did not save.. +if(`SELECT COUNT(*) FROM ti WHERE f=50`) +{ + --die The second update should have rolled back because it failed +} +--echo # ..success + +--echo # Validating that only the first update replicated to slave without incident +--connection master +--source include/save_master_gtid.inc +--connection slave +--source include/sync_with_master_gtid.inc +--let $diff_tables= master:test.ti,slave:test.ti +--source include/diff_tables.inc + + +--echo "#######################################################################" +--echo "# Test Case7: Rolling back a transaction consisting of two updates: +--echo "# S1) Update transactional table +--echo "# S2) Update transactional table +--echo "# with a table_map event write failure on the second event should +--echo "# roll-back both updates without incident +--echo "#######################################################################" +--connection master +--let $old_gtid_binlog_pos= query_get_value(SHOW VARIABLES LIKE 'gtid_binlog_pos', Value, 1) + +SET debug_dbug=""; +BEGIN; +# successful update +UPDATE ti, tm set ti.f=60; +SET debug_dbug="+d,table_map_write_error"; +--error ER_TRANS_CACHE_FULL +UPDATE ti, tm set ti.f=70; +ROLLBACK; + +--let $new_gtid_binlog_pos= query_get_value(SHOW VARIABLES LIKE 'gtid_binlog_pos', Value, 1) +--echo # Validating update was not binlogged.. +if(`SELECT strcmp("$old_gtid_binlog_pos","$new_gtid_binlog_pos") != 0`) +{ + --die Binlog GTID position should have been unchanged after failed update +} +--echo # ..success + +--echo # Validating that neither update saved on master.. +if(`SELECT COUNT(*) FROM ti WHERE f=60`) +{ + --die The first update should not have saved +} +if(`SELECT COUNT(*) FROM ti WHERE f=70`) +{ + --die The second update should not have saved +} +--echo # ..success + +--echo # Validating the transaction did not replicate to the slave +--connection master +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc +--let $diff_tables= master:test.ti,slave:test.ti +--source include/diff_tables.inc + + +--echo "#######################################################################" +--echo "# Test Case8: Committing a transaction consisting of two updates: +--echo "# S1) Update transactional table +--echo "# S2) Update mixed trans/non-trans tables +--echo "# with a table_map event write failure on the second event should +--echo "# roll-back only the second update with incident +--echo "#######################################################################" +--connection master +--let $old_gtid_binlog_pos= query_get_value(SHOW VARIABLES LIKE 'gtid_binlog_pos', Value, 1) + +BEGIN; +# successful update +SET debug_dbug=""; +UPDATE ti, tm set ti.f=80; +SET debug_dbug="+d,table_map_write_error"; +--error ER_TRANS_CACHE_FULL +UPDATE ti, tm set ti.f=90,tm.f=99; +COMMIT; + +--let $new_gtid_binlog_pos= query_get_value(SHOW VARIABLES LIKE 'gtid_binlog_pos', Value, 1) +--echo # Validating binlog GTID position progressed from first update.. +if(`SELECT strcmp("$old_gtid_binlog_pos","$new_gtid_binlog_pos") = 0`) +{ + --die Binlog GTID position should have updated +} +--echo # ..success + +--echo # Validating the first update saved.. +if(`SELECT COUNT(*)!=1 FROM ti WHERE f=80`) +{ + --die The first update should have saved because it was transactional +} +--echo # ..and the transactional part of the second update did not save.. +if(`SELECT COUNT(*) FROM ti WHERE f=90`) +{ + --die The transactional part of the second update should have rolled back because it failed +} +--echo # ..whereas the non-trans part of the second update did save.. +if(`SELECT COUNT(*)!=1 FROM tm WHERE f=99`) +{ + --die The non-trans part from the second update should have saved +} +--echo # ..success + +--echo # Validating that the incident propagated to the slave +--connection slave +# Incident event +# 1590=ER_SLAVE_INCIDENT +--let $slave_sql_errno= 1590 +--source include/wait_for_slave_sql_error_and_skip.inc + +--echo # Validating that the first update replicated to the slave.. +if(`SELECT COUNT(*)!=1 FROM ti WHERE f=80`) +{ + --die The first update should have replicated because it was transactional +} +--echo # ..and neither part of the second update replicated.. +if(`SELECT COUNT(*) FROM ti WHERE f=90`) +{ + --die The trans part from the second update should not have replicated because it was rolled back +} +if(`SELECT COUNT(*) FROM tm WHERE f=99`) +{ + --die The non-trans part from the second update should not have replicated because it was not binlogged +} +--echo # ..success + + +--echo "#######################################################################" +--echo "# Test Case9: Rolling back a transaction consisting of two updates: +--echo "# S1) Update transactional table +--echo "# S2) Update mixed trans/non-trans tables +--echo "# with a table_map event write failure on the second event should +--echo "# roll-back both transactional updates, preserve the non-transactional +--echo "# update on the master (only), and write an incident event +--echo "#######################################################################" +--connection master +--let $old_gtid_binlog_pos= query_get_value(SHOW VARIABLES LIKE 'gtid_binlog_pos', Value, 1) + +SET debug_dbug=""; +BEGIN; +# successful update +UPDATE ti, tm set ti.f=100; +SET debug_dbug="+d,table_map_write_error"; +--error ER_TRANS_CACHE_FULL +UPDATE ti, tm set ti.f=110,tm.f=111; +ROLLBACK; + +--let $new_gtid_binlog_pos= query_get_value(SHOW VARIABLES LIKE 'gtid_binlog_pos', Value, 1) +--echo # Validating update was not binlogged.. +if(`SELECT strcmp("$old_gtid_binlog_pos","$new_gtid_binlog_pos") != 0`) +{ + --die Binlog GTID position should have been unchanged after failed update +} +--echo # ..success + +--echo # Validating trans updates rollback, but the non-trans update stays.. +if(`SELECT COUNT(*) FROM ti WHERE f=100`) +{ + --die The first update should not have saved +} +if(`SELECT COUNT(*) FROM ti WHERE f=110`) +{ + --die The transactional part of the second update should not have saved +} +if(`SELECT COUNT(*)!=1 FROM tm WHERE f=111`) +{ + --die The non-trans part of the second update should have saved +} +--echo # ..success + +--echo # Validating that the incident propagated to the slave +--connection slave +# Incident event +# 1590=ER_SLAVE_INCIDENT +--let $slave_sql_errno= 1590 +--source include/wait_for_slave_sql_error_and_skip.inc + +--echo # Validating that none of the updates replicated to the slave +--let $diff_tables= master:test.ti,slave:test.ti +--source include/diff_tables.inc +if(`SELECT COUNT(*) FROM tm WHERE f=111`) +{ + --die The non-trans part from the second update should not have replicated because it was not binlogged +} +--echo # ..success + + +--echo "#######################################################################" +--echo "# Test Case10: If an incident event fails to write, a specific error +--echo "# should be logged +--echo "# +--echo "# Note: This test case is the same as test case 5, with the caveat of +--echo "# the incident event failing to write. +--echo "#######################################################################" + +--connection master +SET debug_dbug="d,table_map_write_error,incident_event_write_error"; +--error ER_TRANS_CACHE_FULL +UPDATE ti, tm set ti.f=120, tm.f=122; + +--echo # Validate error message indicating incident event failed to write +let $log_error_= `SELECT @@GLOBAL.log_error`; +if(!$log_error_) +{ + # MySQL Server on windows is started with --console and thus + # does not know the location of its .err log, use default location + let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.1.err; +} +--let SEARCH_PATTERN= Incident event write to the binary log file failed +--let SEARCH_FILE= $log_error_ +--source include/search_pattern_in_file.inc + + +--connection master +--echo "******** Clean Up **********" +--eval SET GLOBAL debug_dbug = '$debug_save' +DROP TABLE tm,ti; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mdev10863.test b/mysql-test/suite/rpl/t/rpl_mdev10863.test new file mode 100644 index 00000000..73062df8 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mdev10863.test @@ -0,0 +1,105 @@ +--source include/have_innodb.inc +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +# Test various aspects of parallel replication. + +--connection server_2 +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=10; +SET @old_max_relay= @@GLOBAL.max_relay_log_size; +SET GLOBAL max_relay_log_size = 4096; +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a int PRIMARY KEY, b VARCHAR(100)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, "a"); +--save_master_pos + +--connection server_2 +--sync_with_master + +--echo *** Create a long transaction that will span a relay log file. *** +--connection server_1 + +# Add some transactions in separate domains, that will cause the need to +# have a multi-valued restart position in the relay log for the SQL thread. +SET @old_domain= @@gtid_domain_id; +SET gtid_domain_id=10; +INSERT INTO t1 VALUES (10000, "domain 10"); +SET gtid_domain_id=20; +INSERT INTO t1 VALUES (20000, "domain 20"); +SET gtid_domain_id=@old_domain; + +BEGIN; +--echo [lots of inserts omitted] +--disable_query_log +--let $count = 500 +while ($count) { + eval INSERT INTO t1 VALUES (1000+$count, REPEAT("hulubulu??!?", 8)); + dec $count; +} +--enable_query_log +COMMIT; + +--save_master_pos + +--connection server_2 +--sync_with_master + +--connection server_1 +# Now do another one, to make the inuse_relaylog proceed to somewhere inside +# the first large transaction. + +BEGIN; +--echo [lots of inserts omitted] +--disable_query_log +--let $count = 500 +while ($count) { + eval INSERT INTO t1 VALUES (2000+$count, REPEAT("hulubulu??!?", 8)); + dec $count; +} +--enable_query_log +COMMIT; + +--save_master_pos + +--connection server_2 +--sync_with_master + + +# Stop and restart the SQL thread only. +# The bug was that the SQL thread would restart at the start +# of a relay log file, which could be in the middle of an event group. +# This way, part of that event group could be wrongly re-applied. + +--source include/stop_slave_sql.inc +START SLAVE SQL_THREAD; +--source include/wait_for_slave_to_start.inc + + +--connection server_1 +INSERT INTO t1 VALUES (100000, "More stuffs."); +INSERT INTO t1 VALUES (100001, "And even more"); +--save_master_pos + +--connection server_2 +--sync_with_master +SELECT * FROM t1 WHERE a >= 100000 ORDER BY a; + + +# Clean up. +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +SET GLOBAL max_relay_log_size= @old_max_relay; +--source include/start_slave.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=Aria; +DROP TABLE t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mdev12179.test b/mysql-test/suite/rpl/t/rpl_mdev12179.test new file mode 100644 index 00000000..aa0d0521 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mdev12179.test @@ -0,0 +1,319 @@ +--source include/no_valgrind_without_big.inc +--source include/have_innodb.inc +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +--connection server_2 +call mtr.add_suppression("The automatically created table.*name may not be entirely in lowercase"); + +--error ER_SLAVE_MUST_STOP +SET GLOBAL gtid_pos_auto_engines="innodb"; +--source include/stop_slave.inc +CHANGE MASTER TO master_use_gtid=slave_pos; + +# Test the @@gtid_pos_auto_engines sysvar. +SELECT @@gtid_pos_auto_engines; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@SESSION.gtid_pos_auto_engines; +--error ER_WRONG_VALUE_FOR_VAR +SET GLOBAL gtid_pos_auto_engines= NULL; +SET GLOBAL gtid_pos_auto_engines="innodb"; +SELECT @@gtid_pos_auto_engines; +SET GLOBAL gtid_pos_auto_engines="myisam,innodb"; +SELECT @@gtid_pos_auto_engines; +SET GLOBAL gtid_pos_auto_engines="innodb,myisam"; +SELECT @@gtid_pos_auto_engines; +SET GLOBAL gtid_pos_auto_engines="innodb,innodb,myisam,innodb,myisam,myisam,innodb"; +SELECT @@gtid_pos_auto_engines; +SET GLOBAL gtid_pos_auto_engines=DEFAULT; +SELECT @@gtid_pos_auto_engines; +SET GLOBAL gtid_pos_auto_engines=""; +SELECT @@gtid_pos_auto_engines; + +--source include/start_slave.inc + +--connection server_1 +CREATE TABLE t1 (a INT PRIMARY KEY); +INSERT INTO t1 VALUES (1); +SELECT * FROM t1 ORDER BY a; +--save_master_pos + +--connection server_2 +--sync_with_master +SELECT * FROM t1 ORDER BY a; +--source include/stop_slave.inc +SET sql_log_bin=0; +# Reset storage engine for mysql.gtid_slave_pos in case an earlier test +# might have changed it to InnoDB. +ALTER TABLE mysql.gtid_slave_pos ENGINE=Aria; +CREATE TABLE mysql.gtid_slave_pos_innodb LIKE mysql.gtid_slave_pos; +ALTER TABLE mysql.gtid_slave_pos_innodb ENGINE=InnoDB; +INSERT INTO mysql.gtid_slave_pos_innodb SELECT * FROM mysql.gtid_slave_pos; +TRUNCATE mysql.gtid_slave_pos; +SET sql_log_bin=1; + +# Restart the slave mysqld server, and verify that the GTID position is +# read correctly from the new mysql.gtid_slave_pos_innodb table. + +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF +--shutdown_server +--source include/wait_until_disconnected.inc + +--connection server_1 +INSERT INTO t1 VALUES (2); +INSERT INTO t1 VALUES (3); +SELECT * FROM t1 ORDER BY a; +--source include/save_master_gtid.inc + +# Let the slave mysqld server start again. +# As we are restarting, also take the opportunity to test --gtid-pos-auto-engines +--echo *** Restart server with --gtid-pos-auto-engines=innodb,myisam *** +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +restart: --skip-slave-start=0 --gtid-pos-auto-engines=innodb,myisam +EOF + +--connection server_2 +--enable_reconnect +--source include/wait_until_connected_again.inc + +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; + +--echo *** Verify no new gtid_slave_pos* tables are created *** +SELECT table_name, engine FROM information_schema.tables + WHERE table_schema='mysql' AND table_name LIKE 'gtid_slave_pos%' + ORDER BY table_name; + +SELECT @@gtid_pos_auto_engines; +--source include/stop_slave.inc +SET sql_log_bin=0; +INSERT INTO mysql.gtid_slave_pos_innodb SELECT * FROM mysql.gtid_slave_pos; +DROP TABLE mysql.gtid_slave_pos; +RENAME TABLE mysql.gtid_slave_pos_innodb TO mysql.gtid_slave_pos; +SET sql_log_bin=1; + +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF +--shutdown_server +--source include/wait_until_disconnected.inc + +--connection server_1 +CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES (4); +INSERT INTO t2 VALUES (1); +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +--source include/save_master_gtid.inc + +--echo *** Restart server with --gtid-pos-auto-engines=myisam,innodb *** +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +restart: --skip-slave-start=0 --gtid-pos-auto-engines=myisam,innodb +EOF + +--connection server_2 +--enable_reconnect +--source include/wait_until_connected_again.inc + +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +--echo *** Verify that no new gtid_slave_pos* tables are auto-created *** +SELECT table_name, engine FROM information_schema.tables + WHERE table_schema='mysql' AND table_name LIKE 'gtid_slave_pos%' + ORDER BY table_name; + + +--source include/stop_slave.inc +SET sql_log_bin=0; +ALTER TABLE mysql.gtid_slave_pos ENGINE=Aria; +SET sql_log_bin=1; + +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF +--shutdown_server +--source include/wait_until_disconnected.inc + +--connection server_1 +INSERT INTO t1 VALUES (5); +INSERT INTO t2 VALUES (2); +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +--source include/save_master_gtid.inc + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +--echo *** Restart server with --gtid-pos-auto-engines=innodb *** +restart: --skip-slave-start=0 --gtid-pos-auto-engines=innodb +EOF + +--connection server_2 +--enable_reconnect +--source include/wait_until_connected_again.inc + +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +--echo *** Verify that mysql.gtid_slave_pos_InnoDB is auto-created *** +# Note, the create happens asynchronously, so wait for it. +let $wait_condition= + SELECT EXISTS (SELECT * FROM information_schema.tables + WHERE table_schema='mysql' AND table_name='gtid_slave_pos_InnoDB'); +--source include/wait_condition.inc +# MDEV-15373 lowercases 'table_name' to satisfy --lower-case-table-names options +SELECT lower(table_name), engine FROM information_schema.tables + WHERE table_schema='mysql' AND table_name LIKE 'gtid_slave_pos%' + ORDER BY table_name; + + +--source include/stop_slave.inc +SET sql_log_bin=0; +INSERT INTO mysql.gtid_slave_pos SELECT * FROM mysql.gtid_slave_pos_InnoDB; +DROP TABLE mysql.gtid_slave_pos_InnoDB; +SET sql_log_bin=1; + +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF +--shutdown_server +--source include/wait_until_disconnected.inc + +--connection server_1 +INSERT INTO t1 VALUES (6); +INSERT INTO t2 VALUES (3); +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +--source include/save_master_gtid.inc + +--echo *** Restart server without --gtid-pos-auto-engines *** +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +restart: --skip-slave-start=0 +EOF + +--connection server_2 +--enable_reconnect +--source include/wait_until_connected_again.inc + +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +--echo *** Verify that no mysql.gtid_slave_pos* table is auto-created *** +SELECT table_name, engine FROM information_schema.tables + WHERE table_schema='mysql' AND table_name LIKE 'gtid_slave_pos%' + ORDER BY table_name; +SELECT domain_id, max(seq_no) FROM mysql.gtid_slave_pos GROUP BY domain_id; + +--source include/stop_slave.inc +SET GLOBAL gtid_pos_auto_engines="innodb"; +--source include/start_slave.inc + +--connection server_1 +INSERT INTO t1 VALUES (7); +INSERT INTO t2 VALUES (4); +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +--echo *** Verify that mysql.gtid_slave_pos_InnoDB is auto-created *** +let $wait_condition= + SELECT EXISTS (SELECT * FROM information_schema.tables + WHERE table_schema='mysql' AND table_name='gtid_slave_pos_InnoDB'); +--source include/wait_condition.inc +SELECT lower(table_name), engine FROM information_schema.tables + WHERE table_schema='mysql' AND table_name LIKE 'gtid_slave_pos%' + ORDER BY table_name; +SELECT domain_id, max(seq_no) FROM mysql.gtid_slave_pos GROUP BY domain_id; + +# Check that the auto-created InnoDB table starts being used without +# needing slave restart. The auto-create happens asynchronously, so it +# is non-deterministic when it will start being used. But we can wait +# for it to happen. + +--let $count=300 +--let $done=0 +--let $old_silent= $keep_include_silent +--let $keep_include_silent= 1 +--disable_query_log +while (!$done) +{ + --connection server_1 + INSERT INTO t2(a) SELECT 1+MAX(a) FROM t2; + --source include/save_master_gtid.inc + + --connection server_2 + --source include/sync_with_master_gtid.inc + --let $done=`SELECT COUNT(*) > 0 FROM mysql.gtid_slave_pos_InnoDB` + if (!$done) + { + dec $count; + if (!$count) + { + SELECT * FROM mysql.gtid_slave_pos_InnoDB; + --die Timeout waiting for mysql.gtid_slave_pos_InnoDB to be used + } + real_sleep 0.1; + } +} +--enable_query_log +--let $keep_include_silent=$old_silent +# Note that at this point, the contents of table t2, as well as the GTID +# position, is non-deterministic. + +# MDEV-15373 engine gtid_slave_pos table name disobeys lower-case-table-names +# This snippet verifies that engine gtid_slave_pos table is found, +# its data are up-to-date. +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +wait +EOF +--connection server_2 +--shutdown_server +--source include/wait_until_disconnected.inc + +--echo *** Restart the slave server to prove 'gtid_slave_pos_innodb' autodiscovery *** +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +restart: --skip-slave-start=0 +EOF + +--connection server_2 +--enable_reconnect +--enable_prepare_warnings +--source include/wait_until_connected_again.inc +SELECT max(seq_no) FROM mysql.gtid_slave_pos_InnoDB into @seq_no; +--disable_prepare_warnings + +--connection server_1 +INSERT INTO t2(a) SELECT 1+MAX(a) FROM t2; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc +if (`SELECT max(seq_no) <> @seq_no + 1 FROM mysql.gtid_slave_pos_InnoDB`) +{ + SELECT * FROM mysql.gtid_slave_pos_InnoDB; + --die Inconsistent table +} +# +# end of MDEV-15373 + +#--connection server_2 +--source include/stop_slave.inc +SET GLOBAL gtid_pos_auto_engines=""; +SET sql_log_bin=0; +DROP TABLE mysql.gtid_slave_pos_InnoDB; +SET sql_log_bin=1; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t1, t2; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mdev359.test b/mysql-test/suite/rpl/t/rpl_mdev359.test new file mode 100644 index 00000000..5b02ecd7 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mdev359.test @@ -0,0 +1,31 @@ +--source include/not_embedded.inc +--source include/have_debug_sync.inc +--source include/have_binlog_format_mixed_or_statement.inc +--source include/master-slave.inc + +# MDEV-359: There was a server crash when the code first checks if semisync +# is enabled without lock, then if so takes the lock and tests again. +# If semisync was disabled in-between the first and the second test, an +# assert was incorrectly made that referenced a NULL pointer. +# +# This tests uses debug_sync to pause one thread at the critical point in +# the code, disable the semisync, and then continue the paused thread. + +CREATE TABLE t1 (a INT) ENGINE=MyISAM; +SET GLOBAL rpl_semi_sync_master_enabled = ON; +--connection master1 +SET DEBUG_SYNC = "rpl_semisync_master_commit_trx_before_lock SIGNAL m1_ready WAIT_FOR m1_cont"; +--send +INSERT INTO t1 SELECT * FROM t1; +--connection master +SET DEBUG_SYNC= "now WAIT_FOR m1_ready"; +SET GLOBAL rpl_semi_sync_master_enabled = OFF; +SET DEBUG_SYNC= "now SIGNAL m1_cont"; +--connection master1 +--reap + +connection master; +DROP TABLE t1; +SET DEBUG_SYNC= "RESET"; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mdev382.test b/mysql-test/suite/rpl/t/rpl_mdev382.test new file mode 100644 index 00000000..84e3c849 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mdev382.test @@ -0,0 +1,264 @@ +--source include/not_windows.inc #unix shell escaping used for mysqlbinlog +--source include/have_innodb.inc +--source include/have_binlog_format_statement.inc +--source include/master-slave.inc + +# MDEV-382: multiple SQL injections in replication code. + +# Test previous SQL injection attack against binlog for SAVEPOINT statement. +# The test would cause syntax error on slave due to improper quoting of +# the savepoint name. +connection master; +create table t1 (a int primary key) engine=innodb; +create table t2 (a int primary key) engine=myisam; + +begin; +insert into t1 values (1); +SET sql_mode = 'ANSI_QUOTES'; +savepoint `a``; create database couldbebadthingshere; savepoint ``dummy`; +insert into t1 values (2); +insert into t2 values (1); +SET sql_mode = ''; +rollback to savepoint `a``; create database couldbebadthingshere; savepoint ``dummy`; +insert into t1 values (3); +commit; + +--source include/show_binlog_events2.inc + +# This failed due to syntax error in query when the bug was not fixed. +sync_slave_with_master; +connection slave; + +# Test some more combinations of ANSI_QUOTES and sql_quote_show_create +connection master; +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +BEGIN; +insert into t1 values(10); +set sql_mode = 'ANSI_QUOTES'; +set sql_quote_show_create = 1; +savepoint a; +insert into t1 values(11); +savepoint "a""a"; +insert into t1 values(12); +set sql_quote_show_create = 0; +savepoint b; +insert into t1 values(13); +savepoint "b""b"; +insert into t1 values(14); +set sql_mode = ''; +set sql_quote_show_create = 1; +savepoint c; +insert into t1 values(15); +savepoint `c``c`; +insert into t1 values(16); +set sql_quote_show_create = 0; +savepoint d; +insert into t1 values(17); +savepoint `d``d`; +insert into t1 values(18); +COMMIT; +set sql_quote_show_create = 1; + +--source include/show_binlog_events2.inc + +--echo *** Test correct USE statement in SHOW BINLOG EVENTS *** +connection master; +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +set sql_mode = 'ANSI_QUOTES'; +CREATE DATABASE "db1`; select 'oops!'"; +use "db1`; select 'oops!'"; +CREATE TABLE t1 (a INT PRIMARY KEY) engine=MyISAM; +INSERT INTO t1 VALUES (1); +set sql_mode = ''; +INSERT INTO t1 VALUES (2); +set sql_mode = 'ANSI_QUOTES'; +--source include/show_binlog_events2.inc +set sql_mode = ''; +set sql_quote_show_create = 0; +--source include/show_binlog_events2.inc +set sql_quote_show_create = 1; +--source include/show_binlog_events2.inc +DROP TABLE t1; + +use test; + +--echo ***Test LOAD DATA INFILE with various identifiers that need correct quoting *** + +--let $load_file= $MYSQLTEST_VARDIR/tmp/f'le.txt +--write_file $load_file +'fo\\o','bar' +EOF + +use `db1``; select 'oops!'`; +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +set timestamp=1000000000; +CREATE TABLE `t``1` (`a``1` VARCHAR(4) PRIMARY KEY, `b``2` VARCHAR(3), + `c``3` VARCHAR(7)); +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/f''le.txt' INTO TABLE `t``1` + FIELDS TERMINATED BY ',' ESCAPED BY '\\\\' ENCLOSED BY '''' + LINES TERMINATED BY '\\n' + (`a``1`, @`b```) SET `b``2` = @`b```, `c``3` = concat('|', "b""a'z", "!"); + +SELECT * FROM `t``1`; +# Also test when code prefixes table name with database. +truncate `t``1`; +use test; +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/f''le.txt' + INTO TABLE `db1``; select 'oops!'`.`t``1` + FIELDS TERMINATED BY ',' ESCAPED BY '\\\\' ENCLOSED BY '''' + LINES TERMINATED BY '\\n' + (`a``1`, `b``2`) SET `c``3` = concat('|', "b""a'z", "!"); +SELECT * FROM `db1``; select 'oops!'`.`t``1`; +let $pos2= query_get_value(SHOW MASTER STATUS, Position, 1); + +--source include/show_binlog_events2.inc +let $MYSQLD_DATADIR= `select @@datadir`; +--replace_regex /LOCAL INFILE '.*SQL_LOAD.*' INTO/LOCAL INFILE '<name>' INTO/ +--exec $MYSQL_BINLOG --short-form --start-position=$binlog_start --stop-position=$pos2 $MYSQLD_DATADIR/master-bin.000001 + +sync_slave_with_master; +connection slave; +SELECT * FROM `db1``; select 'oops!'`.`t``1`; +connection master; + +DROP TABLE `db1``; select 'oops!'`.`t``1`; +--remove_file $load_file + +connection master; +drop table t1,t2; + + +--echo *** Test truncation of long SET expression in LOAD DATA *** +CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(1000)); +--let $load_file= $MYSQLTEST_VARDIR/tmp/file.txt +--write_file $load_file +1,X +2,A +EOF + +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +# The bug was that the SET expression was truncated to 256 bytes, so test with +# an expression longer than that. +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +eval LOAD DATA INFILE '$load_file' INTO TABLE t1 + FIELDS TERMINATED BY ',' + (a, @b) SET b = CONCAT(@b, '| 123456789A123456789B123456789C123456789D123456789E123456789F123456789G123456789H123456789I123456789J123456789K123456789L123456789M123456789N123456789O123456789P123456789Q123456789R123456789123456789T123456789U123456789V123456789W123456789X123456789Y123456789Z123456789|', @b); + +SELECT * FROM t1 ORDER BY a; +--source include/show_binlog_events2.inc + +sync_slave_with_master; +connection slave; +SELECT * FROM t1 ORDER BY a; + +connection master; +--remove_file $load_file +DROP TABLE t1; + + +--echo *** Test user variables whose names require correct quoting *** +use `db1``; select 'oops!'`; +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +CREATE TABLE t1 (a1 BIGINT PRIMARY KEY, a2 BIGINT, a3 BIGINT, a4 BIGINT UNSIGNED, b DOUBLE, c DECIMAL(65,10), d VARCHAR(100)); +INSERT INTO t1 VALUES (-9223372036854775808,42,9223372036854775807,18446744073709551615,-1234560123456789e110, -1234501234567890123456789012345678901234567890123456789.0123456789, REPEAT("x", 100)); +SELECT @`a``1`:=a1, @`a``2`:=a2, @`a``3`:=a3, @`a``4`:=a4, @`b```:=b, @```c`:=c, @```d```:=d FROM t1; +INSERT INTO t1 VALUES (@`a``1`+1, @`a``2`*100, @`a``3`-1, @`a``4`-1, @`b```/2, @```c`, substr(@```d```, 2, 98)); +let $pos2= query_get_value(SHOW MASTER STATUS, Position, 1); + +--source include/show_binlog_events2.inc + +--exec $MYSQL_BINLOG --short-form --start-position=$binlog_start --stop-position=$pos2 $MYSQLD_DATADIR/master-bin.000001 + +sync_slave_with_master; +connection slave; +SELECT * FROM `db1``; select 'oops!'`.t1 ORDER BY a1; + +connection master; +DROP TABLE t1; + +--echo *** Test correct quoting in foreign key error message *** +use `db1``; select 'oops!'`; +CREATE TABLE `t``1` ( `a``` INT PRIMARY KEY) ENGINE=innodb; +CREATE TABLE `t``2` ( `b``` INT PRIMARY KEY, `c``` INT NOT NULL, + FOREIGN KEY fk (`c```) REFERENCES `t``1`(`a```)) ENGINE=innodb; +--error ER_TRUNCATE_ILLEGAL_FK +TRUNCATE `t``1`; +DROP TABLE `t``2`; +DROP TABLE `t``1`; + + +--echo *** Test correct quoting of DELETE FROM statement binlogged for HEAP table that is emptied due to server restart + +# Let's keep the slave stopped during master restart, to avoid any potential +# races between slave reconnect and master restart. +connection slave; +--source include/stop_slave.inc + +connection master; +CREATE TABLE `db1``; select 'oops!'`.`t``1` (`a``` INT PRIMARY KEY) ENGINE=heap; +INSERT INTO `db1``; select 'oops!'`.`t``1` VALUES (1), (2), (5); +SELECT * FROM `db1``; select 'oops!'`.`t``1` ORDER BY 1; + +# Restart the master mysqld. +# This will cause an implicit truncation of the memory-based table, which will +# cause logging of an explicit DELETE FROM to binlog. +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait-rpl_mdev382.test +EOF + +--shutdown_server + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart-rpl_mdev382.test +EOF + +connection default; +--enable_reconnect +--source include/wait_until_connected_again.inc +# rpl_end.inc needs to use the connection server_1 +connection server_1; +--enable_reconnect +--source include/wait_until_connected_again.inc +connection master; +--enable_reconnect +--source include/wait_until_connected_again.inc +set timestamp=1000000000; + +--echo # The table should be empty on the master. +let $binlog_file= master-bin.000002; +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +SELECT * FROM `db1``; select 'oops!'`.`t``1`; + +--echo # The DELETE statement should be correctly quoted +--source include/show_binlog_events2.inc + +connection slave; +--source include/start_slave.inc + +connection master; +sync_slave_with_master; +connection slave; +--echo # The table should be empty on the slave also. +SELECT * FROM `db1``; select 'oops!'`.`t``1`; + +connection master; +DROP TABLE `db1``; select 'oops!'`.`t``1`; +sync_slave_with_master; + + +connection master; +use test; +DROP DATABASE `db1``; select 'oops!'`; + +--echo *** Test correct quoting of mysqlbinlog --rewrite-db option *** +CREATE TABLE t1 (a INT PRIMARY KEY); +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +INSERT INTO t1 VALUES(1); +--source include/show_binlog_events2.inc +let $pos2= query_get_value(SHOW MASTER STATUS, Position, 1); +--exec $MYSQL_BINLOG --short-form --start-position=$binlog_start --stop-position=$pos2 --rewrite-db='test->ts`et' $MYSQLD_DATADIR/master-bin.000002 +DROP TABLE t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mdev6020.test b/mysql-test/suite/rpl/t/rpl_mdev6020.test new file mode 100644 index 00000000..06f03be1 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mdev6020.test @@ -0,0 +1,69 @@ +--source include/have_innodb.inc +--source include/have_partition.inc +--source include/have_binlog_format_mixed_or_row.inc +--source include/master-slave.inc +--connection slave +--source include/stop_slave.inc + +--connection master +--let $datadir= `SELECT @@datadir` + +--let $rpl_server_number= 1 +--source include/rpl_stop_server.inc + +--remove_file $datadir/master-bin.000001 +--remove_file $datadir/master-bin.state +--copy_file $MYSQL_TEST_DIR/std_data/mdev6020-mysql-bin.000001 $datadir/master-bin.000001 + +--let $rpl_server_number= 1 +--source include/rpl_start_server.inc + +--source include/wait_until_connected_again.inc + +--connection slave +SET SQL_LOG_BIN=0; +ALTER TABLE mysql.gtid_slave_pos ENGINE = InnoDB; +SET SQL_LOG_BIN=1; +SET @old_engine= @@GLOBAL.default_storage_engine; +SET GLOBAL default_storage_engine=InnoDB; +SET @old_parallel= @@GLOBAL.slave_parallel_threads; +SET GLOBAL slave_parallel_threads=12; +--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1 +eval CHANGE MASTER TO master_host='127.0.0.1', master_port=$SERVER_MYPORT_1, master_user='root', master_log_file='master-bin.000001', master_log_pos=4, master_use_gtid=no; +--source include/start_slave.inc + +--connection master +SET SQL_LOG_BIN=0; +ALTER TABLE mysql.gtid_slave_pos ENGINE = InnoDB; +SET SQL_LOG_BIN=1; +--save_master_pos + +--connection slave +--sync_with_master + +SELECT @@gtid_slave_pos; +CHECKSUM TABLE table0_int_autoinc, table0_key_pk_parts_2_int_autoinc, table100_int_autoinc, table100_key_pk_parts_2_int_autoinc, table10_int_autoinc, table10_key_pk_parts_2_int_autoinc, table1_int_autoinc, table1_key_pk_parts_2_int_autoinc, table2_int_autoinc, table2_key_pk_parts_2_int_autoinc; + +--source include/stop_slave.inc + + +SET GLOBAL default_storage_engine= @old_engine; +SET GLOBAL slave_parallel_threads=@old_parallel; +SET sql_log_bin=0; +DROP TABLE table0_int_autoinc; +DROP TABLE table0_key_pk_parts_2_int_autoinc; +DROP TABLE table100_int_autoinc; +DROP TABLE table100_key_pk_parts_2_int_autoinc; +DROP TABLE table10_int_autoinc; +DROP TABLE table10_key_pk_parts_2_int_autoinc; +DROP TABLE table1_int_autoinc; +DROP TABLE table1_key_pk_parts_2_int_autoinc; +DROP TABLE table2_int_autoinc; +DROP TABLE table2_key_pk_parts_2_int_autoinc; +SET sql_log_bin=1; + +--source include/start_slave.inc + +--connection master + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mdev6386-slave.opt b/mysql-test/suite/rpl/t/rpl_mdev6386-slave.opt new file mode 100644 index 00000000..a5d959ae --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mdev6386-slave.opt @@ -0,0 +1 @@ +--disable-log-slave-updates diff --git a/mysql-test/suite/rpl/t/rpl_mdev6386.test b/mysql-test/suite/rpl/t/rpl_mdev6386.test new file mode 100644 index 00000000..f969d656 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mdev6386.test @@ -0,0 +1,70 @@ +--source include/have_innodb.inc +--source include/master-slave.inc + +--connection master +ALTER TABLE mysql.gtid_slave_pos ENGINE = InnoDB; +CREATE TABLE t1 (a INT PRIMARY KEY, b INT) Engine=InnoDB; +--sync_slave_with_master + +--connection slave +--source include/stop_slave.inc +# Provoke a duplicate key error on replication. +SET sql_log_bin= 0; +CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends"); +INSERT INTO t1 VALUES (1, 2); +SET sql_log_bin= 1; +--echo Contents on slave before: +SELECT * FROM t1 ORDER BY a; + +SET @old_parallel= @@GLOBAL.slave_parallel_threads; +SET GLOBAL slave_parallel_threads=8; + +--connection master + +CREATE TEMPORARY TABLE t2 LIKE t1; +INSERT INTO t2 VALUE (1, 1); +INSERT INTO t2 VALUE (2, 1); +INSERT INTO t2 VALUE (3, 1); +INSERT INTO t2 VALUE (4, 1); +INSERT INTO t2 VALUE (5, 1); +INSERT INTO t1 SELECT * FROM t2; +DROP TEMPORARY TABLE t2; +INSERT INTO t1 VALUE (6, 3); +--source include/save_master_gtid.inc +--echo Contents on master: +SELECT * FROM t1 ORDER BY a; + +--connection slave +START SLAVE; +# The slave will stop with a duplicate key error. +# The bug was 1) that the next DROP TEMPORARY TABLE would be allowed to run +# anyway, and 2) that then record_gtid() would get an error during commit +# (since the prior commit failed), and this error was not correctly handled, +# which caused an assertion about closing tables while a statement was still +# active. +--let $slave_sql_errno=1062 +--source include/wait_for_slave_sql_error.inc + +STOP SLAVE IO_THREAD; +--echo Contents on slave on slave error: +SELECT * FROM t1 ORDER BY a; + +# Resolve the duplicate key error so replication can be resumed. +SET sql_log_bin= 0; +DELETE FROM t1 WHERE a=1; +SET sql_log_bin= 1; + +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +--echo Contents on slave after: +SELECT * FROM t1 ORDER BY a; + +--connection master +DROP TABLE t1; + +--connection slave +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads= @old_parallel; +--source include/start_slave.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mdev8193.test b/mysql-test/suite/rpl/t/rpl_mdev8193.test new file mode 100644 index 00000000..dcad3e5f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mdev8193.test @@ -0,0 +1,56 @@ +--source include/have_binlog_format_statement.inc +--source include/master-slave.inc + +--connection slave + +--source include/stop_slave_sql.inc + +--connection master + +CALL mtr.add_suppression("Statement is unsafe because it uses a system function that may return a different value on the slave"); +create table t1 (i int); +insert into t1 values (1),(2); +insert into t1 values (3),(4); +# This sleep() helps trigger the failure more reliably. +insert into t1 select i+20+0*sleep(1) from t1 where i=1; +flush logs; +insert into t1 values (5),(6); +insert into t1 values (7),(8); +insert into t1 values (9),(10); + +--let $master_file = query_get_value(show master status,File,1) +--let $master_pos = query_get_value(show master status,Position,1) + +insert into t1 values (11),(12); +insert into t1 values (13),(14); +insert into t1 values (15),(16); + +--connection slave + +set global slave_parallel_threads = 1; +--replace_result $master_file MASTER_FILE $master_pos MASTER_POS +eval start slave until master_log_file='$master_file', master_log_pos=$master_pos; + +--let $show_statement = SHOW SLAVE STATUS +--let $field = Slave_SQL_Running +--let $condition = = 'No' +--let $wait_timeout = 10 + +--source include/wait_show_condition.inc + +if (`select COUNT(*) > 11 from t1`) +{ + query_vertical show slave status; + SELECT * FROM t1; + die "Wrong number of rows in the table"; +} + +drop table t1; +--source include/stop_slave_io.inc +set global slave_parallel_threads = DEFAULT; + +--connection master +drop table t1; + +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mdev_17614.test b/mysql-test/suite/rpl/t/rpl_mdev_17614.test new file mode 100644 index 00000000..8d91944a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mdev_17614.test @@ -0,0 +1,172 @@ +source include/have_debug.inc; +source include/have_innodb.inc; +-- source include/have_binlog_format_statement.inc +source include/master-slave.inc; +# MDEV-17614 INSERT on dup key update is replication unsafe +# +# The following cases are tested below: +# 1. 2 unique key, replication is UNSAFE +# 2. 2 unique key, with one auto increment key and implicit value to it. +# It is UNSAFE because autoinc column values of being inserted records +# are revealed dynamically, so unknown at the binlog-format decision time +# and hence this pessimistic expectation +# 3. 2 unique keys +# A. insert is only in 1 unique key, still all colums are specified => UNSAFE +# B. both unique keys are specified => UNSAFE +# C. only one unique key is specified => SAFE (motivated by MDEV-28310) +# 4. 2 unique key, with one auto increment key(but user gives auto inc value) => +# UNSAFE to replicate + +--echo # Case 1: UNSAFE +call mtr.add_suppression("Unsafe statement written to the binary log using statement format"); +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY , b INT, +UNIQUE(b), c int) engine=innodb; +sync_slave_with_master; +connection master; +INSERT INTO t1 VALUES (1, 1, 1); +BEGIN; +INSERT INTO t1 VALUES (2, 1, 2) ON DUPLICATE KEY UPDATE b=VALUES(b), c=VALUES(c); + --connection master1 + INSERT INTO t1 VALUES(2, 2, 3) ON DUPLICATE KEY UPDATE b=VALUES(b), c=VALUES(c); +--connection master +COMMIT; +SELECT * FROM t1; +--connection slave +# show the error message +--let $slave_sql_errno= 1062 +--let $show_slave_sql_error= 1 +--source include/wait_for_slave_sql_error.inc +--echo #Different value from server +SELECT * FROM t1; + +# restart replication for the next testcase +stop slave; +--source include/wait_for_slave_to_stop.inc +--source include/reset_slave.inc +connection master; +reset master; +drop table t1; +connection slave; +start slave; +--source include/wait_for_slave_to_start.inc + +--echo # Case 2: UNSAFE +--connection master +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY auto_increment, b INT, +UNIQUE(b), c int) engine=innodb; +sync_slave_with_master; +connection master; +INSERT INTO t1 VALUES (default, 1, 1); +BEGIN; +INSERT INTO t1 VALUES (default, 1, 2) ON DUPLICATE KEY UPDATE b=VALUES(b), c=VALUES(c); + --connection master1 + INSERT INTO t1 VALUES(default, 2, 3) ON DUPLICATE KEY UPDATE b=VALUES(b), c=VALUES(c); +--connection master +COMMIT; +SELECT * FROM t1; +--sync_slave_with_master +--echo #same data as master +SELECT * FROM t1; + +connection master; +drop table t1; +--sync_slave_with_master + +--echo # Case 3A: UNSAFE +--connection master +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b INT, +UNIQUE(b), c int, d int ) engine=innodb; +sync_slave_with_master; +connection master; +INSERT INTO t1 VALUES (1, 1, 1, 1); +BEGIN; +INSERT INTO t1 VALUES (2, NULL, 2, 2) ON DUPLICATE KEY UPDATE b=VALUES(b), c=VALUES(c); + --connection master1 + INSERT INTO t1 VALUES(3, NULL, 2, 3) ON DUPLICATE KEY UPDATE b=VALUES(b), c=VALUES(c); +--connection master +COMMIT; +SELECT * FROM t1; +--sync_slave_with_master +--echo #same data as master +SELECT * FROM t1; +connection master; +drop table t1; +--sync_slave_with_master + +--echo # Case 3B: UNSAFE - all column specified. +--connection master +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b INT, +UNIQUE(b), c int, d int ) engine=innodb; +sync_slave_with_master; +connection master; +INSERT INTO t1 VALUES (1, 1, 1, 1); +BEGIN; +INSERT INTO t1 VALUES (2, NULL, 2, 2) ON DUPLICATE KEY UPDATE c=VALUES(c); + --connection master1 + INSERT INTO t1 VALUES(3, NULL, 2, 3) ON DUPLICATE KEY UPDATE c=VALUES(c); +--connection master +COMMIT; +SELECT * FROM t1; +--sync_slave_with_master +--echo #same data as master +SELECT * FROM t1; +connection master; +drop table t1; +--sync_slave_with_master + + +--echo # Case 3C: SAFE - only one unique key (PK) specified. +--connection master +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b INT, +UNIQUE(b), c int, d int ) engine=innodb; +sync_slave_with_master; +connection master; +INSERT INTO t1 VALUES (1, 1, 1, 1); +BEGIN; +INSERT INTO t1 (`a`, `c`, `d`) VALUES (2, 2, 2) ON DUPLICATE KEY UPDATE c=99; + --connection master1 + INSERT INTO t1 (`a`, `c`, `d`) VALUES(3, 2, 3) ON DUPLICATE KEY UPDATE c=100; +--connection master +COMMIT; +SELECT * FROM t1; +--sync_slave_with_master +--echo #same data as master +SELECT * FROM t1; +connection master; +drop table t1; +--sync_slave_with_master + +--echo # Case 4: UNSAFE +--connection master +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY auto_increment, b INT, +UNIQUE(b), c int) engine=innodb; +sync_slave_with_master; +connection master; +INSERT INTO t1 VALUES (1, 1, 1); +BEGIN; +INSERT INTO t1 VALUES (2, 1, 2) ON DUPLICATE KEY UPDATE b=VALUES(b), c=VALUES(c); + --connection master1 + INSERT INTO t1 VALUES(2, 2, 3) ON DUPLICATE KEY UPDATE b=VALUES(b), c=VALUES(c); +--connection master +COMMIT; +SELECT * FROM t1; +--connection slave +# show the error message +--let $slave_sql_errno= 1062 +--let $show_slave_sql_error= 1 +--source include/wait_for_slave_sql_error.inc +--echo #Different value from server +SELECT * FROM t1; + +# restart replication for the next testcase +stop slave; +--source include/wait_for_slave_to_stop.inc +--source include/reset_slave.inc +connection master; +reset master; +drop table t1; +connection slave; +start slave; +--source include/wait_for_slave_to_start.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_misc_functions-slave.sh b/mysql-test/suite/rpl/t/rpl_misc_functions-slave.sh new file mode 100644 index 00000000..8ce79797 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_misc_functions-slave.sh @@ -0,0 +1 @@ +rm -f $MYSQLTEST_VARDIR/master-data/test/rpl_misc_functions.outfile diff --git a/mysql-test/suite/rpl/t/rpl_misc_functions.test b/mysql-test/suite/rpl/t/rpl_misc_functions.test new file mode 100644 index 00000000..b9d65844 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_misc_functions.test @@ -0,0 +1,133 @@ +# +# Test of replicating some difficult functions +# +source include/master-slave.inc; + +CALL mtr.add_suppression('Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT'); + +create table t1(id int, i int, r1 int, r2 int, p varchar(100)); +insert into t1 values(1, connection_id(), 0, 0, ""); +# don't put rand and password in the same query, to see if they replicate +# independently +# Pure rand test +--disable_warnings +insert into t1 values(2, 0, rand()*1000, rand()*1000, ""); +--enable_warnings +# change the rand suite on the master (we do this because otherwise password() +# benefits from the fact that the above rand() is well replicated : +# it picks the same sequence element, which hides a possible bug in password() replication. +set sql_log_bin=0; +insert into t1 values(6, 0, rand(), rand(), ""); +delete from t1 where id=6; +set sql_log_bin=1; +# Pure password test +insert into t1 values(3, 0, 0, 0, password('does_this_work?')); +# "altogether now" +--disable_warnings +insert into t1 values(4, connection_id(), rand()*1000, rand()*1000, password('does_this_still_work?')); +--enable_warnings +--disable_ps2_protocol +select * into outfile 'rpl_misc_functions.outfile' from t1; +--enable_ps2_protocol +let $MYSQLD_DATADIR= `select @@datadir`; +sync_slave_with_master; +create temporary table t2 like t1; +# read the values from the master table +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval load data local infile '$MYSQLD_DATADIR/test/rpl_misc_functions.outfile' into table t2; +# compare them with the replica; the SELECT below should return no row +select * from t1, t2 where (t1.id=t2.id) and not(t1.i=t2.i and t1.r1=t2.r1 and t1.r2=t2.r2 and t1.p=t2.p); + +connection master; +drop table t1; + +# End of 4.1 tests + +# +# BUG#25543 test calling rand() multiple times on the master in +# a stored procedure. +# + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + col_a DOUBLE DEFAULT NULL); + +DELIMITER |; + +# Use a SP that calls rand() multiple times +CREATE PROCEDURE test_replication_sp1() +BEGIN + INSERT INTO t1 (col_a) VALUES (rand()), (rand()); + INSERT INTO t1 (col_a) VALUES (rand()); +END| + +# Use a SP that calls another SP to call rand() multiple times +CREATE PROCEDURE test_replication_sp2() +BEGIN + CALL test_replication_sp1(); + CALL test_replication_sp1(); +END| + +# Use a SF that calls rand() multiple times +CREATE FUNCTION test_replication_sf() RETURNS DOUBLE DETERMINISTIC +BEGIN + RETURN (rand() + rand()); +END| + +DELIMITER ;| + +# Exercise the functions and procedures then compare the results on +# the master to those on the slave. +--disable_warnings +CALL test_replication_sp1(); +CALL test_replication_sp2(); +INSERT INTO t1 (col_a) VALUES (test_replication_sf()); +INSERT INTO t1 (col_a) VALUES (test_replication_sf()); +INSERT INTO t1 (col_a) VALUES (test_replication_sf()); +--enable_warnings + +--sync_slave_with_master + +--enable_prepare_warnings +# Dump table on slave +--disable_ps2_protocol +select * from t1 into outfile "../../tmp/t1_slave.txt"; +--disable_prepare_warnings +--enable_ps2_protocol + +# Load data from slave into temp table on master +connection master; +--disable_warnings +create temporary table t1_slave select * from t1 where 1=0; +--enable_warnings +load data infile '../../tmp/t1_slave.txt' into table t1_slave; +--remove_file $MYSQLTEST_VARDIR/tmp/t1_slave.txt + +# Compare master and slave temp table, use subtraction +# for floating point comparison of "double" +select count(*) into @aux from t1 join t1_slave using (id) +where ABS(t1.col_a - t1_slave.col_a) < 0.0000001 ; +SELECT @aux; +if (`SELECT @aux <> 12 OR @aux IS NULL`) +{ + --echo # ERROR: We expected to get count(*) = 12. + SELECT id, col_a FROM t1; + SELECT id, col_a FROM t1_slave; + --echo # abort + exit; +} + +# Cleanup +connection master; +DROP TABLE t1, t1_slave; +DROP PROCEDURE test_replication_sp1; +DROP PROCEDURE test_replication_sp2; +DROP FUNCTION test_replication_sf; +--remove_file $MYSQLD_DATADIR/test/rpl_misc_functions.outfile +--sync_slave_with_master + + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mix_found_rows.test b/mysql-test/suite/rpl/t/rpl_mix_found_rows.test new file mode 100644 index 00000000..af206c55 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mix_found_rows.test @@ -0,0 +1,152 @@ +source include/have_binlog_format_mixed.inc; +source include/master-slave.inc; + +# It is not possible to replicate FOUND_ROWS() using statement-based +# replication, but there is a workaround that stores the result of +# FOUND_ROWS() into a user variable and then replicates this instead. +# +# The purpose of this test case is to test that the workaround works +# properly even when inside stored programs (i.e., stored routines and +# triggers). + +--echo ==== Initialize ==== + +connection master; +CREATE TABLE t1 (a INT); +CREATE TABLE logtbl (sect INT, test INT, count INT); + +INSERT INTO t1 VALUES (1),(2),(3); +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; + +--echo ==== Checking a procedure ==== + +connection master; + +# We will now check some stuff that will not work in statement-based +# replication, but which should cause the binary log to switch to +# row-based logging. + +--delimiter $$ +CREATE PROCEDURE just_log(sect INT, test INT) BEGIN + INSERT INTO logtbl VALUES (sect,test,FOUND_ROWS()); +END $$ +--delimiter ; +sync_slave_with_master; + +connection master1; +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +CALL just_log(1,1); + +connection master; +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +CALL just_log(1,2); + +connection master1; +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; +CALL just_log(1,3); +sync_slave_with_master; + +connection master; +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +CALL just_log(1,4); +sync_slave_with_master; + +connection master; +SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test; +sync_slave_with_master; +SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test; + +--echo ==== Checking a stored function ==== +connection master; +--delimiter $$ +CREATE FUNCTION log_rows(sect INT, test INT) + RETURNS INT +BEGIN + DECLARE found_rows INT; + SELECT FOUND_ROWS() INTO found_rows; + INSERT INTO logtbl VALUES(sect,test,found_rows); + RETURN found_rows; +END $$ +--delimiter ; + +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; +--disable_ps2_protocol +SELECT log_rows(2,1), log_rows(2,2); +--enable_ps2_protocol + +CREATE TABLE t2 (a INT, b INT); + +# Trying with referencing FOUND_ROWS() directly in the trigger. + +--delimiter $$ +CREATE TRIGGER t2_tr BEFORE INSERT ON t2 FOR EACH ROW +BEGIN + INSERT INTO logtbl VALUES (NEW.a, NEW.b, FOUND_ROWS()); +END $$ +--delimiter ; + +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; +INSERT INTO t2 VALUES (2,3), (2,4); + +# Referencing FOUND_ROWS() indirectly. + +DROP TRIGGER t2_tr; + +--delimiter $$ +CREATE TRIGGER t2_tr BEFORE INSERT ON t2 FOR EACH ROW +BEGIN + DECLARE dummy INT; + SELECT log_rows(NEW.a, NEW.b) INTO dummy; +END $$ +--delimiter ; + +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +INSERT INTO t2 VALUES (2,5), (2,6); + +# Putting FOUND_ROWS() even lower in the call chain. + +connection master; +DROP TRIGGER t2_tr; + +--delimiter $$ +CREATE PROCEDURE log_me_inner(sect INT, test INT) +BEGIN + DECLARE dummy INT; + SELECT log_rows(sect, test) INTO dummy; + SELECT log_rows(sect, test+1) INTO dummy; +END $$ + +CREATE PROCEDURE log_me(sect INT, test INT) +BEGIN + CALL log_me_inner(sect,test); +END $$ +--delimiter ; + +--delimiter $$ +CREATE TRIGGER t2_tr BEFORE INSERT ON t2 FOR EACH ROW +BEGIN + CALL log_me(NEW.a, NEW.b); +END $$ +--delimiter ; + +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +INSERT INTO t2 VALUES (2,5), (2,6); + +SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test; +sync_slave_with_master; +SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test; + +connection master; +DROP TABLE t1, t2, logtbl; +DROP PROCEDURE just_log; +DROP PROCEDURE log_me; +DROP PROCEDURE log_me_inner; +DROP FUNCTION log_rows; +sync_slave_with_master; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mixed_binlog_max_cache_size.test b/mysql-test/suite/rpl/t/rpl_mixed_binlog_max_cache_size.test new file mode 100644 index 00000000..c4c89d90 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mixed_binlog_max_cache_size.test @@ -0,0 +1,8 @@ +--source include/have_innodb.inc +--source include/not_embedded.inc +--source include/not_windows.inc +--source include/have_binlog_format_mixed.inc +--source include/master-slave.inc + +--source include/rpl_binlog_max_cache_size.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mixed_bit_pk.test b/mysql-test/suite/rpl/t/rpl_mixed_bit_pk.test new file mode 100644 index 00000000..226a82de --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mixed_bit_pk.test @@ -0,0 +1,83 @@ +# +# BUG +# --- +# BUG#39753: Replication failure on MIXED + bit + myisam + no PK +# +# Description +# ----------- +# Simple statements against a bit column cause failure in mixed-mode +# replication. +# +# Implementation is as follows: +# i) A table with two bit fields is created. One of them is a key. +# ii) A record is inserted without specifying the key value. +# iii) The record is deleted using a where clause that matches it. +# iv) repeat i-iii) for bit key that has different size, generating +# different extra bits values +# v) The slave is synchronized with master +# vi) The table is dropped on master and the slave is re-synchronized +# with master. +# +# Step v) made the bug evident before the patch, as the slave would +# fail to find the correspondent row in its database (although it did +# the insert in step ii) ). +# +# Obs +# --- +# This test is based on the "how to repeat" section from the bug report. +# +# + +--source include/master-slave.inc + +disable_query_log; +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); +enable_query_log; + +--disable_warnings +# setup + +DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8; +CREATE TABLE t1 (`bit_key` bit, `bit` bit, key (`bit_key` )) ENGINE=MyISAM; +CREATE TABLE t2 (`bit_key` bit(4), `bit` bit, key (`bit_key` )) ENGINE=MyISAM; +CREATE TABLE t3 (`bit_key` bit(7), `bit` bit, key (`bit_key` )) ENGINE=MyISAM; +CREATE TABLE t4 (`bit_key` bit(8), `bit` bit, key (`bit_key` )) ENGINE=MyISAM; +CREATE TABLE t5 (`bit_key` bit(9), `bit` bit, key (`bit_key` )) ENGINE=MyISAM; +CREATE TABLE t6 (`bit_key` bit(14), `bit` bit, key (`bit_key` )) ENGINE=MyISAM; +CREATE TABLE t7 (`bit_key` bit(15), `bit` bit, key (`bit_key` )) ENGINE=MyISAM; +CREATE TABLE t8 (`bit_key` bit(16), `bit` bit, key (`bit_key` )) ENGINE=MyISAM; + +# insert and delete +INSERT INTO `t1` ( `bit` ) VALUES ( 0 ); +DELETE FROM `t1` WHERE `bit` < 2 LIMIT 4; + +INSERT INTO `t2` ( `bit` ) VALUES ( 0 ); +DELETE FROM `t2` WHERE `bit` < 2 LIMIT 4; + +INSERT INTO `t3` ( `bit` ) VALUES ( 0 ); +DELETE FROM `t3` WHERE `bit` < 2 LIMIT 4; + +INSERT INTO `t4` ( `bit` ) VALUES ( 0 ); +DELETE FROM `t4` WHERE `bit` < 2 LIMIT 4; + +INSERT INTO `t5` ( `bit` ) VALUES ( 0 ); +DELETE FROM `t5` WHERE `bit` < 2 LIMIT 4; + +INSERT INTO `t6` ( `bit` ) VALUES ( 0 ); +DELETE FROM `t6` WHERE `bit` < 2 LIMIT 4; + +INSERT INTO `t7` ( `bit` ) VALUES ( 0 ); +DELETE FROM `t7` WHERE `bit` < 2 LIMIT 4; + +INSERT INTO `t8` ( `bit` ) VALUES ( 0 ); +DELETE FROM `t8` WHERE `bit` < 2 LIMIT 4; + + +--enable_warnings +sync_slave_with_master; + +# clean up +connection master; +DROP TABLE t1, t2, t3, t4, t5, t6, t7, t8; +sync_slave_with_master; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mixed_ddl_dml.test b/mysql-test/suite/rpl/t/rpl_mixed_ddl_dml.test new file mode 100644 index 00000000..f4a1615a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mixed_ddl_dml.test @@ -0,0 +1,51 @@ +# Mixed DDL-DML (CREATE ... SELECT ...) statements can only be +# replicated properly in statement-based replication. +# Currently statement based due to bug 12345 +--source include/have_binlog_format_mixed_or_statement.inc + +source include/master-slave.inc; + +# Test replication of auto_increment + +create table t1 (n int auto_increment primary key); +set insert_id = 2000; +insert into t1 values (NULL),(NULL),(NULL); +sync_slave_with_master; +select * from t1; +connection master; +--replace_result $SLAVE_MYPORT 9999 +show slave hosts; +drop table t1; +sync_slave_with_master; +stop slave; +--source include/wait_for_slave_to_stop.inc +connection master; + +# Test replication of timestamp + +create table t2(id int auto_increment primary key, created datetime); +SET TIME_ZONE= '+03:00'; +set timestamp=12345; +insert into t2 set created=now(); +select * from t2; + +# Test replication of CREATE .. LIKE (Bug #2557) + +create table t3 like t2; +create temporary table t4 like t2; +create table t5 select * from t4; +save_master_pos; +connection slave; +start slave; +--source include/wait_for_slave_to_start.inc +sync_with_master; +select * from t2; +show create table t3; +show create table t5; +connection master; +drop table t2,t3,t5; +drop temporary table t4; +sync_slave_with_master; + +# End of 4.1 tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mixed_drop_create_temp_table.test b/mysql-test/suite/rpl/t/rpl_mixed_drop_create_temp_table.test new file mode 100644 index 00000000..e707bb99 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mixed_drop_create_temp_table.test @@ -0,0 +1,12 @@ +################################################################################### +# This test cases evaluates the mixture of non-transactional and transcational +# tables. Specifically when drop temporary tables and create temporary tables +# are used. +################################################################################### +--source include/big_test.inc +--source include/have_binlog_format_mixed.inc +--source include/have_innodb.inc +--source include/master-slave.inc + +--source include/rpl_drop_create_temp_table.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mixed_implicit_commit_binlog.test b/mysql-test/suite/rpl/t/rpl_mixed_implicit_commit_binlog.test new file mode 100644 index 00000000..8e40295e --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mixed_implicit_commit_binlog.test @@ -0,0 +1,12 @@ +################################################################################ +# Check file include/rpl_implicit_commit_binlog.test +################################################################################ +--source include/have_udf.inc +--source include/have_binlog_format_mixed.inc +--source include/have_innodb.inc +--source include/master-slave.inc + +--let $engine=Innodb +set session default_storage_engine=innodb; +--source include/rpl_implicit_commit_binlog.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mixed_mixing_engines.test b/mysql-test/suite/rpl/t/rpl_mixed_mixing_engines.test new file mode 100644 index 00000000..ddc7757f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mixed_mixing_engines.test @@ -0,0 +1,14 @@ +################################################################################### +# This test cases evaluates the mixture of non-transactional and transcational +# tables. For further details, please, read WL#2687 and WL#5072. +################################################################################### +--source include/have_binlog_format_mixed.inc +--source include/have_innodb.inc +# MDEV-31790 FIXME: This test is extremely slow +--source include/not_msan.inc +--source include/master-slave.inc + +let $engine_type=Innodb; +let $database_name=test; +--source include/rpl_mixing_engines.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mixed_row_innodb-master.opt b/mysql-test/suite/rpl/t/rpl_mixed_row_innodb-master.opt new file mode 100644 index 00000000..96f0ce3f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mixed_row_innodb-master.opt @@ -0,0 +1 @@ +--default-storage-engine=MyISAM diff --git a/mysql-test/suite/rpl/t/rpl_multi_delete-slave.opt b/mysql-test/suite/rpl/t/rpl_multi_delete-slave.opt new file mode 100644 index 00000000..c98fe0b0 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_multi_delete-slave.opt @@ -0,0 +1 @@ +--replicate-wild-do-table=test.% diff --git a/mysql-test/suite/rpl/t/rpl_multi_delete.test b/mysql-test/suite/rpl/t/rpl_multi_delete.test new file mode 100644 index 00000000..80acf9c8 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_multi_delete.test @@ -0,0 +1,25 @@ +source include/master-slave.inc; +create table t1 (a int primary key); +create table t2 (a int); + +insert into t1 values (1); +insert into t2 values (1); + + +delete t1.* from t1, t2 where t1.a = t2.a; + +save_master_pos; +select * from t1; +select * from t2; + +connection slave; +sync_with_master; +select * from t1; +select * from t2; + +connection master; +drop table t1,t2; +sync_slave_with_master; + +# End of 4.1 tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_multi_delete2-slave.opt b/mysql-test/suite/rpl/t/rpl_multi_delete2-slave.opt new file mode 100644 index 00000000..0febb289 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_multi_delete2-slave.opt @@ -0,0 +1 @@ +"--replicate-rewrite-db=mysqltest_from->mysqltest_to" --replicate-do-table=mysqltest_to.a diff --git a/mysql-test/suite/rpl/t/rpl_multi_delete2.test b/mysql-test/suite/rpl/t/rpl_multi_delete2.test new file mode 100644 index 00000000..7dc7ca41 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_multi_delete2.test @@ -0,0 +1,67 @@ +#multi delete replication bugs + + +source include/master-slave.inc; + +#BUG#11139 - improper wild-table and table rules +#checking for multi deletes with an alias + +connection master; +set sql_log_bin=0; +create database mysqltest_from; +set sql_log_bin=1; + +connection slave; +create database mysqltest_to; + + +connection master; +use mysqltest_from; +--disable_warnings +drop table if exists a; +--enable_warnings +CREATE TABLE a (i INT); +INSERT INTO a VALUES(1); +DELETE alias FROM a alias WHERE alias.i=1; +SELECT * FROM a; +insert into a values(2),(3); +delete alias FROM a alias where alias.i=2; +select * from a; +sync_slave_with_master; + +use mysqltest_to; +select * from a; + +# BUG#3461 +connection master; +create table t1 (a int primary key); +create table t2 (a int); + +insert into t1 values (1); +insert into t2 values (1); + +delete t1.* from t1, t2 where t1.a = t2.a; + +save_master_pos; +select * from t1; +select * from t2; + +connection slave; +# BUG#3461 would cause sync to fail +sync_with_master; +error 1146; +select * from t1; +error 1146; +select * from t2; + +# cleanup +connection master; +set sql_log_bin=0; +drop database mysqltest_from; +set sql_log_bin=1; +connection slave; +drop database mysqltest_to; + +# End of 4.1 tests + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_multi_engine.test b/mysql-test/suite/rpl/t/rpl_multi_engine.test new file mode 100644 index 00000000..704c0935 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_multi_engine.test @@ -0,0 +1,102 @@ +# See if replication between MyISAM, MEMORY and InnoDB works. + +-- source include/master-slave.inc + +connection slave; +-- source include/have_innodb.inc + +connection master; +-- source include/have_innodb.inc +--disable_warnings +drop table if exists t1; +--enable_warnings + +CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc +VARCHAR(255), bc CHAR(255), d DECIMAL(10,4) DEFAULT 0, f FLOAT DEFAULT +0, total BIGINT UNSIGNED, y YEAR, t TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +ON UPDATE CURRENT_TIMESTAMP,PRIMARY KEY(id)); + +sync_slave_with_master; + +# MyISAM to MyISAM then InnoDB then MEMORY + +connection master; +alter table t1 engine=myisam; +show create table t1; +sync_slave_with_master; + +connection slave; +alter table t1 engine=myisam; +show create table t1; + +--source include/rpl_multi_engine.inc + +connection slave; +alter table t1 engine=innodb; +show create table t1; + +--source include/rpl_multi_engine.inc + +connection slave; +alter table t1 engine=memory; +show create table t1; + +--source include/rpl_multi_engine.inc + +# MEMORY to ... + +connection master; +alter table t1 engine=memory; +show create table t1; +sync_slave_with_master; + +connection slave; +alter table t1 engine=myisam; +show create table t1; + +--source include/rpl_multi_engine.inc + +connection slave; +alter table t1 engine=innodb; +show create table t1; + +--source include/rpl_multi_engine.inc + +connection slave; +alter table t1 engine=memory; +show create table t1; + +--source include/rpl_multi_engine.inc + +# InnoDB to ... + +connection master; +alter table t1 engine=innodb; +show create table t1; +sync_slave_with_master; + +connection slave; +alter table t1 engine=myisam; +show create table t1; + +--source include/rpl_multi_engine.inc + +connection slave; +alter table t1 engine=innodb; +show create table t1; + +--source include/rpl_multi_engine.inc + +connection slave; +alter table t1 engine=memory; +show create table t1; + +--source include/rpl_multi_engine.inc + +# cleanup +connection master; +DROP TABLE t1; +sync_slave_with_master; + +# End of 5.1 test case +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_multi_update.test b/mysql-test/suite/rpl/t/rpl_multi_update.test new file mode 100644 index 00000000..3927ed69 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_multi_update.test @@ -0,0 +1,2 @@ +let $engine_type=MyISAM; +-- source include/rpl_multi_update.test diff --git a/mysql-test/suite/rpl/t/rpl_multi_update2-slave.opt b/mysql-test/suite/rpl/t/rpl_multi_update2-slave.opt new file mode 100644 index 00000000..17d4171a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_multi_update2-slave.opt @@ -0,0 +1 @@ +--replicate-ignore-table=nothing.sensible diff --git a/mysql-test/suite/rpl/t/rpl_multi_update2.test b/mysql-test/suite/rpl/t/rpl_multi_update2.test new file mode 100644 index 00000000..d2368f20 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_multi_update2.test @@ -0,0 +1,9 @@ +####################################################### +# Wrapper for rpl_multi_update2.test to allow multi # +# Engines to reuse test code. By JBM 2006-02-15 # +####################################################### +--source include/master-slave.inc +call mtr.add_suppression('Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT'); +let $engine_type=MyISAM; +--source include/rpl_multi_update2.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_multi_update3.test b/mysql-test/suite/rpl/t/rpl_multi_update3.test new file mode 100644 index 00000000..0a15e9aa --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_multi_update3.test @@ -0,0 +1,9 @@ +####################################################### +# Wrapper for rpl_multi_update3.test to allow multi # +# Engines to reuse test code. By JBM 2006-02-15 # +####################################################### +--source include/master-slave.inc +call mtr.add_suppression('Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.'); +let $engine_type=MyISAM; +-- source include/rpl_multi_update3.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_multi_update4-slave.opt b/mysql-test/suite/rpl/t/rpl_multi_update4-slave.opt new file mode 100644 index 00000000..fea27db4 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_multi_update4-slave.opt @@ -0,0 +1 @@ +--replicate-wild-do-table=d1.% diff --git a/mysql-test/suite/rpl/t/rpl_multi_update4.test b/mysql-test/suite/rpl/t/rpl_multi_update4.test new file mode 100644 index 00000000..8f069b9c --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_multi_update4.test @@ -0,0 +1,46 @@ +# Let's verify that multi-update is not always skipped by slave if +# some replicate-* rules exist. +# (BUG#15699) + +source include/master-slave.inc; + +### Clean-up + +connection master; +--disable_warnings +drop database if exists d1; +drop database if exists d2; + +connection slave; +drop database if exists d2; +--enable_warnings + +### Do on master + +connection master; +create database d1; # accepted by slave +create table d1.t0 (id int); +create database d2; # ignored by slave +use d2; +create table t1 (id int); +create table t2 (id int); +insert into t1 values (1), (2), (3), (4), (5); +insert into t2 select id + 3 from t1; +# a problematic query which must be filter out by slave +update t1 join t2 using (id) set t1.id = 0; +insert into d1.t0 values (0); # replication works + +### Check on slave + +sync_slave_with_master; +use d1; +select * from t0 where id=0; # must find + +### Clean-up +connection master; +drop database d1; +drop database d2; +sync_slave_with_master; + +# End of test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mysql57_stm_temporal_round.test b/mysql-test/suite/rpl/t/rpl_mysql57_stm_temporal_round.test new file mode 100644 index 00000000..34001382 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mysql57_stm_temporal_round.test @@ -0,0 +1,58 @@ +--source include/have_binlog_format_statement.inc + +--echo # +--echo # MDEV-8894 Inserting fractional seconds into MySQL 5.6 master breaks consistency on MariaDB 10 slave +--echo # + +--source include/have_innodb.inc +--source include/master-slave.inc + +--connection slave +CREATE TABLE t1 (id SERIAL, a DATETIME(3)); +--source include/stop_slave.inc + +--connection master +--let $datadir= `SELECT @@datadir` + +--let $rpl_server_number= 1 +--source include/rpl_stop_server.inc + +--remove_file $datadir/master-bin.000001 + +# +# Simulate MySQL 5.7.x master +# +# mysql-5.7.11-stm-temporal-round-binlog.000001 was recorded against a +# table with this structure: +#CREATE TABLE t1 (id SERIAL, a DATETIME(3)); +# (note, the CREATE statement is not inside the binary log) +# +# using this command line: +# mysqld --log-bin --binlog-format=statement +# with the following single SQL statement: +# +#INSERT INTO t1 (a) VALUES ('2001-01-01 00:00:00.999999'); +# + +--copy_file $MYSQL_TEST_DIR/std_data/rpl/mysql-5.7.11-stm-temporal-round-binlog.000001 $datadir/master-bin.000001 + +--let $rpl_server_number= 1 +--source include/rpl_start_server.inc + +--source include/wait_until_connected_again.inc + +--connection slave +--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1 +eval CHANGE MASTER TO master_host='127.0.0.1', master_port=$SERVER_MYPORT_1, master_user='root', master_log_file='master-bin.000001', master_log_pos=4, master_use_gtid=no; + +--source include/start_slave.inc + +--connection master +--sync_slave_with_master +SELECT * FROM t1 ORDER BY id; + +--source include/stop_slave.inc +DROP TABLE t1; + +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mysql80_stm_temporal_round.test b/mysql-test/suite/rpl/t/rpl_mysql80_stm_temporal_round.test new file mode 100644 index 00000000..551764ac --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mysql80_stm_temporal_round.test @@ -0,0 +1,62 @@ +--source include/have_binlog_format_statement.inc + +--echo # +--echo # MDEV-8894 Inserting fractional seconds into MySQL 5.6 master breaks consistency on MariaDB 10 slave +--echo # + +--source include/have_innodb.inc +--source include/master-slave.inc + +--connection slave +CREATE TABLE t1 (id SERIAL, a DATETIME(3)); +--source include/stop_slave.inc + +--connection master +--let $datadir= `SELECT @@datadir` + +--let $rpl_server_number= 1 +--source include/rpl_stop_server.inc + +--remove_file $datadir/master-bin.000001 + +# +# Simulate MySQL 8.0.x master +# +# mysql-8.0.13-stm-temporal-round-binlog.000001 was recorded against a +# table with this structure: +#CREATE TABLE t1 (id SERIAL, a DATETIME(3)); +# (note, the CREATE statement is not inside the binary log) +# +# using this command line: +# mysqld --log-bin --binlog-format=statement --server-id=1 --character-set-server=latin1 +# with the following SQL script: +# +#SET NAMES latin1 COLLATE latin1_swedish_ci; +#SET sql_mode=''; +#INSERT INTO t1 (a) VALUES ('2001-01-01 00:00:00.999999'); +#SET sql_mode=TIME_TRUNCATE_FRACTIONAL; +#INSERT INTO t1 (a) VALUES ('2001-01-01 00:00:00.999999'); +# + +--copy_file $MYSQL_TEST_DIR/std_data/rpl/mysql-8.0.13-stm-temporal-round-binlog.000001 $datadir/master-bin.000001 + +--let $rpl_server_number= 1 +--source include/rpl_start_server.inc + +--source include/wait_until_connected_again.inc + +--connection slave +--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1 +eval CHANGE MASTER TO master_host='127.0.0.1', master_port=$SERVER_MYPORT_1, master_user='root', master_log_file='master-bin.000001', master_log_pos=4, master_use_gtid=no; + +--source include/start_slave.inc + +--connection master +--sync_slave_with_master +SELECT * FROM t1 ORDER BY id; + +--source include/stop_slave.inc +DROP TABLE t1; + +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mysql_manager_race_condition-slave.opt b/mysql-test/suite/rpl/t/rpl_mysql_manager_race_condition-slave.opt new file mode 100644 index 00000000..d127ef62 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mysql_manager_race_condition-slave.opt @@ -0,0 +1 @@ +--gtid-cleanup-batch-size=1 diff --git a/mysql-test/suite/rpl/t/rpl_mysql_manager_race_condition.test b/mysql-test/suite/rpl/t/rpl_mysql_manager_race_condition.test new file mode 100644 index 00000000..751da315 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mysql_manager_race_condition.test @@ -0,0 +1,67 @@ +# +# Purpose: +# This test ensures that, during mysqld initialization, the mysql handle +# manager starts before the binlog background thread. This is because the +# binlog background thread uses the mysql handle manager, and if the background +# thread tries to submit a job to the handle manager before it is +# initialized/started, mysqld can crash (the actual behavior is undefined). +# This race condition lead to the problem described in MDEV-26473. +# +# Methodology: +# This test ensures that the binlog background thread cannot be started +# before the mysql manager is started. Specifically, it forces a path in +# the binlog background thread to call mysql_manager_submit() by reducing +# --gtid-cleanup-batch-size to be 1 (which submits a job to delete unused rows +# from the mysql.gtid_slave_pos* tables). With this path forced, the main +# mysqld thread is suspended just before its handle manager initialization to +# allow time for the binlog thread to call mysql_manager_submit. The fix +# associated with this test should enforce that the binlog background thread is +# not created before the handle manager is initialized. +# +# References: +# MDEV-26473 mysqld got exception 0xc0000005 (rpl_slave_state/rpl_load_gtid_slave_state) +# + +--source include/have_debug.inc +--source include/master-slave.inc + +# The race condition discovered from MDEV-26473 is binlog format independent. +# We use ROW format though because it was used by the reporter. +--source include/have_binlog_format_row.inc + +--connection master + +--echo # Create a GTID event so the binlog background thread will submit a +--echo # mysql handler job the next time mysqld is restarted. +create table t1 (a int); +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc + +--echo # Set a debug point that forces the main mysqld thread to sleep before +--echo # anything is initialized for the mysql handle manager +--let $rpl_server_parameters=--debug_dbug="+d,delay_start_handle_manager" + + +--echo # Restart the slave mysqld instance so it re-initializes with the +--echo # binlog background thread submitting a mysql handler job and the +--echo # mysql handler initialization suspending for a second. Without the fix +--echo # associated with this test/patch, the following restart will error +--echo # with a failed assertion. +--source include/rpl_restart_server.inc +--source include/start_slave.inc + + +--echo # +--echo # Cleanup +--echo # + +--connection master +drop table t1; +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mysql_upgrade.test b/mysql-test/suite/rpl/t/rpl_mysql_upgrade.test new file mode 100644 index 00000000..f44c883e --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mysql_upgrade.test @@ -0,0 +1,80 @@ +############################################################################# +# BUG#43579 mysql_upgrade tries to alter log tables on replicated database +# Master and slave should be upgraded separately. All statements executed by +# mysql_upgrade will not be binlogged. --write-binlog and --skip-write-binlog +# options are added into mysql_upgrade. These options control whether sql +# statements are binlogged or not. +############################################################################# +--source include/have_innodb.inc +--source include/mysql_upgrade_preparation.inc +--source include/master-slave.inc + +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); +call mtr.add_suppression("table or database name 'mysqltest-1'"); + +connection master; +--disable_warnings +CREATE DATABASE `mysqltest-1`; +--enable_warnings +sync_slave_with_master; + +connection master; +let $before_position= query_get_value(SHOW MASTER STATUS, Position, 1); + +#With '--force' option, mysql_upgrade always executes all sql statements for upgrading. +--exec $MYSQL_UPGRADE --skip-verbose --force --user=root > $MYSQLTEST_VARDIR/log/mysql_upgrade.log 2>&1 +sync_slave_with_master; + +connection master; +let $after_position= query_get_value(SHOW MASTER STATUS, Position, 1); + +if ($before_position == $after_position) +{ + echo Master position is not changed; +} + +# Some log events of the mysql_upgrade previously caused errors on slave, +# however with MDEV-4851 this should be ok, so we test it: +connection slave; +SET @old_general_log_state = @@global.general_log; +SET @old_slow_log_state = @@global.slow_query_log; +SET @old_log_output = @@global.log_output; +SET GLOBAL general_log = 'ON'; +SET GLOBAL slow_query_log = 'ON'; +SET GLOBAL log_output = 'FILE'; + +connection master; +#With '--force' option, mysql_upgrade always executes all sql statements for upgrading. +ALTER TABLE mysql.slow_log DROP COLUMN thread_id, DROP COLUMN rows_affected; +DROP DATABASE `mysqltest-1`; +sync_slave_with_master; + +connection slave; +SHOW CREATE TABLE mysql.slow_log; +connection master; +--exec $MYSQL_UPGRADE --skip-verbose --write-binlog --force --user=root > $MYSQLTEST_VARDIR/log/mysql_upgrade.log 2>&1 + +let $datadir= `select @@datadir`; +remove_file $datadir/mysql_upgrade_info; + +connection master; +let $after_file= query_get_value(SHOW MASTER STATUS, File, 1); +let $after_position= query_get_value(SHOW MASTER STATUS, Position, 1); + +if ($before_position != $after_position) +{ + echo Master position has been changed; +} + +sync_slave_with_master; +connection slave; +SHOW CREATE TABLE mysql.slow_log; +SET GLOBAL general_log = 'OFF'; +SET GLOBAL slow_query_log = 'OFF'; +truncate mysql.slow_log; +truncate mysql.general_log; +SET GLOBAL general_log = @old_general_log_state; +SET GLOBAL slow_query_log = @old_slow_log_state; +SET GLOBAL log_output = @old_log_output; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mysqlbinlog_slave_consistency.test b/mysql-test/suite/rpl/t/rpl_mysqlbinlog_slave_consistency.test new file mode 100644 index 00000000..d2918e3a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mysqlbinlog_slave_consistency.test @@ -0,0 +1,401 @@ +# +# Purpose: +# +# This test ensures the mariadb-binlog command line tool filters events +# by domain id (via --do-domain-ids and --ignore-domain-ids) and server id (via +# --ignore-server-ids) in the same way that a replica server does. +# +# +# Methodology: +# +# This test validates that the domain and server id filtering logic of +# mariadb-binlog matches that of a replica server. In particular, it validates +# a mariadb-binlog replay of a master's binary log is consistent with a +# replica's state which is configured using the same filtering configuration. +# +# It uses a repeatable process to allow for multiple test cases that span +# different filtering configurations. First, a master is seeded with an initial +# set of SQL statements with varying domain and server ids. Then, a set of +# filtering parameters supported by both mariadb-binlog and replica +# capabilities are defined. The replica is configured using these parameters +# and run it until it has processed all events from the primary server; it is +# stopped afterward. For mariadb-binlog validation, the binary log of the +# primary server is copied to a different location for later replay. The +# primary is then reset to its initial state (i.e. the tables are dropped and +# the logs are reset). The mariadb-binlog tool is then used to replay the +# copied binary log file back onto the clean primary server under the same +# filtering conditions as the replica. At this point, the data on the primary +# and replica should be exactly the same because the filtering conditions were +# the same, and all existing tables on both servers are compared using. +# checksums. +# +# +# References: +# +# MDEV-20119: Implement the --do-domain-ids, --ignore-domain-ids, and +# --ignore-server-ids options for mysqlbinlog +# +--source include/master-slave.inc + +--connection slave +SET sql_log_bin=0; +call mtr.add_suppression("Slave: An attempt was made.*"); +call mtr.add_suppression("Both DO_DOMAIN_IDS & IGNORE_DOMAIN_IDS lists can't be non-empty at the same time"); +SET sql_log_bin=1; + +--source include/stop_slave.inc + +--connection master +RESET MASTER; + +# Save old state +let $ORIG_GTID_DOMAIN_ID = `select @@session.gtid_domain_id`; +let $ORIG_SERVER_ID = `select @@session.server_id`; + +--connection slave +--source include/start_slave.inc + +# Initial tests do not use strict mode +--let $strict_mode=0 +--let $slave_sql_errno=0 + +--echo # +--echo # +--echo # Test Case 1: Base case to ensure that mariadb-binlog and replica +--echo # are consistent without any filtering +--echo # +--let $do_domain_ids= +--let $ignore_domain_ids= +--let $ignore_server_ids= +--let $stop_position= +--let $start_position= +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # +--echo # Test Case 2: Ensure filtering by a single id in --do-domain-ids is +--echo # consistent between mariadb-binlog and replica +--echo # +--let $do_domain_ids=0 +--let $ignore_domain_ids= +--let $ignore_server_ids= +--let $stop_position= +--let $start_position= +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # +--echo # Test Case 3: Ensure filtering by multiple ids in --do-domain-ids is +--echo # consistent between mariadb-binlog and replica +--echo # +--let $do_domain_ids=0,1 +--let $ignore_domain_ids= +--let $ignore_server_ids= +--let $stop_position= +--let $start_position= +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # Test Case 4: Ensure filtering by a single id in --ignore-domain-ids +--echo # is consistent between mariadb-binlog and replica +--echo # +--let $do_domain_ids= +--let $ignore_domain_ids=0 +--let $ignore_server_ids= +--let $stop_position= +--let $start_position= +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # +--echo # Test Case 5: Ensure filtering by multiple ids in --ignore-domain-ids +--echo # is consistent between mariadb-binlog and replica +--echo # +--let $do_domain_ids= +--let $ignore_domain_ids=0,1 +--let $ignore_server_ids= +--let $stop_position= +--let $start_position= +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # Test Case 6: Ensure filtering by a single id in --ignore-server-ids +--echo # is consistent between mariadb-binlog and replica +--echo # +--let $do_domain_ids= +--let $ignore_domain_ids= +--let $ignore_server_ids=1 +--let $stop_position= +--let $start_position= +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # +--echo # Test Case 7: Ensure filtering by multiple ids in --ignore-server-ids +--echo # is consistent between mariadb-binlog and replica +--echo # +--let $do_domain_ids= +--let $ignore_domain_ids= +--let $ignore_server_ids=0,1 +--let $stop_position= +--let $start_position= +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # +--echo # Test Case 8: Ensure stop position consistency +--echo # +--let $do_domain_ids= +--let $ignore_domain_ids= +--let $ignore_server_ids= +--let $stop_position=1-1-2 +--let $start_position= +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # +--echo # Test Case 9: Ensure start position consistency +--echo # +--let $do_domain_ids= +--let $ignore_domain_ids= +--let $ignore_server_ids= +--let $stop_position= +--let $start_position=1-4-2 +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # +--echo # Test Case 10: Ensure consistency when filtering by both +--echo # --do-domain-ids and --ignore-server-ids +--echo # +--let $do_domain_ids=0 +--let $ignore_domain_ids= +--let $ignore_server_ids=1 +--let $stop_position= +--let $start_position= +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # +--echo # Test Case 11: Ensure consistency when filtering by both +--echo # --ignore-domain-ids and --ignore-server-ids +--echo # +--let $do_domain_ids= +--let $ignore_domain_ids=1,2 +--let $ignore_server_ids=1 +--let $stop_position= +--let $start_position= +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # +--echo # Test Case 12: Ensure consistency when filtering by +--echo # --do-domain-ids with a stop position +--echo # +--let $do_domain_ids=0 +--let $ignore_domain_ids= +--let $ignore_server_ids= +--let $stop_position=0-1-4 +--let $start_position= +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # +--echo # Test Case 13: Ensure consistency when filtering by +--echo # --ignore-domain-ids with a stop position +--echo # +--let $do_domain_ids= +--let $ignore_domain_ids=0 +--let $ignore_server_ids= +--let $stop_position=0-1-4 +--let $start_position= +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # +--echo # Test Case 14: Ensure consistency when filtering by +--echo # --ignore-server-ids with a stop position +--echo # +--let $do_domain_ids= +--let $ignore_domain_ids= +--let $ignore_server_ids=3 +--let $stop_position=0-1-4 +--let $start_position= +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # +--echo # Test Case 15: Ensure consistency when filtering by +--echo # --do-domain-ids with a start position +--echo # +--let $do_domain_ids=2 +--let $ignore_domain_ids= +--let $ignore_server_ids= +--let $stop_position= +--let $start_position=1-1-2 +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # +--echo # Test Case 16: Ensure consistency when filtering by +--echo # --ignore-domain-ids with a start position +--echo # +--let $do_domain_ids= +--let $ignore_domain_ids=0 +--let $ignore_server_ids= +--let $stop_position= +--let $start_position=0-1-1 +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # +--echo # Test Case 17: Ensure consistency when filtering by +--echo # --ignore-server-ids with a start position +--echo # +--let $do_domain_ids= +--let $ignore_domain_ids= +--let $ignore_server_ids=1 +--let $stop_position= +--let $start_position=0-1-1 +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # +--echo # Test Case 18: Ensure consistency when filtering by +--echo # --do-domain-ids with both a start position and stop position that +--echo # all have the same domain id +--echo # +--let $do_domain_ids=0 +--let $ignore_domain_ids= +--let $ignore_server_ids= +--let $stop_position=0-3-3 +--let $start_position=0-1-1 +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # +--echo # Test Case 19: Ensure consistency when filtering by +--echo # --do-domain-ids with both a start position and stop position that +--echo # have differing domain ids. Due to the implicit filtering in stop +--echo # position, the result should be empty (no tables replicated). +--echo # +--let $do_domain_ids=1 +--let $ignore_domain_ids= +--let $ignore_server_ids= +--let $stop_position=0-3-3 +--let $start_position=0-1-1 +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # +--echo # Test Case 20: Ensure consistency when filtering by +--echo # --ignore-domain-ids with both a start position and stop position that +--echo # all have the same domain id. The result set should be empty due to +--echo # implicit filtering from stop position and ignoring that same domain. +--echo # +--let $do_domain_ids= +--let $ignore_domain_ids=0 +--let $ignore_server_ids= +--let $stop_position=0-3-3 +--let $start_position=0-1-1 +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # +--echo # Test Case 21: Ensure consistency when filtering by +--echo # --ignore-domain-ids with both a start position and stop position that +--echo # have differing domain ids. The ignore domain ids should take no +--echo # effect due to the implicit filtering by stop position, i.e. the +--echo # specified domain to ignore is already being filtered. +--echo # +--let $do_domain_ids= +--let $ignore_domain_ids=1 +--let $ignore_server_ids= +--let $stop_position=0-3-3 +--let $start_position=0-1-1 +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # +--echo # Test Case 22: Ensure consistency when filtering by +--echo # --ignore-server-ids with both a start position and stop position. +--echo # +--let $do_domain_ids= +--let $ignore_domain_ids= +--let $ignore_server_ids=3 +--let $stop_position=0-3-3 +--let $start_position=0-1-0 +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # +--echo # Test Case 23: Out of order GTIDs from domains or servers which are +--echo # filtered out should not error +--echo # +--let $strict_mode=1 +--let $strict_mode_err=0 +--let $slave_sql_errno=0 +--let $do_domain_ids=0 +--let $ignore_domain_ids= +--let $ignore_server_ids=3 +--let $stop_position= +--let $start_position= +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # +--echo # Test Case 24: Out of order GTIDs from included domains should error +--echo # +--let $strict_mode=1 +--let $strict_mode_err=1 +--let $slave_sql_errno=1950 +--let $do_domain_ids=1 +--let $ignore_domain_ids= +--let $ignore_server_ids= +--let $stop_position= +--let $start_position= +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # +--echo # Test Case 25: Out of order GTIDs from included servers should error +--echo # +--let $strict_mode=1 +--let $strict_mode_err=1 +--let $slave_sql_errno=1950 +--let $do_domain_ids= +--let $ignore_domain_ids= +--let $ignore_server_ids=1 +--let $stop_position= +--let $start_position= +--source include/mysqlbinlog_slave_consistency.inc + +--echo # +--echo # +--echo # Test Case 26: Neither mysqlbinlog nor CHANGE MASTER TO should allow +--echo # both do domain ids and ignore domain ids to be set together +--echo # +--connection slave +--source include/stop_slave.inc + +--error 1201 +CHANGE MASTER TO MASTER_USE_GTID=slave_pos, DO_DOMAIN_IDS=(0), IGNORE_DOMAIN_IDS=(1); + +--let $MYSQLD_DATADIR=`select @@datadir` +--let BINLOG_FILENAME= query_get_value(SHOW BINARY LOGS, Log_name, 1) +--let BINLOG_FILE_PARAM= $MYSQLD_DATADIR/$BINLOG_FILENAME.orig +--error 1 +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/$BINLOG_FILENAME --do-domain-ids=0 --ignore-domain-ids=1 + +RESET MASTER; +set global gtid_slave_pos=""; +CHANGE MASTER TO MASTER_USE_GTID=slave_pos, DO_DOMAIN_IDS=(), IGNORE_DOMAIN_IDS=(); +--source include/start_slave.inc + +# Cleanup +--connection master +RESET MASTER; + +--source include/rpl_end.inc + +--echo # End of tests (rpl.rpl_mysqlbinlog_slave_consistency) diff --git a/mysql-test/suite/rpl/t/rpl_name_const.test b/mysql-test/suite/rpl/t/rpl_name_const.test new file mode 100644 index 00000000..074bc148 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_name_const.test @@ -0,0 +1,45 @@ +# ==== Purpose ==== +# +# Test that aliases of variables in binary log aren't ignored with NAME_CONST. +# +# ==== Method ==== +# +# Create a procedure with aliases of variables, then replicate it to slave. +# BUG#35515 Aliases of variables in binary log are ignored with NAME_CONST. +# + +source include/master-slave.inc; + +--echo ==== Initialize ==== + +--connection master + +create table t1 (id int); + +--echo ==== create a procedure that has a column aliase in a subquery ==== +--disable_warnings +drop procedure if exists test_procedure; +--enable_warnings +delimiter $$; +create procedure test_procedure(_id int) +begin +insert into t1 (id) +select a.id +from +( select _id as id ) a; +end;$$ +delimiter ;$$ + +--echo ==== enable the binary log, then call the procedure ==== +call test_procedure(1234); + + +sync_slave_with_master; +select * from t1 order by id; + +--echo ==== Clean up ==== + +connection master; +drop table t1; +drop procedure test_procedure; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_non_direct_mixed_mixing_engines.test b/mysql-test/suite/rpl/t/rpl_non_direct_mixed_mixing_engines.test new file mode 100644 index 00000000..d6b278ca --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_non_direct_mixed_mixing_engines.test @@ -0,0 +1,17 @@ +################################################################################### +# This test cases evaluates the mixture of non-transactional and transcational +# tables. For further details, please, read WL#2687 and WL#5072. +################################################################################### +--source include/have_binlog_format_mixed.inc +--source include/have_innodb.inc +# MDEV-31790 FIXME: This test is extremely slow +--source include/not_msan.inc +--source include/master-slave.inc + +--disable_query_log +SET SESSION binlog_direct_non_transactional_updates = OFF; +--enable_query_log +let $engine_type=Innodb; +let $database_name=test; +--source include/rpl_mixing_engines.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_non_direct_row_mixing_engines.test b/mysql-test/suite/rpl/t/rpl_non_direct_row_mixing_engines.test new file mode 100644 index 00000000..0161a609 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_non_direct_row_mixing_engines.test @@ -0,0 +1,19 @@ +################################################################################### +# This test cases evaluates the mixture of non-transactional and transcational +# tables. For further details, please, read WL#2687 and WL#5072. +################################################################################### +--source include/have_binlog_format_row.inc +--source include/have_innodb.inc +# MDEV-31790 FIXME: This test is extremely slow +--source include/not_msan.inc +--source include/master-slave.inc + +--disable_query_log +SET SESSION binlog_direct_non_transactional_updates = OFF; +--enable_query_log +let $engine_type=Innodb; +let $database_name=test; +--source include/rpl_mixing_engines.test + +--diff_files suite/rpl/r/rpl_non_direct_row_mixing_engines.result suite/rpl/r/rpl_row_mixing_engines.result +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_non_direct_stm_mixing_engines.test b/mysql-test/suite/rpl/t/rpl_non_direct_stm_mixing_engines.test new file mode 100644 index 00000000..99443707 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_non_direct_stm_mixing_engines.test @@ -0,0 +1,17 @@ +################################################################################### +# This test cases evaluates the mixture of non-transactional and transcational +# tables. For further details, please, read WL#2687 and WL#5072. +################################################################################### +--source include/have_binlog_format_statement.inc +--source include/have_innodb.inc +# MDEV-31790 FIXME: This test is extremely slow +--source include/not_msan.inc +--source include/master-slave.inc + +--disable_query_log +SET SESSION binlog_direct_non_transactional_updates = OFF; +--enable_query_log +let $engine_type=Innodb; +let $database_name=test; +--source include/rpl_mixing_engines.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_nondeterministic_functions.test b/mysql-test/suite/rpl/t/rpl_nondeterministic_functions.test new file mode 100644 index 00000000..a174445f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_nondeterministic_functions.test @@ -0,0 +1,58 @@ +# ==== Purpose ==== +# +# Test that nondeterministic system functions are correctly replicated. +# +# (Some functions are only correctly replicated if binlog_format=MIXED +# or ROW. See binlog_unsafe.test for a test that those variables are +# indeed unsafe.) +# +# ==== Implementation ==== +# +# We insert the values of each unsafe function into a table. Then we +# replicate and check that the table is identical on slave. +# +# ==== Related bugs ==== +# +# BUG#47995 + +--source include/master-slave.inc + +CALL mtr.add_suppression('Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT'); + +CREATE TABLE t1 (a VARCHAR(1000)); + +# We replicate the connection_id in the query_log_event +INSERT INTO t1 VALUES (CONNECTION_ID()); +--connection master1 +INSERT INTO t1 VALUES (CONNECTION_ID()); + +# We replicate the TIMESTAMP variable, so the following functions that +# are affected by the TIMESTAMP variable should be safe to replicate. +INSERT INTO t1 VALUES + (CURDATE()), + (CURRENT_DATE()), + (CURRENT_TIME()), + (CURRENT_TIMESTAMP()), + (CURTIME()), + (LOCALTIME()), + (LOCALTIMESTAMP()), + (NOW()), + (UNIX_TIMESTAMP()), + (UTC_DATE()), + (UTC_TIME()), + (UTC_TIMESTAMP()); + +# We replicate the random seed in a rand_log_event +--disable_warnings +INSERT INTO t1 VALUES (RAND()); +--enable_warnings +# We replicate the last_insert_id in an intvar_log_event +INSERT INTO t1 VALUES (LAST_INSERT_ID()); + +--sync_slave_with_master +--let $diff_tables= master:t1, slave:t1 +--source include/diff_tables.inc + +--connection master +DROP TABLE t1; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_not_null_innodb.test b/mysql-test/suite/rpl/t/rpl_not_null_innodb.test new file mode 100644 index 00000000..0e67cd36 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_not_null_innodb.test @@ -0,0 +1,20 @@ +################################################################################# +# This test checks if the replication between "null" fields to either "null" +# fields or "not null" fields works properly. In the first case, the execution +# should work fine. In the second case, it may fail according to the sql_mode +# being used. +# +# The test is devided in three main parts: +# +# 1 - NULL --> NULL (no failures) +# 2 - NULL --> NOT NULL ( sql-mode = STRICT and failures) +# 3 - NULL --> NOT NULL ( sql-mode != STRICT and no failures) +# +################################################################################# +--source include/have_innodb.inc +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +let $engine=Innodb; +--source include/rpl_not_null.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_not_null_myisam.test b/mysql-test/suite/rpl/t/rpl_not_null_myisam.test new file mode 100644 index 00000000..718761d6 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_not_null_myisam.test @@ -0,0 +1,19 @@ +################################################################################# +# This test checks if the replication between "null" fields to either "null" +# fields or "not null" fields works properly. In the first case, the execution +# should work fine. In the second case, it may fail according to the sql_mode +# being used. +# +# The test is devided in three main parts: +# +# 1 - NULL --> NULL (no failures) +# 2 - NULL --> NOT NULL ( sql-mode = STRICT and failures) +# 3 - NULL --> NOT NULL ( sql-mode != STRICT and no failures) +# +################################################################################# +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +let $engine=MyISAM; +--source include/rpl_not_null.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_old_decimal.test b/mysql-test/suite/rpl/t/rpl_old_decimal.test new file mode 100644 index 00000000..79fd2754 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_old_decimal.test @@ -0,0 +1,25 @@ +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + + +--connection slave +CREATE TABLE t1dec102 (a DECIMAL(10,2)); + +--connection master +let $MYSQLD_DATADIR= `select @@datadir`; + +--copy_file std_data/old_decimal/t1dec102.frm $MYSQLD_DATADIR/test/t1dec102.frm +--copy_file std_data/old_decimal/t1dec102.MYD $MYSQLD_DATADIR/test/t1dec102.MYD +--copy_file std_data/old_decimal/t1dec102.MYI $MYSQLD_DATADIR/test/t1dec102.MYI +INSERT INTO t1dec102 VALUES(999.99); + +--let $slave_sql_errno=1677 +--let $show_slave_sql_error= 1 +call mtr.add_suppression("Slave SQL.*Column 0 of table .* cannot be converted from type.* Error_code: 1677"); +--source include/wait_for_slave_sql_error_and_skip.inc + +--connection master +DROP TABLE t1dec102; +--sync_slave_with_master + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_old_master.test b/mysql-test/suite/rpl/t/rpl_old_master.test new file mode 100644 index 00000000..6faa8212 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_old_master.test @@ -0,0 +1,57 @@ +# Test replicating off old master. +# We simulate old master by copying in pre-generated binlog files from earlier +# server versions. + +--source include/have_innodb.inc +--source include/master-slave.inc + +--connection slave +--source include/stop_slave.inc + +--connection master +--let $datadir= `SELECT @@datadir` + +--let $rpl_server_number= 1 +--source include/rpl_stop_server.inc + +--remove_file $datadir/master-bin.000001 +--copy_file $MYSQL_TEST_DIR/std_data/mariadb-5.5-binlog.000001 $datadir/master-bin.000001 + +--let $rpl_server_number= 1 +--source include/rpl_start_server.inc + +--source include/wait_until_connected_again.inc + +--connection slave +SET @old_parallel= @@GLOBAL.slave_parallel_threads; +SET GLOBAL slave_parallel_threads=10; +--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1 +eval CHANGE MASTER TO master_host='127.0.0.1', master_port=$SERVER_MYPORT_1, master_user='root', master_log_file='master-bin.000001', master_log_pos=4, master_use_gtid=no; + +# Block execution yet when the blocked query timestamp has been already accounted +FLUSH TABLES WITH READ LOCK; +--source include/start_slave.inc +--let $slave_param = Seconds_Behind_Master +--let $slave_param_value = 1 +--let $slave_param_comparison= >= +--source include/wait_for_slave_param.inc +UNLOCK TABLES; + +--connection master +CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t2 VALUES (1); +--save_master_pos + +--connection slave +--sync_with_master +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2; + +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel; +DROP TABLE t1; +--source include/start_slave.inc + +--connection master +DROP TABLE t2; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_old_master_29078-master.opt b/mysql-test/suite/rpl/t/rpl_old_master_29078-master.opt new file mode 100644 index 00000000..3efc6fb8 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_old_master_29078-master.opt @@ -0,0 +1 @@ +--version=10.5.99 diff --git a/mysql-test/suite/rpl/t/rpl_old_master_29078.test b/mysql-test/suite/rpl/t/rpl_old_master_29078.test new file mode 100644 index 00000000..98db6188 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_old_master_29078.test @@ -0,0 +1,53 @@ +--echo # +--echo # MDEV-29078 For old binary logs explicit_defaults_for_timestamp presumed to be OFF, server value ignored +--echo # + +--source include/have_binlog_format_mixed.inc +--source include/master-slave.inc + +--connection slave +--source include/stop_slave.inc + +--connection master +--let $datadir= `SELECT @@datadir` + +flush binary logs; +create table t2 (a timestamp); + +--save_master_pos + +--remove_file $datadir/master-bin.000001 +--copy_file $MYSQL_TEST_DIR/std_data/mdev29078-mysql-bin.000001 $datadir/master-bin.000001 + +--exec $MYSQL_BINLOG --short-form $datadir/master-bin.000001 + +--connection slave + +set global explicit_defaults_for_timestamp=0; +--let $master_use_gtid_option= No +--source include/reset_slave.inc + +--source include/start_slave.inc +--sync_with_master +show create table t1; +show create table t2; +set time_zone='+2:00'; +select * from t1; +drop table t1; +--source include/stop_slave.inc + +set global explicit_defaults_for_timestamp=1; +--let $master_use_gtid_option= No +--source include/reset_slave.inc + +--source include/start_slave.inc +--sync_with_master +show create table t1; +show create table t2; +select * from t1; +drop table t1; + +--connection master +drop table t2; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_optimize.test b/mysql-test/suite/rpl/t/rpl_optimize.test new file mode 100644 index 00000000..bb960d4e --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_optimize.test @@ -0,0 +1,65 @@ +# Test for BUG#1858 "OPTIMIZE TABLE done by a client +# thread stops the slave SQL thread". +# You can replace OPTIMIZE by REPAIR. +##################################### +# Change Author: JBM +# Change Date: 2006-02-09 +# OPTIMIZE for memory tables. If and when +# it does support for Disk Data, a new +# version of this test will be need. +##################################### +# Slow test, don't run during staging part +-- source include/not_staging.inc +-- source include/master-slave.inc + +--disable_warnings +drop tables if exists t1; +--enable_warnings + +disable_query_log; +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); +enable_query_log; + +create table t1 (a int not null auto_increment primary key, b int, key(b)); +INSERT INTO t1 (a) VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); +--disable_warnings +INSERT INTO t1 (a) SELECT null FROM t1; +INSERT INTO t1 (a) SELECT null FROM t1; +INSERT INTO t1 (a) SELECT null FROM t1; +INSERT INTO t1 (a) SELECT null FROM t1; +INSERT INTO t1 (a) SELECT null FROM t1; +INSERT INTO t1 (a) SELECT null FROM t1; +INSERT INTO t1 (a) SELECT null FROM t1; +INSERT INTO t1 (a) SELECT null FROM t1; +INSERT INTO t1 (a) SELECT null FROM t1; +INSERT INTO t1 (a) SELECT null FROM t1; +INSERT INTO t1 (a) SELECT null FROM t1; +INSERT INTO t1 (a) SELECT null FROM t1; +INSERT INTO t1 (a) SELECT null FROM t1; +--enable_warnings +save_master_pos; +# a few updates to force OPTIMIZE to do something +--disable_warnings +update t1 set b=(a/2*rand()); +delete from t1 order by b limit 10000; +--enable_warnings + +connection slave; +sync_with_master; +optimize table t1; +connection master; +save_master_pos; +connection slave; +# Bug was that when the INSERT terminated on slave, +# the slave SQL thread got killed by OPTIMIZE. +sync_with_master; # won't work if slave SQL thread stopped + +connection master; # cleanup +drop table t1; +sync_slave_with_master; + +# If the machine is so fast that slave syncs before OPTIMIZE +# starts, this test will demonstrate nothing but will pass. + +# End of 4.1 tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_packet-master.opt b/mysql-test/suite/rpl/t/rpl_packet-master.opt new file mode 100644 index 00000000..412bc079 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_packet-master.opt @@ -0,0 +1 @@ +--max_allowed_packet=1024 --net_buffer_length=1024 diff --git a/mysql-test/suite/rpl/t/rpl_packet-slave.opt b/mysql-test/suite/rpl/t/rpl_packet-slave.opt new file mode 100644 index 00000000..1aed7d07 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_packet-slave.opt @@ -0,0 +1 @@ +--max_allowed_packet=1024 --net_buffer_length=1024 --slave_max_allowed_packet=1024 diff --git a/mysql-test/suite/rpl/t/rpl_packet.test b/mysql-test/suite/rpl/t/rpl_packet.test new file mode 100644 index 00000000..cbde486b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_packet.test @@ -0,0 +1,184 @@ +# +# This include file is used by more than one test suite +# (currently rpl and binlog_encryption). +# Please check all dependent tests after modifying it +# + +# ==== Purpose ==== +# +# Check replication protocol packet size handling +# +# ==== Related bugs ==== +# Bug#19402 SQL close to the size of the max_allowed_packet fails on slave +# BUG#23755: Replicated event larger that max_allowed_packet infinitely re-transmits +# BUG#42914: No LAST_IO_ERROR for max_allowed_packet errors +# BUG#55322: SHOW BINLOG EVENTS increases @@SESSION.MAX_ALLOWED_PACKET + +# max-out size db name +source include/have_binlog_format_row.inc; +source include/master-slave.inc; + +call mtr.add_suppression("Slave I/O: Got a packet bigger than 'slave_max_allowed_packet' bytes, .*error.* 1153"); +call mtr.add_suppression("Log entry on master is longer than slave_max_allowed_packet"); +let $db= DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________; +disable_warnings; +eval drop database if exists $db; +enable_warnings; +eval create database $db; + +connection master; +let $old_max_allowed_packet= `SELECT @@global.max_allowed_packet`; +let $old_net_buffer_length= `SELECT @@global.net_buffer_length`; +let $old_slave_max_allowed_packet= `SELECT @@global.slave_max_allowed_packet`; +SET @@global.max_allowed_packet=1024; +SET @@global.net_buffer_length=1024; + +sync_slave_with_master; +# Restart slave for setting to take effect +source include/stop_slave.inc; +source include/start_slave.inc; + +# Reconnect to master for new setting to take effect +disconnect master; + +# alas, can't use eval here; if db name changed apply the change here +connect (master,localhost,root,,DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________); + +connection master; +select @@net_buffer_length, @@max_allowed_packet; + +create table `t1` (`f1` LONGTEXT) ENGINE=MyISAM; + +INSERT INTO `t1`(`f1`) VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1023'); +sync_slave_with_master; + +eval select count(*) from `$db`.`t1` /* must be 1 */; + +SHOW STATUS LIKE 'Slave_running'; +select * from information_schema.session_status where variable_name= 'SLAVE_RUNNING'; +connection master; +eval drop database $db; +sync_slave_with_master; + +# +# Bug #23755: Replicated event larger that max_allowed_packet infinitely re-transmits +# +# Check that a situation when the size of event on the master is greater than +# max_allowed_packet on the slave does not lead to infinite re-transmits. + +connection master; + +# Change the max packet size on master + +SET @@global.max_allowed_packet=4096; +SET @@global.net_buffer_length=4096; + +# Restart slave for new setting to take effect +connection slave; +source include/stop_slave.inc; +source include/start_slave.inc; + +# Reconnect to master for new setting to take effect +disconnect master; +connect (master, localhost, root); +connection master; + +CREATE TABLE `t1` (`f1` LONGTEXT) ENGINE=MyISAM; + +sync_slave_with_master; + +connection master; + +INSERT INTO `t1`(`f1`) VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2048'); + + +# +# Bug#42914: The slave I/O thread must stop after trying to read the above +# event, However there is no Last_IO_Error report. +# + +# The slave I/O thread must stop after trying to read the above event +connection slave; +# 1153 = ER_NET_PACKET_TOO_LARGE +--let $slave_io_errno= 1153 +--let $show_slave_io_error= 1 +--source include/wait_for_slave_io_error.inc + +# TODO: this is needed because of BUG#55790. Remove once that is fixed. +--source include/stop_slave_sql.inc + +# +# Bug#42914: On the master, if a binary log event is larger than +# max_allowed_packet, the error message ER_MASTER_FATAL_ERROR_READING_BINLOG +# is sent to a slave when it requests a dump from the master, thus leading the +# I/O thread to stop. However, there is no Last_IO_Error reported. +# + +--let $rpl_only_running_threads= 1 +--source include/rpl_reset.inc +--connection master +DROP TABLE t1; +--sync_slave_with_master + + +connection master; +CREATE TABLE t1 (f1 int PRIMARY KEY, f2 LONGTEXT, f3 LONGTEXT) ENGINE=MyISAM; +sync_slave_with_master; + +connection master; +INSERT INTO t1(f1, f2, f3) VALUES(1, REPEAT('a', @@global.max_allowed_packet), REPEAT('b', @@global.max_allowed_packet)); + +connection slave; +# The slave I/O thread must stop after receiving +# 1153 = ER_NET_PACKET_TOO_LARGE +--let $slave_io_errno= 1153 +--let $show_slave_io_error= 1 +--source include/wait_for_slave_io_error.inc + +# Remove the bad binlog and clear error status on slave. +STOP SLAVE; +RESET SLAVE; +--connection master +RESET MASTER; + + +# +# BUG#55322: SHOW BINLOG EVENTS increases @@SESSION.MAX_ALLOWED_PACKET +# +# In BUG#55322, @@session.max_allowed_packet increased each time SHOW +# BINLOG EVENTS was issued. To verify that this bug is fixed, we +# execute SHOW BINLOG EVENTS twice and check that max_allowed_packet +# never changes. We turn off the result log because we don't care +# about the contents of the binlog. + +--disable_result_log +SET @max_allowed_packet_0= @@session.max_allowed_packet; +SHOW BINLOG EVENTS; +SET @max_allowed_packet_1= @@session.max_allowed_packet; +SHOW BINLOG EVENTS; +SET @max_allowed_packet_2= @@session.max_allowed_packet; +--enable_result_log +if (`SELECT NOT(@max_allowed_packet_0 = @max_allowed_packet_1 AND @max_allowed_packet_1 = @max_allowed_packet_2)`) +{ + --echo ERROR: max_allowed_packet changed after executing SHOW BINLOG EVENTS + --source include/show_rpl_debug_info.inc + SELECT @max_allowed_packet_0, @max_allowed_packet_1, @max_allowed_packet_2; + --die @max_allowed_packet changed after executing SHOW BINLOG EVENTS +} + + +--echo ==== clean up ==== +connection master; +DROP TABLE t1; +eval SET @@global.max_allowed_packet= $old_max_allowed_packet; +eval SET @@global.net_buffer_length= $old_net_buffer_length; +eval SET @@global.slave_max_allowed_packet= $old_slave_max_allowed_packet; +# slave is stopped +connection slave; +DROP TABLE t1; + +# Clear Last_IO_Error +RESET SLAVE; + +--source include/rpl_end.inc +# End of tests diff --git a/mysql-test/suite/rpl/t/rpl_parallel2.test b/mysql-test/suite/rpl/t/rpl_parallel2.test new file mode 100644 index 00000000..8934b15e --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel2.test @@ -0,0 +1,230 @@ +--source include/have_debug.inc +--source include/have_innodb.inc +--source include/have_binlog_format_statement.inc +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +--echo *** MDEV-5509: Incorrect value for Seconds_Behind_Master if parallel replication *** + +--connection server_2 +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +set @old_parallel_mode= @@GLOBAL.slave_parallel_mode; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=5; +set global slave_parallel_mode= optimistic; +--source include/start_slave.inc + +--connection server_1 +CREATE TABLE t1 (a INT PRIMARY KEY, b INT); +CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave"); +--save_master_pos + +--connection server_2 +--sync_with_master + +--connection server_1 +INSERT INTO t1 VALUES (1,sleep(2)); +--save_master_pos + +--connection server_2 +--sync_with_master + +# The slave position (which --sync_with_master waits for) is updated just +# before the Seconds_Behind_Master. So we have to wait for the zero status +# to appear, otherwise there is a small window between --sync_with_master +# and SHOW SLAVE STATUS where we can see a non-zero value. +--let $slave_param= Seconds_Behind_Master +--let $slave_param_value= 0 +--source include/wait_for_slave_param.inc +--echo Seconds_Behind_Master should be zero here because the slave is fully caught up and idle. +--let $status_items= Seconds_Behind_Master +--source include/show_slave_status.inc + + +--echo *** MDEV-8294: Inconsistent behavior of slave parallel threads at runtime *** + +--connection server_1 +INSERT INTO t1 VALUES (10,0); +# Force a duplicate key error on the slave. +SET sql_log_bin= 0; +DELETE FROM t1 WHERE a=10; +SET sql_log_bin= 1; +INSERT INTO t1 VALUES (10,0); +--save_master_pos +SELECT * FROM t1 WHERE a >= 10 ORDER BY a; + +--connection server_2 +--let $slave_sql_errno= 1062 +--source include/wait_for_slave_sql_error.inc + +# At this point, the worker threads should have stopped also. +--let $wait_condition= SELECT COUNT(*)=0 FROM information_schema.processlist WHERE User = "system user" AND State = "Waiting for work from SQL thread"; +--source include/wait_condition.inc + +# Check that the pool can still be resized, but remains inactive as no slave +# SQL thread is running. +SET GLOBAL slave_parallel_threads=8; +--let $wait_condition= SELECT COUNT(*)=0 FROM information_schema.processlist WHERE User = "system user" AND State = "Waiting for work from SQL thread"; +--source include/wait_condition.inc + +STOP SLAVE; +# At this point, the worker threads should have stopped. +--let $wait_condition= SELECT COUNT(*)=0 FROM information_schema.processlist WHERE User = "system user" AND State = "Waiting for work from SQL thread"; +--source include/wait_condition.inc + + +SET GLOBAL sql_slave_skip_counter= 1; +--source include/start_slave.inc +# At this point, the worker threads should have been spawned. +--let $wait_condition= SELECT COUNT(*)=8 FROM information_schema.processlist WHERE User = "system user" AND State = "Waiting for work from SQL thread"; +--source include/wait_condition.inc +--sync_with_master +SELECT * FROM t1 WHERE a >= 10 ORDER BY a; + + +--echo *** MDEV-7818: Deadlock occurring with parallel replication and FTWRL *** + +--connection server_1 +CREATE TABLE t2 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +INSERT INTO t2 VALUES (1,0), (2,0), (3,0); +--save_master_pos + +--connection server_2 +--sync_with_master +--source include/stop_slave.inc + +--connection server_1 +# Create a group commit with two transactions, will be used to provoke the +# problematic thread interaction with FTWRL on the slave. +SET @old_dbug= @@SESSION.debug_dbug; +SET @commit_id= 4242; +SET SESSION debug_dbug="+d,binlog_force_commit_id"; + +BEGIN; +UPDATE t2 SET b=b+1 WHERE a=2; +COMMIT; + +BEGIN; +INSERT INTO t2 VALUES (4,10); +COMMIT; + +SET SESSION debug_dbug= @old_dbug; + +INSERT INTO t2 VALUES (5,0); +INSERT INTO t2 VALUES (6,0); +INSERT INTO t2 VALUES (7,0); +INSERT INTO t2 VALUES (8,0); +INSERT INTO t2 VALUES (9,0); +INSERT INTO t2 VALUES (10,0); +INSERT INTO t2 VALUES (11,0); +INSERT INTO t2 VALUES (12,0); +INSERT INTO t2 VALUES (13,0); +INSERT INTO t2 VALUES (14,0); +INSERT INTO t2 VALUES (15,0); +INSERT INTO t2 VALUES (16,0); +INSERT INTO t2 VALUES (17,0); +INSERT INTO t2 VALUES (18,0); +INSERT INTO t2 VALUES (19,0); +--save_master_pos + +--connection server_2 + +--connect (s1, 127.0.0.1, root,, test, $SLAVE_MYPORT,) +# Block one transaction on a row lock. +BEGIN; +SELECT * FROM t2 WHERE a=2 FOR UPDATE; + +--connection server_2 + +# Wait for slave thread of the other transaction to have the commit lock. +--source include/start_slave.inc +--let $wait_condition= SELECT COUNT(*) > 0 FROM information_schema.processlist WHERE state = "Waiting for prior transaction to commit" +--source include/wait_condition.inc + +--connect (s2, 127.0.0.1, root,, test, $SLAVE_MYPORT,) +send FLUSH TABLES WITH READ LOCK; +# The bug was that at this point we were deadlocked. +# The FTWRL command would wait forever for T2 to commit. +# T2 would wait for T1 to commit first, but T1 is waiting for +# the global read lock to be released. + +--connection s1 +# Release the lock that blocs T1 from replicating. +COMMIT; + +--connection s1 +send STOP SLAVE; + +--connection s2 +reap; + +--connection server_1 +SELECT * FROM t2 ORDER BY a; + +--connection s2 +UNLOCK TABLES; + +SELECT "after UNLOCK TABLES" as state; + +--connection s1 +reap; + +SELECT "after reap of STOP SLAVE" as state; + +--connection server_2 +--source include/wait_for_slave_to_stop.inc +--source include/start_slave.inc +--sync_with_master + +SELECT * FROM t2 ORDER BY a; + + + +--echo *** MDEV-8318: Assertion `!pool->busy' failed in pool_mark_busy(rpl_parallel_thread_pool*) on concurrent FTWRL *** + +--connection server_1 +LOCK TABLE t2 WRITE; + + +--connect (m1,localhost,root,,test) +--connection m1 +--let $cid=`SELECT CONNECTION_ID()` +send FLUSH TABLES WITH READ LOCK; + +--connect (m2,localhost,root,,test) +# We cannot force the race with DEBUG_SYNC, because the race does not +# exist after fixing the bug. At best we could force a debug sync to +# time out, which is effectively just a sleep. +# So just put a small sleep here; it is enough to trigger the bug in +# most run before the bug fix, and the code should work correctly +# however the thread scheduling happens. +--sleep 0.1 +send FLUSH TABLES WITH READ LOCK; + +--connection server_1 +--replace_result $cid CID +eval KILL QUERY $cid; + +--connection m1 +--error ER_QUERY_INTERRUPTED +reap; + +--connection server_1 +UNLOCK TABLES; + +--connection m2 +reap; +UNLOCK TABLES; + + +# Clean up. +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +set global slave_parallel_mode= @old_parallel_mode; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t1, t2; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_29322.test b/mysql-test/suite/rpl/t/rpl_parallel_29322.test new file mode 100644 index 00000000..67596059 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_29322.test @@ -0,0 +1,64 @@ +--echo # +--echo # MDEV-29322 ASAN use-after-free options_written_to_bin_log +--echo # + +# The tests verify that at query execution slave parallel workers successfully +# find a correct options_written_to_bin_log value associated with the query. +# There are three test branches, A and B take care of different server version +# binlogs. The homogeneous binlog case of C. branch is also for how-to-reproduce +# the bug, may need few --repeat :s though. + +--source include/have_binlog_format_mixed.inc +--source include/master-slave.inc + +--echo # A. set the master and slave explicit_defaults_for_timestamp values crisscross to (1,0) +--let $same_version_binlogs=0 + +--connection master +# Configure master and slave with different values of the following variable: +set @sav.explicit_defaults_for_timestamp = @@session.explicit_defaults_for_timestamp; +set @@session.explicit_defaults_for_timestamp = 1; +--connection slave +# slave must produce the master version of the table definition and its data +set @sav.explicit_defaults_for_timestamp = @@global.explicit_defaults_for_timestamp; +set global explicit_defaults_for_timestamp = 0; +# the global var gets changed in the included file +set @sav.slave_parallel_workers = @@global.slave_parallel_workers; +--source include/stop_slave.inc +set @@global.slave_parallel_workers = 1; +--source include/start_slave.inc + +--source suite/rpl/include/rpl_parallel_29322.inc + +--echo # B. alternate the master and slave vars' values to (0,1) + +--connection master +# Configure master and slave with different values of the following variable: +set @@session.explicit_defaults_for_timestamp = 0; +--connection slave +# slave must produce the master version of the table definition and its data +set @@global.explicit_defaults_for_timestamp = 1; + +--source suite/rpl/include/rpl_parallel_29322.inc + + +--echo # C. the bug case on the same version binlogs also to demo on the patch's base +--let $same_version_binlogs=1 +# with more workers the bug shows more likeky on the patch's base slave. +--source include/stop_slave.inc +set @@global.slave_parallel_workers = 4; +--source include/start_slave.inc + +--source suite/rpl/include/rpl_parallel_29322.inc + +# cleanup +--connection master +set @@session.explicit_defaults_for_timestamp = @sav.explicit_defaults_for_timestamp; +--connection slave +set @@global.explicit_defaults_for_timestamp = @sav.explicit_defaults_for_timestamp; +--source include/stop_slave.inc +set @@global.slave_parallel_workers = @sav.slave_parallel_workers; +--source include/start_slave.inc + + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_analyze.test b/mysql-test/suite/rpl/t/rpl_parallel_analyze.test new file mode 100644 index 00000000..921c6f02 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_analyze.test @@ -0,0 +1,84 @@ +# The test file is created to prove fixes to +# MDEV-30323 Some DDLs like ANALYZE can complete on parallel slave out of order +# Debug-sync tests aiming at parallel replication of ADMIN commands +# are welcome here. + +--source include/have_innodb.inc +--source include/have_debug_sync.inc +--source include/master-slave.inc + +--echo # Initialize +--connection slave +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; + +--echo # Setup data +--connection master +CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE ta (a int); +--let $pre_load_gtid=`SELECT @@last_gtid` +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc + +--source suite/rpl/include/create_or_drop_sync_func.inc + +# configure MDEV-30323 slave +--source include/stop_slave.inc +SET @old_parallel_threads =@@GLOBAL.slave_parallel_threads; +SET @old_parallel_mode =@@GLOBAL.slave_parallel_mode; +SET @old_gtid_strict_mode =@@GLOBAL.gtid_strict_mode; +SET GLOBAL slave_parallel_threads=10; +SET GLOBAL slave_parallel_mode=conservative; +SET GLOBAL gtid_strict_mode=ON; +--source include/start_slave.inc + +# MDEV-30323 setup needs two group of events the first of which is a DML +# and ANALYZE is the 2nd. +# The latter is made to race in slave execution over the DML thanks +# to a DML latency simulation. +# In the fixed case the race-over should not be a problem: ultimately +# ANALYZE must wait for its turn to update slave@@global.gtid_binlog_pos. +# Otherwise the reported OOO error must be issued. + +--connection master +SET @old_format= @@SESSION.binlog_format; +SET binlog_format=statement; +INSERT INTO t1 VALUES (foo(1, 'rpl_parallel_after_mark_start_commit WAIT_FOR sig_go', '')); + +ANALYZE TABLE ta; +--source include/save_master_gtid.inc + +--connection slave +--let $wait_condition= SELECT COUNT(*) = 1 FROM information_schema.processlist WHERE state = "Waiting for prior transaction to commit" +--source include/wait_condition.inc + +SELECT info FROM information_schema.processlist WHERE state = "Waiting for prior transaction to commit"; +if (`select strcmp(@@global.gtid_binlog_pos, '$pre_load_gtid') <> 0 or strcmp(@@global.gtid_slave_pos, '$pre_load_gtid') <> 0`) +{ + --let $bs=`SELECT @@global.gtid_binlog_pos` + --let $es=`SELECT @@global.gtid_slave_pos` + --echo Mismatch between expected $pre_load_gtid state and the actual binlog state " @@global.gtid_binlog_pos = $bs or/and slave execution state @@global.gtid_slave_pos = $es. + --die +} + +set @@debug_sync="now signal sig_go"; +--source include/sync_with_master_gtid.inc + +--echo # Cleanup +--connection master +DROP TABLE t1,ta; +--let $create_or_drop=drop +--source suite/rpl/include/create_or_drop_sync_func.inc + +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc +SET @@GLOBAL.slave_parallel_threads=@old_parallel_threads; +SET @@GLOBAL.slave_parallel_mode =@old_parallel_mode; +SET @@GLOBAL.gtid_strict_mode =@old_gtid_strict_mode; +--source include/start_slave.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_analyze_table_hang.test b/mysql-test/suite/rpl/t/rpl_parallel_analyze_table_hang.test new file mode 100644 index 00000000..62a7501c --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_analyze_table_hang.test @@ -0,0 +1,73 @@ +--echo *** MDEV-7888: ANALYZE TABLE does wakeup_subsequent_commits(), causing wrong binlog order and parallel replication hang *** +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/master-slave.inc + +--connection server_2 +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_mode='conservative'; +SET GLOBAL slave_parallel_threads=10; +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +--save_master_pos + +--connection server_2 +--sync_with_master +--source include/stop_slave.inc +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug= '+d,inject_analyze_table_sleep'; + +--connection server_1 +# Inject two group commits. The bug was that ANALYZE TABLE would call +# wakeup_subsequent_commits() too early, allowing the following transaction +# in the same group to run ahead and binlog and free the GCO. Then we get +# wrong binlog order and later access freed GCO, which causes lost wakeup +# of following GCO and thus replication hang. +# We injected a small sleep in ANALYZE to make the race easier to hit (this +# can only cause false negatives in versions with the bug, not false positives, +# so sleep is ok here. And it's in general not possible to trigger reliably +# the race with debug_sync, since the bugfix makes the race impossible). + +SET @old_dbug= @@SESSION.debug_dbug; +SET SESSION debug_dbug="+d,binlog_force_commit_id"; + +# Group commit with cid=10000, two event groups. +SET @commit_id= 10000; +ANALYZE TABLE t2; +INSERT INTO t3 VALUES (120, 0); + +# Group commit with cid=10001, one event group. +SET @commit_id= 10001; +INSERT INTO t3 VALUES (121, 0); + +SET SESSION debug_dbug=@old_dbug; + +SELECT * FROM t3 WHERE a >= 120 ORDER BY a; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + +SELECT * FROM t3 WHERE a >= 120 ORDER BY a; + +# Clean up. +--source include/stop_slave.inc +SET GLOBAL debug_dbug= @old_dbug; +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +SET GLOBAL slave_parallel_mode=@old_parallel_mode; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t2,t3; + +--source include/rpl_end.inc + diff --git a/mysql-test/suite/rpl/t/rpl_parallel_autoinc.test b/mysql-test/suite/rpl/t/rpl_parallel_autoinc.test new file mode 100644 index 00000000..0e96b4df --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_autoinc.test @@ -0,0 +1,140 @@ +--source include/have_binlog_format_statement.inc +--source include/have_innodb.inc +--source include/master-slave.inc + +--echo MDEV-31482: Lock wait timeout with INSERT-SELECT, autoinc, and statement-based replication + +# The scenario is transactions T1, T2, T3: +# +# T1 is waiting for T3 on an autoinc lock +# T2 is waiting for T1 to commit +# T3 is waiting on a normal row lock held by T2 +# +# This caused a hang until innodb_lock_wait_timeout, because autoinc +# locks were not reported to the in-order parallel replication, so T3 +# was not deadlock killed. + +--let $lock_wait_timeout=20 + +--let $rpl_connection_name= slave2 +--let $rpl_server_number= 2 +--source include/rpl_connect.inc + +--let $rpl_connection_name= slave3 +--let $rpl_server_number= 2 +--source include/rpl_connect.inc + +--connection master +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; + +# A table as destination for INSERT-SELECT +CREATE TABLE t1 (a INT PRIMARY KEY AUTO_INCREMENT, b INT, c INT, INDEX (c)) ENGINE=InnoDB; +INSERT INTO t1 (b,c) VALUES (0, 1), (0, 1), (0, 2), (0,3), (0, 5), (0, 7), (0, 8); + +# A table as source for INSERT-SELECT. +CREATE TABLE t2 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +INSERT INTO t2 VALUES (10,1), (20,2), (30,3), (40,4), (50,5); + +# A table to help order slave worker threads to setup the desired scenario. +CREATE TABLE t3 (a VARCHAR(20) PRIMARY KEY, b INT) ENGINE=InnoDB; +INSERT INTO t3 VALUES ('row for T1', 0), ('row for T2', 0), ('row for T3', 0); +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc +--let $save_innodb_lock_wait_timeout= `SELECT @@global.innodb_lock_wait_timeout` +--let $save_slave_parallel_threads= `SELECT @@global.slave_parallel_threads` +--let $save_slave_parallel_mode= `SELECT @@global.slave_parallel_mode` +set @@global.slave_parallel_threads= 3; +set @@global.slave_parallel_mode= OPTIMISTIC; +eval set @@global.innodb_lock_wait_timeout= $lock_wait_timeout; + +--connection master +# Transaction T1. +BEGIN; +UPDATE t3 SET b=b+1 where a="row for T1"; +INSERT INTO t1(b, c) SELECT 1, t2.b FROM t2 WHERE a=10; +COMMIT; + +# Transaction T2. +DELETE FROM t1 WHERE c >= 4 and c < 6; + +# Transaction T3. +BEGIN; +UPDATE t3 SET b=b+1 where a="row for T3"; +INSERT INTO t1(b, c) SELECT 3, t2.b FROM t2 WHERE a >= 20 AND a <= 40; +COMMIT; + +--source include/save_master_gtid.inc + +--connection slave1 +# Temporarily block T1 to create the scheduling that triggers the bug. +BEGIN; +SELECT * FROM t3 WHERE a="row for T1" FOR UPDATE; + +--connection slave2 +# Temporarily block T3 from starting (so T2 can reach commit). +BEGIN; +SELECT * FROM t3 WHERE a="row for T3" FOR UPDATE; + +--connection slave3 +# This critical step blocks T3 after it has inserted its first row, +# and thus taken the auto-increment lock, but before it has reached +# the point where it gets a row lock wait on T2. Even though +# auto-increment lock waits were not reported due to the bug, +# transitive lock waits (T1 waits on autoinc of T3 which waits on row +# on T2) _were_ reported as T1 waiting on T2, and thus a deadlock kill +# happened and the bug was not triggered. +BEGIN; +DELETE FROM t2 WHERE a=30; + +--connection slave +--source include/start_slave.inc + +# First let T2 complete until it is waiting for T1 to commit. +--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state='Waiting for prior transaction to commit' and command LIKE 'Slave_worker'; +--source include/wait_condition.inc + +# Then let T3 reach the point where it has obtained the autoinc lock, +# but it is not yet waiting for a row lock held by T2. +--connection slave2 +ROLLBACK; +--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state='Sending data' and info LIKE 'INSERT INTO t1(b, c) SELECT 3, t2.b%' and time_ms > 500 and command LIKE 'Slave_worker'; +--source include/wait_condition.inc + +# Now let T1 continue, while T3 is holding the autoinc lock but before +# it is waiting for T2. Wait a short while to give the hang a chance to +# happen; T1 needs to get to request the autoinc lock before we let T3 +# continue. (There's a small chance the sleep will be too small, which will +# let the test occasionally pass on non-fixed server). +--connection slave1 +ROLLBACK; +--sleep 0.5 + +# Now let T3 continue; the bug was that this lead to an undetected +# deadlock that remained until innodb lock wait timeout. +--connection slave3 +ROLLBACK; + +--connection slave +--let $slave_timeout= `SELECT $lock_wait_timeout/2` +--source include/sync_with_master_gtid.inc +--let $slave_timeout= +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; + +# Cleanup. +--connection master +CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format"); +DROP TABLE t1, t2, t3; + +--connection slave +--source include/stop_slave.inc +eval SET @@global.slave_parallel_threads= $save_slave_parallel_threads; +eval SET @@global.slave_parallel_mode= $save_slave_parallel_mode; +eval SET @@global.innodb_lock_wait_timeout= $save_innodb_lock_wait_timeout; +--source include/start_slave.inc +SELECT @@GLOBAL.innodb_autoinc_lock_mode; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_charset.test b/mysql-test/suite/rpl/t/rpl_parallel_charset.test new file mode 100644 index 00000000..3e0f4913 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_charset.test @@ -0,0 +1,56 @@ +--source include/have_binlog_format_statement.inc +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +--echo *** MDEV-6156: Parallel replication incorrectly caches charset between worker threads *** + +--connection server_2 +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=5; +--source include/start_slave.inc + +--connection server_1 +CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(100) CHARACTER SET utf8); +SHOW CREATE TABLE t1; +SET character_set_client=latin1; +INSERT INTO t1 VALUES (1, 'Rødgrød med fløde 1'); +INSERT INTO t1 VALUES (2, 'Rødgrød med fløde 2'); +INSERT INTO t1 VALUES (3, 'Rødgrød med fløde 3'); +INSERT INTO t1 VALUES (4, 'Rødgrød med fløde 4'); +INSERT INTO t1 VALUES (5, 'Rødgrød med fløde 5'); +INSERT INTO t1 VALUES (6, 'Rødgrød med fløde 6'); +INSERT INTO t1 VALUES (7, 'Rødgrød med fløde 7'); +INSERT INTO t1 VALUES (8, 'Rødgrød med fløde 8'); +INSERT INTO t1 VALUES (9, 'Rødgrød med fløde 9'); +INSERT INTO t1 VALUES (10, 'Rødgrød med fløde 10'); +SET character_set_client=utf8; +INSERT INTO t1 VALUES (11, 'Rødgrød med fløde 1'); +INSERT INTO t1 VALUES (12, 'Rødgrød med fløde 2'); +INSERT INTO t1 VALUES (13, 'Rødgrød med fløde 3'); +INSERT INTO t1 VALUES (14, 'Rødgrød med fløde 4'); +INSERT INTO t1 VALUES (15, 'Rødgrød med fløde 5'); +INSERT INTO t1 VALUES (16, 'Rødgrød med fløde 6'); +INSERT INTO t1 VALUES (17, 'Rødgrød med fløde 7'); +INSERT INTO t1 VALUES (18, 'Rødgrød med fløde 8'); +INSERT INTO t1 VALUES (19, 'Rødgrød med fløde 9'); +INSERT INTO t1 VALUES (20, 'Rødgrød med fløde 10'); +SET character_set_results=utf8; +SELECT * FROM t1 ORDER BY a; +--save_master_pos + +--connection server_2 +--sync_with_master +SET character_set_results=utf8; +SELECT * FROM t1 ORDER BY a; + + +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_conflicts.test b/mysql-test/suite/rpl/t/rpl_parallel_conflicts.test new file mode 100644 index 00000000..0ba6a2b2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_conflicts.test @@ -0,0 +1,269 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/master-slave.inc + +--echo *** MDEV-7847: "Slave worker thread retried transaction 10 time(s) in vain, giving up", followed by replication hanging *** +--echo *** MDEV-7882: Excessive transaction retry in parallel replication *** + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t7 (a int PRIMARY KEY, b INT) ENGINE=InnoDB; +CREATE TABLE t8 (a int PRIMARY KEY, b INT) ENGINE=InnoDB; +--save_master_pos + +--connection server_2 +--sync_with_master +--source include/stop_slave.inc +SET @old_mode= @@GLOBAL.slave_parallel_mode; +SET GLOBAL slave_parallel_mode='conservative'; +SET @old_threads= @@GLOBAL.slave_parallel_threads; +SET GLOBAL slave_parallel_threads=40; +SET @old_transaction_retries= @@GLOBAL.slave_transaction_retries; +SET GLOBAL slave_transaction_retries=5; + +# Using dbug error injection, we artificially create event groups with a lot of +# conflicting transactions in each event group. The bugs were originally seen +# "in the wild" with transactions that did not conflict on the master, and only +# conflicted very rarely on the slave (maybe some edge case with InnoDB btree +# page splits or something like that). The event groups here loosely reflect +# the structure of the original failure's group commits. + + +--connection server_1 +INSERT INTO t7 VALUES (1,1), (2,2), (3,3), (4,4), (5,5); +SET @old_dbug= @@SESSION.debug_dbug; +SET @commit_id= 42; +SET SESSION debug_dbug="+d,binlog_force_commit_id"; +INSERT INTO t8 VALUES (1,1); +INSERT INTO t8 VALUES (2,2); +INSERT INTO t8 VALUES (3,3); +INSERT INTO t8 VALUES (4,4); +INSERT INTO t8 VALUES (5,5); +INSERT INTO t8 VALUES (6,6); +INSERT INTO t8 VALUES (7,7); +INSERT INTO t8 VALUES (8,8); + +UPDATE t7 SET b=9 WHERE a=3; +UPDATE t7 SET b=10 WHERE a=3; +UPDATE t7 SET b=11 WHERE a=3; + +INSERT INTO t8 VALUES (12,12); +INSERT INTO t8 VALUES (13,13); + +UPDATE t7 SET b=14 WHERE a=3; +UPDATE t7 SET b=15 WHERE a=3; + +INSERT INTO t8 VALUES (16,16); + +UPDATE t7 SET b=17 WHERE a=3; + +INSERT INTO t8 VALUES (18,18); +INSERT INTO t8 VALUES (19,19); + +UPDATE t7 SET b=20 WHERE a=3; + +INSERT INTO t8 VALUES (21,21); + +UPDATE t7 SET b=22 WHERE a=3; + +INSERT INTO t8 VALUES (23,24); +INSERT INTO t8 VALUES (24,24); + +UPDATE t7 SET b=25 WHERE a=3; + +INSERT INTO t8 VALUES (26,26); + +UPDATE t7 SET b=27 WHERE a=3; + +BEGIN; +INSERT INTO t8 VALUES (28,28); +INSERT INTO t8 VALUES (29,28), (30,28); +INSERT INTO t8 VALUES (31,28); +INSERT INTO t8 VALUES (32,28); +INSERT INTO t8 VALUES (33,28); +INSERT INTO t8 VALUES (34,28); +INSERT INTO t8 VALUES (35,28); +INSERT INTO t8 VALUES (36,28); +INSERT INTO t8 VALUES (37,28); +INSERT INTO t8 VALUES (38,28); +INSERT INTO t8 VALUES (39,28); +INSERT INTO t8 VALUES (40,28); +INSERT INTO t8 VALUES (41,28); +INSERT INTO t8 VALUES (42,28); +COMMIT; + + +SET @commit_id=43; +INSERT INTO t8 VALUES (43,43); +INSERT INTO t8 VALUES (44,44); + +UPDATE t7 SET b=45 WHERE a=3; + +INSERT INTO t8 VALUES (46,46); +INSERT INTO t8 VALUES (47,47); + +UPDATE t7 SET b=48 WHERE a=3; + +INSERT INTO t8 VALUES (49,49); +INSERT INTO t8 VALUES (50,50); + + +SET @commit_id=44; +INSERT INTO t8 VALUES (51,51); +INSERT INTO t8 VALUES (52,52); + +UPDATE t7 SET b=53 WHERE a=3; + +INSERT INTO t8 VALUES (54,54); +INSERT INTO t8 VALUES (55,55); + +UPDATE t7 SET b=56 WHERE a=3; + +INSERT INTO t8 VALUES (57,57); + +UPDATE t7 SET b=58 WHERE a=3; + +INSERT INTO t8 VALUES (58,58); +INSERT INTO t8 VALUES (59,59); +INSERT INTO t8 VALUES (60,60); +INSERT INTO t8 VALUES (61,61); + +UPDATE t7 SET b=62 WHERE a=3; + +INSERT INTO t8 VALUES (63,63); +INSERT INTO t8 VALUES (64,64); +INSERT INTO t8 VALUES (65,65); +INSERT INTO t8 VALUES (66,66); + +UPDATE t7 SET b=67 WHERE a=3; + +INSERT INTO t8 VALUES (68,68); + +UPDATE t7 SET b=69 WHERE a=3; +UPDATE t7 SET b=70 WHERE a=3; +UPDATE t7 SET b=71 WHERE a=3; + +INSERT INTO t8 VALUES (72,72); + +UPDATE t7 SET b=73 WHERE a=3; +UPDATE t7 SET b=74 WHERE a=3; +UPDATE t7 SET b=75 WHERE a=3; +UPDATE t7 SET b=76 WHERE a=3; + +INSERT INTO t8 VALUES (77,77); + +UPDATE t7 SET b=78 WHERE a=3; + +INSERT INTO t8 VALUES (79,79); + +UPDATE t7 SET b=80 WHERE a=3; + +INSERT INTO t8 VALUES (81,81); + +UPDATE t7 SET b=82 WHERE a=3; + +INSERT INTO t8 VALUES (83,83); + +UPDATE t7 SET b=84 WHERE a=3; + + +SET @commit_id=45; +INSERT INTO t8 VALUES (85,85); +UPDATE t7 SET b=86 WHERE a=3; +INSERT INTO t8 VALUES (87,87); + + +SET @commit_id=46; +INSERT INTO t8 VALUES (88,88); +INSERT INTO t8 VALUES (89,89); +INSERT INTO t8 VALUES (90,90); + +SET SESSION debug_dbug=@old_dbug; + +INSERT INTO t8 VALUES (91,91); +INSERT INTO t8 VALUES (92,92); +INSERT INTO t8 VALUES (93,93); +INSERT INTO t8 VALUES (94,94); +INSERT INTO t8 VALUES (95,95); +INSERT INTO t8 VALUES (96,96); +INSERT INTO t8 VALUES (97,97); +INSERT INTO t8 VALUES (98,98); +INSERT INTO t8 VALUES (99,99); + + +SELECT * FROM t7 ORDER BY a; +SELECT * FROM t8 ORDER BY a; +--source include/save_master_gtid.inc + + +--connection server_2 +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t7 ORDER BY a; +SELECT * FROM t8 ORDER BY a; + +--echo *** MDEV-8302: Duplicate key with parallel replication *** + +--connection server_2 +--source include/stop_slave.inc +/* Inject a small sleep which makes the race easier to hit. */ +SET @old_dbug=@@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,inject_mdev8302"; + + +--connection server_1 +INSERT INTO t7 VALUES (100,1), (101,2), (102,3), (103,4), (104,5); + +# Artificially create a bunch of group commits with conflicting transactions. +# The bug happened when T1 and T2 was in one group commit, and T3 was in the +# following group commit. T2 is a DELETE of a row with same primary key as a +# row that T3 inserts. T1 and T2 can conflict, causing T2 to be deadlock +# killed after starting to commit. The bug was that T2 could roll back before +# doing unmark_start_commit(); this could allow T3 to run before the retry +# of T2, causing duplicate key violation. + +SET @old_dbug= @@SESSION.debug_dbug; +SET @commit_id= 20000; +SET SESSION debug_dbug="+d,binlog_force_commit_id"; + +--let $n = 100 +--disable_query_log +while ($n) +{ + eval UPDATE t7 SET b=b+1 WHERE a=100+($n MOD 5); + eval DELETE FROM t7 WHERE a=100+($n MOD 5); + + SET @commit_id = @commit_id + 1; + eval INSERT INTO t7 VALUES (100+($n MOD 5), $n); + SET @commit_id = @commit_id + 1; + dec $n; +} +--enable_query_log +SET SESSION debug_dbug=@old_dbug; + + +SELECT * FROM t7 ORDER BY a; +--source include/save_master_gtid.inc + + +--connection server_2 +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t7 ORDER BY a; + +--source include/stop_slave.inc +SET GLOBAL debug_dbug=@old_dbug; +SET GLOBAL slave_parallel_mode=@old_mode; +SET GLOBAL slave_parallel_threads=@old_threads; +SET GLOBAL slave_transaction_retries=@old_transaction_retries; + +# Clean up. +--source include/start_slave.inc +SET DEBUG_SYNC= 'RESET'; + +--connection server_1 +DROP TABLE t7,t8; +SET DEBUG_SYNC= 'RESET'; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_deadlock_corrupt_binlog.test b/mysql-test/suite/rpl/t/rpl_parallel_deadlock_corrupt_binlog.test new file mode 100644 index 00000000..592ffd3b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_deadlock_corrupt_binlog.test @@ -0,0 +1,80 @@ +--echo *** MDEV-7335: Potential parallel slave deadlock with specific binlog corruption *** +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/master-slave.inc + +--connection server_2 +--source include/stop_slave.inc +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +SET GLOBAL slave_parallel_threads=10; +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB; +--save_master_pos + +--connection server_2 +--sync_with_master +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=1; +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,slave_discard_xid_for_gtid_0_x_1000"; +CALL mtr.add_suppression("Unexpected break of being relay-logged GTID"); + +--connection server_1 +INSERT INTO t2 VALUES (101); +INSERT INTO t2 VALUES (102); +INSERT INTO t2 VALUES (103); +INSERT INTO t2 VALUES (104); +INSERT INTO t2 VALUES (105); +# Inject a partial event group (missing XID at the end). The bug was that such +# partial group was not handled appropriately, leading to server deadlock. +SET gtid_seq_no=1000; +INSERT INTO t2 VALUES (106); +INSERT INTO t2 VALUES (107); +INSERT INTO t2 VALUES (108); +INSERT INTO t2 VALUES (109); +INSERT INTO t2 VALUES (110); +INSERT INTO t2 VALUES (111); +INSERT INTO t2 VALUES (112); +INSERT INTO t2 VALUES (113); +INSERT INTO t2 VALUES (114); +INSERT INTO t2 VALUES (115); +INSERT INTO t2 VALUES (116); +INSERT INTO t2 VALUES (117); +INSERT INTO t2 VALUES (118); +INSERT INTO t2 VALUES (119); +INSERT INTO t2 VALUES (120); +INSERT INTO t2 VALUES (121); +INSERT INTO t2 VALUES (122); +INSERT INTO t2 VALUES (123); +INSERT INTO t2 VALUES (124); +INSERT INTO t2 VALUES (125); +INSERT INTO t2 VALUES (126); +INSERT INTO t2 VALUES (127); +INSERT INTO t2 VALUES (128); +INSERT INTO t2 VALUES (129); +INSERT INTO t2 VALUES (130); +--source include/save_master_gtid.inc + +--connection server_2 +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +# The partial event group (a=106) should be rolled back and thus missing. +SELECT * FROM t2 WHERE a >= 100 ORDER BY a; + +# Cleanup +--source include/stop_slave.inc +SET GLOBAL debug_dbug=@old_dbug; +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc +SET DEBUG_SYNC= 'RESET'; + +--connection server_1 +DROP TABLE t2; +SET DEBUG_SYNC= 'RESET'; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_deadlock_victim.test b/mysql-test/suite/rpl/t/rpl_parallel_deadlock_victim.test new file mode 100644 index 00000000..ab634d29 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_deadlock_victim.test @@ -0,0 +1,86 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/master-slave.inc + + +--echo MDEV-31655: Parallel replication deadlock victim preference code erroneously removed +# The problem was that InnoDB would choose the wrong deadlock victim. +# Create a lot of transactions that can cause deadlocks, and use error +# injection to check that the first transactions in each group is never +# selected as deadlock victim. +--let $rows= 10 +--let $transactions= 5 +--let $gcos= 10 + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +BEGIN; +--disable_query_log +--let $i= 0 +while ($i < 10) { + eval INSERT INTO t1 VALUES ($i, 0); + inc $i; +} +--enable_query_log +COMMIT; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode; +eval set @@global.slave_parallel_threads= $transactions; +set @@global.slave_parallel_mode= conservative; +SET @old_dbug= @@GLOBAL.debug_dbug; +# This error injection will allow no retries for GTIDs divisible by 1000. +SET GLOBAL debug_dbug= "+d,rpl_mdev31655_zero_retries"; + +--connection server_1 +SET @old_dbug= @@SESSION.debug_dbug; +SET SESSION debug_dbug="+d,binlog_force_commit_id"; + +--let $j= 1 +while ($j <= $gcos) { + eval SET @commit_id= $j+1000; + --let $i= 0 + while ($i < $transactions) { + --disable_query_log + eval SET SESSION gtid_seq_no= 1000 + 1000*$j + $i; + BEGIN; + --let $k= 0 + while ($k < $rows) { + eval UPDATE t1 SET b=b+1 WHERE a=(($i+$k) MOD $rows); + inc $k; + } + COMMIT; + --enable_query_log + inc $i; + } + inc $j; +} + +SET SESSION debug_dbug= @old_dbug; +SELECT COUNT(*), SUM(a*100*b) FROM t1; + +--source include/save_master_gtid.inc + +--connection server_2 +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SET GLOBAL debug_dbug= @old_dbug; +SELECT COUNT(*), SUM(a*100*b) FROM t1; + + +# Clean up. +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +SET GLOBAL slave_parallel_mode=@old_parallel_mode; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_deadlock_victim2.test b/mysql-test/suite/rpl/t/rpl_parallel_deadlock_victim2.test new file mode 100644 index 00000000..522cec18 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_deadlock_victim2.test @@ -0,0 +1,83 @@ +--source include/master-slave.inc +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_binlog_format_statement.inc + +--connection master +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1(a INT) ENGINE=INNODB; +INSERT INTO t1 VALUES(1); +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc +--let $save_transaction_retries= `SELECT @@global.slave_transaction_retries` +--let $save_slave_parallel_threads= `SELECT @@global.slave_parallel_threads` +--let $save_slave_parallel_mode= `SELECT @@global.slave_parallel_mode` +set @@global.slave_parallel_threads= 2; +set @@global.slave_parallel_mode= OPTIMISTIC; +set @@global.slave_transaction_retries= 2; + +--echo *** MDEV-28776: rpl.rpl_mark_optimize_tbl_ddl fails with timeout on sync_with_master +# This was a failure where a transaction T1 could deadlock multiple times +# with T2, eventually exceeding the default --slave-transaction-retries=10. +# Root cause was MDEV-31655, causing InnoDB to wrongly choose T1 as deadlock +# victim over T2. If thread scheduling is right, it was possible for T1 to +# repeatedly deadlock, roll back, and have time to grab an S lock again before +# T2 woke up and got its waiting X lock, thus repeating the same deadlock over +# and over. +# Once the bug is fixed, it is not possible to re-create the same execution +# and thread scheduling. Instead we inject small sleeps in a way that +# triggered the problem when the bug was there, to demonstrate that the +# problem no longer occurs. + +--connection master +# T1 +SET @@gtid_seq_no= 100; +INSERT INTO t1 SELECT 1+a FROM t1; +# T2 +SET @@gtid_seq_no= 200; +INSERT INTO t1 SELECT 2+a FROM t1; + +SELECT * FROM t1 ORDER BY a; +--source include/save_master_gtid.inc + +--connection slave +SET @save_dbug= @@GLOBAL.debug_dbug; + +# Inject various delays to hint thread scheduling to happen in the way that +# triggered MDEV-28776. + +# Small delay starting T1 so it will be the youngest trx and be chosen over +# T2 as the deadlock victim by default in InnoDB. +SET GLOBAL debug_dbug="+d,rpl_parallel_delay_gtid_0_x_100_start"; + +# Small delay before taking insert X lock to give time for both T1 and T2 to +# get the S lock first and cause a deadlock. +SET GLOBAL debug_dbug="+d,rpl_write_record_small_sleep_gtid_100_200"; + +# Small delay after T2's wait on the X lock, to give time for T1 retry to +# re-aquire the T1 S lock first. +SET GLOBAL debug_dbug="+d,small_sleep_after_lock_wait"; + +# Delay deadlock kill of T2. +SET GLOBAL debug_dbug="+d,rpl_delay_deadlock_kill"; + +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SET GLOBAL debug_dbug= @save_dbug; +SELECT * FROM t1 ORDER BY a; + +# Cleanup. +--connection slave +--source include/stop_slave.inc +eval SET @@global.slave_parallel_threads= $save_slave_parallel_threads; +eval SET @@global.slave_parallel_mode= $save_slave_parallel_mode; +eval SET @@global.slave_transaction_retries= $save_transaction_retries; +--source include/start_slave.inc + +--connection master +DROP TABLE t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_domain.test b/mysql-test/suite/rpl/t/rpl_parallel_domain.test new file mode 100644 index 00000000..eda08cc2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_domain.test @@ -0,0 +1,87 @@ +# Test should work with both conservative and optimistic modes + +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/master-slave.inc + +# Test various aspects of parallel replication. + +--connection server_2 +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +--error ER_SLAVE_MUST_STOP +SET GLOBAL slave_parallel_threads=10; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=10; + +# Check that we do not spawn any worker threads when no slave is running. +SELECT IF(COUNT(*) < 10, "OK", CONCAT("Found too many system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user"; + +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +# Check that worker threads get spawned when slave starts. +SELECT IF(COUNT(*) >= 10, "OK", CONCAT("Found too few system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user"; +# ... and that worker threads get removed when slave stops. +--source include/stop_slave.inc +SELECT IF(COUNT(*) < 10, "OK", CONCAT("Found too many system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user"; +--source include/start_slave.inc +SELECT IF(COUNT(*) >= 10, "OK", CONCAT("Found too few system user processes: ", COUNT(*))) FROM information_schema.processlist WHERE user = "system user"; + +--echo *** Test long-running query in domain 1 can run in parallel with short queries in domain 0 *** + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM; +CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1); +--save_master_pos + +--connection server_2 +--sync_with_master + +# Block the table t1 to simulate a replicated query taking a long time. +--connect (con_temp1,127.0.0.1,root,,test,$SERVER_MYPORT_2,) +LOCK TABLE t1 WRITE; + +--connection server_1 +SET gtid_domain_id=1; +# This query will be blocked on the slave until UNLOCK TABLES. +INSERT INTO t1 VALUES (2); +SET gtid_domain_id=0; +# These t2 queries can be replicated in parallel with the prior t1 query, as +# they are in a separate replication domain. +INSERT INTO t2 VALUES (2); +INSERT INTO t2 VALUES (3); +BEGIN; +INSERT INTO t2 VALUES (4); +INSERT INTO t2 VALUES (5); +COMMIT; +INSERT INTO t2 VALUES (6); + +--connection server_2 +--let $wait_condition= SELECT COUNT(*) = 6 FROM t2 +--source include/wait_condition.inc + +SELECT * FROM t2 ORDER by a; + +--connection con_temp1 +SELECT * FROM t1; +UNLOCK TABLES; + +--connection server_2 +--let $wait_condition= SELECT COUNT(*) = 2 FROM t1 +--source include/wait_condition.inc + +SELECT * FROM t1 ORDER BY a; + +# Clean up. +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t1,t2; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_domain_slave_single_grp.test b/mysql-test/suite/rpl/t/rpl_parallel_domain_slave_single_grp.test new file mode 100644 index 00000000..856efd06 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_domain_slave_single_grp.test @@ -0,0 +1,128 @@ +# Test is independent of slave_parallel_mode +--echo *** Test two transactions in different domains committed in opposite order on slave but in a single group commit. *** + +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/master-slave.inc + +# Test various aspects of parallel replication. + +--connection server_2 +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=10; +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM; +CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1); +--save_master_pos + +--connection server_2 +--sync_with_master +--source include/stop_slave.inc + +--connection server_1 +# Use a stored function to inject a debug_sync into the appropriate THD. +# The function does nothing on the master, and on the slave it injects the +# desired debug_sync action(s). +SET sql_log_bin=0; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + RETURN x; + END +|| +--delimiter ; +SET sql_log_bin=1; + +SET @old_format= @@SESSION.binlog_format; +SET binlog_format='statement'; +SET gtid_domain_id=1; +INSERT INTO t2 VALUES (foo(10, + 'commit_before_enqueue SIGNAL ready1 WAIT_FOR cont1', + 'commit_after_release_LOCK_prepare_ordered SIGNAL ready2')); + +--connection server_2 +FLUSH LOGS; +--source include/wait_for_binlog_checkpoint.inc +SET sql_log_bin=0; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + IF d1 != '' THEN + SET debug_sync = d1; + END IF; + IF d2 != '' THEN + SET debug_sync = d2; + END IF; + RETURN x; + END +|| +--delimiter ; +SET sql_log_bin=1; +SET @old_format=@@GLOBAL.binlog_format; +SET GLOBAL binlog_format=statement; +# We need to restart all parallel threads for the new global setting to +# be copied to the session-level values. +SET GLOBAL slave_parallel_threads=0; +SET GLOBAL slave_parallel_threads=10; +--source include/start_slave.inc + +# First make sure the first insert is ready to commit, but not queued yet. +SET debug_sync='now WAIT_FOR ready1'; + +--connection server_1 +SET gtid_domain_id=2; +INSERT INTO t2 VALUES (foo(11, + 'commit_before_enqueue SIGNAL ready3 WAIT_FOR cont3', + 'commit_after_release_LOCK_prepare_ordered SIGNAL ready4 WAIT_FOR cont4')); +SET gtid_domain_id=0; +SELECT * FROM t2 WHERE a >= 10 ORDER BY a; + +--connection server_2 +# Now wait for the second insert to queue itself as the leader, and then +# wait for more commits to queue up. +SET debug_sync='now WAIT_FOR ready3'; +SET debug_sync='now SIGNAL cont3'; +SET debug_sync='now WAIT_FOR ready4'; +# Now allow the first insert to queue up to participate in group commit. +SET debug_sync='now SIGNAL cont1'; +SET debug_sync='now WAIT_FOR ready2'; +# Finally allow the second insert to proceed and do the group commit. +SET debug_sync='now SIGNAL cont4'; + +--let $wait_condition= SELECT COUNT(*) = 2 FROM t2 WHERE a >= 10 +--source include/wait_condition.inc +SELECT * FROM t2 WHERE a >= 10 ORDER BY a; +# The two INSERT transactions should have been committed in opposite order, +# but in the same group commit (seen by precense of cid=# in the SHOW +# BINLOG output). +--let $binlog_file= slave-bin.000002 +--source include/show_binlog_events.inc +FLUSH LOGS; +--source include/wait_for_binlog_checkpoint.inc + + +# Clean up. +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc +SET DEBUG_SYNC= 'RESET'; +SET GLOBAL binlog_format=@old_format; + +--connection server_1 +DROP function foo; +DROP TABLE t1,t2; +SET DEBUG_SYNC= 'RESET'; +SET GLOBAL binlog_format=@old_format; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_free_deferred_event.test b/mysql-test/suite/rpl/t/rpl_parallel_free_deferred_event.test new file mode 100644 index 00000000..41f372ed --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_free_deferred_event.test @@ -0,0 +1,67 @@ +--echo *** MDEV-5788 Incorrect free of rgi->deferred_events in parallel replication *** + +--source include/have_innodb.inc +--source include/master-slave.inc + +--connection server_2 +--source include/stop_slave.inc +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +--save_master_pos + +--connection server_2 +--sync_with_master +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +# Use just two worker threads, so we are sure to get the rpl_group_info added +# to the free list, which is what triggered the bug. +--source include/stop_slave.inc +SET GLOBAL replicate_ignore_table="test.t3"; +SET GLOBAL slave_parallel_threads=2; +--source include/start_slave.inc + +--connection server_1 +INSERT INTO t3 VALUES (100, rand()); +INSERT INTO t3 VALUES (101, rand()); +--save_master_pos + +--connection server_2 +--sync_with_master + +--connection server_1 +INSERT INTO t3 VALUES (102, rand()); +INSERT INTO t3 VALUES (103, rand()); +INSERT INTO t3 VALUES (104, rand()); +INSERT INTO t3 VALUES (105, rand()); +--save_master_pos + +--connection server_2 +--sync_with_master +--source include/stop_slave.inc +SET GLOBAL replicate_ignore_table=""; +--source include/start_slave.inc + +--connection server_1 +INSERT INTO t3 VALUES (106, rand()); +INSERT INTO t3 VALUES (107, rand()); +--save_master_pos + +--connection server_2 +--sync_with_master +--replace_column 2 # +SELECT * FROM t3 WHERE a >= 100 ORDER BY a; + + +# Clean up. +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t3; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_ftwrl.test b/mysql-test/suite/rpl/t/rpl_parallel_ftwrl.test new file mode 100644 index 00000000..308fcd0b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_ftwrl.test @@ -0,0 +1,143 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/have_binlog_format_mixed.inc +--source include/master-slave.inc + +--connection slave +--source include/stop_slave.inc +SET @old_parallel_threads= @@GLOBAL.slave_parallel_threads; +SET GLOBAL slave_parallel_threads=3; +SET @old_parallel_mode= @@GLOBAL.slave_parallel_mode; +SET GLOBAL slave_parallel_mode=aggressive; +SET @old_dbug= @@GLOBAL.debug_dbug; +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--echo *** MDEV-31509: Lost data with FTWRL and STOP SLAVE +# The bug was as follows: +# 1. Event groups T1 and T2 are queued but not started yet. +# 2. FLUSH TABLE WITH READ LOCKS starts, sets rpl_parallel_entry::pause_sub_id +# 3. T2 Sees pause_sub_id, goes to wait for the pause to complete. +# 4. FTWRL completes, UNLOCK TABLES is run. +# 5. STOP SLAVE is run, sets rpl_parallel_entry::stop_sub_id. +# 6. T2 wakes up after FTWRL pause, only now sets +# rpl_parallel_entry::largest_started_sub_id. This is the bug, +# largest_started_sub_id is set too late here. +# 7. T1 starts, it sees stop_sub_id<T1, so T1 is skipped due to STOP SLAVE. +# 8. T2 continues, its check for stop_sub_id was before STOP SLAVE. So T2 is +# wrongly applied, silently losing transaction T1. + + +--connection master +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +CREATE TABLE t2 (a INT PRIMARY KEY, b INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (0,0); +INSERT INTO t2 VALUES (0,0); +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc + +--connection slave +--echo *** Arrange for T1 to delay before entering GCO wait. +SET GLOBAL debug_dbug="+d,gco_wait_delay_gtid_0_x_99"; +--echo *** Arrange for T2 to wait for FTWRL to start. +SET GLOBAL debug_dbug="+d,hold_worker_on_schedule"; +--echo *** Arrange for T2 to delay wakeup from FTWRL pause. +SET GLOBAL debug_dbug="+d,delay_ftwrl_wait_gtid_0_x_100"; + +--connection master +--echo *** Event group T1 +SET SESSION gtid_seq_no=99; +INSERT INTO t1 VALUES (1,1); + +--connection slave +--echo *** 1a. Wait for T1 to be queued. +SET debug_sync="now WAIT_FOR gco_wait_paused"; + +--connection master +--echo *** Event group T2 +SET SESSION gtid_seq_no=100; +INSERT INTO t2 VALUES (2,2); + +--connection slave +--echo *** 1b. Wait for T2 to be queued. +SET debug_sync= "now WAIT_FOR reached_pause"; + +--connection slave1 +--echo *** 2. Run FTWRL +SET GLOBAL debug_dbug= "+d,pause_for_ftwrl_wait"; +send FLUSH TABLES WITH READ LOCK; + +--connection slave +SET debug_sync= "now WAIT_FOR pause_ftwrl_waiting"; + +--echo *** 3. Wait for T2 to be waiting for FTWRL pause +SET debug_sync= "now SIGNAL continue_worker"; +--let $wait_condition= SELECT count(*) = 1 FROM information_schema.processlist WHERE state LIKE "%Waiting due to global read lock%" and command="Slave_worker"; +--source include/wait_condition.inc + +--echo *** 4. FTWRL completes, UNLOCK TABLES. +SET debug_sync="now SIGNAL pause_ftwrl_cont"; + +--connection slave1 +reap; +UNLOCK TABLES; + +--connection slave +--echo *** T2 is now ready to proceed after FTWRL pause, but did not wake up yet. +SET debug_sync="now WAIT_FOR pause_wait_started"; + +--echo *** 5. STOP SLAVE is run. +--connection slave1 +SET GLOBAL debug_dbug="+d,rpl_parallel_wait_for_done_trigger"; +send STOP SLAVE; + +--connection slave +SET debug_sync="now WAIT_FOR wait_for_done_waiting"; + +--echo *** 5. T2 wakes up after FTWRL pause, reaches wait_for_prior_commit(). +SET debug_sync="now SIGNAL pause_wait_continue"; +--let $wait_condition= SELECT count(*) = 1 FROM information_schema.processlist WHERE state LIKE "%Waiting for prior transaction to commit%" and command="Slave_worker"; +--source include/wait_condition.inc + +--echo *** 6. T1 starts. +SET debug_sync="now SIGNAL gco_wait_cont"; + +--connection slave1 +reap; + +--connection slave +--source include/wait_for_slave_to_stop.inc + +--connection master +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +--source include/save_master_gtid.inc + +--connection slave +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + +# The bug here was that T2 was errorneously replicated while T1 was +# being skipped due to STOP SLAVE. So the @@gtid_slave_pos was at T2, +# but we were missing the data from T1. +SELECT @@GLOBAL.gtid_slave_pos; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +--echo *** Clean up. +--connection slave +--source include/stop_slave.inc +SET DEBUG_SYNC= "RESET"; +SET GLOBAL slave_parallel_threads= @old_parallel_threads; +SET GLOBAL slave_parallel_mode= @old_parallel_mode; +SET GLOBAL debug_dbug=@old_dbug; +--source include/start_slave.inc + +--connection master +DROP TABLE t1, t2; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_gco_wait_kill.test b/mysql-test/suite/rpl/t/rpl_parallel_gco_wait_kill.test new file mode 100644 index 00000000..c5d2b85c --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_gco_wait_kill.test @@ -0,0 +1,369 @@ +--echo *** Test killing thread that is waiting to start transaction until previous transaction commits *** + +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/have_binlog_format_statement.inc +--source include/master-slave.inc + +--connection server_2 +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +SET @old_parallel_mode= @@GLOBAL.slave_parallel_mode; +--source include/stop_slave.inc +SET sql_log_bin=0; +CALL mtr.add_suppression("Query execution was interrupted"); +CALL mtr.add_suppression("Slave: Connection was killed"); +CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends"); +SET sql_log_bin=1; +SET GLOBAL slave_parallel_threads=10; +SET GLOBAL slave_parallel_mode= 'conservative'; +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_1 +--connect (con_temp3,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +--connect (con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +--connect (con_temp5,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +# MDEV-515 takes X-lock on the table for the first insert. +# So concurrent insert won't happen on the table +INSERT INTO t3 VALUES(100, 100); +--save_master_pos + +--connection server_2 +--sync_with_master + +--connection server_1 +# Use a stored function to inject a debug_sync into the appropriate THD. +# The function does nothing on the master, and on the slave it injects the +# desired debug_sync action(s). +SET sql_log_bin=0; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + RETURN x; + END +|| +--delimiter ; +SET sql_log_bin=1; + +--connection server_2 +SET sql_log_bin=0; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + IF d1 != '' THEN + SET debug_sync = d1; + END IF; + IF d2 != '' THEN + SET debug_sync = d2; + END IF; + RETURN x; + END +|| +--delimiter ; +SET sql_log_bin=1; +# We need to restart all parallel threads for the new global setting to +# be copied to the session-level values. +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=0; +SET GLOBAL slave_parallel_threads=4; +--source include/start_slave.inc + + +# We set up four transactions T1, T2, T3, and T4 on the master. T2, T3, and T4 +# can run in parallel with each other (same group commit and commit id), +# but not in parallel with T1. +# +# We use four worker threads, each Ti will be queued on each their own +# worker thread. We will delay T1 commit, T3 will wait for T1 to begin +# commit before it can start. We will kill T3 during this wait, and +# check that everything works correctly. +# +# It is rather tricky to get the correct thread id of the worker to kill. +# We start by injecting four dummy transactions in a debug_sync-controlled +# manner to be able to get known thread ids for the workers in a pool with +# just 4 worker threads. Then we let in each of the real test transactions +# T1-T4 one at a time in a way which allows us to know which transaction +# ends up with which thread id. + +--connection server_1 +SET gtid_domain_id=2; +BEGIN; +# This debug_sync will linger on and be used to control T4 later. +INSERT INTO t3 VALUES (70, foo(70, + 'rpl_parallel_start_waiting_for_prior SIGNAL t4_waiting', '')); +INSERT INTO t3 VALUES (60, foo(60, + 'ha_write_row_end SIGNAL d2_query WAIT_FOR d2_cont2', + 'rpl_parallel_end_of_group SIGNAL d2_done WAIT_FOR d2_cont')); +COMMIT; +SET gtid_domain_id=0; + +--connection server_2 +SET debug_sync='now WAIT_FOR d2_query'; +--let $d2_thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%foo(60%' AND INFO NOT LIKE '%LIKE%'` + +--connection server_1 +SET gtid_domain_id=1; +BEGIN; +# These debug_sync's will linger on and be used to control T3 later. +INSERT INTO t3 VALUES (61, foo(61, + 'rpl_parallel_start_waiting_for_prior SIGNAL t3_waiting', + 'rpl_parallel_start_waiting_for_prior_killed SIGNAL t3_killed')); +INSERT INTO t3 VALUES (62, foo(62, + 'ha_write_row_end SIGNAL d1_query WAIT_FOR d1_cont2', + 'rpl_parallel_end_of_group SIGNAL d1_done WAIT_FOR d1_cont')); +COMMIT; +SET gtid_domain_id=0; + +--connection server_2 +SET debug_sync='now WAIT_FOR d1_query'; +--let $d1_thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%foo(62%' AND INFO NOT LIKE '%LIKE%'` + +--connection server_1 +SET gtid_domain_id=0; +INSERT INTO t3 VALUES (63, foo(63, + 'ha_write_row_end SIGNAL d0_query WAIT_FOR d0_cont2', + 'rpl_parallel_end_of_group SIGNAL d0_done WAIT_FOR d0_cont')); + +--connection server_2 +SET debug_sync='now WAIT_FOR d0_query'; +--let $d0_thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%foo(63%' AND INFO NOT LIKE '%LIKE%'` + +--connection server_1 +SET gtid_domain_id=3; +BEGIN; +# These debug_sync's will linger on and be used to control T2 later. +INSERT INTO t3 VALUES (68, foo(68, + 'rpl_parallel_start_waiting_for_prior SIGNAL t2_waiting', '')); +INSERT INTO t3 VALUES (69, foo(69, + 'ha_write_row_end SIGNAL d3_query WAIT_FOR d3_cont2', + 'rpl_parallel_end_of_group SIGNAL d3_done WAIT_FOR d3_cont')); +COMMIT; +SET gtid_domain_id=0; + +--connection server_2 +SET debug_sync='now WAIT_FOR d3_query'; +--let $d3_thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%foo(69%' AND INFO NOT LIKE '%LIKE%'` + +SET debug_sync='now SIGNAL d2_cont2'; +SET debug_sync='now WAIT_FOR d2_done'; +SET debug_sync='now SIGNAL d1_cont2'; +SET debug_sync='now WAIT_FOR d1_done'; +SET debug_sync='now SIGNAL d0_cont2'; +SET debug_sync='now WAIT_FOR d0_done'; +SET debug_sync='now SIGNAL d3_cont2'; +SET debug_sync='now WAIT_FOR d3_done'; + +# Now prepare the real transactions T1, T2, T3, T4 on the master. + +--connection con_temp3 +# Create transaction T1. +INSERT INTO t3 VALUES (64, foo(64, + 'rpl_parallel_before_mark_start_commit SIGNAL t1_waiting WAIT_FOR t1_cont', '')); + +# Create transaction T2, as a group commit leader on the master. +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2 WAIT_FOR master_cont2'; +send INSERT INTO t3 VALUES (65, foo(65, '', '')); + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued2'; + +--connection con_temp4 +# Create transaction T3, participating in T2's group commit. +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3'; +send INSERT INTO t3 VALUES (66, foo(66, '', '')); + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued3'; + +--connection con_temp5 +# Create transaction T4, participating in group commit with T2 and T3. +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued4'; +send INSERT INTO t3 VALUES (67, foo(67, '', '')); + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued4'; +SET debug_sync='now SIGNAL master_cont2'; + +--connection con_temp3 +REAP; +--connection con_temp4 +REAP; +--connection con_temp5 +REAP; + +--connection server_1 +SELECT * FROM t3 WHERE a >= 60 ORDER BY a; +SET debug_sync='RESET'; + +--connection server_2 +# Now we have the four transactions pending for replication on the slave. +# Let them be queued for our three worker threads in a controlled fashion. +# We put them at a stage where T1 is delayed and T3 is waiting for T1 to +# commit before T3 can start. Then we kill T3. + +# Make the worker D0 free, and wait for T1 to be queued in it. +SET debug_sync='now SIGNAL d0_cont'; +SET debug_sync='now WAIT_FOR t1_waiting'; + +# Make the worker D3 free, and wait for T2 to be queued in it. +SET debug_sync='now SIGNAL d3_cont'; +SET debug_sync='now WAIT_FOR t2_waiting'; + +# Now release worker D1, and wait for T3 to be queued in it. +# T3 will wait for T1 to commit before it can start. +SET debug_sync='now SIGNAL d1_cont'; +SET debug_sync='now WAIT_FOR t3_waiting'; + +# Release worker D2. Wait for T4 to be queued, so we are sure it has +# received the debug_sync signal (else we might overwrite it with the +# next debug_sync). +SET debug_sync='now SIGNAL d2_cont'; +SET debug_sync='now WAIT_FOR t4_waiting'; + +# Now we kill the waiting transaction T3 in worker D1. +--replace_result $d1_thd_id THD_ID +eval KILL $d1_thd_id; + +# Wait until T3 has reacted on the kill. +SET debug_sync='now WAIT_FOR t3_killed'; + +# Now we can allow T1 to proceed. +SET debug_sync='now SIGNAL t1_cont'; + +--let $slave_sql_errno= 1317,1927,1964 +--source include/wait_for_slave_sql_error.inc +STOP SLAVE IO_THREAD; +# Since T2, T3, and T4 run in parallel, we can not be sure if T2 will have time +# to commit or not before the stop. However, T1 should commit, and T3/T4 may +# not have committed. (After slave restart we check that all become committed +# eventually). +SELECT * FROM t3 WHERE a >= 60 AND a != 65 ORDER BY a; + +# Now we have to disable the debug_sync statements, so they do not trigger +# when the events are retried. +SET debug_sync='RESET'; +SET GLOBAL slave_parallel_threads=0; +SET GLOBAL slave_parallel_threads=10; +SET sql_log_bin=0; +DROP FUNCTION foo; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + RETURN x; + END +|| +--delimiter ; +SET sql_log_bin=1; + +--connection server_1 +UPDATE t3 SET b=b+1 WHERE a=60; +--save_master_pos + +--connection server_2 +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t3 WHERE a >= 60 ORDER BY a; +# Restore the foo() function. +SET sql_log_bin=0; +DROP FUNCTION foo; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + IF d1 != '' THEN + SET debug_sync = d1; + END IF; + IF d2 != '' THEN + SET debug_sync = d2; + END IF; + RETURN x; + END +|| +--delimiter ; +SET sql_log_bin=1; + +--connection server_2 +# Respawn all worker threads to clear any left-over debug_sync or other stuff. +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=0; +SET GLOBAL slave_parallel_threads=10; +--source include/start_slave.inc + +--echo *** 5. Test killing thread that is waiting for queue of max length to shorten *** + +# Find the thread id of the driver SQL thread that we want to kill. +--let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE '%Slave has read all relay log%' +--source include/wait_condition.inc +--let $thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE '%Slave has read all relay log%'` +SET @old_max_queued= @@GLOBAL.slave_parallel_max_queued; +SET GLOBAL slave_parallel_max_queued=9000; + +--connection server_1 +--let bigstring= `SELECT REPEAT('x', 10000)` +# Create an event that will wait to be signalled. +INSERT INTO t3 VALUES (80, foo(0, + 'ha_write_row_end SIGNAL query_waiting WAIT_FOR query_cont', '')); + +--connection server_2 +SET debug_sync='now WAIT_FOR query_waiting'; +# Inject that the SQL driver thread will signal `wait_queue_ready' to debug_sync +# as it goes to wait for the event queue to become smaller than the value of +# @@slave_parallel_max_queued. +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,rpl_parallel_wait_queue_max"; + +--connection server_1 +--disable_query_log +# Create an event that will fill up the queue. +# The Xid event at the end of the event group will have to wait for the Query +# event with the INSERT to drain so the queue becomes shorter. However that in +# turn waits for the prior event group to continue. +eval INSERT INTO t3 VALUES (81, LENGTH('$bigstring')); +--enable_query_log +SELECT * FROM t3 WHERE a >= 80 ORDER BY a; + +--connection server_2 +SET debug_sync='now WAIT_FOR wait_queue_ready'; + +--replace_result $thd_id THD_ID +eval KILL $thd_id; + +SET debug_sync='now WAIT_FOR wait_queue_killed'; +SET debug_sync='now SIGNAL query_cont'; + +--let $slave_sql_errno= 1317,1927,1964 +--source include/wait_for_slave_sql_error.inc +STOP SLAVE IO_THREAD; + +SET GLOBAL debug_dbug=@old_dbug; +SET GLOBAL slave_parallel_max_queued= @old_max_queued; + +--connection server_1 +INSERT INTO t3 VALUES (82,0); +--save_master_pos + +--connection server_2 +SET debug_sync='RESET'; +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t3 WHERE a >= 80 ORDER BY a; + +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_mode=@old_parallel_mode; +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc +SET DEBUG_SYNC= 'RESET'; + +--connection server_1 +DROP function foo; +DROP TABLE t3; +SET DEBUG_SYNC= 'RESET'; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_gtid_slave_pos_update_fail.test b/mysql-test/suite/rpl/t/rpl_parallel_gtid_slave_pos_update_fail.test new file mode 100644 index 00000000..da1a07d3 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_gtid_slave_pos_update_fail.test @@ -0,0 +1,98 @@ +# MDEV-6549, failing to update gtid_slave_pos for a transaction that was retried. + +# The problem was that when a transaction updates the mysql.gtid_slave_pos +# table, it clears the flag that marks that there is a GTID position that +# needs to be updated. Then, if the transaction got killed after that due +# to a deadlock, the subsequent retry would fail to notice that the GTID needs +# to be recorded in gtid_slave_pos. +# +# (In the original bug report, the symptom was an assertion; this was however +# just a side effect of the missing update of gtid_slave_pos, which also +# happened to cause a missing clear of OPTION_GTID_BEGIN). +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +# Must use statement-based binlogging. Otherwise the transaction will not be +# binlogged at all, as it modifies no rows. +--source include/have_binlog_format_statement.inc +--source include/master-slave.inc + +--connection server_2 +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=10; +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t4 (a INT PRIMARY KEY, b INT, KEY b_idx(b)) ENGINE=InnoDB; +INSERT INTO t4 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6); +--connect (con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +--connect (con2,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +--save_master_pos + +--connection server_2 +--sync_with_master +--source include/stop_slave.inc + +# Create two transactions that can run in parallel on the slave but cause +# a deadlock if the second runs before the first. +--connection con1 +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1'; +send UPDATE t4 SET b=NULL WHERE a=6; +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued1'; + +--connection con2 +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2'; +send DELETE FROM t4 WHERE b <= 1; + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued2'; +SET debug_sync='now SIGNAL master_cont1'; + +--connection con1 +REAP; +--connection con2 +REAP; +SET debug_sync='RESET'; +--save_master_pos +--let $last_gtid= `SELECT @@last_gtid` + +--connection server_2 +# Disable the usual skip of gap locks for transactions that are run in +# parallel, using DBUG. This allows the deadlock to occur, and this in turn +# triggers a retry of the second transaction, and the code that was buggy and +# caused the gtid_slave_pos update to be skipped in the retry. +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,disable_thd_need_ordering_with"; +--source include/start_slave.inc +--sync_with_master +SET GLOBAL debug_dbug=@old_dbug; + +SELECT * FROM t4 ORDER BY a; +# Check that the GTID of the second transaction was correctly recorded in +# gtid_slave_pos, in the variable as well as in the table. +--replace_result $last_gtid GTID +eval SET @last_gtid= '$last_gtid'; +SELECT IF(@@gtid_slave_pos LIKE CONCAT('%',@last_gtid,'%'), "GTID found ok", + CONCAT("GTID ", @last_gtid, " not found in gtid_slave_pos=", @@gtid_slave_pos)) + AS result; +SELECT "ROW FOUND" AS `Is the row found?` + FROM mysql.gtid_slave_pos + WHERE CONCAT(domain_id, "-", server_id, "-", seq_no) = @last_gtid; + +# Clean up. +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc +SET DEBUG_SYNC= 'RESET'; + +--connection server_1 +DROP TABLE t4; +SET DEBUG_SYNC= 'RESET'; +--disconnect con1 +--disconnect con2 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_ignore_error_on_rotate.test b/mysql-test/suite/rpl/t/rpl_parallel_ignore_error_on_rotate.test new file mode 100644 index 00000000..2fab9f80 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_ignore_error_on_rotate.test @@ -0,0 +1,96 @@ +--echo *** MDEV-6551: Some replication errors are ignored if slave_parallel_threads > 0 *** + +--source include/have_innodb.inc +--source include/have_binlog_format_statement.inc +--source include/master-slave.inc + +--connection server_2 +--source include/stop_slave.inc +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode; +SET GLOBAL slave_parallel_threads=1; +CHANGE MASTER TO master_use_gtid=slave_pos; +CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends"); +--source include/start_slave.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB; +SET gtid_domain_id=1; +INSERT INTO t2 VALUES (1); +SET gtid_domain_id=0; +SET gtid_domain_id=2; +INSERT INTO t2 VALUES (2); +SET gtid_domain_id=0; +INSERT INTO t2 VALUES (31); +--let $gtid1= `SELECT @@LAST_GTID` +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads= 0; +--source include/start_slave.inc + +# Force a duplicate key error on the slave. +SET sql_log_bin= 0; +INSERT INTO t2 VALUES (32); +SET sql_log_bin= 1; + +--connection server_1 +INSERT INTO t2 VALUES (32); +--let $gtid2= `SELECT @@LAST_GTID` +# Rotate the binlog; the bug is triggered when the master binlog file changes +# after the event group that causes the duplicate key error. +FLUSH LOGS; +INSERT INTO t2 VALUES (33); +INSERT INTO t2 VALUES (34); +SELECT * FROM t2 WHERE a >= 30 ORDER BY a; +--source include/save_master_gtid.inc + +--connection server_2 +--let $slave_sql_errno= 1062 +--source include/wait_for_slave_sql_error.inc + +--connection server_2 +--source include/stop_slave_io.inc +SET GLOBAL slave_parallel_threads=10; +START SLAVE; + +--let $slave_sql_errno= 1062 +--source include/wait_for_slave_sql_error.inc + +# Note: IO thread is still running at this point. +# The bug seems to have been that restarting the SQL thread after an error with +# the IO thread still running, somehow picks up a later relay log position and +# thus ends up skipping the failing event, rather than re-executing. + +START SLAVE SQL_THREAD; +--let $slave_sql_errno= 1062 +--source include/wait_for_slave_sql_error.inc + +SELECT * FROM t2 WHERE a >= 30 ORDER BY a; + +# Skip the duplicate error, so we can proceed. +--error ER_SLAVE_SKIP_NOT_IN_GTID +SET sql_slave_skip_counter= 1; +--source include/stop_slave_io.inc +--disable_query_log +eval SET GLOBAL gtid_slave_pos = REPLACE(@@gtid_slave_pos, "$gtid1", "$gtid2"); +--enable_query_log +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + +SELECT * FROM t2 WHERE a >= 30 ORDER BY a; + +# Clean up. +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +SET GLOBAL slave_parallel_mode=@old_parallel_mode; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t2; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_ignored_errors.test b/mysql-test/suite/rpl/t/rpl_parallel_ignored_errors.test new file mode 100644 index 00000000..493385f1 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_ignored_errors.test @@ -0,0 +1,115 @@ +# ==== Purpose ==== +# +# Test verifies that, in parallel replication, transaction failure notification +# is propagated to all the workers. Workers should abort the execution of +# transaction event groups, whose event positions are higher than the failing +# transaction group. +# +# ==== Implementation ==== +# +# Steps: +# 0 - Create a table t1 on master which has a primary key. Enable parallel +# replication on slave with slave_parallel_mode='optimistic' and +# slave_parallel_threads=3. +# 1 - On slave start a transaction and execute a local INSERT statement +# which will insert value 32. This is done to block the INSERT coming +# from master. +# 2 - On master execute an INSERT statement with value 32, so that it is +# blocked on slave. +# 3 - On slave enable a debug sync point such that it holds the worker thread +# execution as soon as work is scheduled to it. +# 4 - INSERT value 33 on master. It will be held on slave by other worker +# thread due to debug simulation. +# 5 - INSERT value 34 on master. +# 6 - On slave, enusre that INSERT 34 has reached a state where it waits for +# its prior transactions to commit. +# 7 - Commit the local INSERT 32 on slave server so that first worker will +# error out. +# 8 - Now send a continue signal to second worker processing 33. It should +# wakeup and propagate the error to INSERT 34. +# 9 - Upon slave stop due to error, check that no rows are found after the +# failed INSERT 32. +# +# ==== References ==== +# +# MDEV-20645: Replication consistency is broken as workers miss the error +# notification from an earlier failed group. +# + +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/have_binlog_format_statement.inc +--source include/master-slave.inc + +--enable_connect_log +--connection server_2 +--source include/stop_slave.inc +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode; +SET @old_debug= @@GLOBAL.debug_dbug; +SET GLOBAL slave_parallel_mode='optimistic'; +SET GLOBAL slave_parallel_threads= 3; +CHANGE MASTER TO master_use_gtid=slave_pos; +CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends"); +--source include/start_slave.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=InnoDB; +# MDEV-515 takes X-lock on the table for the first insert. +# So concurrent insert won't happen on the table +INSERT INTO t1 VALUES(1); +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc + +--connect (con_temp2,127.0.0.1,root,,test,$SERVER_MYPORT_2,) +BEGIN; +INSERT INTO t1 VALUES (32); + +--connection server_1 +INSERT INTO t1 VALUES (32); + +--connection server_2 +--let $wait_condition= SELECT COUNT(*) = 1 FROM information_schema.processlist WHERE info like "INSERT INTO t1 VALUES (32)" +--source include/wait_condition.inc +SET GLOBAL debug_dbug="+d,hold_worker_on_schedule"; +SET debug_sync="debug_sync_action SIGNAL reached_pause WAIT_FOR continue_worker"; + +--connection server_1 +SET gtid_seq_no=100; +INSERT INTO t1 VALUES (33); + +--connection server_2 +SET debug_sync='now WAIT_FOR reached_pause'; + +--connection server_1 +INSERT INTO t1 VALUES (34); + +--connection server_2 +--let $wait_condition= SELECT COUNT(*) = 1 FROM information_schema.processlist WHERE state like "Waiting for prior transaction to commit" +--source include/wait_condition.inc +--connection con_temp2 +COMMIT; + +# Clean up. +--connection server_2 +--source include/stop_slave.inc +--let $assert_cond= COUNT(*) = 0 FROM t1 WHERE a>32 +--let $assert_text= table t1 should have zero rows where a>32 +--source include/assert.inc +SELECT * FROM t1 WHERE a>32; +DELETE FROM t1 WHERE a=32; + +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +SET GLOBAL slave_parallel_mode=@old_parallel_mode; +SET GLOBAL debug_dbug=@old_debug; +SET DEBUG_SYNC= 'RESET'; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t1; +--disable_connect_log +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_incorrect_relay_pos.test b/mysql-test/suite/rpl/t/rpl_parallel_incorrect_relay_pos.test new file mode 100644 index 00000000..e0226d94 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_incorrect_relay_pos.test @@ -0,0 +1 @@ +--source include/rpl_parallel_incorrect_relay_pos.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_innodb_lock_conflict.test b/mysql-test/suite/rpl/t/rpl_parallel_innodb_lock_conflict.test new file mode 100644 index 00000000..90304937 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_innodb_lock_conflict.test @@ -0,0 +1,107 @@ +--echo ***MDEV-5914: Parallel replication deadlock due to InnoDB lock conflicts *** + +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/master-slave.inc + +--connection server_2 +SET sql_log_bin=0; +CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends"); +SET sql_log_bin=1; +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=10; +CHANGE MASTER TO master_use_gtid=slave_pos; + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t4 (a INT PRIMARY KEY, b INT, KEY b_idx(b)) ENGINE=InnoDB; +INSERT INTO t4 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6); +--connect (con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +--connect (con2,127.0.0.1,root,,test,$SERVER_MYPORT_1,) + +# Create a group commit with UPDATE and DELETE, in that order. +# The bug was that while the UPDATE's row lock does not block the DELETE, the +# DELETE's gap lock _does_ block the UPDATE. This could cause a deadlock +# on the slave. +--connection con1 +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1'; +send UPDATE t4 SET b=NULL WHERE a=6; +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued1'; + +--connection con2 +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2'; +send DELETE FROM t4 WHERE b <= 3; + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued2'; +SET debug_sync='now SIGNAL master_cont1'; + +--connection con1 +REAP; +--connection con2 +REAP; +SET debug_sync='RESET'; +--save_master_pos + +--connection server_2 +--source include/start_slave.inc +--sync_with_master +--source include/stop_slave.inc + +SELECT * FROM t4 ORDER BY a; + + +# Another example, this one with INSERT vs. DELETE +--connection server_1 +DELETE FROM t4; +INSERT INTO t4 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6); + +# Create a group commit with INSERT and DELETE, in that order. +# The bug was that while the INSERT's insert intention lock does not block +# the DELETE, the DELETE's gap lock _does_ block the INSERT. This could cause +# a deadlock on the slave. +--connection con1 +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1'; +send INSERT INTO t4 VALUES (7, NULL); +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued1'; + +--connection con2 +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2'; +send DELETE FROM t4 WHERE b <= 3; + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued2'; +SET debug_sync='now SIGNAL master_cont1'; + +--connection con1 +REAP; +--connection con2 +REAP; +SET debug_sync='RESET'; +--save_master_pos + +--connection server_2 +--source include/start_slave.inc +--sync_with_master +--source include/stop_slave.inc + +SELECT * FROM t4 ORDER BY a; + + +# Clean up. +--connection server_2 +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc +SET DEBUG_SYNC= 'RESET'; + +--connection server_1 +--disconnect con1 +--disconnect con2 +DROP TABLE t4; +SET DEBUG_SYNC= 'RESET'; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_kill.test b/mysql-test/suite/rpl/t/rpl_parallel_kill.test new file mode 100644 index 00000000..563b0aa6 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_kill.test @@ -0,0 +1,15 @@ +--source include/master-slave.inc +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_binlog_format_row.inc + +--source include/mdev-31448_conservative.inc + +--let $killed_trx_commits=1 +--source include/mdev-31448_optimistic.inc +--let $killed_trx_commits=0 +--source include/mdev-31448_optimistic.inc + + + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_mdev6589.test b/mysql-test/suite/rpl/t/rpl_parallel_mdev6589.test new file mode 100644 index 00000000..3a5af7bd --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_mdev6589.test @@ -0,0 +1,132 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/master-slave.inc + +--connection server_2 +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=10; +--source include/start_slave.inc + + +--echo *** MDEV-6589: Incorrect relay log start position when restarting SQL thread after error in parallel replication *** + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM; +CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1); +--save_master_pos + +--connection server_2 +--sync_with_master +SELECT * FROM t1; +SELECT * FROM t2; + +# Block one domain, which we will later cause to give an error. And let some +# other domains proceed so we can check that after restart, the slave is able +# to correctly restart each domain in a separate position. + +--connect (con_temp1,127.0.0.1,root,,test,$SERVER_MYPORT_2,) +SET sql_log_bin=0; +BEGIN; +INSERT INTO t2 VALUES (5); + +--connection server_1 +SET gtid_domain_id=0; +INSERT INTO t1 VALUES (2); +INSERT INTO t2 VALUES (3); +FLUSH LOGS; +INSERT INTO t1 VALUES (4); + +SET gtid_domain_id=1; +# This query will be blocked on the slave, and later give a duplicate key error. +INSERT INTO t2 VALUES (5); + +SET gtid_domain_id=0; +INSERT INTO t1 VALUES (6); +INSERT INTO t1 VALUES (7); + +SET gtid_domain_id=2; +INSERT INTO t2 VALUES (8); +INSERT INTO t1 VALUES (9); +FLUSH LOGS; + +SET gtid_domain_id=3; +INSERT INTO t2 VALUES (10); +INSERT INTO t1 VALUES (11); + +# These cannot be replicated before the error, as a prior commit is blocked. +SET gtid_domain_id=1; +INSERT INTO t1 VALUES (12); +INSERT INTO t2 VALUES (13); + +SET gtid_domain_id=0; +INSERT INTO t2 VALUES (14); +FLUSH LOGS; + +SET gtid_domain_id=3; +INSERT INTO t2 VALUES (15); + +SET gtid_domain_id=2; +INSERT INTO t2 VALUES (16); + +SET gtid_domain_id=0; +INSERT INTO t1 VALUES (17); +SET @gtid0 = @@last_gtid; +SET gtid_domain_id=2; +INSERT INTO t1 VALUES (18); +SET @gtid2 = @@last_gtid; +SET gtid_domain_id=3; +INSERT INTO t1 VALUES (19); +SET @gtid3 = @@last_gtid; +--let $wait_pos= `SELECT CONCAT(@gtid0, ",", @gtid2, ",", @gtid3)` + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +--source include/save_master_gtid.inc + + +--connection server_2 +# First wait for domains 0, 2, and 3 to complete. +--replace_result $wait_pos WAIT_POS +eval SELECT MASTER_GTID_WAIT('$wait_pos'); + +# Then release the row lock, and wait for the domain 1 to fail with +# duplicate key error. +--connection con_temp1 +COMMIT; +CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends"); +SET sql_log_bin=1; + +--connection server_2 +--let $slave_sql_errno= 1062 +--source include/wait_for_slave_sql_error.inc + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +SET sql_log_bin=0; +DELETE FROM t2 WHERE a=5; +SET sql_log_bin=1; +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + + +# Clean up. +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc +SET DEBUG_SYNC= 'RESET'; + +--connection server_1 +DROP TABLE t1,t2; +SET DEBUG_SYNC= 'RESET'; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_missed_error_handling.test b/mysql-test/suite/rpl/t/rpl_parallel_missed_error_handling.test new file mode 100644 index 00000000..33b1bcb1 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_missed_error_handling.test @@ -0,0 +1,87 @@ +--echo *** MDEV-5921: In parallel replication, an error is not correctly signalled to the next transaction *** + +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/master-slave.inc + +--connection server_2 +--source include/stop_slave.inc +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +SET GLOBAL slave_parallel_threads=10; +CHANGE MASTER TO master_use_gtid=slave_pos; +CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends"); +--source include/start_slave.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +--save_master_pos + +--connection server_2 +--sync_with_master + +--connection server_1 +INSERT INTO t3 VALUES (110, 1); +--save_master_pos + +--connection server_2 +--sync_with_master +SELECT * FROM t3 WHERE a >= 110 ORDER BY a; +# Inject a duplicate key error. +SET sql_log_bin=0; +INSERT INTO t3 VALUES (111, 666); +SET sql_log_bin=1; + +--connection server_1 + +# Create a group commit with two inserts, the first one conflicts with a row on the slave +--connect (con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1'; +send INSERT INTO t3 VALUES (111, 2); +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued1'; + +--connect (con2,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2'; +send INSERT INTO t3 VALUES (112, 3); + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued2'; +SET debug_sync='now SIGNAL master_cont1'; + +--connection con1 +REAP; +--connection con2 +REAP; +SET debug_sync='RESET'; +--save_master_pos + +--connection server_2 +--let $slave_sql_errno= 1062 +--source include/wait_for_slave_sql_error.inc +--source include/wait_for_slave_sql_to_stop.inc +# We should not see the row (112,3) here, it should be rolled back due to +# error signal from the prior transaction. +SELECT * FROM t3 WHERE a >= 110 ORDER BY a; +SET sql_log_bin=0; +DELETE FROM t3 WHERE a=111 AND b=666; +SET sql_log_bin=1; +START SLAVE SQL_THREAD; +--sync_with_master +SELECT * FROM t3 WHERE a >= 110 ORDER BY a; + +# Clean up. +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc +SET DEBUG_SYNC= 'RESET'; + +--connection server_1 +--disconnect con1 +--disconnect con2 +DROP TABLE t3; +SET DEBUG_SYNC= 'RESET'; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_mode.test b/mysql-test/suite/rpl/t/rpl_parallel_mode.test new file mode 100644 index 00000000..67104069 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_mode.test @@ -0,0 +1,87 @@ +--echo *** MDEV-6676 - test syntax of @@slave_parallel_mode *** + +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/master-slave.inc + +--connection server_2 +--source include/stop_slave.inc +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode; +SET GLOBAL slave_parallel_threads=10; +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB; +--save_master_pos + +--connection server_2 +--sync_with_master + +--let $status_items= Parallel_Mode +--source include/show_slave_status.inc +--source include/stop_slave.inc +SET GLOBAL slave_parallel_mode='aggressive'; +--let $status_items= Parallel_Mode +--source include/show_slave_status.inc +SET GLOBAL slave_parallel_mode='conservative'; +--let $status_items= Parallel_Mode +--source include/show_slave_status.inc + +--echo *** MDEV-6676 - test that empty parallel_mode does not replicate in parallel *** +--connection server_1 +INSERT INTO t2 VALUES (1040); +--source include/save_master_gtid.inc + +--connection server_2 +SET GLOBAL slave_parallel_mode='none'; +# Test that we do not use parallel apply, by injecting an unconditional +# crash in the parallel apply code. +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,slave_crash_if_parallel_apply"; +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t2 WHERE a >= 1040 ORDER BY a; +--source include/stop_slave.inc +SET GLOBAL debug_dbug=@old_dbug; + + +--echo *** MDEV-6676 - test disabling domain-based parallel replication *** +--connection server_1 +# Let's do a bunch of transactions that will conflict if run out-of-order in +# domain-based parallel replication mode. +SET gtid_domain_id = 1; +INSERT INTO t2 VALUES (1041); +INSERT INTO t2 VALUES (1042); +INSERT INTO t2 VALUES (1043); +INSERT INTO t2 VALUES (1044); +INSERT INTO t2 VALUES (1045); +INSERT INTO t2 VALUES (1046); +DELETE FROM t2 WHERE a >= 1041; +SET gtid_domain_id = 2; +INSERT INTO t2 VALUES (1041); +INSERT INTO t2 VALUES (1042); +INSERT INTO t2 VALUES (1043); +INSERT INTO t2 VALUES (1044); +INSERT INTO t2 VALUES (1045); +INSERT INTO t2 VALUES (1046); +SET gtid_domain_id = 0; +--source include/save_master_gtid.inc +--connection server_2 +SET GLOBAL slave_parallel_mode=minimal; +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t2 WHERE a >= 1040 ORDER BY a; + +# Cleanup +--source include/stop_slave.inc +SET GLOBAL debug_dbug=@old_dbug; +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +SET GLOBAL slave_parallel_mode=@old_parallel_mode; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t2; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_multilevel.cnf b/mysql-test/suite/rpl/t/rpl_parallel_multilevel.cnf new file mode 100644 index 00000000..3ff94e45 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_multilevel.cnf @@ -0,0 +1,24 @@ +!include ../my.cnf + +[mysqld.1] +log-slave-updates +loose-innodb + +[mysqld.2] +log-slave-updates +loose-innodb + +[mysqld.3] +log-slave-updates +loose-innodb + +[mysqld.4] +log-slave-updates +loose-innodb + +[ENV] +SERVER_MYPORT_3= @mysqld.3.port +SERVER_MYSOCK_3= @mysqld.3.socket + +SERVER_MYPORT_4= @mysqld.4.port +SERVER_MYSOCK_4= @mysqld.4.socket diff --git a/mysql-test/suite/rpl/t/rpl_parallel_multilevel.test b/mysql-test/suite/rpl/t/rpl_parallel_multilevel.test new file mode 100644 index 00000000..168b7ea5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_multilevel.test @@ -0,0 +1,284 @@ +--source include/have_innodb.inc +--source include/have_debug_sync.inc +--let $rpl_topology=1->2->3->4 +--source include/rpl_init.inc + +# Test parallel replication with a multi-level replication hierarchy. + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a int PRIMARY KEY, b INT) ENGINE=InnoDB; +--save_master_pos + +--connection server_2 +--sync_with_master +--save_master_pos +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=10; +CHANGE MASTER TO master_use_gtid=slave_pos; +SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode; +SET GLOBAL slave_parallel_mode='optimistic'; + + +--connection server_3 +--sync_with_master +--save_master_pos +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=10; +CHANGE MASTER TO master_use_gtid=slave_pos; +SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode; +SET GLOBAL slave_parallel_mode='optimistic'; + + +--connection server_4 +--sync_with_master +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=10; +CHANGE MASTER TO master_use_gtid=slave_pos; +SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode; +SET GLOBAL slave_parallel_mode='optimistic'; + + +--echo *** MDEV-6676: Test that @@skip_parallel_replication is preserved in slave binlog *** +--connection server_1 + +INSERT INTO t1 VALUES(1,1); +BEGIN; +INSERT INTO t1 VALUES(2,1); +INSERT INTO t1 VALUES(3,1); +COMMIT; +# Do a lot of updates on same row in sequence. These would be likely to cause +# conflicts and rollbacks in optimistic parallel replication, but we disable +# that by enabling @@skip_parallel_replication. We can test that the flag is +# preserved down the replication hierarchy by checking that no slave retries +# are made. +SET SESSION skip_parallel_replication=1; +UPDATE t1 SET b=b+1 WHERE a=2; +UPDATE t1 SET b=b+1 WHERE a=2; +UPDATE t1 SET b=b+1 WHERE a=2; +UPDATE t1 SET b=b+1 WHERE a=2; +UPDATE t1 SET b=b+1 WHERE a=2; +UPDATE t1 SET b=b+1 WHERE a=2; +UPDATE t1 SET b=b+1 WHERE a=2; +UPDATE t1 SET b=b+1 WHERE a=2; +UPDATE t1 SET b=b+1 WHERE a=2; +UPDATE t1 SET b=b+1 WHERE a=2; +SET SESSION skip_parallel_replication=0; +SELECT * FROM t1 ORDER BY a; +--source include/save_master_gtid.inc + +--connection server_2 +--let $retry1= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1) +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; +--let $retry2= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1) +--disable_query_log +eval SELECT IF($retry1=$retry2, "Ok, no retry", + CONCAT("ERROR: ", $retry2-$retry1, " retries during replication (was ", + $retry1, " now ", $retry2, ")")) AS status; +--enable_query_log + +--connection server_3 +--let $retry1= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1) +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; +--let $retry2= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1) +--disable_query_log +eval SELECT IF($retry1=$retry2, "Ok, no retry", + CONCAT("ERROR: ", $retry2-$retry1, " retries during replication (was ", + $retry1, " now ", $retry2, ")")) AS status; +--enable_query_log + +--connection server_4 +--let $retry1= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1) +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; +--let $retry2= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1) +--disable_query_log +eval SELECT IF($retry1=$retry2, "Ok, no retry", + CONCAT("ERROR: ", $retry2-$retry1, " retries during replication (was ", + $retry1, " now ", $retry2, ")")) AS status; +--enable_query_log + + +--echo *** MDEV-6676: Test that the FL_WAITED flag in GTID is preserved in slave binlog *** + +--connection server_2 +--source include/stop_slave.inc +CHANGE MASTER TO master_use_gtid=slave_pos; +SET GLOBAL slave_parallel_mode='optimistic'; + + +--connection server_3 +--source include/stop_slave.inc +CHANGE MASTER TO master_use_gtid=slave_pos; +SET GLOBAL slave_parallel_mode='optimistic'; + + +--connection server_4 +--source include/stop_slave.inc +CHANGE MASTER TO master_use_gtid=slave_pos; +SET GLOBAL slave_parallel_mode='optimistic'; + +--connection server_1 +# Do a lot of updates on same row in sequence. Ensure that all of these but the +# first have to do a lock wait on the master, setting FL_WAITED in the GTID +# event. This should cause all slaves to not attempt to run those updates in +# parallel with prior events, so that no retries are made. + +BEGIN; +UPDATE t1 SET b=b+1 WHERE a=2; + +--connect (con_temp1,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +SET debug_sync="thd_report_wait_for SIGNAL waiting1"; +send UPDATE t1 SET b=b+1 WHERE a=2; +--connection server_1 +SET debug_sync="now WAIT_FOR waiting1"; + +--connect (con_temp2,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +SET debug_sync="thd_report_wait_for SIGNAL waiting2"; +send UPDATE t1 SET b=b+1 WHERE a=2; +--connection server_1 +SET debug_sync="now WAIT_FOR waiting2"; + +--connect (con_temp3,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +SET debug_sync="thd_report_wait_for SIGNAL waiting3"; +send UPDATE t1 SET b=b+1 WHERE a=2; +--connection server_1 +SET debug_sync="now WAIT_FOR waiting3"; + +--connect (con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +SET debug_sync="thd_report_wait_for SIGNAL waiting4"; +send UPDATE t1 SET b=b+1 WHERE a=2; +--connection server_1 +SET debug_sync="now WAIT_FOR waiting4"; + +--connect (con_temp5,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +SET debug_sync="thd_report_wait_for SIGNAL waiting5"; +send UPDATE t1 SET b=b+1 WHERE a=2; +--connection server_1 +SET debug_sync="now WAIT_FOR waiting5"; + +--connect (con_temp6,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +SET debug_sync="thd_report_wait_for SIGNAL waiting6"; +send UPDATE t1 SET b=b+1 WHERE a=2; +--connection server_1 +SET debug_sync="now WAIT_FOR waiting6"; + +--connect (con_temp7,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +SET debug_sync="thd_report_wait_for SIGNAL waiting7"; +send UPDATE t1 SET b=b+1 WHERE a=2; +--connection server_1 +SET debug_sync="now WAIT_FOR waiting7"; + +--connect (con_temp8,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +SET debug_sync="thd_report_wait_for SIGNAL waiting8"; +send UPDATE t1 SET b=b+1 WHERE a=2; +--connection server_1 +SET debug_sync="now WAIT_FOR waiting8"; + +COMMIT; +SET debug_sync="RESET"; + +--connection con_temp1 +reap; + +COMMIT; +--connection con_temp2 +reap; + +COMMIT; +--connection con_temp3 +reap; + +COMMIT; +--connection con_temp4 +reap; + +COMMIT; +--connection con_temp5 +reap; + +COMMIT; +--connection con_temp6 +reap; + +COMMIT; +--connection con_temp7 +reap; + +COMMIT; +--connection con_temp8 +reap; + +--connection server_1 +SELECT * FROM t1 ORDER BY a; +--source include/save_master_gtid.inc + +--connection server_2 +--let $retry1= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1) +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; +--let $retry2= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1) +--disable_query_log +eval SELECT IF($retry1=$retry2, "Ok, no retry", + CONCAT("ERROR: ", $retry2-$retry1, " retries during replication (was ", + $retry1, " now ", $retry2, ")")) AS status; +--enable_query_log + +--connection server_3 +--let $retry1= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1) +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; +--let $retry2= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1) +--disable_query_log +eval SELECT IF($retry1=$retry2, "Ok, no retry", + CONCAT("ERROR: ", $retry2-$retry1, " retries during replication (was ", + $retry1, " now ", $retry2, ")")) AS status; +--enable_query_log + +--connection server_4 +--let $retry1= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1) +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; +--let $retry2= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1) +--disable_query_log +eval SELECT IF($retry1=$retry2, "Ok, no retry", + CONCAT("ERROR: ", $retry2-$retry1, " retries during replication (was ", + $retry1, " now ", $retry2, ")")) AS status; +--enable_query_log + + +# Clean up + +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_mode=@old_parallel_mode; +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc + +--connection server_3 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_mode=@old_parallel_mode; +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc + +--connection server_4 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_mode=@old_parallel_mode; +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_multilevel2.cnf b/mysql-test/suite/rpl/t/rpl_parallel_multilevel2.cnf new file mode 100644 index 00000000..4e1d3878 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_multilevel2.cnf @@ -0,0 +1,17 @@ +!include ../my.cnf + +[mysqld.1] +log-slave-updates +loose-innodb + +[mysqld.2] +log-slave-updates +loose-innodb + +[mysqld.3] +log-slave-updates +loose-innodb + +[ENV] +SERVER_MYPORT_3= @mysqld.3.port +SERVER_MYSOCK_3= @mysqld.3.socket diff --git a/mysql-test/suite/rpl/t/rpl_parallel_multilevel2.test b/mysql-test/suite/rpl/t/rpl_parallel_multilevel2.test new file mode 100644 index 00000000..da8a996f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_multilevel2.test @@ -0,0 +1,78 @@ +--source include/have_innodb.inc +--let $rpl_topology=1->2->3 +--source include/rpl_init.inc + +--echo *** MDEV-7668: Intermediate master groups CREATE with INSERT, causing parallel replication failure *** + +--connection server_1 +SET @old_updates= @@GLOBAL.binlog_direct_non_transactional_updates; +SET GLOBAL binlog_direct_non_transactional_updates=OFF; +SET SESSION binlog_direct_non_transactional_updates=OFF; +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a int PRIMARY KEY, b INT) ENGINE=InnoDB; +--save_master_pos + +--connection server_2 +--sync_with_master +--save_master_pos +--source include/stop_slave.inc +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +SET GLOBAL slave_parallel_threads=10; +SET @old_commit_count=@@GLOBAL.binlog_commit_wait_count; +SET GLOBAL binlog_commit_wait_count=2; +SET @old_commit_usec=@@GLOBAL.binlog_commit_wait_usec; +SET GLOBAL binlog_commit_wait_usec=2000000; +SET @old_updates= @@GLOBAL.binlog_direct_non_transactional_updates; +SET GLOBAL binlog_direct_non_transactional_updates=OFF; +SET SESSION binlog_direct_non_transactional_updates=OFF; + +--connection server_3 +--sync_with_master +--save_master_pos +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=10; + + +--connection server_1 + +BEGIN; +CREATE TEMPORARY TABLE t2 (a INT PRIMARY KEY) ENGINE=MEMORY; +COMMIT; +INSERT INTO t2 VALUES (1); +INSERT INTO t1 SELECT a, a*10 FROM t2; +DROP TABLE t2; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; + +--connection server_3 +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; + + +# Clean up + +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +SET GLOBAL binlog_commit_wait_count=@old_commit_count; +SET GLOBAL binlog_commit_wait_usec=@old_commit_usec; +SET GLOBAL binlog_direct_non_transactional_updates= @old_updates; +--source include/start_slave.inc + +--connection server_3 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc + +--connection server_1 +SET GLOBAL binlog_direct_non_transactional_updates= @old_updates; +CALL mtr.add_suppression("Statement accesses nontransactional table as well as transactional or temporary table"); +DROP TABLE t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_no_log_slave_updates-slave.opt b/mysql-test/suite/rpl/t/rpl_parallel_no_log_slave_updates-slave.opt new file mode 100644 index 00000000..acd68493 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_no_log_slave_updates-slave.opt @@ -0,0 +1 @@ +--log-slave-updates=0 diff --git a/mysql-test/suite/rpl/t/rpl_parallel_no_log_slave_updates.test b/mysql-test/suite/rpl/t/rpl_parallel_no_log_slave_updates.test new file mode 100644 index 00000000..2e4c5795 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_no_log_slave_updates.test @@ -0,0 +1,205 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/have_binlog_format_statement.inc +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +--echo *** Test killing transaction waiting in commit for previous transaction to commit, when not using 2-phase commit *** + +--connection server_2 +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=10; +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +# Use a stored function to inject a debug_sync into the appropriate THD. +# The function does nothing on the master, and on the slave it injects the +# desired debug_sync action(s). +SET sql_log_bin=0; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + RETURN x; + END +|| +--delimiter ; +SET sql_log_bin=1; +CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +--save_master_pos + +--connection server_2 +SET sql_log_bin=0; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + IF d1 != '' THEN + SET debug_sync = d1; + END IF; + IF d2 != '' THEN + SET debug_sync = d2; + END IF; + RETURN x; + END +|| +--delimiter ; +SET sql_log_bin=1; +--sync_with_master + + +# Set up three transactions on the master that will be group-committed +# together so they can be replicated in parallel on the slave. +--connect (con_temp3,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1'; +SET binlog_format=statement; + +SET debug_dbug='+d,row_ins_row_level'; +send INSERT INTO t3 VALUES (31, foo(31, + 'ha_commit_one_phase WAIT_FOR t2_waiting', + 'commit_one_phase_2 SIGNAL t1_ready WAIT_FOR t1_cont')); + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued1'; + +--connect (con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2'; +SET binlog_format=statement; +SET debug_dbug='+d,row_ins_row_level'; +BEGIN; +# This insert is just so we can get T2 to wait while a query is running that we +# can see in SHOW PROCESSLIST so we can get its thread_id to kill later. +INSERT INTO t3 VALUES (32, foo(32, + 'ha_write_row_end SIGNAL t2_query WAIT_FOR t2_cont', + '')); +# This insert sets up debug_sync points so that T2 will tell when it is at its +# wait point where we want to kill it - and when it has been killed. +INSERT INTO t3 VALUES (33, foo(33, + 'wait_for_prior_commit_waiting SIGNAL t2_waiting', + 'wait_for_prior_commit_killed SIGNAL t2_killed')); +send COMMIT; + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued2'; + +--connect (con_temp5,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3'; +SET binlog_format=statement; +SET debug_dbug='+d,row_ins_row_level'; +send INSERT INTO t3 VALUES (34, foo(34, + '', + '')); + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued3'; +SET debug_sync='now SIGNAL master_cont1'; + +--connection con_temp3 +REAP; +--connection con_temp4 +REAP; +--connection con_temp5 +REAP; + +--connection server_1 +SELECT * FROM t3 WHERE a >= 30 ORDER BY a; + +--connection server_2 +SET sql_log_bin=0; +CALL mtr.add_suppression("Query execution was interrupted"); +CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends"); +CALL mtr.add_suppression("Slave: Connection was killed"); +SET sql_log_bin=1; +# Wait until T2 is inside executing its insert of 32, then find it in SHOW +# PROCESSLIST to know its thread id for KILL later. +SET debug_sync='now WAIT_FOR t2_query'; +--let $thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%foo(32%' AND INFO NOT LIKE '%LIKE%'` +SET debug_sync='now SIGNAL t2_cont'; + +# Wait until T2 has entered its wait for T1 to commit, and T1 has +# progressed into its commit phase. +SET debug_sync='now WAIT_FOR t1_ready'; + +# Now kill the transaction T2. +--replace_result $thd_id THD_ID +eval KILL $thd_id; + +# Wait until T2 has reacted on the kill. +SET debug_sync='now WAIT_FOR t2_killed'; + +# Now we can allow T1 to proceed. +SET debug_sync='now SIGNAL t1_cont'; + +--let $slave_sql_errno= 1317,1927,1963 +--source include/wait_for_slave_sql_error.inc +STOP SLAVE IO_THREAD; +SELECT * FROM t3 WHERE a >= 30 ORDER BY a; + +# Now we have to disable the debug_sync statements, so they do not trigger +# when the events are retried. +SET GLOBAL slave_parallel_threads=0; +SET GLOBAL slave_parallel_threads=10; +SET sql_log_bin=0; +DROP FUNCTION foo; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + RETURN x; + END +|| +--delimiter ; +SET sql_log_bin=1; + +--connection server_1 +INSERT INTO t3 VALUES (39,0); +--save_master_pos + +--connection server_2 +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t3 WHERE a >= 30 ORDER BY a; +# Restore the foo() function. +SET sql_log_bin=0; +DROP FUNCTION foo; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + IF d1 != '' THEN + SET debug_sync = d1; + END IF; + IF d2 != '' THEN + SET debug_sync = d2; + END IF; + RETURN x; + END +|| +--delimiter ; +SET sql_log_bin=1; + + +--connection server_2 +# Respawn all worker threads to clear any left-over debug_sync or other stuff. +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=0; +SET GLOBAL slave_parallel_threads=10; +--source include/start_slave.inc + + +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +SET debug_sync = 'reset'; +--source include/start_slave.inc + +--connection server_1 +DROP function foo; +DROP TABLE t3; +SET debug_sync = 'reset'; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_optimistic.test b/mysql-test/suite/rpl/t/rpl_parallel_optimistic.test new file mode 100644 index 00000000..f5e48282 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_optimistic.test @@ -0,0 +1,583 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +call mtr.add_suppression("Deadlock found when trying to get lock; try restarting transaction"); +call mtr.add_suppression("Can't find record in 't1'"); +call mtr.add_suppression("Can't find record in 't2'"); + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a int PRIMARY KEY, b INT) ENGINE=InnoDB; +--save_master_pos + +--connection server_2 +--sync_with_master +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=10; +CHANGE MASTER TO master_use_gtid=slave_pos; +SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode; +SET GLOBAL slave_parallel_mode='optimistic'; +# Run the first part of the test with high batch size and see that +# old rows remain in the table. +SET @old_gtid_cleanup_batch_size= @@GLOBAL.gtid_cleanup_batch_size; +SET GLOBAL gtid_cleanup_batch_size= 1000000; + + +--connection server_1 + +INSERT INTO t1 VALUES(1,1); +BEGIN; +INSERT INTO t1 VALUES(2,1); +INSERT INTO t1 VALUES(3,1); +COMMIT; + +# Do a bunch of INSERT/DELETE on the same rows, bound to conflict. +# We will get a lot of rollbacks, probably, but they should be handled without +# any visible errors. + +DELETE FROM t1 WHERE a=2; +INSERT INTO t1 VALUES (2,2); +DELETE FROM t1 WHERE a=2; +INSERT INTO t1 VALUES (2,3); +DELETE FROM t1 WHERE a=2; +INSERT INTO t1 VALUES (2,4); +DELETE FROM t1 WHERE a=2; +INSERT INTO t1 VALUES (2,5); + +DELETE FROM t1 WHERE a=3; +INSERT INTO t1 VALUES(3,2); +DELETE FROM t1 WHERE a=1; +INSERT INTO t1 VALUES(1,2); +DELETE FROM t1 WHERE a=3; +INSERT INTO t1 VALUES(3,3); + +DELETE FROM t1 WHERE a=2; +INSERT INTO t1 VALUES (2,6); +--source include/save_master_gtid.inc +SELECT * FROM t1 ORDER BY a; + +--connection server_2 +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; +#SHOW STATUS LIKE 'Slave_retried_transactions'; + + +--echo *** Test a bunch of non-transactional/DDL event groups. *** + +--connection server_2 +--source include/stop_slave.inc + +--connection server_1 + +INSERT INTO t1 VALUES (4,4); +INSERT INTO t1 VALUES (5,5); +CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t2 VALUES (1); +CREATE TABLE t3 (a INT PRIMARY KEY) ENGINE=MyISAM; +ALTER TABLE t2 ADD b INT; +INSERT INTO t2 VALUES (2,2); +ALTER TABLE t2 DROP b; +INSERT INTO t2 VALUES (3); +ALTER TABLE t2 ADD c INT; +INSERT INTO t2 VALUES (4,5); +INSERT INTO t2 VALUES (5,5); +INSERT INTO t3 VALUES (1); +UPDATE t2 SET c=NULL WHERE a=4; +ALTER TABLE t2 ADD UNIQUE (c); +INSERT INTO t2 VALUES (6,6); +UPDATE t2 SET c=c+100 WHERE a=2; +INSERT INTO t3(a) VALUES (2); +DELETE FROM t3 WHERE a=2; +INSERT INTO t3(a) VALUES (2); +DELETE FROM t3 WHERE a=2; +ALTER TABLE t3 CHANGE a c INT NOT NULL; +INSERT INTO t3(c) VALUES (2); +DELETE FROM t3 WHERE c=2; +INSERT INTO t3 SELECT a+200 FROM t2; +DELETE FROM t3 WHERE c >= 200; +INSERT INTO t3 SELECT a+200 FROM t2; +--source include/save_master_gtid.inc +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY c; + +--connection server_2 +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY c; +# Check that we have a bunch of old rows left-over - they were not deleted +# due to high @@gtid_cleanup_batch_size. Then set a low +# @@gtid_cleanup_batch_size so we can test that rows start being deleted. +SELECT IF(COUNT(*) >= 30, "OK", CONCAT("Error: too few old rows found: ", COUNT(*))) + FROM mysql.gtid_slave_pos; +SET GLOBAL gtid_cleanup_batch_size=1; + + +--echo *** Test @@skip_parallel_replication. *** + +--connection server_2 +--source include/stop_slave.inc +--let $retry1= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1) + +--connection server_1 +# We do a bunch of conflicting transactions on the master with +# skip_parallel_replication set to true, and check that we do not +# get any retries on the slave. + +UPDATE t1 SET b=10 WHERE a=3; +SET SESSION skip_parallel_replication=1; +UPDATE t1 SET b=20 WHERE a=3; +UPDATE t1 SET b=30 WHERE a=3; +UPDATE t1 SET b=50 WHERE a=3; +UPDATE t1 SET b=80 WHERE a=3; +UPDATE t1 SET b=130 WHERE a=3; +UPDATE t1 SET b=210 WHERE a=3; +UPDATE t1 SET b=340 WHERE a=3; +UPDATE t1 SET b=550 WHERE a=3; +UPDATE t1 SET b=890 WHERE a=3; +SET SESSION skip_parallel_replication=0; +SELECT * FROM t1 ORDER BY a; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; +--let $retry2= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1) +--disable_query_log +eval SELECT IF($retry1=$retry2, "Ok, no retry", + CONCAT("ERROR: ", $retry2-$retry1, " retries during replication (was ", + $retry1, " now ", $retry2, ")")) AS status; +--enable_query_log + + +--echo *** Test that we do not replicate in parallel transactions that had row lock waits on the master *** + +--connection server_2 +--source include/stop_slave.inc +--let $retry1= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1) + +--connection server_1 +# Setup a bunch of transactions that all needed to wait. +--connect (m1,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +--connect (m2,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +--connect (m3,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +--connect (m4,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +--connect (m5,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +--connect (m6,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +--connect (m7,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +--connect (m8,127.0.0.1,root,,test,$SERVER_MYPORT_1,) + +--connection default +BEGIN; UPDATE t1 SET b=b+1 WHERE a=3; + +--connection m1 +SET debug_sync='thd_report_wait_for SIGNAL waiting1'; +send UPDATE t1 SET b=1001 WHERE a=3; +--connection default +SET debug_sync='now WAIT_FOR waiting1'; + +--connection m2 +BEGIN; +UPDATE t1 SET b=1002 WHERE a=5; +SET debug_sync='thd_report_wait_for SIGNAL waiting2'; +send UPDATE t1 SET b=102 WHERE a=3; +--connection default +SET debug_sync='now WAIT_FOR waiting2'; + +UPDATE t1 SET b=1000 WHERE a=1; +--connection m3 +SET debug_sync='thd_report_wait_for SIGNAL waiting3'; +send UPDATE t1 SET b=1003 WHERE a=5; +--connection default +SET debug_sync='now WAIT_FOR waiting3'; + +--connection m4 +SET debug_sync='thd_report_wait_for SIGNAL waiting4'; +send UPDATE t1 SET b=1004 WHERE a=3; +--connection default +SET debug_sync='now WAIT_FOR waiting4'; + +--connection m5 +SET debug_sync='thd_report_wait_for SIGNAL waiting5'; +send UPDATE t1 SET b=1005 WHERE a=5; +--connection default +SET debug_sync='now WAIT_FOR waiting5'; + +--connection m6 +SET debug_sync='thd_report_wait_for SIGNAL waiting6'; +send UPDATE t1 SET b=1006 WHERE a=1; +--connection default +SET debug_sync='now WAIT_FOR waiting6'; + +--connection m7 +SET debug_sync='thd_report_wait_for SIGNAL waiting7'; +send UPDATE t1 SET b=1007 WHERE a=5; +--connection default +SET debug_sync='now WAIT_FOR waiting7'; + +--connection m8 +SET debug_sync='thd_report_wait_for SIGNAL waiting8'; +send UPDATE t1 SET b=1008 WHERE a=3; +--connection default +SET debug_sync='now WAIT_FOR waiting8'; + +--connection default +COMMIT; +--connection m1 +REAP; +--connection m2 +REAP; +COMMIT; +--connection m3 +REAP; +--connection m4 +REAP; +--connection m5 +REAP; +--connection m6 +REAP; +--connection m7 +REAP; +--connection m8 +REAP; +--connection default +SET debug_sync='RESET'; +SELECT * FROM t1 ORDER BY a; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; +--let $retry2= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1) +--disable_query_log +eval SELECT IF($retry1=$retry2, "Ok, no retry", + CONCAT("ERROR: ", $retry2-$retry1, " retries during replication (was ", + $retry1, " now ", $retry2, ")")) AS status; +--enable_query_log + + +--echo *** Test that we replicate correctly when using READ COMMITTED and binlog_format=MIXED on the slave *** + +--connection server_2 +--source include/stop_slave.inc +SET @old_format= @@GLOBAL.binlog_format; +# Use MIXED format; we cannot binlog ROW events on slave in STATEMENT format. +SET GLOBAL binlog_format= MIXED; +SET @old_isolation= @@GLOBAL.tx_isolation; +SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED; +# Reset the worker threads to make the new settings take effect. +SET GLOBAL slave_parallel_threads=0; +SET GLOBAL slave_parallel_threads=10; + +--connection server_1 +DROP TABLE t1, t2; +CREATE TABLE t1 (a int PRIMARY KEY, b INT) ENGINE=InnoDB; +CREATE TABLE t2 (a int PRIMARY KEY, b INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1,0), (2,0), (3,0); +INSERT INTO t2 VALUES (1,0), (2,0); +INSERT INTO t1 SELECT 4, COUNT(*) FROM t2; +INSERT INTO t2 SELECT 4, COUNT(*) FROM t1; + +INSERT INTO t1 SELECT 5, COUNT(*) FROM t2; +INSERT INTO t2 SELECT 5, COUNT(*) FROM t1; + +INSERT INTO t2 SELECT 6, COUNT(*) FROM t1; +INSERT INTO t1 SELECT 6, COUNT(*) FROM t2; + +INSERT INTO t1 SELECT 7, COUNT(*) FROM t2; +INSERT INTO t2 SELECT 7, COUNT(*) FROM t1; + +INSERT INTO t2 SELECT 8, COUNT(*) FROM t1; +INSERT INTO t1 SELECT 8, COUNT(*) FROM t2; + +INSERT INTO t2 SELECT 9, COUNT(*) FROM t1; +INSERT INTO t1 SELECT 9, COUNT(*) FROM t2; + +INSERT INTO t1 SELECT 10, COUNT(*) FROM t2; +INSERT INTO t2 SELECT 10, COUNT(*) FROM t1; + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +--source include/stop_slave.inc +SET GLOBAL binlog_format= @old_format; +SET GLOBAL tx_isolation= @old_isolation; +--source include/start_slave.inc + + +--echo *** MDEV-7888: ANALYZE TABLE does wakeup_subsequent_commits(), causing wrong binlog order and parallel replication hang *** + +--connection server_1 +DROP TABLE t1, t2, t3; +CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +CREATE TABLE t2 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1,1), (2,1), (3,1), (4,1), (5,1); +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc +SET @old_debug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug= '+d,inject_analyze_table_sleep'; + +--connection server_1 +# The bug was that ANALYZE TABLE would call +# wakeup_subsequent_commits() too early, allowing the following +# transaction in the same group to run ahead and binlog and free the +# GCO. Then we get wrong binlog order and later access freed GCO, +# which causes lost wakeup of following GCO and thus replication hang. +# We injected a small sleep in ANALYZE to make the race easier to hit (this +# can only cause false negatives in versions with the bug, not false positives, +# so sleep is ok here. And it's in general not possible to trigger reliably +# the race with debug_sync, since the bugfix makes the race impossible). + +ALTER TABLE t2 COMMENT "123abc"; +ANALYZE TABLE t2; +INSERT INTO t1 VALUES (1,2); +INSERT INTO t1 VALUES (2,2); +INSERT INTO t1 VALUES (3,2); +INSERT INTO t1 VALUES (4,2); +INSERT INTO t3 VALUES (1,3); +ALTER TABLE t2 COMMENT "hello, world"; +BEGIN; +INSERT INTO t1 VALUES (5,4); +INSERT INTO t1 VALUES (6,4); +INSERT INTO t1 VALUES (7,4); +INSERT INTO t1 VALUES (8,4); +INSERT INTO t1 VALUES (9,4); +INSERT INTO t1 VALUES (10,4); +INSERT INTO t1 VALUES (11,4); +INSERT INTO t1 VALUES (12,4); +INSERT INTO t1 VALUES (13,4); +INSERT INTO t1 VALUES (14,4); +INSERT INTO t1 VALUES (15,4); +INSERT INTO t1 VALUES (16,4); +INSERT INTO t1 VALUES (17,4); +INSERT INTO t1 VALUES (18,4); +INSERT INTO t1 VALUES (19,4); +INSERT INTO t1 VALUES (20,4); +COMMIT; +INSERT INTO t1 VALUES (21,5); +INSERT INTO t1 VALUES (22,5); + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; + +--source include/stop_slave.inc +SET GLOBAL debug_dbug= @old_debug; +--source include/start_slave.inc + +--echo *** MDEV-7929: record_gtid() for non-transactional event group calls wakeup_subsequent_commits() too early, causing slave hang. *** + +--connection server_2 +--source include/stop_slave.inc +SET @old_dbug= @@GLOBAL.debug_dbug; +# The bug was that record_gtid(), when there is no existing transaction from +# a DML event being replicated, would commit its own transaction. This wrongly +# caused wakeup_subsequent_commits(), with similar consequences as MDEV-7888 +# above. We simulate this condition with a small sleep in record_gtid() for +# a specific ANALYZE that we binlog with server id 100. +SET GLOBAL debug_dbug= '+d,inject_record_gtid_serverid_100_sleep'; + +--connection server_1 + +ALTER TABLE t3 COMMENT "DDL statement 1"; +INSERT INTO t1 VALUES (30,0); +INSERT INTO t1 VALUES (31,0); +INSERT INTO t1 VALUES (32,0); +INSERT INTO t1 VALUES (33,0); +INSERT INTO t1 VALUES (34,0); +INSERT INTO t1 VALUES (35,0); +INSERT INTO t1 VALUES (36,0); +SET @old_server_id= @@SESSION.server_id; +SET SESSION server_id= 100; +ANALYZE TABLE t2; +SET SESSION server_id= @old_server_id; +INSERT INTO t1 VALUES (37,0); +ALTER TABLE t3 COMMENT "DDL statement 2"; +INSERT INTO t1 VALUES (38,0); +INSERT INTO t1 VALUES (39,0); +ALTER TABLE t3 COMMENT "DDL statement 3"; + +SELECT * FROM t1 WHERE a >= 30 ORDER BY a; + +--source include/save_master_gtid.inc + + +--connection server_2 +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 WHERE a >= 30 ORDER BY a; + + +--source include/stop_slave.inc +SET GLOBAL debug_dbug= @old_debug; +--source include/start_slave.inc + + +--echo *** MDEV-8113: ALTER TABLE causes slave hang in optimistic parallel replication *** + +--connection server_2 +--source include/stop_slave.inc + +--connection server_1 +ALTER TABLE t2 ADD c INT; +INSERT INTO t2 (a,b) VALUES (50, 0); +INSERT INTO t2 (a,b) VALUES (51, 1); +INSERT INTO t2 (a,b) VALUES (52, 2); +INSERT INTO t2 (a,b) VALUES (53, 3); +INSERT INTO t2 (a,b) VALUES (54, 4); +INSERT INTO t2 (a,b) VALUES (55, 5); +INSERT INTO t2 (a,b) VALUES (56, 6); +INSERT INTO t2 (a,b) VALUES (57, 7); +INSERT INTO t2 (a,b) VALUES (58, 8); +INSERT INTO t2 (a,b) VALUES (59, 9); +ALTER TABLE t2 DROP COLUMN c; +SELECT * FROM t2 WHERE a >= 50 ORDER BY a; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t2 WHERE a >= 50 ORDER BY a; + + +--echo *** MDEV-8075: DROP TEMPORARY TABLE not marked as ddl, causing optimistic parallel replication to fail *** + +--connection server_2 +--source include/stop_slave.inc + +--connection server_1 +INSERT INTO t1 VALUES (40, 10); +CREATE TEMPORARY TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES (41); +BEGIN; +INSERT INTO t2 SELECT a, 20 FROM t1; +DROP TEMPORARY TABLE t1; +COMMIT; +INSERT INTO t1 VALUES (42, 10); +--source include/save_master_gtid.inc +SELECT * FROM t1 WHERE a >= 40 ORDER BY a; +SELECT * FROM t2 WHERE a >= 40 ORDER BY a; + +--connection server_2 +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 WHERE a >= 40 ORDER BY a; +SELECT * FROM t2 WHERE a >= 40 ORDER BY a; + +# partial cleanup to reuse the tables by following tests +--connection server_1 +DELETE FROM t1; +DELETE FROM t2; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc + +# +# MDEV-13577 optimistic parallel slave errors out to error log unnecessary +# + +# The 1st of the following two trx:s a blocker on slave +--connection server_2 +set global log_warnings=2; +BEGIN; +INSERT INTO t1 SET a=1; + +--connection server_1 +SET @save.binlog_format=@@session.binlog_format; +SET @@SESSION.binlog_format=row; + +BEGIN; + INSERT INTO t1 SET a=1; + INSERT INTO t2 SET a=1; +COMMIT; + +# This transaction is going to win optimistical race with above INSERT +# on slave while being depend on it. That means it will face a kind of temporary error +# and then will retry to succeed. +BEGIN; + DELETE FROM t2; +COMMIT; + +# First make sure DELETE raced indeed to get stuck at retrying stage +# where it runs "realistically" now. There is nomore optimistic error +# in the errorlog, which is downgraded to the warning level (when +# --log-warnings > 1), see above suppression. +--connection server_2 +--let $wait_condition= SELECT COUNT(*) = 1 FROM information_schema.processlist WHERE state = "Waiting for prior transaction to commit" +--source include/wait_condition.inc + +# Next release the 1st trx to commit. +--connection server_2 +ROLLBACK; + +# MDEV-13577 local cleanup: +--connection server_1 +SET @@SESSION.binlog_format= @save.binlog_format; +DELETE FROM t1; +DELETE FROM t2; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc + +# +# Clean up. +# +--connection server_2 +--source include/stop_slave.inc +set global log_warnings=default; +SET GLOBAL slave_parallel_mode=@old_parallel_mode; +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t1, t2, t3; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc +# Check that old rows are deleted from mysql.gtid_slave_pos. +# Deletion is asynchronous, so use wait_condition.inc. +# Also, there is a small amount of non-determinism in the deletion of old +# rows, so it is not guaranteed that there can never be more than +# @@gtid_cleanup_batch_size rows in the table; so allow a bit of slack +# here. +let $wait_condition= + SELECT COUNT(*) <= 5*@@GLOBAL.gtid_cleanup_batch_size + FROM mysql.gtid_slave_pos; +--source include/wait_condition.inc +eval $wait_condition; +SET GLOBAL gtid_cleanup_batch_size= @old_gtid_cleanup_batch_size; + +--connection server_1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_optimistic_error_stop.test b/mysql-test/suite/rpl/t/rpl_parallel_optimistic_error_stop.test new file mode 100644 index 00000000..27f38d47 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_optimistic_error_stop.test @@ -0,0 +1,180 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +call mtr.add_suppression("Slave: Commit failed due to failure of an earlier commit"); +call mtr.add_suppression("Slave: Duplicate entry '99'"); + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a int PRIMARY KEY, b INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES(1,1); # hit a dup entry on slave +INSERT INTO t1 VALUES(2,1); # races to "win" the last exit +INSERT INTO t1 VALUES(3,1); +INSERT INTO t1 VALUES(4,1); # make W3 race over W1 +--save_master_pos + +--connection server_2 +--sync_with_master +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +--source include/stop_slave.inc +SET @old_debug_dbug = @@global.debug_dbug; +# In a group of W1,W2,W3 of the same batch W2 simulates slowness. +SET @@global.debug_dbug = "d,hold_worker2_favor_worker3"; +SET GLOBAL slave_parallel_threads=4; +CHANGE MASTER TO master_use_gtid=slave_pos; +SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode; +SET GLOBAL slave_parallel_mode='optimistic'; + +# MDEV-30780 optimistic parallel slave hangs after hit an error +# Test workers hang scenario to prove it's no more neither +# out-of-order access to the active gco list. +# +# The test provides how to reproduce on the OLD version, false by default. +# That branch approximates the original hang with an assert that +# confirms the OLD version indeed could access already reclaimed gco. +--let $old_version_regression=0 + + +--connection server_1 + +# Let W1,W2,W3,W4 parallel workers that are going to execute +# the following transaction. +# W1 holds on with the 1st statement +# then crashes W3 with the 2nd into retry, +# finally hits with the 3rd a dup entry, on slave. +SET @@gtid_seq_no = 2001; +BEGIN; + UPDATE t1 SET b = 11 WHERE a = 4; + UPDATE t1 SET b = 11 WHERE a = 3; + UPDATE t1 SET a = 99 WHERE a = 1; +COMMIT; +# In the buggy version W2 races to "win" the exit last (of W1..3) +# and by that to access last a gco struct, garbage-collected. +UPDATE t1 SET b = 2 WHERE a = 2; +# W3 garbage-collects the gco struct in the buggy version. +UPDATE t1 SET b = 3 WHERE a = 3; +# W4 resides in following "singleton" batch to a W2 replacement +# in the buggy version to allow W3 reclaim the batch's gco. +DROP TABLE IF EXISTS phantom_1; + +--source include/save_master_gtid.inc + +--connect (slave_local_0, 127.0.0.1, root,, test, $SLAVE_MYPORT,) +begin; + UPDATE t1 set b = 11 where a = 4; +--connect (slave_local_1, 127.0.0.1, root,, test, $SLAVE_MYPORT,) +begin; + INSERT INTO t1 VALUES (99, 11); + +--connect (slave_local_2, 127.0.0.1, root,, test, $SLAVE_MYPORT,) +begin; + UPDATE t1 SET b = 12 WHERE a = 2; + +--connect (slave_local_3, 127.0.0.1, root,, test, $SLAVE_MYPORT,) +begin; + UPDATE t1 SET b = 13 WHERE a = 3; + +--connection server_2 +--source include/start_slave.inc + +--echo # W4 is waiting to start its DROP + +--let $wait_condition= SELECT count(*) = 1 FROM information_schema.processlist WHERE state LIKE "Waiting for prior transaction to start commit%" +--source include/wait_condition.inc + +--connection slave_local_3 +# make W3 to set E.cc <- 1 + rollback; +--let $wait_condition= SELECT count(*) = 1 FROM information_schema.processlist WHERE state LIKE "Waiting for prior transaction to commit%" +--source include/wait_condition.inc + +--connection slave_local_0 +# make W3 into retry and delay it to let W1 hit a dupicate error first, +# see 'commit' by slave_local_1. + rollback; +--let $wait_condition= SELECT count(*) = 1 FROM information_schema.processlist WHERE state LIKE "debug sync point: now" +--source include/wait_condition.inc +SELECT count(*) = 0 as "W3 undid its commit state" FROM information_schema.processlist WHERE state LIKE "Waiting for prior transaction to commit%"; + + +--connection slave_local_2 + rollback; +# wait for W2 to start committing E.cc <- 2 +--let $wait_condition= SELECT count(*) = 1 FROM information_schema.processlist WHERE state like "Waiting for prior transaction to commit" +--source include/wait_condition.inc + +--connection slave_local_1 + +# W1 errors out +# A. to alert W3 +# B. W3 will *not* wake up W4 in the fixed version, having to wait for W2 demise. +# C. W2 will notify W3 that releases W4 as it would do in normal cases. +commit; + +if (!$old_version_regression) +{ +# A. In the fixed version show-processlist W4 is still in the ordered waiting +SELECT COUNT(*) = 1 as "W4 remains with the same status" FROM information_schema.processlist WHERE state LIKE "Waiting for prior transaction to start commit%"; +--let $status= query_get_value("show slave status", Slave_SQL_Running, 1) +--echo # Slave_SQL_Running YES = $status + +# B. In the fixed version W3 is waiting for W2,... +--let $wait_condition= SELECT count(*) = 1 as "W4 is waiting" FROM information_schema.processlist WHERE state LIKE "Waiting for prior transaction to commit%" +--source include/wait_condition.inc +--echo # while W2 is held back ... +--let $wait_condition= SELECT count(*) = 1 as "W2 simulates slowness" FROM information_schema.processlist WHERE state LIKE "debug sync point: now" +--source include/wait_condition.inc + +# C. # ...until NOW. +SET DEBUG_SYNC = 'now SIGNAL cont_worker2'; + +} + +# To reproduce the hang on the OLD version ... +if ($old_version_regression) +{ + # replace the actual fixes block with checking W3,W4 have actually committed, + # followed by signaling to W2 like on behalf of W4 which would end up in the hang. + --let $wait_condition= SELECT COUNT(*) = 0 as "W4 has moved on" FROM information_schema.processlist WHERE state like "Waiting for prior transaction to start commit" + --source include/wait_condition.inc + --let $wait_condition= SELECT count(*) = 0 as "W3 does not wait on W2" FROM information_schema.processlist WHERE state LIKE "Waiting for prior transaction to commit%" +--source include/wait_condition.inc + + --let $wait_condition= SELECT count(*) = 1 as "W2 simulates slowness" FROM information_schema.processlist WHERE state LIKE "debug sync point: now" + --source include/wait_condition.inc + + # Like above, but signaling is done after W4 is done to violate the commit order + # that must fire a debug assert. + SET DEBUG_SYNC = 'now SIGNAL cont_worker2'; +} + +--let $slave_sql_errno= 1062 +--source include/wait_for_slave_sql_error.inc + +# Restore the slave data and resume with replication +DELETE FROM t1 WHERE a=99; +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + +# +# Clean up. +# +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_mode=@old_parallel_mode; +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +SET @@global.debug_dbug = @old_debug_dbug; +SET debug_sync = RESET; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t1; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_optimistic_nobinlog.cnf b/mysql-test/suite/rpl/t/rpl_parallel_optimistic_nobinlog.cnf new file mode 100644 index 00000000..b85a84f6 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_optimistic_nobinlog.cnf @@ -0,0 +1,10 @@ +!include ../my.cnf + +[mysqld.1] +log-slave-updates=0 +loose-innodb + +[mysqld.2] +slave-transaction-retries=100 +log-slave-updates=0 +loose-innodb diff --git a/mysql-test/suite/rpl/t/rpl_parallel_optimistic_nobinlog.test b/mysql-test/suite/rpl/t/rpl_parallel_optimistic_nobinlog.test new file mode 100644 index 00000000..ee0de499 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_optimistic_nobinlog.test @@ -0,0 +1,77 @@ +--source include/have_innodb.inc +--source include/have_binlog_format_statement.inc +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a int PRIMARY KEY, b INT) ENGINE=InnoDB; +CREATE TABLE t2 (a int PRIMARY KEY, b INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1,0), (2,0), (3,0); +INSERT INTO t2 VALUES (1,0), (2,0); +--save_master_pos + + +--connection server_2 +--sync_with_master +SET @old_isolation= @@GLOBAL.tx_isolation; +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +--source include/stop_slave.inc +SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED; +SET GLOBAL slave_parallel_threads=10; +CHANGE MASTER TO master_use_gtid=slave_pos; +SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode; +SET GLOBAL slave_parallel_mode='aggressive'; + + +--echo *** Test that we replicate correctly when using READ COMMITTED and --log-slave-updates=0 on the slave *** + +--connection server_1 + +INSERT INTO t1 SELECT 4, COUNT(*) FROM t2; +INSERT INTO t2 SELECT 4, COUNT(*) FROM t1; + +INSERT INTO t1 SELECT 5, COUNT(*) FROM t2; +INSERT INTO t2 SELECT 5, COUNT(*) FROM t1; + +INSERT INTO t2 SELECT 6, COUNT(*) FROM t1; +INSERT INTO t1 SELECT 6, COUNT(*) FROM t2; + +INSERT INTO t1 SELECT 7, COUNT(*) FROM t2; +INSERT INTO t2 SELECT 7, COUNT(*) FROM t1; + +INSERT INTO t2 SELECT 8, COUNT(*) FROM t1; +INSERT INTO t1 SELECT 8, COUNT(*) FROM t2; + +INSERT INTO t2 SELECT 9, COUNT(*) FROM t1; +INSERT INTO t1 SELECT 9, COUNT(*) FROM t2; + +INSERT INTO t1 SELECT 10, COUNT(*) FROM t2; +INSERT INTO t2 SELECT 10, COUNT(*) FROM t1; + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + + +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL tx_isolation= @old_isolation; +SET GLOBAL slave_parallel_mode=@old_parallel_mode; +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t1, t2; + +--connection server_2 +call mtr.add_suppression("Deadlock found when trying to get lock.*"); + +--source include/rpl_end.inc + diff --git a/mysql-test/suite/rpl/t/rpl_parallel_optimistic_until.test b/mysql-test/suite/rpl/t/rpl_parallel_optimistic_until.test new file mode 100644 index 00000000..0797e8bf --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_optimistic_until.test @@ -0,0 +1,486 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/master-slave.inc +# Format is restricted because the test expects a specific result of +# relay-logging that splits a transaction into two different files. +--source include/have_binlog_format_row.inc + +# +# MDEV-15152 Optimistic parallel slave doesn't cope well with START SLAVE UNTIL +# +--connection slave +--source include/stop_slave.inc +RESET MASTER; +RESET SLAVE; + +--connection master +RESET MASTER; +CREATE TABLE t1 (a int primary key, b text) ENGINE=InnoDB; +--let $a0 = 25 +--eval INSERT INTO t1 SET a=$a0, b='trx0' +# Memorize the position for replication restart from it +--let $pos_trx0 = query_get_value(SHOW MASTER STATUS, Position, 1) + +--connection slave +--source include/start_slave.inc + +--connection master +# --connection slave +--sync_slave_with_master +--source include/stop_slave.inc +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +SET GLOBAL slave_parallel_threads=2; +SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode; +SET GLOBAL slave_parallel_mode='optimistic'; + +# Run the slave in the following modes one by one. +# +# 1. the until position is set in the middle of trx2 +# below $pos_trx0 of the last exec position in the first file +# 2. and above $pos_trx0 +# In either case trx2 must commit before slave stops. +# 3. the until postion is inside trx1 +# 4. RELAY log until inside trx1 +# 5. RELAY log until inside a "big" trx +# 6. RELAY log until inside a trx within a sequence of relay logs +# +# Execution flaw for Until_Master_Pos cases follows as: +# create the transaction trx1, trx2 +# logged at the beginning of two subsequent binlog files. +# Set the until position to at the middle of the 2rd transaction. +# Engage the optimistic scheduler while having trx1 execution blocked. +# Lift the block after trx2 has reached waiting its order to commit. +# *Proof 1* +# Observe that the slave applier stops at a correct position. +# In the bug condition it would stop prematurely having the stop position +# in the first file, therefore trx2 not committed. +# Specifically, an internal transaction position until makes the applier to run +# beyond it to commit commit the current transaction. +# *Proof 2* +# Observe the following START SLAVE resumes OK. +# +# Auxiliary third trx3 on master is just for triggering the actual stop +# (whihc is a legacy UNTIL's property). +# trx0 is to produce a specific value of the last executed binlog file:pos +# to emulate the bug condition. +# +# Intermediate checks via SELECT are supposed to succeed +# with putting out value 1. +# +# NOTE: Relay log until tests have to use explicit log names and position +# which may require to adjust with future changes to event formats etc. +# + +--connection slave +SET @old_max_relay_log_size = @@global.max_relay_log_size; +SET @@global.max_relay_log_size=4096; + +--connection master +# trx1 +--let $a=1 +BEGIN; +while (`SELECT $a < $a0`) +{ + --eval INSERT INTO t1 SET a=$a, b='trx1' +--inc $a +} +COMMIT; +--let $fil_1 = query_get_value(SHOW MASTER STATUS, File, 1) +--let $pos_trx1 = query_get_value(SHOW MASTER STATUS, Position, 1) + +FLUSH LOGS; + +# $pos_0 the offset of the first event of trx2 in new file +--let $pos_0=query_get_value(SHOW MASTER STATUS, Position, 1) +# trx2 +--let $a=$a0 +BEGIN; +--eval UPDATE t1 SET b='trx2_0' WHERE a = $a +--eval UPDATE t1 SET b='trx2' WHERE a = $a +COMMIT; +--let $fil_2=query_get_value(SHOW MASTER STATUS, File, 1) +--let $pos_trx2=query_get_value(SHOW MASTER STATUS, Position, 1) + +# trx3 +--let $a=$a0 +--inc $a +--eval INSERT INTO t1 SET a=$a,b='trx3' +--let $pos_trx3=query_get_value(SHOW MASTER STATUS, Position, 1) +--let $a= + + +--echo *** case 1 UNTIL inside trx2 + +--connection slave1 +# Blocker to hold off EXEC_MASTER_LOG_POS advance +BEGIN; + --eval INSERT INTO t1 SET a= 1 +--connection slave +--let $pos_until=`SELECT $pos_trx0 - 1` +--replace_result $pos_0 <pos_0> $pos_until <pos_until> $pos_trx2 <pos_trx2> +--eval SELECT $pos_0 <= $pos_until AND $pos_until < $pos_trx2 as "pos_until < trx0 and is within trx2" +CHANGE MASTER TO MASTER_USE_GTID=no; +--replace_result $fil_2 file_2 $pos_until <pos_until> +--eval START SLAVE UNTIL MASTER_LOG_FILE = '$fil_2', MASTER_LOG_POS = $pos_until + +--let $wait_condition= SELECT COUNT(*) > 0 FROM information_schema.processlist WHERE state = "Waiting for prior transaction to commit" +--source include/wait_condition.inc + +--connection slave1 +# unblock to see the slave applier stops at $until +ROLLBACK; + +--echo Proof 1: Correct stop +--connection slave +--source include/wait_for_slave_sql_to_stop.inc +--let $file_stop= query_get_value(SHOW SLAVE STATUS, Relay_Master_Log_File, 1) +--let $pos_stop= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1) +if (`SELECT "$file_stop" != "$fil_2" OR $pos_stop < $pos_until`) +{ + --echo *** ERROR: Slave stopped at $file_stop:$pos_stop which is not $fil_2:$pos_until. + --die +} +--eval SELECT count(*) = 1 as 'trx2 is committed' FROM t1 WHERE b = 'trx2' +--eval SELECT count(*) = 0 as 'trx3 is not committed' FROM t1 WHERE b = 'trx3' + +--echo Proof 2: Resume works out +--source include/start_slave.inc +--connection master +--sync_slave_with_master + + +--echo *** case 2 UNTIL inside trx2 + +--connection slave +--eval DELETE FROM t1 WHERE a <> $a0 +--eval UPDATE t1 SET b='trx0' WHERE a = $a0 + +--connection slave1 +# Blocker to hold off EXEC_MASTER_LOG_POS advance +BEGIN; + --eval INSERT INTO t1 SET a= 1 + +--connection slave +--source include/stop_slave.inc + +--let $pos_until=`SELECT $pos_trx2 - 1` +--replace_result $pos_trx0 <pos_0> $pos_until <pos_until> $pos_trx2 <pos_trx2> +--eval SELECT $pos_trx0 <= $pos_until AND $pos_until < $pos_trx2 as "pos_until >= trx0 and is within trx2" +--replace_result $fil_1 file_1 $pos_trx0 <pos_trx0> +--eval CHANGE MASTER TO MASTER_LOG_FILE = '$fil_1', MASTER_LOG_POS = $pos_trx0, MASTER_USE_GTID=no +--replace_result $fil_2 file_2 $pos_until <pos_until> +--eval START SLAVE UNTIL MASTER_LOG_FILE = '$fil_2', MASTER_LOG_POS = $pos_until + +--let $wait_condition= SELECT COUNT(*) > 0 FROM information_schema.processlist WHERE state = "Waiting for prior transaction to commit" +--source include/wait_condition.inc + +--connection slave1 +# unblock to see the slave applier stops at $until +ROLLBACK; + +--echo Proof 1: Correct stop +--connection slave +--source include/wait_for_slave_sql_to_stop.inc +--let $file_stop= query_get_value(SHOW SLAVE STATUS, Relay_Master_Log_File, 1) +--let $pos_stop= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1) +if (`SELECT "$file_stop" != "$fil_2" OR $pos_stop < $pos_until`) +{ + --echo *** ERROR: Slave stopped at $file_stop:$pos_stop which is not $fil_2:$pos_until. + --die +} +--eval SELECT count(*) = 1 as 'trx2 is committed' FROM t1 WHERE b = 'trx2' +--eval SELECT count(*) = 0 as 'trx3 is not committed' FROM t1 WHERE b = 'trx3' + +--echo Proof 2: Resume works out +--source include/start_slave.inc +--connection master +--sync_slave_with_master + + +--echo *** case 3 UNTIL inside trx1 + +--connection slave +--eval DELETE FROM t1 WHERE a <> $a0 +--eval UPDATE t1 SET b='trx0' WHERE a = $a0 + + +--connection slave1 +# Blocker to hold off EXEC_MASTER_LOG_POS advance +BEGIN; + --eval INSERT INTO t1 SET a= 1; # block trx1 + +--connection slave +--source include/stop_slave.inc + +--let $pos_until=`SELECT $pos_0 - 1` +--replace_result $pos_0 <pos_0> $pos_until <pos_until> $pos_trx2 <pos_trx2> +--eval SELECT $pos_until < $pos_0 as "pos_until before trx2 start position" +--replace_result $fil_1 file_1 $pos_trx0 <pos_trx0> +--eval CHANGE MASTER TO MASTER_LOG_FILE = '$fil_1', MASTER_LOG_POS = $pos_trx0, MASTER_USE_GTID=no +--replace_result $fil_2 file_2 $pos_until <pos_until> +--eval START SLAVE UNTIL MASTER_LOG_FILE = '$fil_2', MASTER_LOG_POS = $pos_until + +--connection slave1 +# unblock to see the slave applier stops at $until +ROLLBACK; + +--echo Proof 1: Correct stop +--connection slave +--source include/wait_for_slave_sql_to_stop.inc +--let $file_stop= query_get_value(SHOW SLAVE STATUS, Relay_Master_Log_File, 1) +--let $pos_stop= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1) +if (`SELECT "$file_stop" != "$fil_2" OR $pos_stop < $pos_until`) +{ + --echo *** ERROR: Slave stopped at $file_stop:$pos_stop which is not $fil_2:$pos_until. + --die +} +--eval SELECT count(*) = $a0-1 as 'trx1 is committed' FROM t1 WHERE b = 'trx1' +--eval SELECT count(*) = 0 as 'trx2 is not committed' FROM t1 WHERE b = 'trx2' + +--echo Proof 2: Resume works out +--source include/start_slave.inc +--connection master +--sync_slave_with_master + + +--echo *** case 4 Relay-log UNTIL inside trx1 + +--connection slave +--eval DELETE FROM t1 WHERE a <> $a0 +--eval UPDATE t1 SET b='trx0' WHERE a = $a0 + +--connection slave1 +# Blocker to hold off EXEC_MASTER_LOG_POS advance +BEGIN; + --eval INSERT INTO t1 SET a= 1; # block trx1 + +--connection slave +--source include/stop_slave.inc +--replace_result $fil_1 file_1 $pos_trx0 <pos_trx0> +--eval CHANGE MASTER TO MASTER_LOG_FILE = '$fil_1', MASTER_LOG_POS = $pos_trx0, MASTER_USE_GTID=no +START SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_start.inc + +# The following test sets the stop coordinate to inside the first event +# of a relay log that holds events of a transaction started in an earlier log. +# Peek the stop position in the middle of trx1, not even on a event boundary. +--let $pos_until=255 +--let $file_rl=slave-relay-bin.000003 +--let $binlog_file=$file_rl + +# Wait for the IO thread to write the trx1 to the relaylog before querying it. +# (wait_for_slave_param.inc isn't flexible enough, so do it manually.) +--let $continue= 1 +--let $count=600 +while ($continue) +{ + --let $cur_file= query_get_value(SHOW SLAVE STATUS, 'Master_Log_File', 1) + --let $cur_pos= query_get_value(SHOW SLAVE STATUS, 'Read_Master_Log_Pos', 1) + --let $continue= `SELECT '$cur_file' = '$fil_1' AND $cur_pos < $pos_trx1` + if ($continue) + { + --dec $count + if (!$count) + { + --echo **** ERROR: timeout waiting for Read_Master_Log_Pos($cur_pos) >= $pos_trx1 (file='$cur_file') ****" + --die Timeout waiting for IO thread to write master events to the relaylog + } + --sleep 0.1 + } +} + +--let $pos_xid=508 +--let $info= query_get_value(SHOW RELAYLOG EVENTS IN '$file_rl' FROM $pos_xid LIMIT 1, Info, 1) + +if (`SELECT "$info" NOT LIKE "COMMIT /* xid=% */" OR $pos_xid < $pos_until`) +{ + --echo *** Unexpected offset. Refine it to point to the correct XID event! + --die +} + +--replace_result $file_rl file_2 $pos_until <pos_until> +--eval START SLAVE UNTIL RELAY_LOG_FILE = '$file_rl', RELAY_LOG_POS = $pos_until + +--connection slave1 +# unblock to see the slave applier stops at $until +ROLLBACK; + +--echo Proof 1: Correct stop +--connection slave +--source include/wait_for_slave_sql_to_stop.inc +--let $file_stop= query_get_value(SHOW SLAVE STATUS, Relay_Log_File, 1) +--let $pos_stop= query_get_value(SHOW SLAVE STATUS, Relay_Log_Pos, 1) +if (`SELECT strcmp("$file_rl","$file_stop") > -1`) +{ + --echo *** ERROR: Slave stopped at $file_stop:$pos_stop which is not $file_rl:$pos_until. + --die +} + +--eval SELECT count(*) = $a0-1 as 'trx1 is committed' FROM t1 WHERE b = 'trx1' +--eval SELECT count(*) = 0 as 'trx2 is not committed' FROM t1 WHERE b = 'trx2' + +--echo Proof 2: Resume works out +--source include/start_slave.inc +--connection master +--sync_slave_with_master + + + +--echo *** case 5 Relay-log UNTIL inside a "big" trx that spawns few relay logs + +--connection master +CREATE TABLE t2 (a TEXT) ENGINE=InnoDB; +FLUSH LOGS; + +--sync_slave_with_master +--let $file_stop= query_get_value(SHOW SLAVE STATUS, Relay_Log_File, 1) +--let $pos_stop= query_get_value(SHOW SLAVE STATUS, Relay_Log_Pos, 1) +--let $records=`SELECT floor(4*@@global.max_relay_log_size / 1024) + 1` + +--connection slave +--source include/stop_slave.inc + +--connection master +# trx4 +BEGIN; +--let $i=$records +while ($i) +{ + INSERT INTO t2 SET a=repeat('a',1024); + +--dec $i +} +COMMIT; + +# slave will stop there: +--let $file_trx4 = query_get_value(SHOW MASTER STATUS, File, 1) +--let $pos_trx4 = query_get_value(SHOW MASTER STATUS, Position, 1) + +# trx5 +INSERT INTO t2 SET a='a'; +--let $pos_trx5 = query_get_value(SHOW MASTER STATUS, Position, 1) + +--connection slave +START SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_start.inc + +# Set position inside the transaction though the value +# specified is beyond that relay log file. +# The coordianate may point to in a different event in future changes +# but should not move away from inside this big group of events. +# So we don't test which event in the transaction it points to. +--let $pos_until= 4500 +--let $file_rl= slave-relay-bin.000010 + +--replace_result $file_rl file_2 $pos_until <pos_until> +--eval START SLAVE UNTIL RELAY_LOG_FILE = '$file_rl', RELAY_LOG_POS = $pos_until + +--echo Proof 1: Correct stop +--connection slave +--source include/wait_for_slave_sql_to_stop.inc +--let $file_stop= query_get_value(SHOW SLAVE STATUS, Relay_Master_Log_File, 1) +--let $pos_stop= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1) +# It's showed the actual stop occurred before trx5 +if (`SELECT strcmp("$file_trx4", "$file_stop") <> 0 OR $pos_stop >= $pos_trx5 OR count(*) <> $records FROM t2`) +{ + --echo *** ERROR: Slave stopped at *binlog* $file_stop:$pos_stop which is not $file_trx4:$pos_trx4. + --die +} + +--echo Proof 2: Resume works out +--source include/start_slave.inc +--connection master +--sync_slave_with_master + +--let $diff_tables=master:t2,slave:t2 +--source include/diff_tables.inc + + + +--echo *** case 6 Relay-log UNTIL inside a small trx inside a sequence of relay logs + +--connection slave +--source include/stop_slave.inc + +--connection master +# trx6 +--let $records=`SELECT count(*) FROM t2` +while ($records) +{ + BEGIN; + DELETE FROM t2 LIMIT 1; + COMMIT; +--dec $records +} +COMMIT; + +--connection slave +START SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_start.inc + +--connection master +--source include/sync_slave_io_with_master.inc + +--connection slave +# The relay-log coordinate is not at an event boundary and +# also may change across the server version. +# The test makes its best to check its coherance. +--let $pos_until= 3130 +--let $file_rl= slave-relay-bin.000018 + +--let $pos_gtid = 2987 +--let $info= query_get_value(SHOW RELAYLOG EVENTS IN '$file_rl' FROM $pos_gtid LIMIT 1, Info, 1) + +if (`SELECT "$info" != "BEGIN GTID 0-1-23"`) +{ + --echo *** Unexpected offset. Refine it to point to the correct GTID! + --die +} +--let $pos_event = 3120 +--let $type= query_get_value(SHOW RELAYLOG EVENTS IN '$file_rl' FROM $pos_event LIMIT 1, Event_type, 1) +if (`SELECT "$type" != "Delete_rows_v1"`) +{ + --echo *** Unexpected offset. Refine it to point to the expected event! + --die +} + +--replace_result $file_rl file_2 $pos_until <pos_until> +--eval START SLAVE UNTIL RELAY_LOG_FILE = '$file_rl', RELAY_LOG_POS = $pos_until + +--echo Proof 1: Correct stop +--connection slave +--source include/wait_for_slave_sql_to_stop.inc +--let $file_stop= query_get_value(SHOW SLAVE STATUS, Relay_Log_File, 1) +--let $pos_stop= query_get_value(SHOW SLAVE STATUS, Relay_Log_Pos, 1) +if (`SELECT strcmp("$file_stop", "$file_rl") = -1 OR + strcmp("$file_stop", "$file_rl") = 0 AND $pos_stop < $pos_until`) +{ + --echo *** ERROR: Slave stopped at *relay* $file_stop:$pos_stop which is not $file_rl:$pos_until. + --die +} + +--echo Proof 2: Resume works out +--source include/start_slave.inc +--connection master +--sync_slave_with_master + +--let $diff_tables=master:t2,slave:t2 +--source include/diff_tables.inc + +# +# Clean up. +# +--connection slave +--source include/stop_slave.inc +SET GLOBAL max_relay_log_size=@old_max_relay_log_size; +SET GLOBAL slave_parallel_mode=@old_parallel_mode; +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc + +--connection master +DROP TABLE t1, t2; + +--sync_slave_with_master +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_optimistic_xa.test b/mysql-test/suite/rpl/t/rpl_parallel_optimistic_xa.test new file mode 100644 index 00000000..35c22d1e --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_optimistic_xa.test @@ -0,0 +1,235 @@ +# The tests verify concurrent execution of replicated (MDEV-742) +# XA transactions in the parallel optimistic mode. + +--source include/have_innodb.inc +--source include/have_perfschema.inc +--source include/master-slave.inc + +# Tests' global declarations +--let $trx = _trx_ + +call mtr.add_suppression("Deadlock found when trying to get lock; try restarting transaction"); +call mtr.add_suppression("WSREP: handlerton rollback failed"); +#call mtr.add_suppression("Can't find record in 't1'"); +CREATE VIEW v_processlist as SELECT * FROM performance_schema.threads where type = 'FOREGROUND'; + +--connection master +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +--save_master_pos + +# Prepare to restart slave into optimistic parallel mode +--connection slave +--sync_with_master +--source include/stop_slave.inc +SET @old_parallel_threads = @@GLOBAL.slave_parallel_threads; +SET @@global.slave_parallel_threads = 7; +SET @old_parallel_mode = @@GLOBAL.slave_parallel_mode; +SET @@global.slave_parallel_mode ='optimistic'; +# Run the first part of the test with high batch size and see that +# old rows remain in the table. +SET @old_gtid_cleanup_batch_size = @@GLOBAL.gtid_cleanup_batch_size; +SET @@global.gtid_cleanup_batch_size = 1000000; + +CHANGE MASTER TO master_use_gtid=slave_pos; + +# LOAD GENERATOR creates XA:s interleaved in binlog when they are from +# different connections. All the following block XA:s of the same connection +# update the same data which challenges slave optimistic scheduler's correctness. +# Slave must eventually apply such load, and correctly (checked). + +--connection master +CREATE TABLE t0 (a int, b INT) ENGINE=InnoDB; +CREATE TABLE t1 (a int PRIMARY KEY, b INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, 0); + + +# I. Logging some sequence of XA:s by one connection. +# +# The slave applier's task is to successfully execute a series of +# Prepare and Complete parts of a sequence of XA:s + +--let $trx_num = 300 +--let $i = $trx_num +--let $conn = master +--disable_query_log +while($i > 0) +{ + # 'decision' to commit 0, or rollback 1 + --let $decision = `SELECT $i % 2` + --eval XA START '$conn$trx$i' + --eval UPDATE t1 SET b = 1 - 2 * $decision WHERE a = 1 + --eval XA END '$conn$trx$i' + --let $one_phase = `SELECT IF(floor(rand()*10)%2, "ONE PHASE", 0)` + if (!$one_phase) + { + --eval XA PREPARE '$conn$trx$i' + --let $one_phase = + } + + --let $term = COMMIT + if ($decision) + { + --let $term = ROLLBACK + --let $one_phase = + } + --eval XA $term '$conn$trx$i' $one_phase + + --dec $i +} +--enable_query_log +--source include/save_master_gtid.inc + +--connection slave +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc + + +# II. Logging XS:s from multiple connections in random interweaving manner: +# +# in a loop ($i) per connection +# arrange an inner ($k) loop where +# start and prepare an XA; +# decide whether to terminate it and then continue to loop innerly +# OR disconnect to break the inner loop; +# the disconnected one's XA is taken care by 'master' connection +# +# Effectively binlog must collect a well mixed XA- prepared and terminated +# groups for slave to handle. + +--connection master +# Total # of connections +--let $conn_num=53 + +--let $i = $conn_num +--disable_query_log +while($i > 0) +{ + --connect (master_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,) +--dec $i +} +--enable_query_log + +--let $i = $conn_num +while($i > 0) +{ + --let $conn_i = conn$i + # $i2 indexes the current connection's "own" row + --let $i2 = `SELECT $i + 2` +--disable_query_log + --connection master_conn$i +--enable_query_log + --disable_query_log + --let $i_conn_id = `SELECT connection_id()` + + --let $decision = 0 + # the row id of the last connection that committed its XA + --let $c_max = 1 + --let $k = 0 + while ($decision < 3) + { + --inc $k + --eval XA START '$conn_i$trx$k' + # UPDATE depends on previously *committed* transactions + --eval UPDATE t1 SET b = b + $k + 1 WHERE a = $c_max + if (`SELECT $k % 2 = 1`) + { + --eval REPLACE INTO t1 VALUES ($i2, $k) + } + if (`SELECT $k % 2 = 0`) + { + --eval DELETE FROM t1 WHERE a = $i2 + } + CREATE TEMPORARY TABLE tmp LIKE t0; + --eval INSERT INTO tmp SET a=$i, b= $k + INSERT INTO t0 SELECT * FROM tmp; + DROP TEMPORARY TABLE tmp; + --eval XA END '$conn_i$trx$k' + + --let $term = COMMIT + --let $decision = `SELECT (floor(rand()*10 % 10) + ($i+$k)) % 4` + if ($decision == 1) + { + --let $term = ROLLBACK + } + if ($decision < 2) + { + --eval XA PREPARE '$conn_i$trx$k' + --eval XA $term '$conn_i$trx$k' + # Iteration counter is taken care *now* + } + if ($decision == 2) + { + --eval XA COMMIT '$conn_i$trx$k' ONE PHASE + } + } + + # $decision = 3 + --eval XA PREPARE '$conn_i$trx$k' + # disconnect now + --disconnect master_conn$i + --connection master + + --let $wait_condition= SELECT count(*) = 0 FROM v_processlist WHERE PROCESSLIST_ID = $i_conn_id + --source include/wait_condition.inc + + --disable_query_log + --let $decision = `SELECT ($i+$k) % 2` + --let $term = COMMIT + if ($decision == 1) + { + --let $term = ROLLBACK + } + --eval XA $term '$conn_i$trx$k' + --let $c_max = $i2 + +--dec $i +} +--enable_query_log +--source include/save_master_gtid.inc + +--connection slave +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + +# +# Overall consistency check +# +--let $diff_tables= master:t0, slave:t0 +--source include/diff_tables.inc +--let $diff_tables= master:t1, slave:t1 +--source include/diff_tables.inc + + +# +# Clean up. +# +--connection slave +--source include/stop_slave.inc +set global log_warnings=default; +SET GLOBAL slave_parallel_mode=@old_parallel_mode; +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc + +--connection master +DROP VIEW v_processlist; +DROP TABLE t0, t1; +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc +# Check that old rows are deleted from mysql.gtid_slave_pos. +# Deletion is asynchronous, so use wait_condition.inc. +# Also, there is a small amount of non-determinism in the deletion of old +# rows, so it is not guaranteed that there can never be more than +# @@gtid_cleanup_batch_size rows in the table; so allow a bit of slack +# here. +let $wait_condition= + SELECT COUNT(*) <= 5*@@GLOBAL.gtid_cleanup_batch_size + FROM mysql.gtid_slave_pos; +--source include/wait_condition.inc +eval $wait_condition; +SET GLOBAL gtid_cleanup_batch_size= @old_gtid_cleanup_batch_size; + +--connection master +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_optimistic_xa_lsu_off-slave.opt b/mysql-test/suite/rpl/t/rpl_parallel_optimistic_xa_lsu_off-slave.opt new file mode 100644 index 00000000..88cf77fd --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_optimistic_xa_lsu_off-slave.opt @@ -0,0 +1 @@ +--log-slave-updates=OFF diff --git a/mysql-test/suite/rpl/t/rpl_parallel_optimistic_xa_lsu_off.test b/mysql-test/suite/rpl/t/rpl_parallel_optimistic_xa_lsu_off.test new file mode 100644 index 00000000..f82b522e --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_optimistic_xa_lsu_off.test @@ -0,0 +1,2 @@ +# --log-slave-updates OFF version of rpl_parallel_optimistic_xa +--source rpl_parallel_optimistic_xa.test diff --git a/mysql-test/suite/rpl/t/rpl_parallel_partial_binlog_trans.test b/mysql-test/suite/rpl/t/rpl_parallel_partial_binlog_trans.test new file mode 100644 index 00000000..72479252 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_partial_binlog_trans.test @@ -0,0 +1,71 @@ +--echo *** MDEV_6435: Incorrect error handling when query binlogged partially on master with "killed" error *** + +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/have_binlog_format_statement.inc +--source include/master-slave.inc + +--connection server_2 +--source include/stop_slave.inc +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +SET GLOBAL slave_parallel_threads=1; +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t6 (a INT) ENGINE=MyISAM; +CREATE TRIGGER tr AFTER INSERT ON t6 FOR EACH ROW SET @a = 1; +--connect (con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,) + +--connection con1 +--let $conid = `SELECT CONNECTION_ID()` +SET debug_sync='sp_head_execute_before_loop SIGNAL ready WAIT_FOR cont'; +send INSERT INTO t6 VALUES (1), (2), (3); + +--connection server_1 +SET debug_sync='now WAIT_FOR ready'; +--replace_result $conid CONID +eval KILL QUERY $conid; +SET debug_sync='now SIGNAL cont'; + +--connection con1 +--error ER_QUERY_INTERRUPTED +--reap +SET debug_sync='RESET'; +--let $after_error_gtid_pos= `SELECT @@gtid_binlog_pos` + +--connection server_1 +SET debug_sync='RESET'; + +--connection server_2 +--let $slave_sql_errno= 1317 +--source include/wait_for_slave_sql_error.inc +STOP SLAVE IO_THREAD; +--replace_result $after_error_gtid_pos AFTER_ERROR_GTID_POS +eval SET GLOBAL gtid_slave_pos= '$after_error_gtid_pos'; +--source include/start_slave.inc + +--connection server_1 +INSERT INTO t6 VALUES (4); +SELECT * FROM t6 ORDER BY a; +--save_master_pos + +--connection server_2 +--sync_with_master +SELECT * FROM t6 ORDER BY a; + +# Clean up. +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc +SET DEBUG_SYNC= 'RESET'; + +--connection server_1 +DROP TABLE t6; +SET DEBUG_SYNC= 'RESET'; +--disconnect con1 + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_partition.test b/mysql-test/suite/rpl/t/rpl_parallel_partition.test new file mode 100644 index 00000000..ea6c5dca --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_partition.test @@ -0,0 +1,81 @@ +--source include/have_partition.inc +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/master-slave.inc + +--connection server_2 +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +--source include/stop_slave.inc +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,inject_wakeup_subsequent_commits_sleep"; +SET GLOBAL slave_parallel_threads=8; + +--echo *** MDEV-8147: Assertion `m_lock_type == 2' failed in handler::ha_close() during parallel replication *** +--connection server_1 +CREATE TABLE E ( + pk INTEGER AUTO_INCREMENT, + col_int_nokey INTEGER /*! NULL */, + col_int_key INTEGER /*! NULL */, + + col_date_key DATE /*! NULL */, + col_date_nokey DATE /*! NULL */, + + col_time_key TIME /*! NULL */, + col_time_nokey TIME /*! NULL */, + + col_datetime_key DATETIME /*! NULL */, + col_datetime_nokey DATETIME /*! NULL */, + + col_varchar_key VARCHAR(1) /*! NULL */, + col_varchar_nokey VARCHAR(1) /*! NULL */, + + PRIMARY KEY (pk), + KEY (col_int_key), + KEY (col_date_key), + KEY (col_time_key), + KEY (col_datetime_key), + KEY (col_varchar_key, col_int_key) + ) ENGINE=InnoDB; + +ALTER TABLE `E` PARTITION BY KEY() PARTITIONS 5; +ALTER TABLE `E` REMOVE PARTITIONING; +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait +EOF +--shutdown_server +--source include/wait_until_disconnected.inc +--connection default +--source include/wait_until_disconnected.inc +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart: +EOF +--enable_reconnect +--source include/wait_until_connected_again.inc +--connection server_1 +--enable_reconnect +--source include/wait_until_connected_again.inc +CREATE TABLE t1 (a INT PRIMARY KEY); +--save_master_pos + +--connection server_2 +--source include/start_slave.inc +--sync_with_master + +# Re-spawn worker threads to clear dbug injection. +--source include/stop_slave.inc +SET GLOBAL debug_dbug=@old_dbug; +SET GLOBAL slave_parallel_threads=0; +SET GLOBAL slave_parallel_threads=8; +--source include/start_slave.inc + + +# Clean up. +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE `E`; +DROP TABLE t1; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_record_gtid_wakeup.test b/mysql-test/suite/rpl/t/rpl_parallel_record_gtid_wakeup.test new file mode 100644 index 00000000..0f94d8f9 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_record_gtid_wakeup.test @@ -0,0 +1,72 @@ +--echo *** MDEV-7929: record_gtid() for non-transactional event group calls wakeup_subsequent_commits() too early, causing slave hang. *** + +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/master-slave.inc + +--connection server_2 +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=10; +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM; +CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +--save_master_pos + +--connection server_2 +--sync_with_master +--source include/stop_slave.inc +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug= '+d,inject_record_gtid_serverid_100_sleep'; + +--connection server_1 +# Inject two group commits. The bug was that record_gtid for a +# non-transactional event group would commit its own transaction, which would +# cause ha_commit_trans() to call wakeup_subsequent_commits() too early. This +# in turn lead to access to freed group_commit_orderer object, losing a wakeup +# and causing slave threads to hang. +# We inject a small sleep in the corresponding record_gtid() to make the race +# easier to hit. + +SET @old_dbug= @@SESSION.debug_dbug; +SET SESSION debug_dbug="+d,binlog_force_commit_id"; + +# Group commit with cid=10010, two event groups. +SET @old_server_id= @@SESSION.server_id; +SET SESSION server_id= 100; +SET @commit_id= 10010; +ALTER TABLE t1 COMMENT "Hulubulu!"; +SET SESSION server_id= @old_server_id; +INSERT INTO t3 VALUES (130, 0); + +# Group commit with cid=10011, one event group. +SET @commit_id= 10011; +INSERT INTO t3 VALUES (131, 0); + +SET SESSION debug_dbug=@old_dbug; + +SELECT * FROM t3 WHERE a >= 130 ORDER BY a; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + +SELECT * FROM t3 WHERE a >= 130 ORDER BY a; + +# Clean up. +--source include/stop_slave.inc +SET GLOBAL debug_dbug= @old_dbug; +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t1,t3; + +--source include/rpl_end.inc + diff --git a/mysql-test/suite/rpl/t/rpl_parallel_retry.test b/mysql-test/suite/rpl/t/rpl_parallel_retry.test new file mode 100644 index 00000000..8b2affed --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_retry.test @@ -0,0 +1,514 @@ +--source include/have_innodb.inc +--source include/have_perfschema.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +--echo *** Test retry of transactions that fail to replicate due to deadlock or similar temporary error. *** + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a int PRIMARY KEY, b INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1,1); +--save_master_pos + +# Use a stored function to inject a debug_sync into the appropriate THD. +# The function does nothing on the master, and on the slave it injects the +# desired debug_sync action(s). +SET sql_log_bin=0; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + RETURN x; + END +|| +--delimiter ; +SET sql_log_bin=1; + +--connection server_2 +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=5; +--source include/start_slave.inc +--sync_with_master +SET sql_log_bin=0; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + IF d1 != '' THEN + SET debug_sync = d1; + END IF; + IF d2 != '' THEN + SET debug_sync = d2; + END IF; + RETURN x; + END +|| +--delimiter ; +SET sql_log_bin=1; +--source include/stop_slave.inc + +--connection server_1 +SET gtid_seq_no = 100; +BEGIN; +INSERT INTO t1 VALUES (2,1); +UPDATE t1 SET b=b+1 WHERE a=1; +INSERT INTO t1 VALUES (3,1); +COMMIT; +SELECT * FROM t1 ORDER BY a; +--save_master_pos + +--connection server_2 +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_gtid_0_x_100"; +let $old_retry= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); +--source include/start_slave.inc +--sync_with_master +SET GLOBAL debug_dbug=@old_dbug; +let $new_retry= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); +let $ps_value= query_get_value(select last_trans_retry_count from + performance_schema.replication_applier_status_by_worker where + last_trans_retry_count > 0, last_trans_retry_count, 1); +let $assert_text= Performance Schema retries should match with actual retries; +let $assert_cond= "$ps_value" = $new_retry - $old_retry; +source include/assert.inc; + + +SELECT * FROM t1 ORDER BY a; + + +--echo *** Test that double retry works when the first retry also fails with temp error *** +--source include/stop_slave.inc + +--connection server_1 +SET gtid_seq_no = 100; +SET @old_server_id = @@server_id; +SET server_id = 10; +BEGIN; +INSERT INTO t1 VALUES (4,1); +UPDATE t1 SET b=b+1 WHERE a=1; +INSERT INTO t1 VALUES (5,1); +INSERT INTO t1 VALUES (6,1); +COMMIT; +SET server_id = @old_server_id; +SELECT * FROM t1 ORDER BY a; +--save_master_pos + +--connection server_2 +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_gtid_0_x_100,rpl_parallel_simulate_double_temp_err_gtid_0_x_100"; +let $old_retry= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); +--source include/start_slave.inc +--sync_with_master +SET GLOBAL debug_dbug=@old_dbug; +let $new_retry= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); +let $ps_value= query_get_value(select last_trans_retry_count from + performance_schema.replication_applier_status_by_worker where + last_trans_retry_count > 0, last_trans_retry_count, 1); +let $assert_text= Performance Schema retries should match with actual retries; +let $assert_cond= "$ps_value" = $new_retry - $old_retry; +source include/assert.inc; + +SELECT * FROM t1 ORDER BY a; + + +--echo *** Test too many retries, eventually causing failure. *** +--source include/stop_slave.inc + +--connection server_1 +SET gtid_seq_no = 100; +SET @old_server_id = @@server_id; +SET server_id = 11; +BEGIN; +INSERT INTO t1 VALUES (7,1); +UPDATE t1 SET b=b+1 WHERE a=1; +INSERT INTO t1 VALUES (8,1); +INSERT INTO t1 VALUES (9,1); +COMMIT; +SET server_id = @old_server_id; +SELECT * FROM t1 ORDER BY a; +--save_master_pos + +--connection server_2 +SET sql_log_bin=0; +CALL mtr.add_suppression("Slave worker thread retried transaction 10 time\\(s\\) in vain, giving up"); +CALL mtr.add_suppression("Slave: Deadlock found when trying to get lock; try restarting transaction"); +CALL mtr.add_suppression("Slave worker thread retried transaction .* in vain, giving up"); +SET sql_log_bin=1; + +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_gtid_0_x_100,rpl_parallel_simulate_infinite_temp_err_gtid_0_x_100"; +let $old_retry= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); +START SLAVE; +--let $slave_sql_errno= 1213 +--source include/wait_for_slave_sql_error.inc +SET GLOBAL debug_dbug=@old_dbug; +let $new_retry= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); +--disable_query_log +eval SELECT $new_retry - $old_retry AS retries; +--enable_query_log +let $ps_value= query_get_value(select last_trans_retry_count from + performance_schema.replication_applier_status_by_worker where + last_trans_retry_count > 0, last_trans_retry_count, 1); +let $assert_text= Performance Schema retries should match with actual retries; +let $assert_cond= "$ps_value" = $new_retry - $old_retry; +source include/assert.inc; + +SELECT * FROM t1 ORDER BY a; +STOP SLAVE IO_THREAD; +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 ORDER BY a; + +--echo *** Test retry of event group that spans multiple relay log files. *** + +--connection server_1 +CREATE TABLE t2 (a int PRIMARY KEY, b BLOB) ENGINE=InnoDB; +INSERT INTO t2 VALUES (1,"Hulubullu"); +--save_master_pos + +--connection server_2 +--sync_with_master +--source include/stop_slave.inc +SET @old_max= @@GLOBAL.max_relay_log_size; +SET GLOBAL max_relay_log_size=4096; + +--connection server_1 +--let $big= `SELECT REPEAT("*", 5000)` +SET gtid_seq_no = 100; +SET @old_server_id = @@server_id; +SET server_id = 12; +BEGIN; +--disable_query_log +eval INSERT INTO t2 VALUES (2, CONCAT("Hello ", "$big")); +eval INSERT INTO t2 VALUES (3, CONCAT("Long data: ", "$big")); +--enable_query_log +INSERT INTO t1 VALUES (10, 4); +COMMIT; +SET server_id = @old_server_id; +SELECT * FROM t1 WHERE a >= 10 ORDER BY a; +SELECT a, LENGTH(b) FROM t2 ORDER BY a; +--save_master_pos + +--connection server_2 +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_gtid_0_x_100"; +let $old_retry= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); +--source include/start_slave.inc +--sync_with_master +SET GLOBAL debug_dbug=@old_dbug; +let $new_retry= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); +let $ps_value= query_get_value(select last_trans_retry_count from + performance_schema.replication_applier_status_by_worker where + last_trans_retry_count > 0, last_trans_retry_count, 1); +let $assert_text= Performance Schema retries should match with actual retries; +let $assert_cond= "$ps_value" = $new_retry - $old_retry; +source include/assert.inc; + +SELECT * FROM t1 WHERE a >= 10 ORDER BY a; +SELECT a, LENGTH(b) FROM t2 ORDER BY a; + +--connection server_1 +INSERT INTO t1 VALUES (11,11); +--disable_query_log +eval INSERT INTO t2 VALUES (4, "$big"); +--enable_query_log +--save_master_pos + +--connection server_2 +--sync_with_master +SELECT * FROM t1 WHERE a >= 10 ORDER BY a; +SELECT a, LENGTH(b) FROM t2 ORDER BY a; +SET GLOBAL max_relay_log_size=@old_max; + + +--echo *** MDEV-7065: Incorrect relay log position in parallel replication after retry of transaction *** + +--connection server_2 +--source include/stop_slave.inc + +--connection server_1 +BEGIN; +INSERT INTO t1 VALUES (100, 0); +INSERT INTO t1 VALUES (101, 0); +INSERT INTO t1 VALUES (102, 0); +INSERT INTO t1 VALUES (103, 0); +COMMIT; +SELECT * FROM t1 WHERE a >= 100 ORDER BY a; +--save_master_pos + +--connection server_2 +# Inject a DBUG error insert to cause the XID event of the single transaction +# from the master to fail with a deadlock error and be retried. +# The bug was that the retry of the XID would leave the relay log position +# incorrect (off by the size of XID event). +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_xid"; +let $old_retry= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); +--source include/start_slave.inc +--sync_with_master +SET GLOBAL debug_dbug=@old_dbug; +let $new_retry= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); +let $ps_value= query_get_value(select last_trans_retry_count from + performance_schema.replication_applier_status_by_worker where + last_trans_retry_count > 0, last_trans_retry_count, 1); +let $assert_text= Performance Schema retries should match with actual retries; +let $assert_cond= "$ps_value" = $new_retry - $old_retry; +source include/assert.inc; + +SELECT * FROM t1 WHERE a >= 100 ORDER BY a; +# Stop the SQL thread. When the bug was there to give the incorrect relay log +# position, the restart of the SQL thread would read garbage data from the +# middle of an event and fail with relay log IO error. +--source include/stop_slave_sql.inc + +--connection server_1 +INSERT INTO t1 VALUES (104, 1); +INSERT INTO t1 VALUES (105, 1); +INSERT INTO t1 VALUES (106, 1); +INSERT INTO t1 VALUES (107, 1); +INSERT INTO t1 VALUES (108, 1); +INSERT INTO t1 VALUES (109, 1); +--save_master_pos + +--connection server_2 +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 WHERE a >= 100 ORDER BY a; + + +--echo *** MDEV-6917: Parallel replication: "Commit failed due to failure of an earlier commit on which this one depends", but no prior failure seen ** + +--connection server_1 +CREATE TABLE t3 (a INT PRIMARY KEY, b INT, KEY b_idx(b)) ENGINE=InnoDB; +INSERT INTO t3 VALUES (1,NULL), (2,2), (3,NULL), (4,4), (5, NULL), (6, 6); +CREATE TABLE t4 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +# MDEV-515 takes X-lock on the table for the first insert. +# So concurrent insert won't happen on the table +INSERT INTO t4 VALUES(100, 100); + +# We need statement binlog format to be able to inject debug_sync statements +# on the slave with calls to foo(). +SET @old_format= @@SESSION.binlog_format; +SET binlog_format='statement'; +--save_master_pos + +--connection server_2 +--sync_with_master +--source include/stop_slave.inc +CHANGE MASTER TO master_use_gtid=no; + +--connection server_1 + +# Create a group commit with three transactions T1, T2, T3. +# T2 will block T1 on the slave where we will make it run first, so it will be +# deadlock killed. +# The bug was that in this case, T3 was signalled to fail due to T2 failing, +# even though the retry of T2 was later successful. + +--connect (con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +SET @old_format= @@SESSION.binlog_format; +SET binlog_format='statement'; +BEGIN; +INSERT INTO t4 VALUES (10, foo(1, 'before_execute_sql_command WAIT_FOR t1_start', '')); +UPDATE t3 SET b=NULL WHERE a=6; +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1'; +send COMMIT; +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued1'; + +--connect (con2,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +SET @old_format= @@SESSION.binlog_format; +SET binlog_format='statement'; +BEGIN; +INSERT INTO t4 VALUES (20, foo(2, 'group_commit_waiting_for_prior SIGNAL t2_waiting', '')); +DELETE FROM t3 WHERE b <= 3; +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2'; +send COMMIT; + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued2'; + +--connect (con3,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +SET @old_format= @@SESSION.binlog_format; +SET binlog_format='statement'; +BEGIN; +INSERT INTO t4 VALUES (30, foo(3, 'before_execute_sql_command WAIT_FOR t3_start', 'group_commit_waiting_for_prior SIGNAL t3_waiting')); +INSERT INTO t3 VALUES (7,7); +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3'; +send COMMIT; + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued3'; +SET debug_sync='now SIGNAL master_cont1'; + +--connection con1 +REAP; +SET binlog_format=@old_format; +--connection con2 +REAP; +SET binlog_format=@old_format; +--connection con3 +REAP; +SET debug_sync='RESET'; +SET binlog_format=@old_format; + +--connection server_1 +--save_master_pos +SELECT * FROM t3 ORDER BY a; + + +--connection server_2 +let $old_retry= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); +SET @old_dbug=@@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,thd_need_ordering_with_force"; +--source include/start_slave.inc +# First, wait for T2 to complete up to where it is waiting for T1 to group +# commit for both of them. This will set locks that will block T1, causing +# a deadlock kill and retry of T2. T1 and T3 are still blocked at the start +# of each their SQL statements. +SET debug_sync='now WAIT_FOR t2_waiting'; +# Now let T3 move on until the point where it is itself ready to commit. +SET debug_sync='now SIGNAL t3_start'; +SET debug_sync='now WAIT_FOR t3_waiting'; +# Now T2 and T3 are set up, so we can let T1 proceed. +SET debug_sync='now SIGNAL t1_start'; +# Now we can wait for the slave to catch up. +# We should see T2 being deadlock killed and retried. +# The bug was that T2 deadlock kill would cause T3 to fail due to failure +# of an earlier commit. This is wrong as T2 did not fail, it was only +# retried. +--sync_with_master +SET GLOBAL debug_dbug=@old_dbug; +SET debug_sync='RESET'; +let $new_retry= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); +let $ps_value= query_get_value(select last_trans_retry_count from + performance_schema.replication_applier_status_by_worker where + last_trans_retry_count > 0, last_trans_retry_count, 1); +let $assert_text= Performance Schema retries should match with actual retries; +let $assert_cond= "$ps_value" = $new_retry - $old_retry; +source include/assert.inc; +SELECT * FROM t3 ORDER BY a; + + +--connection server_1 +SET binlog_format=@old_format; + + +# Clean up of the above part. +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t1, t2, t3, t4; +DROP function foo; + +--sync_slave_with_master server_2 + +# +# MDEV-12746 rpl.rpl_parallel_optimistic_nobinlog fails committing out of order at retry +# + +--connection server_1 +CREATE TABLE t1 (a int PRIMARY KEY, b INT) ENGINE=InnoDB; +# MDEV-515 takes X-lock on the table for the first insert. +# So concurrent insert won't happen on the table +INSERT INTO t1 VALUES(100, 100); + +# Replicate create-t1 and prepare to re-start slave in optimistic mode +--sync_slave_with_master server_2 +--source include/stop_slave.inc +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +SET @@GLOBAL.slave_parallel_threads=5; +SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode; +SET @@GLOBAL.slave_parallel_mode='aggressive'; +SET @old_lock_wait_timeout=@@GLOBAL.innodb_lock_wait_timeout; +SET @@GLOBAL.innodb_lock_wait_timeout=2; +SET @old_slave_transaction_retries=@@GLOBAL.slave_transaction_retries; +SET @@GLOBAL.slave_transaction_retries=1; + +--echo # Spoilers on the slave side causing temporary errors +--connect (spoiler_21,127.0.0.1,root,,test,$SLAVE_MYPORT) +BEGIN; + INSERT INTO t1 SET a=1,b=2; + +--connect (spoiler_22,127.0.0.1,root,,test,$SLAVE_MYPORT) +BEGIN; + INSERT INTO t1 SET a=2,b=2; + +--echo # Master payload +--connection server_1 +SET @@SESSION.GTID_SEQ_NO=1000; +INSERT INTO t1 SET a=1,b=1; +SET @@SESSION.GTID_SEQ_NO=1001; +INSERT INTO t1 SET a=2,b=1; + +--echo # Start slave whose both appliers is destined to being blocked +--connection server_2 +SET @old_dbug= @@GLOBAL.debug_dbug; +SET @@GLOBAL.debug_dbug="+d,rpl_parallel_simulate_wait_at_retry"; +--source include/start_slave.inc + +--echo # Make sure both workers are waiting at their sync points +--let $wait_condition= SELECT count(*)=2 FROM information_schema.processlist WHERE state LIKE '%debug sync point%'; +--source include/wait_condition.inc + + +--echo # Signal to the 1st to proceed after it has reached termination state +SET @@DEBUG_SYNC='now SIGNAL proceed_by_1000'; +--connection spoiler_21 +ROLLBACK; + +--let $wait_condition= SELECT count(*)=1 FROM information_schema.processlist WHERE state LIKE '%debug sync point%'; +--source include/wait_condition.inc + +--echo # Release the 2nd worker to proceed +--connection spoiler_22 +ROLLBACK; +--connection server_2 +SET @@DEBUG_SYNC='now SIGNAL proceed_by_1001'; + +--echo # observe how it all ends +if (`SELECT count(*) = 1 FROM t1 WHERE a = 1`) +{ + --echo "*** Unexpected commit by the first Worker ***" + SELECT * from t1; + --die +} + +--echo # Wait for the workers to go home and check the result of applying +--let $wait_condition=SELECT count(*) = 0 FROM information_schema.processlist WHERE command = 'Slave_worker' +--source include/wait_condition.inc +if (`SELECT count(*) = 1 FROM t1 WHERE a = 2`) +{ + --echo + --echo "*** Error: congrats, you hit MDEV-12746 issue. ***" + --echo + --die +} +--echo # which is OK + +# +# Clean up +# +--connection server_2 +--source include/stop_slave.inc +SET @@GLOBAL.slave_parallel_threads=@old_parallel_threads; +SET @@GLOBAL.slave_parallel_mode=@old_parallel_mode; +SET @@GLOBAL.innodb_lock_wait_timeout=@old_lock_wait_timeout; +SET @@GLOBAL.slave_transaction_retries=@old_slave_transaction_retries; +SET @@GLOBAL.debug_dbug=@old_dbug; +SET debug_sync='RESET'; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t1; + +--sync_slave_with_master server_2 + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_retry_deadlock.test b/mysql-test/suite/rpl/t/rpl_parallel_retry_deadlock.test new file mode 100644 index 00000000..54ac859b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_retry_deadlock.test @@ -0,0 +1,281 @@ +--echo *** MDEV-7326 Server deadlock in connection with parallel replication *** +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/master-slave.inc + +--connection server_2 +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode; +--source include/stop_slave.inc +# Test assumes that 'conservative' mode is in effect. i.e +# Do not start parallel execution of this event group until all prior groups +# have reached the commit phase. Refer 'rpl_parallel_start_waiting_for_prior' +# debug simumation. +SET GLOBAL slave_parallel_mode='conservative'; +SET GLOBAL slave_parallel_threads=10; +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM; +CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t6 (a INT) ENGINE=MyISAM; +--save_master_pos + +--connection server_2 +--sync_with_master + +--connection server_1 +# Use a stored function to inject a debug_sync into the appropriate THD. +# The function does nothing on the master, and on the slave it injects the +# desired debug_sync action(s). +SET sql_log_bin=0; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + RETURN x; + END +|| +--delimiter ; +SET sql_log_bin=1; + +--connection server_2 +SET sql_log_bin=0; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + IF d1 != '' THEN + SET debug_sync = d1; + END IF; + IF d2 != '' THEN + SET debug_sync = d2; + END IF; + RETURN x; + END +|| +--delimiter ; +SET sql_log_bin=1; + +# We use three transactions, each in a separate group commit. +# T1 does mark_start_commit(), then gets a deadlock error. +# T2 wakes up and starts running +# T1 does unmark_start_commit() +# T3 goes to wait for T2 to start its commit +# T2 does mark_start_commit() +# The bug was that at this point, T3 got deadlocked. Because T1 has unmarked(), +# T3 did not yet see the count_committing_event_groups reach its target value +# yet. But when T1 later re-did mark_start_commit(), it failed to send a wakeup +# to T3. + +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=0; +SET GLOBAL slave_parallel_threads=3; +SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_xid"; +--source include/start_slave.inc + +--connection server_1 +SET @old_format= @@SESSION.binlog_format; +SET binlog_format= STATEMENT; +# This debug_sync will linger on and be used to control T3 later. +INSERT INTO t1 VALUES (foo(50, + "rpl_parallel_start_waiting_for_prior SIGNAL t3_ready", + "rpl_parallel_end_of_group SIGNAL prep_ready WAIT_FOR prep_cont")); +--save_master_pos +--connection server_2 +# Wait for the debug_sync point for T3 to be set. But let the preparation +# transaction remain hanging, so that T1 and T2 will be scheduled for the +# remaining two worker threads. +SET DEBUG_SYNC= "now WAIT_FOR prep_ready"; + +--connection server_1 +INSERT INTO t2 VALUES (foo(50, + "rpl_parallel_simulate_temp_err_xid SIGNAL t1_ready1 WAIT_FOR t1_cont1", + "rpl_parallel_retry_after_unmark SIGNAL t1_ready2 WAIT_FOR t1_cont2")); +--save_master_pos + +--connection server_2 +SET DEBUG_SYNC= "now WAIT_FOR t1_ready1"; +# T1 has now done mark_start_commit(). It will later do a rollback and retry. + +--connection server_1 +# Use a MyISAM table for T2 and T3, so they do not trigger the +# rpl_parallel_simulate_temp_err_xid DBUG insertion on XID event. +INSERT INTO t1 VALUES (foo(51, + "rpl_parallel_before_mark_start_commit SIGNAL t2_ready1 WAIT_FOR t2_cont1", + "rpl_parallel_after_mark_start_commit SIGNAL t2_ready2")); + +--connection server_2 +SET DEBUG_SYNC= "now WAIT_FOR t2_ready1"; +# T2 has now started running, but has not yet done mark_start_commit() +SET DEBUG_SYNC= "now SIGNAL t1_cont1"; +SET DEBUG_SYNC= "now WAIT_FOR t1_ready2"; +# T1 has now done unmark_start_commit() in preparation for its retry. + +--connection server_1 +INSERT INTO t1 VALUES (52); +SET BINLOG_FORMAT= @old_format; +SELECT * FROM t2 WHERE a>=50 ORDER BY a; +SELECT * FROM t1 WHERE a>=50 ORDER BY a; + +--connection server_2 +# Let the preparation transaction complete, so that the same worker thread +# can continue with the transaction T3. +SET DEBUG_SYNC= "now SIGNAL prep_cont"; +SET DEBUG_SYNC= "now WAIT_FOR t3_ready"; +# T3 has now gone to wait for T2 to start committing +SET DEBUG_SYNC= "now SIGNAL t2_cont1"; +SET DEBUG_SYNC= "now WAIT_FOR t2_ready2"; +# T2 has now done mark_start_commit(). +# Let things run, and check that T3 does not get deadlocked. +SET DEBUG_SYNC= "now SIGNAL t1_cont2"; +--sync_with_master + +--connection server_1 +--save_master_pos +--connection server_2 +--sync_with_master +SELECT * FROM t2 WHERE a>=50 ORDER BY a; +SELECT * FROM t1 WHERE a>=50 ORDER BY a; +SET DEBUG_SYNC="reset"; + +# Re-spawn the worker threads to remove any DBUG injections or DEBUG_SYNC. +--source include/stop_slave.inc +SET GLOBAL debug_dbug=@old_dbug; +SET GLOBAL slave_parallel_mode=@old_parallel_mode; +SET GLOBAL slave_parallel_threads=0; +SET GLOBAL slave_parallel_threads=10; +--source include/start_slave.inc + + +--echo *** MDEV-7326 Server deadlock in connection with parallel replication *** +# Similar to the previous test, but with T2 and T3 in the same GCO. +# We use three transactions, T1 in one group commit and T2/T3 in another. +# T1 does mark_start_commit(), then gets a deadlock error. +# T2 wakes up and starts running +# T1 does unmark_start_commit() +# T3 goes to wait for T1 to start its commit +# T2 does mark_start_commit() +# The bug was that at this point, T3 got deadlocked. T2 increments the +# count_committing_event_groups but does not signal T3, as they are in +# the same GCO. Then later when T1 increments, it would also not signal +# T3, because now the count_committing_event_groups is not equal to the +# wait_count of T3 (it is one larger). + +--connect (con_temp3,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +--connect (con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,) + +--connection server_2 +--source include/stop_slave.inc +SET @old_parallel_mode= @@GLOBAL.slave_parallel_mode; +SET GLOBAL slave_parallel_mode='conservative'; +SET GLOBAL slave_parallel_threads=0; +SET GLOBAL slave_parallel_threads=3; +SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_xid"; +--source include/start_slave.inc + +--connection server_1 +SET @old_format= @@SESSION.binlog_format; +SET binlog_format= STATEMENT; +# This debug_sync will linger on and be used to control T3 later. +INSERT INTO t1 VALUES (foo(60, + "rpl_parallel_start_waiting_for_prior SIGNAL t3_ready", + "rpl_parallel_end_of_group SIGNAL prep_ready WAIT_FOR prep_cont")); +--save_master_pos +--connection server_2 +# Wait for the debug_sync point for T3 to be set. But let the preparation +# transaction remain hanging, so that T1 and T2 will be scheduled for the +# remaining two worker threads. +SET DEBUG_SYNC= "now WAIT_FOR prep_ready"; + +--connection server_1 +INSERT INTO t2 VALUES (foo(60, + "rpl_parallel_simulate_temp_err_xid SIGNAL t1_ready1 WAIT_FOR t1_cont1", + "rpl_parallel_retry_after_unmark SIGNAL t1_ready2 WAIT_FOR t1_cont2")); +--save_master_pos + +--connection server_2 +SET DEBUG_SYNC= "now WAIT_FOR t1_ready1"; +# T1 has now done mark_start_commit(). It will later do a rollback and retry. + +# Do T2 and T3 in a single group commit. +# Use a MyISAM table for T2 and T3, so they do not trigger the +# rpl_parallel_simulate_temp_err_xid DBUG insertion on XID event. +--connection con_temp3 +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1'; +SET binlog_format=statement; +send INSERT INTO t1 VALUES (foo(61, + "rpl_parallel_before_mark_start_commit SIGNAL t2_ready1 WAIT_FOR t2_cont1", + "rpl_parallel_after_mark_start_commit SIGNAL t2_ready2")); + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued1'; + +--connection con_temp4 +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2'; +send INSERT INTO t6 VALUES (62); + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued2'; +SET debug_sync='now SIGNAL master_cont1'; + +--connection con_temp3 +REAP; +--connection con_temp4 +REAP; + +--connection server_1 +SET debug_sync='RESET'; +SET BINLOG_FORMAT= @old_format; +SELECT * FROM t2 WHERE a>=60 ORDER BY a; +SELECT * FROM t1 WHERE a>=60 ORDER BY a; +SELECT * FROM t6 WHERE a>=60 ORDER BY a; + +--connection server_2 +SET DEBUG_SYNC= "now WAIT_FOR t2_ready1"; +# T2 has now started running, but has not yet done mark_start_commit() +SET DEBUG_SYNC= "now SIGNAL t1_cont1"; +SET DEBUG_SYNC= "now WAIT_FOR t1_ready2"; +# T1 has now done unmark_start_commit() in preparation for its retry. + +--connection server_2 +# Let the preparation transaction complete, so that the same worker thread +# can continue with the transaction T3. +SET DEBUG_SYNC= "now SIGNAL prep_cont"; +SET DEBUG_SYNC= "now WAIT_FOR t3_ready"; +# T3 has now gone to wait for T2 to start committing +SET DEBUG_SYNC= "now SIGNAL t2_cont1"; +SET DEBUG_SYNC= "now WAIT_FOR t2_ready2"; +# T2 has now done mark_start_commit(). +# Let things run, and check that T3 does not get deadlocked. +SET DEBUG_SYNC= "now SIGNAL t1_cont2"; +--sync_with_master + +--connection server_1 +--save_master_pos +--connection server_2 +--sync_with_master +SELECT * FROM t2 WHERE a>=60 ORDER BY a; +SELECT * FROM t1 WHERE a>=60 ORDER BY a; +SELECT * FROM t6 WHERE a>=60 ORDER BY a; +SET DEBUG_SYNC="reset"; + +# Clean up. +--source include/stop_slave.inc +SET GLOBAL debug_dbug=@old_dbug; +SET GLOBAL slave_parallel_mode=@old_parallel_mode; +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc + +--connection server_1 +DROP function foo; +DROP TABLE t1,t2,t6; +--disconnect con_temp3 +--disconnect con_temp4 +SET DEBUG_SYNC= 'RESET'; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_rollback_assert.test b/mysql-test/suite/rpl/t/rpl_parallel_rollback_assert.test new file mode 100644 index 00000000..eec331b3 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_rollback_assert.test @@ -0,0 +1,62 @@ +--echo *** MDEV-8725: Assertion on ROLLBACK statement in the binary log *** +--source include/have_innodb.inc +--source include/master-slave.inc + +--connection server_2 +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=10; +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM; +CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB; +--save_master_pos + +--connection server_2 +--sync_with_master + +--connection server_1 +# Inject an event group terminated by ROLLBACK, by mixing MyISAM and InnoDB +# in a transaction. The bug was an assertion on the ROLLBACK due to +# mark_start_commit() being already called. +--disable_warnings +BEGIN; +INSERT INTO t2 VALUES (2000); +INSERT INTO t1 VALUES (2000); +INSERT INTO t2 VALUES (2001); +ROLLBACK; +--enable_warnings +SELECT * FROM t1 WHERE a>=2000 ORDER BY a; +SELECT * FROM t2 WHERE a>=2000 ORDER BY a; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc + +--connection server_1 +INSERT INTO t2 VALUES (2020); +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc +SELECT * FROM t2 WHERE a>=2000 ORDER BY a; +let $rows_in_t1= `SELECT COUNT(*) FROM t1 WHERE a>=2000 ORDER BY a`; +if ($rows_in_t1 == 0) +{ +--query_vertical SHOW SLAVE STATUS +} +SELECT * FROM t1 WHERE a>=2000 ORDER BY a; + +# Clean up. +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t1,t2; + +--source include/rpl_end.inc + diff --git a/mysql-test/suite/rpl/t/rpl_parallel_sbm-slave.opt b/mysql-test/suite/rpl/t/rpl_parallel_sbm-slave.opt new file mode 100644 index 00000000..c3407cde --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_sbm-slave.opt @@ -0,0 +1 @@ +--slave-parallel-threads=2 diff --git a/mysql-test/suite/rpl/t/rpl_parallel_sbm.test b/mysql-test/suite/rpl/t/rpl_parallel_sbm.test new file mode 100644 index 00000000..58c0db15 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_sbm.test @@ -0,0 +1,218 @@ +# +# Ensure that Seconds_Behind_Master works correctly on the parallel replica. +# +--source include/master-slave.inc +--source include/have_log_bin.inc +--source include/have_debug.inc + +--echo # +--echo # MDEV-29639: Seconds_Behind_Master is incorrect for Delayed, Parallel Replicas +--echo # + +# This test ensures that after a delayed parallel slave has idled, i.e. +# executed everything in its relay log, the next event group that the SQL +# thread reads from the relay log will immediately be used in the +# Seconds_Behind_Master. In particular, it ensures that the calculation for +# Seconds_Behind_Master is based on the timestamp of the new transaction, +# rather than the last committed transaction. +# + +--connection slave +--source include/stop_slave.inc +--let $save_dbug= `SELECT @@GLOBAL.debug_dbug` +--let $save_parallel_mode= `SELECT @@GLOBAL.slave_parallel_mode` +set @@GLOBAL.debug_dbug= "d,negate_clock_diff_with_master"; +set @@GLOBAL.slave_parallel_mode= CONSERVATIVE; +--let $master_delay= 3 +--eval change master to master_delay=$master_delay, master_use_gtid=Slave_Pos +--source include/start_slave.inc + +--connection master +--let insert_ctr= 0 +create table t1 (a int); +create table t2 (a int); +--source include/sync_slave_sql_with_master.inc + +--echo # +--echo # Pt 1) Ensure SBM is updated immediately upon arrival of the next event + +--connection master +--echo # Sleep 2 to allow a buffer between events for SBM check +sleep 2; + +--let $ts_trx_before_ins= `SELECT UNIX_TIMESTAMP()` +--eval insert into t1 values ($insert_ctr) +--inc $insert_ctr +--source include/save_master_gtid.inc + +--connection slave + +--echo # Waiting for transaction to arrive on slave and begin SQL Delay.. +--let $wait_condition= SELECT count(*) FROM information_schema.processlist WHERE state LIKE 'Waiting until MASTER_DELAY seconds after master executed event'; +--source include/wait_condition.inc + +--echo # Validating SBM is updated on event arrival.. +--let $sbm_trx1_arrive= query_get_value(SHOW SLAVE STATUS, Seconds_Behind_Master, 1) +--let $seconds_since_idling= `SELECT UNIX_TIMESTAMP() - $ts_trx_before_ins` +if (`SELECT $sbm_trx1_arrive > ($seconds_since_idling + 1)`) +{ + --echo # SBM was $sbm_trx1_arrive yet shouldn't have been larger than $seconds_since_idling + 1 (for possible negative clock_diff_with_master) + --die Seconds_Behind_Master should reset after idling +} +--echo # ..done + + +--echo # MDEV-32265. At time of STOP SLAVE, if the SQL Thread is currently +--echo # delaying a transaction; then when the reciprocal START SLAVE occurs, +--echo # if the event is still to be delayed, SBM should resume accordingly + +--source include/stop_slave.inc +--source include/start_slave.inc + +--connection slave +--echo # Waiting for replica to resume the delay for the transaction +--let $wait_condition= SELECT count(*) FROM information_schema.processlist WHERE state LIKE 'Waiting until MASTER_DELAY seconds after master executed event'; +--source include/wait_condition.inc + +--echo # Sleeping 1s to increment SBM +sleep 1; + +--echo # Ensuring Seconds_Behind_Master increases after sleeping.. +--let $sbm_trx1_after_1s_sleep= query_get_value(SHOW SLAVE STATUS, Seconds_Behind_Master, 1) +if (`SELECT $sbm_trx1_after_1s_sleep <= $sbm_trx1_arrive`) +{ + --echo # ..failed + --die Seconds_Behind_Master did not increase after sleeping, but should have +} +--echo # ..done + +--source include/sync_with_master_gtid.inc + +--echo # +--echo # Pt 2) If the worker threads have not entered an idle state, ensure +--echo # following events do not update SBM + +--connection slave +LOCK TABLES t1 WRITE; + +--connection master +--echo # Sleep 2 to allow a buffer between events for SBM check +sleep 2; +--let $ts_trxpt2_before_ins= `SELECT UNIX_TIMESTAMP()` +--eval insert into t1 values ($insert_ctr) +--inc $insert_ctr +--echo # Sleep 3 to create gap between events +sleep 3; +--eval insert into t1 values ($insert_ctr) +--inc $insert_ctr +--let $ts_trx_after_ins= `SELECT UNIX_TIMESTAMP()` +--source include/save_master_pos.inc + +--connection slave +--echo # Wait for first transaction to complete SQL delay and begin execution.. +--let $wait_condition= SELECT count(*) FROM information_schema.processlist WHERE state LIKE 'Waiting for table metadata lock%' AND command LIKE 'Slave_Worker'; +--source include/wait_condition.inc + +--echo # Validate SBM calculation doesn't use the second transaction because worker threads shouldn't have gone idle.. +--let $sbm_after_trx_no_idle= query_get_value(SHOW SLAVE STATUS, Seconds_Behind_Master, 1) +--let $timestamp_trxpt2_arrive= `SELECT UNIX_TIMESTAMP()` +if (`SELECT $sbm_after_trx_no_idle < $timestamp_trxpt2_arrive - $ts_trx_after_ins - 1`) +{ + --let $cmpv= `SELECT $timestamp_trxpt2_arrive - $ts_trx_after_ins` + --echo # SBM $sbm_after_trx_no_idle was more recent than time since last transaction ($cmpv seconds) + --die Seconds_Behind_Master should not have used second transaction timestamp +} +--let $seconds_since_idling= `SELECT ($timestamp_trxpt2_arrive - $ts_trxpt2_before_ins)` +--echo # ..and that SBM wasn't calculated using prior committed transactions +if (`SELECT $sbm_after_trx_no_idle > ($seconds_since_idling + 1)`) +{ + --echo # SBM was $sbm_after_trx_no_idle yet shouldn't have been larger than $seconds_since_idling + 1 (for possible negative clock_diff_with_master) + --die Seconds_Behind_Master calculation should not have used prior committed transaction +} +--echo # ..done + +--connection slave +UNLOCK TABLES; +--source include/sync_with_master.inc + +--echo # Cleanup +--source include/stop_slave.inc +--eval CHANGE MASTER TO master_delay=0 +--source include/start_slave.inc + + +--echo # +--echo # MDEV-30619: Parallel Slave SQL Thread Can Update Seconds_Behind_Master with Active Workers +--echo # + +# This test ensures that a parallel slave will not update +# Seconds_Behind_Master after the SQL Thread has idled if the worker threads +# are still executing events. To test this, two events are executed on the +# primary with $sleep seconds in-between them. Once the second event begins +# execution on the replica, Seconds_Behind_Master is queried to ensure it +# reflects the value of the first transaction, rather than the second. + +--connection slave +--echo # Ensure the replica is fully idle before starting transactions +--let $wait_condition= SELECT count(*) FROM information_schema.processlist WHERE state LIKE 'Slave has read all relay log%'; +--source include/wait_condition.inc +--let $wait_condition= SELECT count(*)=2 FROM information_schema.processlist WHERE state LIKE 'Waiting for work from SQL thread'; +--source include/wait_condition.inc + +--echo # Lock t1 on slave so the first received transaction does not complete/commit +LOCK TABLES t1 WRITE; + +--connection master +--let $ts_t1_before_master_ins= `SELECT UNIX_TIMESTAMP()` +--eval insert into t1 values ($insert_ctr) +--inc $insert_ctr +--source include/save_master_gtid.inc + +--connection slave +--echo # Waiting for first transaction to begin.. +--let $wait_condition= SELECT count(*) FROM information_schema.processlist WHERE state LIKE 'Waiting for table metadata lock'; +--source include/wait_condition.inc + +--let $sbm_1= query_get_value(SHOW SLAVE STATUS, Seconds_Behind_Master, 1) + +--connection master +--let $sleep = 2 +--echo # Sleep $sleep sec to create a gap between events +sleep $sleep; +INSERT INTO t2 VALUES (1); +--source include/save_master_gtid.inc + +--connection slave +--echo # Waiting for second transaction to begin.. +--let $wait_condition= SELECT count(*) FROM information_schema.processlist WHERE state LIKE 'Waiting for prior transaction to start commit%'; +--source include/wait_condition.inc + +--let $sbm_2= query_get_value(SHOW SLAVE STATUS, Seconds_Behind_Master, 1) + +if (`SELECT $sbm_1 + $sleep > $sbm_2`) +{ + --echo # Seconds_Behind_Masters: $sbm_1 $sbm_2_0 + --die Two successive Seconds_Behind_Master timestamps must be separated by the sleep parameter value or greater +} + +--connection slave +UNLOCK TABLES; +--source include/sync_with_master_gtid.inc + + +--echo # +--echo # Cleanup + +--connection master +DROP TABLE t1, t2; +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc +--eval set @@GLOBAL.debug_dbug= "$save_dbug" +--evalp set @@GLOBAL.slave_parallel_mode= "$save_parallel_mode" +--source include/start_slave.inc + +--source include/rpl_end.inc +--echo # End of rpl_parallel_sbm.test diff --git a/mysql-test/suite/rpl/t/rpl_parallel_seq.test b/mysql-test/suite/rpl/t/rpl_parallel_seq.test new file mode 100644 index 00000000..b1b15412 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_seq.test @@ -0,0 +1,198 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +--connection slave +--source include/stop_slave.inc +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; + +--echo # MDEV-29621 the sequence engine binlog_row_image-full events +--echo # MDL-deadlock on the parallel slave. +--connection master +CREATE SEQUENCE s1; +SET @@session.binlog_row_image=FULL; +SET @@session.debug_dbug="+d,binlog_force_commit_id"; +SET @commit_id=7; +SET @@gtid_seq_no=100; +--disable_ps2_protocol +SELECT NEXT VALUE FOR s1; +--enable_ps2_protocol +INSERT INTO s1 VALUES(2, 1, 10, 1, 2, 1, 1, 0); +SET @@session.debug_dbug=""; + +--connection slave +--let $slave_parallel_threads=`select @@global.slave_parallel_threads` +--let $slave_parallel_mode=`select @@global.slave_parallel_mode` +SET @@global.slave_parallel_threads=2; +SET @@global.slave_parallel_mode=optimistic; +SET @@global.debug_dbug="+d,hold_worker_on_schedule"; +--source include/start_slave.inc + +--let $wait_condition= SELECT count(*) = 1 FROM information_schema.processlist WHERE state LIKE "Waiting for prior transaction to start commit" +--source include/wait_condition.inc +SET DEBUG_SYNC = 'now SIGNAL continue_worker'; + +--connection master +DROP SEQUENCE s1; +--sync_slave_with_master +--source include/stop_slave.inc + +--echo # Simulate buggy 10.3.36 master to prove the parallel applier +--echo # does not deadlock now at replaying the above master load. +--connection master +--let $datadir= `SELECT @@datadir` + +--let $rpl_server_number= 1 +--source include/rpl_stop_server.inc + +--remove_file $datadir/master-bin.000001 +--copy_file $MYSQL_TEST_DIR/std_data/rpl/master-bin-seq_10.3.36.000001 $datadir/master-bin.000001 + +--let $rpl_server_number= 1 +--source include/rpl_start_server.inc + +--source include/wait_until_connected_again.inc +--save_master_pos + +--connection slave +RESET MASTER; +SET @@global.gtid_slave_pos=""; + +--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1 +eval CHANGE MASTER TO master_host='127.0.0.1', master_port=$SERVER_MYPORT_1, master_user='root', master_use_gtid=slave_pos; + +START SLAVE UNTIL MASTER_GTID_POS='0-1-102'; + +--let $wait_condition= SELECT count(*) = 1 FROM information_schema.processlist WHERE state LIKE "Waiting for prior transaction to commit" +--source include/wait_condition.inc +SET DEBUG_SYNC = 'now SIGNAL continue_worker'; + +--echo # Normal stop is expected +--source include/wait_for_slave_to_stop.inc + +--echo # MDEV-31077 ALTER SEQUENCE may end up in optimistic parallel slave binlog out-of-order +--echo # The test proves ALTER-SEQUENCE binlogs first before the following transaction does so. + +--connection slave +--source include/stop_slave.inc +RESET MASTER; +SET @@global.gtid_slave_pos=""; +--connection master +RESET MASTER; + +# Load from master +CREATE TABLE ti (a INT) ENGINE=innodb; +CREATE SEQUENCE s2 ENGINE=innodb; +--source include/save_master_gtid.inc + +--connection slave +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc +--let $rpl_server_number= 2 +--source include/rpl_restart_server.inc +# upon restart +SET @@global.slave_parallel_threads=2; +SET @@global.slave_parallel_mode=optimistic; +SET @@global.debug_dbug="+d,hold_worker_on_schedule"; +--let $slave_gtid_strict_mode=`select @@global.gtid_strict_mode` +SET @@global.gtid_strict_mode=1; + +--connection master +SET @@gtid_seq_no=100; +ALTER SEQUENCE s2 restart with 1; +INSERT INTO ti SET a=1; +--source include/save_master_gtid.inc +SELECT @@global.gtid_binlog_state "Master gtid state"; + +--connection slave +# The following FT complicates the opening table time with committing +# an internal transaction. The rest of the test also proves +# MDEV-31503 "branch" of the OOO error is fixed. +SET STATEMENT sql_log_bin=0 FOR FLUSH TABLES; +--source include/start_slave.inc + +--let $wait_condition= SELECT count(*) = 1 FROM information_schema.processlist WHERE state LIKE "Waiting for prior transaction to commit" +--source include/wait_condition.inc + +SELECT @@global.gtid_binlog_state, @@global.gtid_slave_pos as "no 100,101 yet in both"; + +# DEBUG_DBUG extension point of hold_worker_on_schedule is reused +# (gets deployed) in Sql_cmd_alter_sequence::execute. +SET DEBUG_SYNC = 'now SIGNAL continue_worker'; + +--echo # Normal sync with master proves the fixes correct +--source include/sync_with_master_gtid.inc + +SELECT @@global.gtid_binlog_state, @@global.gtid_slave_pos as "all through 101 have been committed"; + +# MDEV-31792 Assertion in MDL_context::acquire_lock upon parallel replication of CREATE SEQUENCE + +--let $iter = 3 +while ($iter) +{ +--connection slave +if (`select $iter > 1`) +{ + flush tables with read lock; +} +if (`select $iter = 1`) +{ + BEGIN /* slave local Trx */; + select count(*) from s3; +} + +--connection master +CREATE OR REPLACE SEQUENCE s3 ENGINE=innodb; +# select may return non-deterministically, don't print its result +SELECT NEXT VALUE FOR s3 into @tmpvar; +--source include/save_master_gtid.inc + +--connection slave +--let $wait_condition= SELECT count(*) = 1 FROM information_schema.processlist WHERE state LIKE "Waiting for prior transaction to start commit%" +--source include/wait_condition.inc + +if (`select $iter > 1`) +{ + unlock tables; +} +if (`select $iter = 1`) +{ +--connection slave +rollback /* Trx */; +} + + +--source include/sync_with_master_gtid.inc + +--dec $iter +} + + +# +# MDEV-29621/MDEV-31077/MDEV-31792 clean up. +# +--connection slave +--source include/stop_slave.inc + +SET debug_sync = RESET; +--eval SET @@global.slave_parallel_threads= $slave_parallel_threads +--eval SET @@global.slave_parallel_mode= $slave_parallel_mode + SET @@global.debug_dbug = ""; +--eval SET @@global.gtid_strict_mode=$slave_gtid_strict_mode +--source include/start_slave.inc + +--connection master +# MDEV-32593 Assertion failure upon CREATE SEQUENCE +BEGIN; +INSERT INTO ti SET a=32593; +CREATE SEQUENCE s4; + +DROP SEQUENCE s2,s3,s4; +DROP TABLE ti; + +--sync_slave_with_master + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_show_binlog_events_purge_logs.test b/mysql-test/suite/rpl/t/rpl_parallel_show_binlog_events_purge_logs.test new file mode 100644 index 00000000..cddc9286 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_show_binlog_events_purge_logs.test @@ -0,0 +1,38 @@ +# +# This include file is used by more than one test suite +# (currently rpl and binlog_encryption). +# Please check all dependent tests after modifying it +# + +# BUG#13979418: SHOW BINLOG EVENTS MAY CRASH THE SERVER +# +# The function mysql_show_binlog_events has a local stack variable +# 'LOG_INFO linfo;', which is assigned to thd->current_linfo, however +# this variable goes out of scope and is destroyed before clean +# thd->current_linfo. +# +# This test case runs SHOW BINLOG EVENTS and FLUSH LOGS to make sure +# that with the fix local variable linfo is valid along all +# mysql_show_binlog_events function scope. +# +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/master-slave.inc + +--connection slave +SET DEBUG_SYNC= 'after_show_binlog_events SIGNAL on_show_binlog_events WAIT_FOR end'; +--send SHOW BINLOG EVENTS + +--connection slave1 +SET DEBUG_SYNC= 'now WAIT_FOR on_show_binlog_events'; +FLUSH LOGS; +SET DEBUG_SYNC= 'now SIGNAL end'; + +--connection slave +--disable_result_log +--reap +--enable_result_log +SET DEBUG_SYNC= 'RESET'; + +--connection master +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_single_grpcmt.test b/mysql-test/suite/rpl/t/rpl_parallel_single_grpcmt.test new file mode 100644 index 00000000..cf4c547b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_single_grpcmt.test @@ -0,0 +1,170 @@ +--echo *** Test that group-committed transactions on the master can replicate in parallel on the slave. *** + +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/have_binlog_format_statement.inc +--source include/master-slave.inc + +# Test various aspects of parallel replication. + +--connection server_1 +# The function does nothing on the master, and on the slave it injects the +# desired debug_sync action(s). +SET sql_log_bin=0; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + RETURN x; + END +|| +--delimiter ; +SET sql_log_bin=1; + +--connection server_2 +--source include/stop_slave.inc +SET sql_log_bin=0; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + IF d1 != '' THEN + SET debug_sync = d1; + END IF; + IF d2 != '' THEN + SET debug_sync = d2; + END IF; + RETURN x; + END +|| +--delimiter ; +SET sql_log_bin=1; + +# We need to restart all parallel threads for the new global setting to +# be copied to the session-level values. +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +SET GLOBAL slave_parallel_threads=10; +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +# Create some sentinel rows so that the rows inserted in parallel fall into +# separate gaps and do not cause gap lock conflicts. +INSERT INTO t3 VALUES (1,1), (3,3), (5,5), (7,7); +--save_master_pos +--connection server_2 +--sync_with_master + + +# We want to test that the transactions can execute out-of-order on +# the slave, but still end up committing in-order, and in a single +# group commit. +# +# The idea is to group-commit three transactions together on the master: +# A, B, and C. On the slave, C will execute the insert first, then A, +# and then B. But B manages to complete before A has time to commit, so +# all three end up committing together. +# +# So we start by setting up some row locks that will block transactions +# A and B from executing, allowing C to run first. + +--connect (con_temp1,127.0.0.1,root,,test,$SERVER_MYPORT_2,) +BEGIN; +INSERT INTO t3 VALUES (2,102); +--connect (con_temp2,127.0.0.1,root,,test,$SERVER_MYPORT_2,) +BEGIN; +INSERT INTO t3 VALUES (4,104); + +# On the master, queue three INSERT transactions as a single group commit. +--connect (con_temp3,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1'; +SET binlog_format=statement; +send INSERT INTO t3 VALUES (2, foo(12, + 'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued1 WAIT_FOR slave_cont1', + '')); + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued1'; + +--connect (con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2'; +SET binlog_format=statement; +send INSERT INTO t3 VALUES (4, foo(14, + 'commit_after_release_LOCK_prepare_ordered SIGNAL slave_queued2', + '')); + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued2'; + +--connect (con_temp5,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3'; +SET binlog_format=statement; +send INSERT INTO t3 VALUES (6, foo(16, + 'group_commit_waiting_for_prior SIGNAL slave_queued3', + '')); + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued3'; +SET debug_sync='now SIGNAL master_cont1'; + +--connection con_temp3 +REAP; +--connection con_temp4 +REAP; +--connection con_temp5 +REAP; +SET debug_sync='RESET'; + +--connection server_1 +SELECT * FROM t3 ORDER BY a; +--let $binlog_file= master-bin.000001 +--source include/show_binlog_events.inc + +# First, wait until insert 3 is ready to queue up for group commit, but is +# waiting for insert 2 to commit before it can do so itself. +--connection server_2 +SET debug_sync='now WAIT_FOR slave_queued3'; + +# Next, let insert 1 proceed, and allow it to queue up as the group commit +# leader, but let it wait for insert 2 to also queue up before proceeding. +--connection con_temp1 +ROLLBACK; +--connection server_2 +SET debug_sync='now WAIT_FOR slave_queued1'; + +# Now let insert 2 proceed and queue up. +--connection con_temp2 +ROLLBACK; +--connection server_2 +SET debug_sync='now WAIT_FOR slave_queued2'; +# And finally, we can let insert 1 proceed and do the group commit with all +# three insert transactions together. +SET debug_sync='now SIGNAL slave_cont1'; + +# Wait for the commit to complete and check that all three transactions +# group-committed together (will be seen in the binlog as all three having +# cid=# on their GTID event). +--let $wait_condition= SELECT COUNT(*) = 3 FROM t3 WHERE a IN (2,4,6) +--source include/wait_condition.inc +SELECT * FROM t3 ORDER BY a; +--let $binlog_file= slave-bin.000001 +--source include/show_binlog_events.inc + + +# Clean up. +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc +SET DEBUG_SYNC= 'RESET'; + +--connection server_1 +DROP function foo; +DROP TABLE t3; +SET DEBUG_SYNC= 'RESET'; + +--disable_connect_log +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_slave_bgc_kill.test b/mysql-test/suite/rpl/t/rpl_parallel_slave_bgc_kill.test new file mode 100644 index 00000000..efb998b0 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_slave_bgc_kill.test @@ -0,0 +1,458 @@ +--echo *** Test killing slave threads at various wait points *** + +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/have_binlog_format_statement.inc +--source include/master-slave.inc + +# Test various aspects of parallel replication. + +--connection server_2 +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=10; +SET GLOBAL slave_parallel_mode='conservative'; +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_1 +--connect (con_temp3,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +--connect (con_temp4,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +--connect (con_temp5,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM; +CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +# MDEV-515 takes X-lock on the table for the first insert. +# So concurrent insert won't happen on the table +INSERT INTO t2 VALUES(100); +INSERT INTO t3 VALUES(100, 100); +--save_master_pos + +--connection server_2 +--sync_with_master + +--connection server_1 +# Use a stored function to inject a debug_sync into the appropriate THD. +# The function does nothing on the master, and on the slave it injects the +# desired debug_sync action(s). +SET sql_log_bin=0; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + RETURN x; + END +|| +--delimiter ; +SET sql_log_bin=1; + +--connection server_2 +SET sql_log_bin=0; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + IF d1 != '' THEN + SET debug_sync = d1; + END IF; + IF d2 != '' THEN + SET debug_sync = d2; + END IF; + RETURN x; + END +|| +--delimiter ; +SET sql_log_bin=1; + +--echo *** 1. Test killing transaction waiting in commit for previous transaction to commit *** + +# Set up three transactions on the master that will be group-committed +# together so they can be replicated in parallel on the slave. +--connection con_temp3 +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1'; +send INSERT INTO t3 VALUES (31, foo(31, + 'commit_before_prepare_ordered WAIT_FOR t2_waiting', + 'commit_after_prepare_ordered SIGNAL t1_ready WAIT_FOR t1_cont')); + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued1'; + +--connection con_temp4 +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2'; +BEGIN; +# This insert is just so we can get T2 to wait while a query is running that we +# can see in SHOW PROCESSLIST so we can get its thread_id to kill later. +INSERT INTO t3 VALUES (32, foo(32, + 'ha_write_row_end SIGNAL t2_query WAIT_FOR t2_cont', + '')); +# This insert sets up debug_sync points so that T2 will tell when it is at its +# wait point where we want to kill it - and when it has been killed. +INSERT INTO t3 VALUES (33, foo(33, + 'group_commit_waiting_for_prior SIGNAL t2_waiting', + 'group_commit_waiting_for_prior_killed SIGNAL t2_killed')); +send COMMIT; + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued2'; + +--connection con_temp5 +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3'; +send INSERT INTO t3 VALUES (34, foo(34, + '', + '')); + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued3'; +SET debug_sync='now SIGNAL master_cont1'; + +--connection con_temp3 +REAP; +--connection con_temp4 +REAP; +--connection con_temp5 +REAP; + +--connection server_1 +SELECT * FROM t3 WHERE a >= 30 ORDER BY a; +SET debug_sync='RESET'; + +--connection server_2 +SET sql_log_bin=0; +CALL mtr.add_suppression("Query execution was interrupted"); +CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends"); +CALL mtr.add_suppression("Slave: Connection was killed"); +SET sql_log_bin=1; +# Wait until T2 is inside executing its insert of 32, then find it in SHOW +# PROCESSLIST to know its thread id for KILL later. +SET debug_sync='now WAIT_FOR t2_query'; +--let $thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%foo(32%' AND INFO NOT LIKE '%LIKE%'` +SET debug_sync='now SIGNAL t2_cont'; + +# Wait until T2 has entered its wait for T1 to commit, and T1 has +# progressed into its commit phase. +SET debug_sync='now WAIT_FOR t1_ready'; + +# Now kill the transaction T2. +--replace_result $thd_id THD_ID +eval KILL $thd_id; + +# Wait until T2 has reacted on the kill. +SET debug_sync='now WAIT_FOR t2_killed'; + +# Now we can allow T1 to proceed. +SET debug_sync='now SIGNAL t1_cont'; + +--let $slave_sql_errno= 1317,1927,1964 +--source include/wait_for_slave_sql_error.inc +STOP SLAVE IO_THREAD; +SELECT * FROM t3 WHERE a >= 30 ORDER BY a; + +# Now we have to disable the debug_sync statements, so they do not trigger +# when the events are retried. +SET debug_sync='RESET'; +SET GLOBAL slave_parallel_threads=0; +SET GLOBAL slave_parallel_threads=10; +SET sql_log_bin=0; +DROP FUNCTION foo; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + RETURN x; + END +|| +--delimiter ; +SET sql_log_bin=1; + +--connection server_1 +INSERT INTO t3 VALUES (39,0); +--save_master_pos + +--connection server_2 +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t3 WHERE a >= 30 ORDER BY a; +# Restore the foo() function. +SET sql_log_bin=0; +DROP FUNCTION foo; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + IF d1 != '' THEN + SET debug_sync = d1; + END IF; + IF d2 != '' THEN + SET debug_sync = d2; + END IF; + RETURN x; + END +|| +--delimiter ; +SET sql_log_bin=1; + + +--connection server_2 +# Respawn all worker threads to clear any left-over debug_sync or other stuff. +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=0; +SET GLOBAL slave_parallel_threads=10; +--source include/start_slave.inc + + +--echo *** 2. Same as (1), but without restarting IO thread after kill of SQL threads *** + +# Set up three transactions on the master that will be group-committed +# together so they can be replicated in parallel on the slave. +--connection con_temp3 +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1'; +send INSERT INTO t3 VALUES (41, foo(41, + 'commit_before_prepare_ordered WAIT_FOR t2_waiting', + 'commit_after_prepare_ordered SIGNAL t1_ready WAIT_FOR t1_cont')); + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued1'; + +--connection con_temp4 +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2'; +BEGIN; +# This insert is just so we can get T2 to wait while a query is running that we +# can see in SHOW PROCESSLIST so we can get its thread_id to kill later. +INSERT INTO t3 VALUES (42, foo(42, + 'ha_write_row_end SIGNAL t2_query WAIT_FOR t2_cont', + '')); +# This insert sets up debug_sync points so that T2 will tell when it is at its +# wait point where we want to kill it - and when it has been killed. +INSERT INTO t3 VALUES (43, foo(43, + 'group_commit_waiting_for_prior SIGNAL t2_waiting', + 'group_commit_waiting_for_prior_killed SIGNAL t2_killed')); +send COMMIT; + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued2'; + +--connection con_temp5 +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3'; +send INSERT INTO t3 VALUES (44, foo(44, + '', + '')); + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued3'; +SET debug_sync='now SIGNAL master_cont1'; + +--connection con_temp3 +REAP; +--connection con_temp4 +REAP; +--connection con_temp5 +REAP; + +--connection server_1 +SELECT * FROM t3 WHERE a >= 40 ORDER BY a; +SET debug_sync='RESET'; + +--connection server_2 +# Wait until T2 is inside executing its insert of 42, then find it in SHOW +# PROCESSLIST to know its thread id for KILL later. +SET debug_sync='now WAIT_FOR t2_query'; +--let $thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%foo(42%' AND INFO NOT LIKE '%LIKE%'` +SET debug_sync='now SIGNAL t2_cont'; + +# Wait until T2 has entered its wait for T1 to commit, and T1 has +# progressed into its commit phase. +SET debug_sync='now WAIT_FOR t1_ready'; + +# Now kill the transaction T2. +--replace_result $thd_id THD_ID +eval KILL $thd_id; + +# Wait until T2 has reacted on the kill. +SET debug_sync='now WAIT_FOR t2_killed'; + +# Now we can allow T1 to proceed. +SET debug_sync='now SIGNAL t1_cont'; + +--let $slave_sql_errno= 1317,1927,1964 +--source include/wait_for_slave_sql_error.inc + +# Now we have to disable the debug_sync statements, so they do not trigger +# when the events are retried. +SET debug_sync='RESET'; +SET GLOBAL slave_parallel_threads=0; +SET GLOBAL slave_parallel_threads=10; +SET sql_log_bin=0; +DROP FUNCTION foo; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + RETURN x; + END +|| +--delimiter ; +SET sql_log_bin=1; + +--connection server_1 +INSERT INTO t3 VALUES (49,0); +--save_master_pos + +--connection server_2 +START SLAVE SQL_THREAD; +--sync_with_master +SELECT * FROM t3 WHERE a >= 40 ORDER BY a; +# Restore the foo() function. +SET sql_log_bin=0; +DROP FUNCTION foo; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + IF d1 != '' THEN + SET debug_sync = d1; + END IF; + IF d2 != '' THEN + SET debug_sync = d2; + END IF; + RETURN x; + END +|| +--delimiter ; +SET sql_log_bin=1; + + +--connection server_2 +# Respawn all worker threads to clear any left-over debug_sync or other stuff. +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=0; +SET GLOBAL slave_parallel_threads=10; +--source include/start_slave.inc + + +--echo *** 3. Same as (2), but not using gtid mode *** + +--connection server_2 +--source include/stop_slave.inc +CHANGE MASTER TO master_use_gtid=no; +--source include/start_slave.inc + +--connection server_1 +# Set up three transactions on the master that will be group-committed +# together so they can be replicated in parallel on the slave. +--connection con_temp3 +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1'; +send INSERT INTO t3 VALUES (51, foo(51, + 'commit_before_prepare_ordered WAIT_FOR t2_waiting', + 'commit_after_prepare_ordered SIGNAL t1_ready WAIT_FOR t1_cont')); + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued1'; + +--connection con_temp4 +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2'; +BEGIN; +# This insert is just so we can get T2 to wait while a query is running that we +# can see in SHOW PROCESSLIST so we can get its thread_id to kill later. +INSERT INTO t3 VALUES (52, foo(52, + 'ha_write_row_end SIGNAL t2_query WAIT_FOR t2_cont', + '')); +# This insert sets up debug_sync points so that T2 will tell when it is at its +# wait point where we want to kill it - and when it has been killed. +INSERT INTO t3 VALUES (53, foo(53, + 'group_commit_waiting_for_prior SIGNAL t2_waiting', + 'group_commit_waiting_for_prior_killed SIGNAL t2_killed')); +send COMMIT; + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued2'; + +--connection con_temp5 +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued3'; +send INSERT INTO t3 VALUES (54, foo(54, + '', + '')); + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued3'; +SET debug_sync='now SIGNAL master_cont1'; + +--connection con_temp3 +REAP; +--connection con_temp4 +REAP; +--connection con_temp5 +REAP; + +--connection server_1 +SELECT * FROM t3 WHERE a >= 50 ORDER BY a; +SET debug_sync='RESET'; + +--connection server_2 +# Wait until T2 is inside executing its insert of 52, then find it in SHOW +# PROCESSLIST to know its thread id for KILL later. +SET debug_sync='now WAIT_FOR t2_query'; +--let $thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%foo(52%' AND INFO NOT LIKE '%LIKE%'` +SET debug_sync='now SIGNAL t2_cont'; + +# Wait until T2 has entered its wait for T1 to commit, and T1 has +# progressed into its commit phase. +SET debug_sync='now WAIT_FOR t1_ready'; + +# Now kill the transaction T2. +--replace_result $thd_id THD_ID +eval KILL $thd_id; + +# Wait until T2 has reacted on the kill. +SET debug_sync='now WAIT_FOR t2_killed'; + +# Now we can allow T1 to proceed. +SET debug_sync='now SIGNAL t1_cont'; + +--let $slave_sql_errno= 1317,1927,1964 +--source include/wait_for_slave_sql_error.inc +SELECT * FROM t3 WHERE a >= 50 ORDER BY a; + +# Now we have to disable the debug_sync statements, so they do not trigger +# when the events are retried. +SET debug_sync='RESET'; +SET GLOBAL slave_parallel_threads=0; +SET GLOBAL slave_parallel_threads=10; +SET sql_log_bin=0; +DROP FUNCTION foo; +--delimiter || +CREATE FUNCTION foo(x INT, d1 VARCHAR(500), d2 VARCHAR(500)) + RETURNS INT DETERMINISTIC + BEGIN + RETURN x; + END +|| +--delimiter ; +SET sql_log_bin=1; + +--connection server_1 +INSERT INTO t3 VALUES (59,0); +--save_master_pos + +--connection server_2 +START SLAVE SQL_THREAD; +--sync_with_master +SELECT * FROM t3 WHERE a >= 50 ORDER BY a; + +# Clean up. +--connection server_2 +--source include/stop_slave.inc +CHANGE MASTER TO master_use_gtid=slave_pos; +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +SET GLOBAL slave_parallel_mode=@old_parallel_mode; +--source include/start_slave.inc +SET DEBUG_SYNC= 'RESET'; + +--connection server_1 +DROP function foo; +DROP TABLE t1,t2,t3; +SET DEBUG_SYNC= 'RESET'; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_stop_on_con_kill.test b/mysql-test/suite/rpl/t/rpl_parallel_stop_on_con_kill.test new file mode 100644 index 00000000..63c483ea --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_stop_on_con_kill.test @@ -0,0 +1,129 @@ +--echo *** MDEV-8031: Parallel replication stops on "connection killed" error (probably incorrectly handled deadlock kill) *** + +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/master-slave.inc + +--connection server_2 +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=10; +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +INSERT INTO t3 VALUES (201,0), (202,0); +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug= '+d,inject_mdev8031'; + +--connection server_1 +# We artificially create a situation that hopefully resembles the original +# bug which was only seen "in the wild", and only once. +# Setup a fake group commit with lots of conflicts that will lead to deadloc +# kill. The slave DBUG injection causes the slave to be deadlock killed at +# a particular point during the retry, and then later do a small sleep at +# another critical point where the prior transaction then has a chance to +# complete. Finally an extra KILL check catches an unhandled, lingering +# deadlock kill. So rather artificial, but at least it exercises the +# relevant code paths. +SET @old_dbug= @@SESSION.debug_dbug; +SET SESSION debug_dbug="+d,binlog_force_commit_id"; + +SET @commit_id= 10200; +INSERT INTO t3 VALUES (203, 1); +INSERT INTO t3 VALUES (204, 1); +INSERT INTO t3 VALUES (205, 1); +UPDATE t3 SET b=b+1 WHERE a=201; +UPDATE t3 SET b=b+1 WHERE a=201; +UPDATE t3 SET b=b+1 WHERE a=201; +UPDATE t3 SET b=b+1 WHERE a=202; +UPDATE t3 SET b=b+1 WHERE a=202; +UPDATE t3 SET b=b+1 WHERE a=202; +UPDATE t3 SET b=b+1 WHERE a=202; +UPDATE t3 SET b=b+1 WHERE a=203; +UPDATE t3 SET b=b+1 WHERE a=203; +UPDATE t3 SET b=b+1 WHERE a=204; +UPDATE t3 SET b=b+1 WHERE a=204; +UPDATE t3 SET b=b+1 WHERE a=204; +UPDATE t3 SET b=b+1 WHERE a=203; +UPDATE t3 SET b=b+1 WHERE a=205; +UPDATE t3 SET b=b+1 WHERE a=205; +SET SESSION debug_dbug=@old_dbug; + +SELECT * FROM t3 WHERE a>=200 ORDER BY a; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + +SELECT * FROM t3 WHERE a>=200 ORDER BY a; +--source include/stop_slave.inc +SET GLOBAL debug_dbug= @old_dbug; +--source include/start_slave.inc + + +--echo *** Check getting deadlock killed inside open_binlog() during retry. *** + +--connection server_2 +--source include/stop_slave.inc +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug= '+d,inject_retry_event_group_open_binlog_kill'; +SET @old_max= @@GLOBAL.max_relay_log_size; +SET GLOBAL max_relay_log_size= 4096; + +--connection server_1 +SET @old_dbug= @@SESSION.debug_dbug; +SET SESSION debug_dbug="+d,binlog_force_commit_id"; + +--let $large= `SELECT REPEAT("*", 8192)` +SET @commit_id= 10210; +--echo Omit long queries that cause relaylog rotations and transaction retries... +--disable_query_log +eval UPDATE t3 SET b=b+1 WHERE a=201 /* $large */; +eval UPDATE t3 SET b=b+1 WHERE a=201 /* $large */; +eval UPDATE t3 SET b=b+1 WHERE a=201 /* $large */; +eval UPDATE t3 SET b=b+1 WHERE a=202 /* $large */; +eval UPDATE t3 SET b=b+1 WHERE a=202 /* $large */; +eval UPDATE t3 SET b=b+1 WHERE a=202 /* $large */; +eval UPDATE t3 SET b=b+1 WHERE a=202 /* $large */; +eval UPDATE t3 SET b=b+1 WHERE a=203 /* $large */; +eval UPDATE t3 SET b=b+1 WHERE a=203 /* $large */; +eval UPDATE t3 SET b=b+1 WHERE a=204 /* $large */; +eval UPDATE t3 SET b=b+1 WHERE a=204 /* $large */; +eval UPDATE t3 SET b=b+1 WHERE a=204 /* $large */; +eval UPDATE t3 SET b=b+1 WHERE a=203 /* $large */; +eval UPDATE t3 SET b=b+1 WHERE a=205 /* $large */; +eval UPDATE t3 SET b=b+1 WHERE a=205 /* $large */; +--enable_query_log +SET SESSION debug_dbug=@old_dbug; + +SELECT * FROM t3 WHERE a>=200 ORDER BY a; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + +SELECT * FROM t3 WHERE a>=200 ORDER BY a; + +# Cleanup +--source include/stop_slave.inc +SET GLOBAL debug_dbug= @old_debg; +SET GLOBAL max_relay_log_size= @old_max; +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t3; + +--source include/rpl_end.inc + diff --git a/mysql-test/suite/rpl/t/rpl_parallel_stop_slave.test b/mysql-test/suite/rpl/t/rpl_parallel_stop_slave.test new file mode 100644 index 00000000..35879e98 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_stop_slave.test @@ -0,0 +1,118 @@ +--echo *** Test STOP SLAVE in parallel mode *** + +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/have_binlog_format_statement.inc +--source include/master-slave.inc + +--connection server_2 +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=10; +SET GLOBAL slave_parallel_mode='conservative'; + +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc +--connect (con_temp1,127.0.0.1,root,,test,$SERVER_MYPORT_2,) +--connect (con_temp2,127.0.0.1,root,,test,$SERVER_MYPORT_2,) + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=MyISAM; +CREATE TABLE t2 (a int PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +# MDEV-515 takes X-lock on the table for the first insert. +# So concurrent insert won't happen on the table +INSERT INTO t2 VALUES(100); +INSERT INTO t3 VALUES(100, 100); +--save_master_pos + +--connection server_2 +--sync_with_master +--source include/stop_slave.inc + +--connection server_1 +# Set up a couple of transactions. The first will be blocked halfway +# through on a lock, and while it is blocked we initiate STOP SLAVE. +# We then test that the halfway-initiated transaction is allowed to +# complete, but no subsequent ones. +# We have to use statement-based mode and set +# binlog_direct_non_transactional_updates=0; otherwise the binlog will +# be split into two event groups, one for the MyISAM part and one for the +# InnoDB part. +SET binlog_direct_non_transactional_updates=0; +SET sql_log_bin=0; +CALL mtr.add_suppression("Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction"); +SET sql_log_bin=1; +BEGIN; +INSERT INTO t2 VALUES (20); +--disable_warnings +INSERT INTO t1 VALUES (20); +--enable_warnings +INSERT INTO t2 VALUES (21); +INSERT INTO t3 VALUES (20, 20); +COMMIT; +INSERT INTO t3 VALUES(21, 21); +INSERT INTO t3 VALUES(22, 22); +--save_master_pos + +# Start a connection that will block the replicated transaction halfway. +--connection con_temp1 +BEGIN; +INSERT INTO t2 VALUES (21); + +--connection server_2 +START SLAVE; +# Wait for the MyISAM change to be visible, after which replication will wait +# for con_temp1 to roll back. +--let $wait_condition= SELECT COUNT(*) = 1 FROM t1 WHERE a=20 +--source include/wait_condition.inc + +--connection con_temp2 +# Initiate slave stop. It will have to wait for the current event group +# to complete. +# The dbug injection causes debug_sync to signal 'wait_for_done_waiting' +# when the SQL driver thread is ready. +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,rpl_parallel_wait_for_done_trigger"; +send STOP SLAVE; + +--connection con_temp1 +SET debug_sync='now WAIT_FOR wait_for_done_waiting'; +ROLLBACK; + +--connection con_temp2 +reap; +SET GLOBAL debug_dbug=@old_dbug; +SET debug_sync='RESET'; + +--connection server_2 +--source include/wait_for_slave_to_stop.inc +# We should see the first transaction applied, but not the two others. +SELECT * FROM t1 WHERE a >= 20 ORDER BY a; +SELECT * FROM t2 WHERE a >= 20 ORDER BY a; +SELECT * FROM t3 WHERE a >= 20 ORDER BY a; + +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 WHERE a >= 20 ORDER BY a; +SELECT * FROM t2 WHERE a >= 20 ORDER BY a; +SELECT * FROM t3 WHERE a >= 20 ORDER BY a; + +--connection server_2 +# Respawn all worker threads to clear any left-over debug_sync or other stuff. +--source include/stop_slave.inc +SET GLOBAL slave_parallel_mode=@old_parallel_mode; +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc +SET DEBUG_SYNC= 'RESET'; +--disconnect con_temp1 +--disconnect con_temp2 + +--connection server_1 +DROP TABLE t1,t2,t3; +SET DEBUG_SYNC= 'RESET'; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_temptable-master.opt b/mysql-test/suite/rpl/t/rpl_parallel_temptable-master.opt new file mode 100644 index 00000000..590d44a6 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_temptable-master.opt @@ -0,0 +1 @@ +--loose-skip-stack-trace --skip-core-file diff --git a/mysql-test/suite/rpl/t/rpl_parallel_temptable.test b/mysql-test/suite/rpl/t/rpl_parallel_temptable.test new file mode 100644 index 00000000..3684763d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_temptable.test @@ -0,0 +1,277 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_binlog_format_statement.inc +# Valgrind does not work well with test that crashes the server +--source include/not_valgrind.inc +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +--echo *** MDEV-6321: close_temporary_tables() in format description event not serialised correctly *** + +--connection server_2 +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=5; +--source include/start_slave.inc + +--connection server_1 +CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(100) CHARACTER SET utf8); +--save_master_pos + +--connection server_2 +--sync_with_master +--source include/stop_slave.inc + + +--connection server_1 +SET gtid_domain_id= 1; +INSERT INTO t1 VALUES (1, 0); + +CREATE TEMPORARY TABLE t2 (a int); + +--connection default +SET gtid_domain_id= 2; +CREATE TEMPORARY TABLE t3 (a INT PRIMARY KEY); +CREATE TEMPORARY TABLE t4 (a int); +INSERT INTO t3 VALUES (100); +INSERT INTO t4 SELECT a+1 FROM t3; + +--connection server_1 +INSERT INTO t2 VALUES (2), (4), (6), (8), (10), (12), (14), (16), (18), (20); +INSERT INTO t2 VALUES (3), (6), (9), (12), (15), (18); +INSERT INTO t2 VALUES (4), (8), (12), (16), (20); + +--connection default +INSERT INTO t3 SELECT a+2 FROM t4; +INSERT INTO t4 SELECT a+4 FROM t3; + +--connection server_1 +INSERT INTO t2 VALUES (5), (10), (15), (20); +INSERT INTO t2 VALUES (6), (12), (18); +INSERT INTO t2 VALUES (7), (14); +INSERT INTO t2 VALUES (8), (16); +INSERT INTO t2 VALUES (9), (18); +INSERT INTO t2 VALUES (10), (20); + +--connection default +INSERT INTO t3 SELECT a+8 FROM t4; +INSERT INTO t4 SELECT a+16 FROM t3; + +--connection server_1 +INSERT INTO t2 VALUES (11); +INSERT INTO t2 VALUES (12); +INSERT INTO t2 VALUES (13); + +--connection default +INSERT INTO t3 SELECT a+32 FROM t4; + +--connection server_1 +INSERT INTO t2 VALUES (14); +INSERT INTO t2 VALUES (15); +INSERT INTO t2 VALUES (16); + +--connection default +INSERT INTO t4 SELECT a+64 FROM t3; + +--connection server_1 +INSERT INTO t2 VALUES (17); +INSERT INTO t2 VALUES (18); +INSERT INTO t2 VALUES (19); + +--connection default +INSERT INTO t3 SELECT a+128 FROM t4; + +--connection server_1 +INSERT INTO t2 VALUES (20); + +--connection default +INSERT INTO t1 SELECT a, a MOD 7 FROM t3; +INSERT INTO t1 SELECT a, a MOD 7 FROM t4; + +--connection server_1 +INSERT INTO t1 SELECT a, COUNT(*) FROM t2 GROUP BY a; + +# Crash the master server, so that temporary tables are implicitly dropped. +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait +EOF + +FLUSH TABLES; +SET SESSION debug_dbug="+d,crash_dispatch_command_before"; +--error 2006,2013 +SELECT 1; + +--source include/wait_until_disconnected.inc +--connection default +--source include/wait_until_disconnected.inc + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart +EOF + +--connection default +--enable_reconnect +--source include/wait_until_connected_again.inc + +--connection server_1 +--enable_reconnect +--source include/wait_until_connected_again.inc + +INSERT INTO t1 VALUES (0, 1); +--save_master_pos + +--connection server_2 +# Start the slave replicating the events. +# The bug was that the format description event written after the crash could +# be fetched ahead of the execution of the temporary table events and executed +# out-of-band. This would cause drop of all temporary tables and thus failure +# for execution of remaining events. + +--source include/start_slave.inc +--sync_with_master + +SELECT * FROM t1 WHERE a <= 20 ORDER BY a; +SELECT COUNT(*) FROM t1 WHERE a BETWEEN 100+0 AND 100+256; +SHOW STATUS LIKE 'Slave_open_temp_tables'; + + +--echo *** Test that if master logged partial event group before crash, we finish that group correctly before executing format description event *** + +--source include/stop_slave.inc + +--connection server_1 +CALL mtr.add_suppression("Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them"); +SET gtid_domain_id= 1; +DELETE FROM t1; +ALTER TABLE t1 ENGINE=InnoDB; +CREATE TEMPORARY TABLE t2 (a INT PRIMARY KEY); +INSERT INTO t2 VALUES (1); +INSERT INTO t2 VALUES (2); + +--connection default +SET gtid_domain_id= 2; +CREATE TEMPORARY TABLE t3 (a INT PRIMARY KEY); +INSERT INTO t3 VALUES (10); +INSERT INTO t3 VALUES (20); + +--connection server_1 +INSERT INTO t1 SELECT a, 'server_1' FROM t2; + +--connection default +INSERT INTO t1 SELECT a, 'default' FROM t3; + +--connection server_1 +INSERT INTO t1 SELECT a+2, '+server_1' FROM t2; + +# Crash the master server in the middle of writing an event group. +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait +EOF + +FLUSH TABLES; +SET SESSION debug_dbug="+d,crash_before_writing_xid"; +--error 2006,2013 +INSERT INTO t1 SELECT a+4, '++server_1' FROM t2; + +--source include/wait_until_disconnected.inc +--connection default +--source include/wait_until_disconnected.inc + +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart +EOF + +--connection default +--enable_reconnect +--source include/wait_until_connected_again.inc + +--connection server_1 +--enable_reconnect +--source include/wait_until_connected_again.inc + +INSERT INTO t1 VALUES (0, 1); +#--save_master_pos +--source include/save_master_gtid.inc + +--connection server_2 +# Start the slave replicating the events. +# The main thing to test here is that the slave will know that it +# needs to abort the partially received event group, so that the +# execution of format_description event will not wait infinitely +# for a commit of the incomplete group that never happens. + +# Apart from the suppression, MDEV-27697 refinement to the original test needs +# an allowance to one time accept malformed event group. +set @@sql_log_bin=0; +call mtr.add_suppression("Unexpected break of being relay-logged GTID 1-1-32 event group by the current GTID event 0-1-4"); +set @@sql_log_bin=1; +set @@global.debug_dbug="+d,slave_discard_xid_for_gtid_0_x_1000"; +--source include/start_slave.inc +#--sync_with_master +--source include/sync_with_master_gtid.inc +set @@global.debug_dbug=""; + +SELECT * FROM t1 ORDER BY a; +SHOW STATUS LIKE 'Slave_open_temp_tables'; + +--connection server_1 +# This FLUSH can be removed once MDEV-6608 is fixed. +FLUSH LOGS; + + +--echo *** MDEV-7936: Assertion `!table || table->in_use == _current_thd()' failed on parallel replication in optimistic mode *** + +--connection server_1 +CREATE TEMPORARY TABLE t4 (a INT PRIMARY KEY) ENGINE=InnoDB; +SET @old_dbug= @@SESSION.debug_dbug; +SET SESSION debug_dbug="+d,binlog_force_commit_id"; +SET @commit_id= 10000; +INSERT INTO t4 VALUES (30); +INSERT INTO t4 VALUES (31); +SET SESSION debug_dbug= @old_dbug; +INSERT INTO t1 SELECT a, "conservative" FROM t4; +DROP TEMPORARY TABLE t4; +SELECT * FROM t1 WHERE a >= 30 ORDER BY a; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc + +SELECT * FROM t1 WHERE a >= 30 ORDER BY a; + +--source include/stop_slave.inc +SET @old_mode= @@GLOBAL.slave_parallel_mode; +SET GLOBAL slave_parallel_mode=optimistic; + +--connection server_1 +CREATE TEMPORARY TABLE t4 (a INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t4 VALUES (32); +INSERT INTO t4 VALUES (33); +INSERT INTO t1 SELECT a, "optimistic" FROM t4; +DROP TEMPORARY TABLE t4; + +SELECT * FROM t1 WHERE a >= 30 ORDER BY a; +--source include/save_master_gtid.inc + +--connection server_2 +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + +SELECT * FROM t1 WHERE a >= 30 ORDER BY a; + +--source include/stop_slave.inc +SET GLOBAL slave_parallel_mode=@old_mode; +--source include/start_slave.inc + + +# Clean up. + +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_wrong_binlog_order.test b/mysql-test/suite/rpl/t/rpl_parallel_wrong_binlog_order.test new file mode 100644 index 00000000..093693d4 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_wrong_binlog_order.test @@ -0,0 +1,91 @@ +--echo *** MDEV-6775: Wrong binlog order in parallel replication *** + +# A bit tricky bug to reproduce. On the master, we binlog in statement-mode +# two transactions, an UPDATE followed by a DELETE. On the slave, we replicate +# with binlog-mode set to ROW, which means the DELETE, which modifies no rows, +# is not binlogged. Then we inject a wait in the group commit code on the +# slave, shortly before the actual commit of the UPDATE. The bug was that the +# DELETE could wake up from wait_for_prior_commit() before the commit of the +# UPDATE. So the test could see the slave position updated to after DELETE, +# while the UPDATE was still not visible. + +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/master-slave.inc + +--connection server_2 +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=10; +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t4 (a INT PRIMARY KEY, b INT, KEY b_idx(b)) ENGINE=InnoDB; +INSERT INTO t4 VALUES (1,NULL), (3,NULL), (4,4), (5, NULL), (6, 6); +--connect (con1,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +--connect (con2,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +--source include/save_master_gtid.inc + +--connection server_2 +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc +SET @old_dbug= @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,inject_binlog_commit_before_get_LOCK_log"; +SET @old_format=@@GLOBAL.binlog_format; +SET GLOBAL binlog_format=ROW; +# Re-spawn the worker threads to be sure they pick up the new binlog format +SET GLOBAL slave_parallel_threads=0; +SET GLOBAL slave_parallel_threads=10; + +--connection con1 +SET @old_format= @@binlog_format; +SET binlog_format= statement; +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1'; +send UPDATE t4 SET b=NULL WHERE a=6; +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued1'; + +--connection con2 +SET @old_format= @@binlog_format; +SET binlog_format= statement; +SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2'; +send DELETE FROM t4 WHERE b <= 3; + +--connection server_1 +SET debug_sync='now WAIT_FOR master_queued2'; +SET debug_sync='now SIGNAL master_cont1'; + +--connection con1 +REAP; +SET binlog_format= @old_format; +--connection con2 +REAP; +SET binlog_format= @old_format; +SET debug_sync='RESET'; +--save_master_pos +SELECT * FROM t4 ORDER BY a; + +--connection server_2 +--source include/start_slave.inc +SET debug_sync= 'now WAIT_FOR waiting'; +--sync_with_master +SELECT * FROM t4 ORDER BY a; +SET debug_sync= 'now SIGNAL cont'; + +# Re-spawn the worker threads to remove any DBUG injections or DEBUG_SYNC. +--source include/stop_slave.inc +SET GLOBAL debug_dbug=@old_dbug; +SET GLOBAL binlog_format= @old_format; +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc +SET DEBUG_SYNC= 'RESET'; + +--connection server_1 +DROP TABLE t4; +SET DEBUG_SYNC= 'RESET'; +--disconnect con1 +--disconnect con2 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_wrong_exec_master_pos.test b/mysql-test/suite/rpl/t/rpl_parallel_wrong_exec_master_pos.test new file mode 100644 index 00000000..672ade57 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_wrong_exec_master_pos.test @@ -0,0 +1,56 @@ +--echo *** MDEV-5938: Exec_master_log_pos not updated at log rotate in parallel replication *** +--source include/have_innodb.inc +--source include/master-slave.inc + +--connection server_2 +--source include/stop_slave.inc +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +SET GLOBAL slave_parallel_threads=1; +CHANGE MASTER TO master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +CREATE TABLE t5 (a INT PRIMARY KEY, b INT); +INSERT INTO t5 VALUES (1,1); +INSERT INTO t5 VALUES (2,2), (3,8); +INSERT INTO t5 VALUES (4,16); +--save_master_pos + +--connection server_2 +--sync_with_master +let $io_file= query_get_value(SHOW SLAVE STATUS, Master_Log_File, 1); +let $io_pos= query_get_value(SHOW SLAVE STATUS, Read_Master_Log_Pos, 1); +let $sql_file= query_get_value(SHOW SLAVE STATUS, Relay_Master_Log_File, 1); +let $sql_pos= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1); +--disable_query_log +eval SELECT IF('$io_file' = '$sql_file', "OK", "Not ok, $io_file <> $sql_file") AS test_check; +eval SELECT IF('$io_pos' = '$sql_pos', "OK", "Not ok, $io_pos <> $sql_pos") AS test_check; +--enable_query_log + +--connection server_1 +FLUSH LOGS; +--source include/wait_for_binlog_checkpoint.inc +--save_master_pos + +--connection server_2 +--sync_with_master +let $io_file= query_get_value(SHOW SLAVE STATUS, Master_Log_File, 1); +let $io_pos= query_get_value(SHOW SLAVE STATUS, Read_Master_Log_Pos, 1); +let $sql_file= query_get_value(SHOW SLAVE STATUS, Relay_Master_Log_File, 1); +let $sql_pos= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1); +--disable_query_log +eval SELECT IF('$io_file' = '$sql_file', "OK", "Not ok, $io_file <> $sql_file") AS test_check; +eval SELECT IF('$io_pos' = '$sql_pos', "OK", "Not ok, $io_pos <> $sql_pos") AS test_check; +--enable_query_log + +# Clean up. +--connection server_2 +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t5; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_xa_same_xid.test b/mysql-test/suite/rpl/t/rpl_parallel_xa_same_xid.test new file mode 100644 index 00000000..888dd2f1 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_xa_same_xid.test @@ -0,0 +1,138 @@ +# The tests verify concurrent execution of replicated (MDEV-742) +# XA transactions in the parallel optimistic mode. +# Prove optimistic scheduler handles xid-namesake XA:s. +# That is despite running in parallel there must be no conflicts +# caused by multiple transactions' same xid. + +--source include/have_binlog_format_mixed_or_row.inc +--source include/have_innodb.inc +--source include/have_perfschema.inc +--source include/master-slave.inc + +--let $xid_num = 19 +--let $repeat = 17 +--let $workers = 7 +--connection slave +call mtr.add_suppression("WSREP: handlerton rollback failed"); + +--source include/stop_slave.inc +# a measure against MDEV-20605 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; + +SET @old_parallel_threads = @@GLOBAL.slave_parallel_threads; +--disable_query_log +--eval SET @@global.slave_parallel_threads = $workers +--enable_query_log +SET @old_parallel_mode = @@GLOBAL.slave_parallel_mode; +SET @@global.slave_parallel_mode ='optimistic'; +--source include/start_slave.inc + +--connection master +CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB; + +--let $i = $xid_num +--let $t = t1 +--disable_query_log +while ($i) +{ +--let $k = $repeat +while ($k) +{ +--eval XA START 'xid_$i' +--eval INSERT INTO $t SET a=$i, b=$k +--eval XA END 'xid_$i' +--let $one_phase = `SELECT IF(floor(rand()*10)%2, "ONE PHASE", 0)` + if (!$one_phase) + { + --eval XA PREPARE 'xid_$i' + --eval XA COMMIT 'xid_$i' + } + if ($one_phase) + { + --eval XA COMMIT 'xid_$i' ONE PHASE + } + + if (!$one_phase) + { + --eval XA START 'xid_$i' + --eval INSERT INTO $t SET a=$i, b=$k + --eval XA END 'xid_$i' + --eval XA PREPARE 'xid_$i' + --eval XA ROLLBACK 'xid_$i' + } + +--dec $k +} + +--dec $i +} +--enable_query_log + + + +# Above-like test complicates execution env to create +# data conflicts as well. They will be resolved by the optmistic +# scheduler as usual. + +CREATE TABLE t2 (a INT AUTO_INCREMENT PRIMARY KEY, b INT) ENGINE=InnoDB; + +--let $i = $xid_num +--let $t = t2 +--disable_query_log +while ($i) +{ +--let $k = $repeat +while ($k) +{ +--eval XA START 'xid_$i' +--eval INSERT INTO $t SET a=NULL, b=$k +--eval UPDATE $t SET b=$k + 1 WHERE a=last_insert_id() % $workers +--eval XA END 'xid_$i' +--let $one_phase = `SELECT IF(floor(rand()*10)%2, "ONE PHASE", 0)` + if (!$one_phase) + { + --eval XA PREPARE 'xid_$i' + --eval XA COMMIT 'xid_$i' + } + if ($one_phase) + { + --eval XA COMMIT 'xid_$i' ONE PHASE + } + +--eval XA START 'xid_$i' +--eval UPDATE $t SET b=$k + 1 WHERE a=last_insert_id() % $workers +--eval DELETE FROM $t WHERE a=last_insert_id() +--eval XA END 'xid_$i' +--eval XA PREPARE 'xid_$i' +--eval XA ROLLBACK 'xid_$i' + +--let $do_drop_create = `SELECT IF(floor(rand()*10)%100, 1, 0)` +if ($do_drop_create) +{ + DROP TABLE t1; + CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB; +} +--dec $k +} + +--dec $i +} +--enable_query_log + +--source include/sync_slave_sql_with_master.inc +--let $diff_tables= master:t1, slave:t1 +--source include/diff_tables.inc + +# +# Clean up. +# +--connection slave +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +SET GLOBAL slave_parallel_mode=@old_parallel_mode; +--source include/start_slave.inc + +--connection master +DROP TABLE t1, t2; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_partition_archive.test b/mysql-test/suite/rpl/t/rpl_partition_archive.test new file mode 100644 index 00000000..5b64576d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_partition_archive.test @@ -0,0 +1,12 @@ +# Test of partitioning features with replication for archive +--source include/have_archive.inc +--source include/have_partition.inc +--source include/master-slave.inc + +# Set the default connection to 'master' + +let $engine_type= 'Archive'; + +--source suite/rpl/include/rpl_partition.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_partition_innodb-master.opt b/mysql-test/suite/rpl/t/rpl_partition_innodb-master.opt new file mode 100644 index 00000000..0eed7aaa --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_partition_innodb-master.opt @@ -0,0 +1 @@ +--innodb_autoinc_lock_mode=0 diff --git a/mysql-test/suite/rpl/t/rpl_partition_innodb.test b/mysql-test/suite/rpl/t/rpl_partition_innodb.test new file mode 100644 index 00000000..098bc407 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_partition_innodb.test @@ -0,0 +1,12 @@ +# Test of partitioning features with replication for InnoDB +--source include/have_innodb.inc +--source include/have_partition.inc +--source include/master-slave.inc + +# Set the default connection to 'master' + +let $engine_type= 'InnoDB'; + +--source suite/rpl/include/rpl_partition.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_partition_memory.test b/mysql-test/suite/rpl/t/rpl_partition_memory.test new file mode 100644 index 00000000..4ce68d6f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_partition_memory.test @@ -0,0 +1,11 @@ +# Test of partitioning features with replication for Memory +--source include/have_partition.inc +--source include/master-slave.inc + +# Set the default connection to 'master' + +let $engine_type= 'Memory'; + +--source suite/rpl/include/rpl_partition.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_partition_myisam.test b/mysql-test/suite/rpl/t/rpl_partition_myisam.test new file mode 100644 index 00000000..56003d89 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_partition_myisam.test @@ -0,0 +1,11 @@ +# Test of partitioning features with replication for MyISAM +--source include/have_partition.inc +--source include/master-slave.inc + +# Set the default connection to 'master' + +let $engine_type= 'MyISAM'; + +--source suite/rpl/include/rpl_partition.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_password_boundaries.test b/mysql-test/suite/rpl/t/rpl_password_boundaries.test new file mode 100644 index 00000000..567fe35e --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_password_boundaries.test @@ -0,0 +1,104 @@ +source include/not_embedded.inc; +source include/master-slave.inc; +source include/rpl_reset.inc; + +# Suppress warnings that might be generated during the test +disable_query_log; +connection master; +call mtr.add_suppression("Timeout waiting for reply of binlog"); +connection slave; +call mtr.add_suppression("Slave SQL.*Request to stop slave SQL Thread received while applying a group that has non-transactional changes; waiting for completion of the group"); +enable_query_log; + +connection master; + +# wait for dying connections (if any) to disappear +let $wait_condition= select count(*) = 0 from information_schema.processlist where command='killed'; +--source include/wait_condition.inc + +# 32*3-character ASCII password should work all right + +set sql_log_bin=0; +grant replication slave on *.* to rpl32@127.0.0.1 identified by '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; +set sql_log_bin=1; + +connection slave; +source include/stop_slave.inc; +change master to master_user='rpl32',master_password='0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; +source include/start_slave.inc; + +connection master; +drop table if exists t1; +create table t1 (i int); +insert into t1 values (1); +sync_slave_with_master; +echo [ synchronized ]; + +connection master; + +# 32*3+1 -character ASCII password expected to fail +set sql_log_bin=0; +grant replication slave on *.* to rpl33@127.0.0.1 identified by '0123456789abcdef0123456789abcdef!'; +set sql_log_bin=1; + +connection slave; +source include/stop_slave.inc; +--error ER_WRONG_STRING_LENGTH +change master to master_user='rpl33',master_password='0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef!'; + +# Check also master_user and master_host + +--error ER_WRONG_STRING_LENGTH +change master to master_user='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'; + +# One more char to the master host naturally max ends up with +--error ER_WRONG_STRING_LENGTH +change master to master_host='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddE'; + +# 48-character cyrillic password should work all right +connection master; +set sql_log_bin=0; +grant replication slave on *.* to rpl16cyr@127.0.0.1 identified by 'воттакойужпарольвоттакойужпарольвоттакойужпароль'; +set sql_log_bin=1; + +connection slave; +SET NAMES utf8; +change master to master_user='rpl16cyr',master_password='воттакойужпарольвоттакойужпарольвоттакойужпароль'; +source include/start_slave.inc; + +connection master; +drop table if exists t1; +create table t1 (i int); +insert into t1 values (1); +sync_slave_with_master; +echo [ synchronized ]; + +# 48+1-character cyrillic password should fail + +connection master; +set sql_log_bin=0; +grant replication slave on *.* to rpl17mix@127.0.0.1 identified by 'воттакойужпарольвоттакойужпарольвоттакойужпароль!'; +set sql_log_bin=1; + +connection slave; +source include/stop_slave.inc; +--error ER_WRONG_STRING_LENGTH +change master to master_user='rpl17mix',master_password='воттакойужпарольвоттакойужпарольвоттакойужпароль!'; + +# Cleanup + +connection master; +set sql_log_bin=0; +drop user rpl32@127.0.0.1, rpl33@127.0.0.1, rpl16cyr@127.0.0.1, rpl17mix@127.0.0.1; +set sql_log_bin=1; + +connection slave; +change master to master_user='root',master_password=''; +source include/start_slave.inc; + +connection master; +drop table if exists t1; +sync_slave_with_master; + +connection master; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_performance_schema.test b/mysql-test/suite/rpl/t/rpl_performance_schema.test new file mode 100644 index 00000000..18aabe52 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_performance_schema.test @@ -0,0 +1,10 @@ +--source include/have_perfschema.inc +--source include/have_binlog_format_mixed.inc +--source include/master-slave.inc + +UPDATE performance_schema.setup_instruments SET ENABLED="NO"; + +--sync_slave_with_master +--source include/rpl_end.inc + +# End of test case diff --git a/mysql-test/suite/rpl/t/rpl_perfschema_applier_config.test b/mysql-test/suite/rpl/t/rpl_perfschema_applier_config.test new file mode 100644 index 00000000..5e7b1104 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_perfschema_applier_config.test @@ -0,0 +1,97 @@ +# ==== Purpose ==== +# +# This test script serves as the functionality testing for the table +# performance_schema.replication_applier_configuration. Test for ddl and dml +# operations is a part of the perfschema suite. The ddl/dml tests are named: +# 1) ddl_replication_applier_configuration.test and +# 2) dml_replication_applier_configuration.test. +# +# The follwing scenarios are tested in this script: +# +# - Verify that output is same as SSS on a fresh slave. +# - Verify that the value of this field is correct after STOP SLAVE. +# - Verify that, when desired delay is set, the value is shown corectly. +# - Verify that the value is preserved after STOP SLAVE. +# - Verify that, when desired delay is reset, the value is shown corectly. +# +# ==== Related Worklog ==== +# +# MDEV-16437: merge 5.7 P_S replication instrumentation and tables +# + +source include/have_perfschema.inc; +source include/have_binlog_format_mixed.inc; +source include/master-slave.inc; + +let $assert_text= On master, the table should return an empty set.; +let $assert_cond= count(*) = 0 from performance_schema.replication_applier_configuration; +source include/assert.inc; + +--connection slave + +--echo +--echo # Verify that SELECT works and produces an output similar to +--echo # the corresponding field in SHOW SLAVE STATUS(SSS) in all scenarios. +--echo + +--echo +--echo # Verify that output is same as SSS on a fresh slave. +--echo + +let $sss_value= query_get_value(SHOW SLAVE STATUS, SQL_Delay, 1); +let $ps_value= query_get_value(select Desired_Delay from performance_schema.replication_applier_configuration, Desired_Delay, 1); +let $assert_text= Value returned by SSS and PS table for Desired_Delay should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +--echo +--echo # Verify that the value of this field is correct after STOP SLAVE. +--echo + +source include/stop_slave.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, SQL_Delay, 1); +let $ps_value= query_get_value(select Desired_Delay from performance_schema.replication_applier_configuration, Desired_Delay, 1); +let $assert_text= Value returned by SSS and PS table for Desired_Delay should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +--echo +--echo # Verify that, when desired delay is set, the value is shown corectly. +--echo + +eval change master to master_delay= 2; +source include/start_slave.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, SQL_Delay, 1); +let $ps_value= query_get_value(select Desired_Delay from performance_schema.replication_applier_configuration, Desired_Delay, 1); +let $assert_text= Value returned by SSS and PS table for Desired_Delay should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +--echo +--echo # Verify that the value is preserved after STOP SLAVE. +--echo + +source include/stop_slave.inc; + +let $ss_value= query_get_value(SHOW SLAVE STATUS, SQL_Delay, 1); +let $ps_value= query_get_value(select Desired_Delay from performance_schema.replication_applier_configuration, Desired_Delay, 1); +let $assert_text= Value returned by SSS and PS table for Desired_Delay should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +--echo +--echo # Verify that, when desired delay is reset, the value is shown corectly. +--echo + +eval change master to master_delay= 0; +source include/start_slave.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, SQL_Delay, 1); +let $ps_value= query_get_value(select Desired_Delay from performance_schema.replication_applier_configuration, Desired_Delay, 1); +let $assert_text= Value returned by SSS and PS table for Desired_Delay should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +source include/rpl_end.inc; diff --git a/mysql-test/suite/rpl/t/rpl_perfschema_applier_status.test b/mysql-test/suite/rpl/t/rpl_perfschema_applier_status.test new file mode 100644 index 00000000..7a0e9cf9 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_perfschema_applier_status.test @@ -0,0 +1,73 @@ +# ==== Purpose ==== +# +# This test script serves as the functionality testing for the table +# performance_schema.replication_applier_status. Test for ddl and dml +# operations is a part of the perfschema suite. The ddl/dml tests are named: +# 1) ddl_replication_applier_status.test and +# 2) dml_replication_applier_status.test. +# +# The follwing scenarios are tested in this script: +# +# - Verify that output is same as SSS on a fresh slave. +# - Verify that the value of this field is correct after STOP SLAVE. +# - Remaining delay is not tested. +# - Count_trnsaction is partially tested here making sure it can be queried. +# More testing in rpl/include/rpl_deadlock.test +# +# ==== Related Worklog ==== +# +# MDEV-16437: merge 5.7 P_S replication instrumentation and tables +# + +source include/have_perfschema.inc; +source include/have_binlog_format_mixed.inc; +source include/master-slave.inc; + +let $assert_text= On master, the table should return an empty set.; +let $assert_cond= count(*) = 0 from performance_schema.replication_applier_status; +source include/assert.inc; + +--connection slave + +--echo +--echo # Verify that SELECT works and produces an output similar to +--echo # the corresponding field in SHOW SLAVE STATUS(SSS) in all scenarios. +--echo + +--echo +--echo # Verify that output is same as SSS on a fresh slave. +--echo + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Slave_SQL_Running, 1); +let $ps_value= query_get_value(select Service_State from performance_schema.replication_applier_status, Service_State, 1); +let $assert_text= SSS shows Slave_SQL_Running as "Yes". So, Service_State from this PS table should be "ON".; +let $assert_cond= "$sss_value" = "Yes" AND "$ps_value"= "ON"; +source include/assert.inc; + +let $ss_value= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); +let $ps_value= query_get_value(select count_transactions_retries from performance_schema.replication_applier_status, count_transactions_retries, 1); +let $assert_text= COUNT_TRANSACTION_RETRIES should be equal to Slave_retried_transactions.; +let $assert_cond= "$ps_value"= "$ss_value"; +source include/assert.inc; + +--echo +--echo # Verify that the fields show the correct values after STOP SLAVE. +--echo + +source include/stop_slave.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Slave_SQL_Running, 1); +let $ps_value= query_get_value(select Service_State from performance_schema.replication_applier_status, Service_State, 1); +let $assert_text= SSS shows Slave_SQL_Running as "No". So, Service_State from this PS table should be "OFF".; +let $assert_cond= "$sss_value" = "No" AND "$ps_value"= "OFF"; +source include/assert.inc; + +let $ss_value= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); +let $ps_value= query_get_value(select count_transactions_retries from performance_schema.replication_applier_status, count_transactions_retries, 1); +let $assert_text= COUNT_TRANSACTION_RETRIES should be equal to Slave_retried_transactions.; +let $assert_cond= "$ps_value"= "$ss_value"; +source include/assert.inc; + +source include/start_slave.inc; +source include/rpl_end.inc; + diff --git a/mysql-test/suite/rpl/t/rpl_perfschema_applier_status_by_coordinator-slave.opt b/mysql-test/suite/rpl/t/rpl_perfschema_applier_status_by_coordinator-slave.opt new file mode 100644 index 00000000..3f82baff --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_perfschema_applier_status_by_coordinator-slave.opt @@ -0,0 +1 @@ +--loose-innodb-lock-wait-timeout=1 diff --git a/mysql-test/suite/rpl/t/rpl_perfschema_applier_status_by_coordinator.test b/mysql-test/suite/rpl/t/rpl_perfschema_applier_status_by_coordinator.test new file mode 100644 index 00000000..44df3ca4 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_perfschema_applier_status_by_coordinator.test @@ -0,0 +1,318 @@ +# ==== Purpose ==== +# +# This test script serves as the functionality testing for the table +# performance_schema.replication_applier_status_by_coordinator. Test +# for ddl and dml operations is a part of the perfschema suite. +# The ddl/dml tests are named: +# 1) ddl_replication_connection_configuration.test and +# 2) dml_replication_connection_configuration.test. +# +# This test script does the following: + +# - Verify that SELECT works for every field in the table. +# - The SELECT per field produces an output similar to the corresponding field +# in SHOW SLAVE STATUS(SSS), if there is one. +# - If there is no matching field in SSS, we resort to other method of testing +# those fields. +# - We perform all the testing on connection "slave". On master, the table +# returns an empty set. +# +# The follwing scenarios are tested in this test script: +# +# - Test each field in STS on a fresh replication setup. +# - Change configuration parameters using CHANGE MASTER TO and verify that +# these changes are seen in SELECTs from PS table. +# - Verify that, the change in values are correctly shown by the table. +# - Verify that the values are preserved after STOP SLAVE, thread_id +# changes to NULL and service_state changes to "Off". +# - A priliminary test for Multi-threaded slave(MTS) mode. +# +# ==== Reference ==== +# +# MDEV:16437: merge 5.7 P_S replication instrumentation and tables +# +--source include/have_innodb.inc +--source include/have_binlog_format_mixed.inc +--source include/have_perfschema.inc +--source include/master-slave.inc + +call mtr.add_suppression("Error 'Table 'test.t' doesn't exist' on query."); + +let $assert_text= On master, the table should return an empty set.; +let $assert_cond= count(*) = 0 from performance_schema.replication_applier_status_by_coordinator; +source include/assert.inc; + +--connection slave + +--let $slave_param= Slave_SQL_Running_State +--let $slave_param_value= Slave has read all relay log; waiting for more updates +source include/wait_for_slave_param.inc; + +--echo +--echo # Testing on fresh slave. +--echo + +# To verify the correctness of thread_id field, we check for the name of +# the thread. +let $thread_name= `select name from performance_schema.threads where thread_id= (select Thread_Id from performance_schema.replication_applier_status_by_coordinator)`; +let $assert_text= thread_name should should indicate sql thread.; +let $assert_cond= "$thread_name" = "thread/sql/slave_sql"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Slave_SQL_Running, 1); +let $ps_value= query_get_value(select Service_State from performance_schema.replication_applier_status_by_coordinator, Service_State, 1); +let $assert_text= SSS shows Slave_IO_Running as "Yes". So, Service_State from this PS table should be "ON".; +let $assert_cond= "$sss_value" = "Yes" AND "$ps_value"= "ON"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1); +let $ps_value= query_get_value(select Last_Error_Number from performance_schema.replication_applier_status_by_coordinator, Last_Error_Number, 1); +let $assert_text= Value returned by SSS and PS table for Last_Error_Number should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1); +let $ps_value= query_get_value(select Last_Error_Message from performance_schema.replication_applier_status_by_coordinator, Last_Error_Message, 1); +let $assert_text= Value returned by SSS and PS table for Last_Error_Message should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +let $ps_value= query_get_value(select Last_Error_Timestamp from performance_schema.replication_applier_status_by_coordinator, Last_Error_Timestamp, 1); +let $assert_text= Value returned by SSS and PS table for Last_Error_Timestamp should be 0000-00-00 00:00:00.; +let $assert_cond= "$ps_value" = "0000-00-00 00:00:00"; +source include/assert.inc; + +let $ps_value= query_get_value(select Last_Trans_Retry_Count from performance_schema.replication_applier_status_by_coordinator, Last_Trans_Retry_Count, 1); +let $assert_text= Last_trans_retry_count should be 0.; +let $assert_cond= "$ps_value"= 0; +source include/assert.inc; + +--echo +--echo # Cause an error in the SQL thread and check for the correctness of +--echo # values in error number, message and timestamp fields. +--echo + +# Cause an error in SQL thread. +# 1) Ceate a table 't' at master, replicate at slave. +# 2) Drop table 't' at slave only. +# 3) Insert a value in table 't' on master and replicate on slave. +# Since slave doesnt have table 't' anymore, SQL thread will show an error. + +--connection master +use test; +create table t(a int primary key); +--source include/sync_slave_sql_with_master.inc +drop table t; +--connection master +insert into t values(1); +--connection slave +let $slave_sql_errno=1146; +source include/wait_for_slave_sql_error.inc; + +--echo +--echo # Extract the error related fields from SSS and PS table and compare +--echo # them for correctness. +--echo + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1); +let $ps_value= query_get_value(select Last_Error_Number from performance_schema.replication_applier_status_by_coordinator, Last_Error_Number, 1); +let $assert_text= Value returned by SSS and PS table for Last_Error_Number should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +# Availability of special characters like single quote and backtick character +# makes it difficult use the assert.inc or mysql functionstrcmp(). +# So, the equality of error messages is checked using the below perl code. + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1); +let $ps_value= query_get_value(select Last_Error_Message from performance_schema.replication_applier_status_by_coordinator, Last_Error_Message, 1); + +let PS_VALUE= $ps_value; +let SSS_VALUE= $sss_value; + +perl; +use strict; +my $ps_value= $ENV{'PS_VALUE'}; +my $sss_value= $ENV{'SSS_VALUE'}; + +if ($ps_value eq $sss_value) +{ + print "Value returned by SSS and PS table for Last_Error_Message is same.\n"; +} +else +{ + print "Value returned by SSS and PS table for Last_Error_Message is NOT same\n"; +} +EOF + +--echo +--echo # Verify that the error fields are preserved after STOP SLAVE, thread_id +--echo # changes to NULL and service_state changes to "Off". +--echo + +--echo +--echo # 1. Verify that thread_id changes to NULL and service_state to "off" on +--echo # STOP SLAVE. +--echo + +let $ps_value= query_get_value(select thread_id from performance_schema.replication_applier_status_by_coordinator, thread_id, 1); +let $assert_text= After STOP SLAVE, thread_id should be NULL; +let $assert_cond= "$ps_value" = "NULL"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Slave_SQL_Running, 1); +let $ps_value= query_get_value(select Service_State from performance_schema.replication_applier_status_by_coordinator, Service_State, 1); +let $assert_text= SSS shows Slave_SQL_Running as "No". So, Service_State from this PS table should be "OFF".; +let $assert_cond= "$sss_value" = "No" AND "$ps_value"= "OFF"; +source include/assert.inc; + +--echo +--echo # 2. Extract the error related fields from SSS and PS table and compare +--echo # them. These fields should preserve their values. +--echo + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1); +let $ps_value= query_get_value(select Last_Error_Number from performance_schema.replication_applier_status_by_coordinator, Last_Error_Number, 1); +let $assert_text= Value returned by SSS and PS table for Last_Error_Number should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +# Availability of special characters like single quote and backtick character +# makes it difficult use the assert.inc or mysql functionstrcmp(). +# So, the equality of error messages is checked using the below perl code. + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1); +let $ps_value= query_get_value(select Last_Error_Message from performance_schema.replication_applier_status_by_coordinator, Last_Error_Message, 1); + +let PS_VALUE= $ps_value; +let SSS_VALUE= $sss_value; + +perl; +use strict; +my $ps_value= $ENV{'PS_VALUE'}; +my $sss_value= $ENV{'SSS_VALUE'}; + +if ($ps_value eq $sss_value) +{ + print "Value returned by SSS and PS table for Last_Error_Message is same.\n"; +} +else +{ + print "Value returned by SSS and PS table for Last_Error_Message is NOT same\n"; +} +EOF + +# End of perl code for testing the error message. + +--connection master +drop table t; +reset master; + +--connection slave +--source include/stop_slave.inc +reset slave; +reset master; +set @@global.gtid_slave_pos= ""; +set @saved_slave_trans_retry_interval= @@GLOBAL.slave_transaction_retry_interval; +set global slave_transaction_retry_interval=1; +--source include/start_slave.inc +# End of perl code for testing error message. + + +--echo # +--echo # Test Last_Trans_Retry_Count value. +--echo # + +--connection master +create table t1 (f int primary key) engine=innodb; +insert into t1 values (10); +--sync_slave_with_master +connect (slave2,127.0.0.1,root,,test,$SLAVE_MYPORT,); +--connection slave2 +begin; +update t1 set f=40 where f=10; + +--connection master +begin; +update t1 set f=60 where f=10; +commit; + +--connection slave +--let $wait_condition= SELECT COUNT(*) > 0 FROM information_schema.processlist WHERE Info = "update t1 set f=60 where f=10" +--source include/wait_condition.inc +sleep 4 ; +--connection slave2 +rollback; + +let $ps_value= query_get_value(select Last_Trans_Retry_Count from performance_schema.replication_applier_status_by_coordinator, Last_Trans_Retry_Count, 1); +let $assert_text= Value returned by PS table for Last_Trans_Retry_Count should be > 0.; +let $assert_cond= "$ps_value" > 0; +source include/assert.inc; + +--connection master +drop table t1; +--sync_slave_with_master +--disconnect slave2 +set global slave_transaction_retry_interval=@saved_slave_trans_retry_interval; + +source include/stop_slave.inc; + +--echo +--echo # Restarting servers and setting up MTS now. Since, SQL thread and +--echo # coordinator are the same and follow same code path, we can skip +--echo # testing for coordinator thread in all scenarios. Testing for one +--echo # scenario is enough. +--echo + +--let $rpl_server_number= 1 +--source include/rpl_restart_server.inc + +--let $rpl_server_number= 2 +--source include/rpl_restart_server.inc + +--connection slave +replace_result $MASTER_MYPORT MASTER_MYPORT; +replace_column 2 ###; +eval change master to + master_host='127.0.0.1', + master_port=$MASTER_MYPORT, + master_user='root'; +SET @save.slave_parallel_workers=@@global.slave_parallel_workers; +SET @@global.slave_parallel_workers=1; +# to avoid warnings +set @save.slave_transaction_retries= @@global.slave_transaction_retries; +source include/start_slave.inc; + +--let $slave_param= Slave_SQL_Running_State +--let $slave_param_value= Slave has read all relay log; waiting for more updates +source include/wait_for_slave_param.inc; + +# To verify the correctness of thread_id field, we check for the name of +# the thread. +let $thread_name= `select name from performance_schema.threads where thread_id= (select Thread_Id from performance_schema.replication_applier_status_by_coordinator)`; +let $assert_text= thread_name should should indicate sql thread.; +let $assert_cond= "$thread_name" = "thread/sql/slave_sql"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Slave_SQL_Running, 1); +let $ps_value= query_get_value(select Service_State from performance_schema.replication_applier_status_by_coordinator, Service_State, 1); +let $assert_text= SSS shows Slave_SQL_Running as "Yes". So, Service_State from this PS table should be "ON".; +let $assert_cond= "$sss_value" = "Yes" AND "$ps_value"= "ON"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1); +let $ps_value= query_get_value(select Last_Error_Number from performance_schema.replication_applier_status_by_coordinator, Last_Error_Number, 1); +let $assert_text= Value returned by SSS and PS table for Last_Error_Number should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +--echo +--echo # Cleanup. +--echo + +source include/stop_slave.inc; +set @@global.slave_parallel_workers= @save.slave_parallel_workers; +set @@global.slave_transaction_retries= @save.slave_transaction_retries; +source include/start_slave.inc; + +source include/rpl_end.inc; diff --git a/mysql-test/suite/rpl/t/rpl_perfschema_applier_status_by_worker.test b/mysql-test/suite/rpl/t/rpl_perfschema_applier_status_by_worker.test new file mode 100644 index 00000000..857979d0 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_perfschema_applier_status_by_worker.test @@ -0,0 +1,257 @@ +# ==== Purpose ==== +# +# This test script serves as the functionality testing for the table +# performance_schema.replication_applier_status_by_worker. Test +# for ddl and dml operations is a part of the perfschema suite. +# The ddl/dml tests are named: +# 1) ddl_replication_applier_status_by_worker.test and +# 2) dml_replication_applier_status_by_worker.test. +# +# This test script does the following: + +# - Verify that SELECT works for every field in the table. +# - The SELECT per field produces an output similar to the corresponding field +# in SHOW SLAVE STATUS(SSS), if there is one. +# - If there is no matching field in SSS, we resort to other method of testing +# those fields. +# - We perform all the testing on connection "slave". On master, the table +# returns an empty set. +# +# The follwing scenarios are tested in this test script: +# +# - Test each field on a fresh replication setup. +# - Introduce error in worker thread and check for the correctness of error +# error number, message and timestamp. +# - Verify that, the change in values are correctly shown by the table. +# - Verify that the values are preserved after STOP SLAVE. +# - Set up replication in gtid-mode=on and test 'Last_Seen_Transaction' field. +# - Verify that the value in 'Last_Seen_Transaction' field is preserved after +# STOP SLAVE. +# +# ==== Related Bugs and Worklogs ==== +# +# MDEV-20220: Merge 5.7 P_S replication table 'replication_applier_status_by_worker +# +--source include/have_perfschema.inc +--source include/have_binlog_format_mixed.inc +--source include/have_innodb.inc +--source include/master-slave.inc + + +let $assert_text= On master, the table should return an empty set.; +let $assert_cond= count(*) = 0 from performance_schema.replication_applier_status_by_worker; +source include/assert.inc; + +--echo +--echo # Setup MTS and perform testing on a fresh slave. +--echo +--connection slave +call mtr.add_suppression("Error 'Table 'test.t' doesn't exist' on query."); +source include/stop_slave.inc; +set @save_slave_parallel_workers= @@global.slave_parallel_workers; +# to avoid warnings +set @save_slave_transaction_retries= @@global.slave_transaction_retries; +RESET SLAVE ALL; +evalp CHANGE MASTER 'slave1' TO MASTER_USER='root',MASTER_PORT=$MASTER_MYPORT, MASTER_HOST='127.0.0.1', MASTER_USE_GTID=slave_pos; +SET default_master_connection='slave1'; +SET @@global.slave_parallel_workers=1; +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +START SLAVE 'slave1'; +--source include/wait_for_slave_to_start.inc + +let $ps_value= query_get_value(select channel_name from performance_schema.replication_applier_status_by_worker, channel_name, 1); +let $assert_text= Channel_name will be empty for a worker when it has not processed any transaction; +let $assert_cond= "$ps_value"= ""; +source include/assert.inc; + +# To verify the correctness of thread_id field, we check for the name of +# the thread. +let $thread_name= `select name from performance_schema.threads where thread_id= (select Thread_Id from performance_schema.replication_applier_status_by_worker)`; +let $assert_text= thread_name should should indicate worker thread.; +let $assert_cond= "$thread_name" = "thread/sql/rpl_parallel_thread"; +source include/assert.inc; + +let $ps_value= query_get_value(select Service_State from performance_schema.replication_applier_status_by_worker, Service_State, 1); +let $assert_text= Service_State should be "ON" on a fresh slave server.; +let $assert_cond= "$ps_value"= "ON"; +source include/assert.inc; + +let $ps_value= query_get_value(select Last_Seen_Transaction from performance_schema.replication_applier_status_by_worker, Last_Seen_Transaction, 1); +let $assert_text= Last_Seen_Transaction should show "" if no transaction applierd; +let $assert_cond= "$ps_value" = ""; +source include/assert.inc; + +--connection master +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +--source include/save_master_gtid.inc + +connection slave; +--source include/sync_with_master_gtid.inc + +let $ps_value= query_get_value(select channel_name from performance_schema.replication_applier_status_by_worker, channel_name, 1); +let $assert_text= Channel_name must be slave1; +let $assert_cond= "$ps_value"= "slave1"; +source include/assert.inc; + +let $ps_value= query_get_value(select Last_Seen_Transaction from performance_schema.replication_applier_status_by_worker, Last_Seen_Transaction, 1); +let $sss_value= query_get_value(SHOW SLAVE STATUS, Gtid_IO_Pos, 1); +let $assert_text= Last_Seen_Transaction should show $sss_value; +let $assert_cond= "$ps_value" = "$sss_value"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1); +let $ps_value= query_get_value(select Last_Error_Number from performance_schema.replication_applier_status_by_worker, Last_Error_Number, 1); +let $assert_text= Value returned by SSS and PS table for Last_Error_Number should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1); +let $ps_value= query_get_value(select Last_Error_Message from performance_schema.replication_applier_status_by_worker, Last_Error_Message, 1); +let $assert_text= Value returned by SSS and PS table for Last_Error_Message should both be empty.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +let $ps_value= query_get_value(select Last_Error_Timestamp from performance_schema.replication_applier_status_by_worker, Last_Error_Timestamp, 1); +let $assert_text= Value returned by PS table for Last_Error_Timestamp should be 0000-00-00 00:00:00.; +let $assert_cond= "$ps_value" = "0000-00-00 00:00:00"; +source include/assert.inc; + +--connection master +sleep 1; +--connection slave +let $ps_value= query_get_value(select worker_idle_time from performance_schema.replication_applier_status_by_worker, worker_idle_time, 1); +let $assert_text= Value returned by PS table for worker_idle_time should be >= 1; +let $assert_cond= "$ps_value" >= "1"; +source include/assert.inc; + +--connection master +DROP TABLE t1; +--save_master_pos + +--connection slave +--sync_with_master 0,'slave1' + +STOP SLAVE 'slave1'; +--source include/wait_for_slave_to_stop.inc +RESET SLAVE ALL; +SET default_master_connection=''; +evalp CHANGE MASTER TO MASTER_USER='root', MASTER_HOST='127.0.0.1',MASTER_PORT=$MASTER_MYPORT; +--source include/start_slave.inc + +--echo +--echo # Introduce an error in the worker thread and check for the correctness +--echo # of error number, message and timestamp fields. +--echo + +# Cause an error in Worker thread. +# 1) Create a table 't' at master, replicate at slave. +# 2) Drop table 't' at slave only. +# 3) Insert a value in table 't' on master and replicate on slave. +# Since slave doesnt have table 't' anymore, worker thread will report an error. + +--connection master +use test; +create table t(a int primary key); +sync_slave_with_master; +drop table t; +--connection master +insert into t values(1); +--connection slave +let $slave_sql_errno=1146; +source include/wait_for_slave_sql_error.inc; + +--echo +--echo # Extract the error related fields from SSS and PS table and compare +--echo # them for correctness. +--echo + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1); +let $ps_value= query_get_value(select Last_Error_Number from performance_schema.replication_applier_status_by_worker, Last_Error_Number, 1); +let $assert_text= Value returned by SSS and PS table for Last_Error_Number should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +--disable_query_log +--replace_regex /master-bin.[0-9]+/FILENAME/ /end_log_pos [0-9]+/end_log_pos POSITION/ +select Last_Error_Message from performance_schema.replication_applier_status_by_worker; +--enable_query_log + +--echo +--echo # Verify that the error fields are preserved after STOP SLAVE. +--echo + +--echo +--echo # 1. Verify that thread_id changes to NULL and service_state to "off" on +--echo # STOP SLAVE. +--echo + +let $ps_value= query_get_value(select thread_id from performance_schema.replication_applier_status_by_worker, thread_id, 1); +let $assert_text= After STOP SLAVE, thread_id should be NULL; +let $assert_cond= "$ps_value" = "NULL"; +source include/assert.inc; + +let $ps_value= query_get_value(select service_state from performance_schema.replication_applier_status_by_worker, service_state, 1); +let $assert_text= So, Service_State after STOP SLAVE should be "OFF".; +let $assert_cond= "$ps_value"= "OFF"; +source include/assert.inc; + +--echo +--echo # 2. Extract the worker_id and the error related fields from SSS and PS +--echo # table and compare them. These fields should preserve their values. +--echo + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1); +let $ps_value= query_get_value(select Last_Error_Number from performance_schema.replication_applier_status_by_worker, Last_Error_Number, 1); +let $assert_text= Value returned by SSS and PS table for Last_Error_Number should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +--disable_query_log +--replace_regex /master-bin.[0-9]+/FILENAME/ /end_log_pos [0-9]+/end_log_pos POSITION/ +select Last_Error_Message from performance_schema.replication_applier_status_by_worker; +--enable_query_log + +# The timestamp format is slightly different in SSS and PS. +# SSS => YYMMDD HH:MM:SS +# PS => YYYY-MM-DD HH:MM:SS +# To match the two, we get rid of hyphons from PS output and first two digits +# the year field so that it can be matched directly. + +#--- TODO: Can we include Last_SQL_Error_Timestamp as part of SSS + +#let $sss_value= query_get_value(SHOW SLAVE STATUS, Last_SQL_Error_Timestamp, 1); +#let $ps_value= query_get_value(select Last_Error_Timestamp from performance_schema.replication_applier_status_by_worker, Last_Error_Timestamp, 1); +#let $ps_value_without_hyphons= `SELECT REPLACE("$ps_value", '-', '')`; +#let $ps_value_in_sss_format= `select substring("$ps_value_without_hyphons", 3)`; +#let $assert_text= Value returned by SSS and PS table for Last_Error_Timestamp should be same.; +#let $assert_cond= "$sss_value" = "$ps_value_in_sss_format"; +#source include/assert.inc; + +--source include/stop_slave.inc +RESET SLAVE; +--connection master +DROP TABLE t; +RESET MASTER; + +--echo +--echo # Verify that number of rows in 'replication_applier_status_by_worker' table match with +--echo # number of slave_parallel_workers. +--echo + +--connection slave +SET @@global.slave_parallel_workers=4; +--source include/start_slave.inc +--let $assert_text= On slave, the table should return 4 rows. +--let $assert_cond= count(*) = 4 from performance_schema.replication_applier_status_by_worker +--source include/assert.inc +--source include/stop_slave.inc + +--echo +--echo # Cleanup. +--echo + +set @@global.slave_parallel_workers= @save_slave_parallel_workers; +set @@global.slave_transaction_retries= @save_slave_transaction_retries; +source include/start_slave.inc; + +source include/rpl_end.inc; diff --git a/mysql-test/suite/rpl/t/rpl_perfschema_connect_config.test b/mysql-test/suite/rpl/t/rpl_perfschema_connect_config.test new file mode 100644 index 00000000..7b2bf8d5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_perfschema_connect_config.test @@ -0,0 +1,331 @@ +# ==== Purpose ==== +# +# This test script serves as the functionality testing for the table +# performance_schema.replication_connection_configuration. Test for ddl and dml +# operations is a part of the perfschema suite. The ddl/dml tests are named: +# 1) ddl_replication_connection_configuration.test and +# 2) dml_replication_connection_configuration.test. +# +# This test script does the following: + +# - On master, the table returns an empty set. +# - We perform all other testing on connection "slave". So, the below points +# are checked on slave only. +# - Verify that SELECT works for every field in the table. +# - The SELECT per field produces an output similar to the corresponding field +# in SHOW SLAVE STATUS(SSS), if there is one. +# - If there is no matching field in SSS, we resort to other method of testing +# those fields. +# +# The follwing scenarios are tested: +# +# - Test each field on a fresh replication setup. +# - Change configuration parameters using CHANGE MASTER TO and verify that +# these changes are seen in SELECTs from PS table. +# - Verify that, the change in values are correctly shown by the table. +# - Verify different values for MASTER_USE_GTID are present in table. +# - Verify IGNORE_SERVER_IDS, DO_DOMAIN_IDS and IGNORE_DOMAIN_IDS +# +# ==== Related Worklog ==== +# +# MDEV-16437: merge 5.7 P_S replication instrumentation and tables +# + +source include/have_ssl_communication.inc; +source include/have_binlog_format_mixed.inc; +source include/have_perfschema.inc; +source include/master-slave.inc; + +--let $assert_text= On master, the table should return an empty set. +--let $assert_cond= count(*) = 0 from performance_schema.replication_connection_configuration +--source include/rpl_assert.inc + +--connection slave + +--echo +--echo # Verify that SELECT works for every field and produces an output +--echo # similar to the corresponding field in SHOW SLAVE STATUS(SSS). +--echo + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Master_Host, 1); +let $ps_value= query_get_value(select Host from performance_schema.replication_connection_configuration, Host, 1); +let $assert_text= Value returned by SSS and PS table for Host should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Master_Port, 1); +let $ps_value= query_get_value(select Port from performance_schema.replication_connection_configuration, Port, 1); +let $assert_text= Value returned by SSS and PS table for Port should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Master_User, 1); +let $ps_value= query_get_value(select User from performance_schema.replication_connection_configuration, User, 1); +let $assert_text= Value returned by SSS and PS table for User should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Using_Gtid, 1); +let $ps_value= query_get_value(select Using_Gtid from performance_schema.replication_connection_configuration, Using_Gtid, 1); +let $assert_text= Value returned by SSS and PS table for Using_Gtid should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Master_SSL_Allowed, 1); +let $ps_value= query_get_value(select SSL_Allowed from performance_schema.replication_connection_configuration, SSL_Allowed, 1); +let $assert_text= Value returned by SSS and PS table for SSL_Allowed should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Master_SSL_CA_File, 1); +let $ps_value= query_get_value(select SSL_CA_File from performance_schema.replication_connection_configuration, SSL_CA_File, 1); +let $assert_text= Value returned by SSS and PS table for SSL_CA_File should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Master_SSL_CA_Path, 1); +let $ps_value= query_get_value(select SSL_CA_Path from performance_schema.replication_connection_configuration, SSL_CA_Path, 1); +let $assert_text= Value returned by SSS and PS table for SSL_CA_Path should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Master_SSL_Cert, 1); +let $ps_value= query_get_value(select SSL_Certificate from performance_schema.replication_connection_configuration, SSL_Certificate, 1); +let $assert_text= Value returned by SSS and PS table for SSL_Certificate should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Master_SSL_Cipher, 1); +let $ps_value= query_get_value(select SSL_Cipher from performance_schema.replication_connection_configuration, SSL_Cipher, 1); +let $assert_text= Value returned by SSS and PS table for SSL_Cipher should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Master_SSL_Key, 1); +let $ps_value= query_get_value(select SSL_Key from performance_schema.replication_connection_configuration, SSL_Key, 1); +let $assert_text= Value returned by SSS and PS table for SSL_Key should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Master_SSL_Verify_Server_Cert, 1); +let $ps_value= query_get_value(select SSL_Verify_Server_Certificate from performance_schema.replication_connection_configuration, SSL_Verify_Server_Certificate, 1); +let $assert_text= Value returned by SSS and PS table for SSL_Verify_Server_Certificate should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Master_SSL_Crl, 1); +let $ps_value= query_get_value(select SSL_Crl_File from performance_schema.replication_connection_configuration, SSL_Crl_File, 1); +let $assert_text= Value returned by SSS and PS table for SSL_Crl_File should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Master_SSL_Crlpath, 1); +let $ps_value= query_get_value(select SSL_Crl_Path from performance_schema.replication_connection_configuration, SSL_Crl_Path, 1); +let $assert_text= Value returned by SSS and PS table for SSL_Crl_Path should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Connect_Retry, 1); +let $ps_value= query_get_value(select Connection_Retry_Interval from performance_schema.replication_connection_configuration, Connection_Retry_Interval, 1); +let $assert_text= Value returned by SSS and PS table for Connection_Retry_Interval should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +let $ps_value= query_get_value(select Connection_Retry_Count from performance_schema.replication_connection_configuration, Connection_Retry_Count, 1); +let $assert_text= Value returned by PS table for Connection_Retry_Count should be 10.; # master-retry-count=10, as part of default my.cnf used by MTR +let $assert_cond= "$ps_value" = 10; +source include/assert.inc; + +--echo +--echo # Heartbeat_Interval is part of I_S and P_S. We will compare the +--echo # two to make sure both match. +--echo + +let $is_value= query_get_value(select Variable_Value from information_schema.GLOBAL_STATUS where variable_name= 'Slave_heartbeat_period', Variable_Value, 1); +let $ps_value= query_get_value(select Heartbeat_Interval from performance_schema.replication_connection_configuration, Heartbeat_Interval, 1); +let $assert_text= Value returned by IS and PS table for Heartbeat_Interval should be same.; +let $assert_cond= $is_value = $ps_value; +source include/assert.inc; + +--echo +--echo # Change configuration parameters and verify that these changes +--echo # are shown correctly by SELECTs from PS table. +--echo + +# create a user for replication that requires ssl encryption +--connection master +create user replssl@localhost; +grant replication slave on *.* to replssl@localhost require ssl; +--source include/sync_slave_sql_with_master.inc + +# Setup slave to use SSL for connection to master +--source include/stop_slave.inc +replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR; +replace_column 2 ####; +eval change master to + master_user= 'replssl', + master_password= '', + master_ssl= 1, + master_ssl_ca= '$MYSQL_TEST_DIR/std_data/cacert.pem', + master_ssl_cert= '$MYSQL_TEST_DIR/std_data/client-cert.pem', + master_ssl_key= '$MYSQL_TEST_DIR/std_data/client-key.pem'; +--source include/start_slave.inc + +--connection slave +--echo +--echo # Checking SSL parameters, they were empty in tests done in the +--echo # previous section. +--echo + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Master_SSL_Allowed, 1); +let $ps_value= query_get_value(select SSL_Allowed from performance_schema.replication_connection_configuration, SSL_Allowed, 1); +let $assert_text= Value returned by SSS and PS table for SSL_Allowed should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Master_SSL_CA_File, 1); +let $ps_value= query_get_value(select SSL_CA_File from performance_schema.replication_connection_configuration, SSL_CA_File, 1); +let $assert_text= Value returned by SSS and PS table for SSL_CA_File should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Master_SSL_CA_Path, 1); +let $ps_value= query_get_value(select SSL_CA_Path from performance_schema.replication_connection_configuration, SSL_CA_Path, 1); +let $assert_text= Value returned by SSS and PS table for SSL_CA_Path should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Master_SSL_Cert, 1); +let $ps_value= query_get_value(select SSL_Certificate from performance_schema.replication_connection_configuration, SSL_Certificate, 1); +let $assert_text= Value returned by SSS and PS table for SSL_Certificate should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Master_SSL_Cipher, 1); +let $ps_value= query_get_value(select SSL_Cipher from performance_schema.replication_connection_configuration, SSL_Cipher, 1); +let $assert_text= Value returned by SSS and PS table for SSL_Cipher should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Master_SSL_Key, 1); +let $ps_value= query_get_value(select SSL_Key from performance_schema.replication_connection_configuration, SSL_Key, 1); +let $assert_text= Value returned by SSS and PS table for SSL_Key should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Master_SSL_Verify_Server_Cert, 1); +let $ps_value= query_get_value(select SSL_Verify_Server_Certificate from performance_schema.replication_connection_configuration, SSL_Verify_Server_Certificate, 1); +let $assert_text= Value returned by SSS and PS table for SSL_Verify_Server_Certificate should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +--connection master +drop user replssl@localhost; +--sync_slave_with_master +--source include/stop_slave.inc + +CHANGE MASTER TO + master_host= '127.0.0.1', + master_user= 'root', + master_password= '', + master_ssl_ca= '', + master_ssl_cert= '', + master_ssl_key= '', + master_ssl_verify_server_cert=0, + master_ssl=0, + master_use_gtid=no; +--source include/start_slave.inc + +--echo +--echo # Test with different MASTER_USE_GTID values +--echo + +--echo +--echo # 1) Test for MASTER_USE_GTID=NO +--echo +--source include/stop_slave.inc +replace_column 2 ####; +change master to + master_user = 'root', + master_use_gtid = NO; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Using_Gtid, 1); +let $ps_value= query_get_value(select Using_Gtid from performance_schema.replication_connection_configuration, Using_Gtid, 1); +let $assert_text= Value returned by SSS and PS table for Using_Gtid should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +--echo +--echo # 2) Test for Auto_position= CURRENT_POS. +--echo +replace_column 2 ####; +change master to + master_user = 'root', + master_use_gtid= CURRENT_POS; + +let $sss_value= query_get_value(SHOW SLAVE STATUS, Using_Gtid, 1); +let $ps_value= query_get_value(select Using_Gtid from performance_schema.replication_connection_configuration, Using_Gtid, 1); +let $assert_text= Value returned by SSS and PS table for Using_Gtid should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +--echo +--echo # 3) Test for Auto_position= SLAVE_POS +--echo +replace_column 2 ####; +change master to + master_user = 'root', + master_use_gtid= SLAVE_POS; +let $sss_value= query_get_value(SHOW SLAVE STATUS, Using_Gtid, 1); +let $ps_value= query_get_value(select Using_Gtid from performance_schema.replication_connection_configuration, Using_Gtid, 1); +let $assert_text= Value returned by SSS and PS table for Using_Gtid should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; + +--echo +--echo # Test INOGRE_SERVER_IDS +--echo + +--echo +--echo # 1) Test for IGNORE_SERVER_IDS= (10, 100); +--echo + +--connection slave +change master to IGNORE_SERVER_IDS= (10, 100); +let $sss_value= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Server_Ids, 1); +let $ps_value= query_get_value(select Ignore_Server_Ids from performance_schema.replication_connection_configuration, Ignore_Server_Ids, 1); +let $assert_text= Value returned by SSS and PS table for Ignore_server_ids should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; +CHANGE MASTER TO IGNORE_SERVER_IDS=(); + +--echo +--echo # 2) Test for IGNORE_DOMAIN_IDS(2) +--echo + +CHANGE MASTER TO IGNORE_DOMAIN_IDS=(2), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc +let $sss_value= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Domain_Ids, 1); +let $ps_value= query_get_value(select Repl_Ignore_Domain_Ids from performance_schema.replication_connection_configuration, Repl_Ignore_Domain_Ids, 1); +let $assert_text= Value returned by SSS and PS table for Replicate_Ignore_Domain_Ids should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; +--source include/stop_slave.inc + +--echo +--echo # 3) Test for DO_DOMAIN_IDS(1) +--echo + +CHANGE MASTER TO DO_DOMAIN_IDS=(1), IGNORE_DOMAIN_IDS=(), MASTER_USE_GTID=slave_pos; +--source include/start_slave.inc +let $sss_value= query_get_value(SHOW SLAVE STATUS, Replicate_Do_Domain_Ids, 1); +let $ps_value= query_get_value(select Repl_Do_Domain_Ids from performance_schema.replication_connection_configuration, Repl_Do_Domain_Ids, 1); +let $assert_text= Value returned by SSS and PS table for Replicate_Do_Domain_Ids should be same.; +let $assert_cond= "$sss_value" = "$ps_value"; +source include/assert.inc; +--source include/stop_slave.inc + +CHANGE MASTER TO DO_DOMAIN_IDS=(), IGNORE_DOMAIN_IDS=(); +--source include/start_slave.inc + +source include/rpl_end.inc; diff --git a/mysql-test/suite/rpl/t/rpl_plugin_load.test b/mysql-test/suite/rpl/t/rpl_plugin_load.test new file mode 100644 index 00000000..c319479a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_plugin_load.test @@ -0,0 +1,59 @@ +# +# Bug#35807 - INSTALL PLUGIN replicates row-based, but not stmt-based +# +# The test verifies that INSTALL PLUGIN and UNINSTALL PLUGIN +# work with replication. +# +# The test tries to install and uninstall a plugin on master, +# and verifies that it does not affect the slave, +# and that it does not add anything to the binlog. + +--source include/not_embedded.inc +--source include/have_log_bin.inc +--source include/have_example_plugin.inc + +# Initialize replication. +--source include/master-slave.inc +--echo Verify that example engine is not installed. +SELECT * FROM INFORMATION_SCHEMA.ENGINES WHERE ENGINE='EXAMPLE'; +--echo Get binlog position before install plugin. +let $before_pos = query_get_value("SHOW MASTER STATUS", Position, 1); +--echo Install example engine. +--replace_regex /\.dll/.so/ +eval INSTALL PLUGIN example SONAME '$HA_EXAMPLE_SO'; +--echo Get binlog position after install plugin. +let $after_pos = query_get_value("SHOW MASTER STATUS", Position, 1); +--echo Compute the difference of the binlog positions. +--echo Should be zero as install plugin should not be replicated. +--disable_query_log +eval SELECT $after_pos - $before_pos AS Delta; +--enable_query_log +--echo Verify that example engine is installed. +SELECT * FROM INFORMATION_SCHEMA.ENGINES WHERE ENGINE='EXAMPLE'; +# Wait for slave to catch up with master. +sync_slave_with_master; +# + --echo Verify that example engine is not installed. + connection slave; + SELECT * FROM INFORMATION_SCHEMA.ENGINES WHERE ENGINE='EXAMPLE'; +# +--echo Uninstall example engine. +connection master; +--echo Get binlog position before uninstall plugin. +let $before_pos = query_get_value("SHOW MASTER STATUS", Position, 1); +UNINSTALL PLUGIN example; +--echo Get binlog position after uninstall plugin. +let $after_pos = query_get_value("SHOW MASTER STATUS", Position, 1); +--echo Compute the difference of the binlog positions. +--echo Should be zero as uninstall plugin should not be replicated. +--disable_query_log +eval SELECT $after_pos - $before_pos AS Delta; +--enable_query_log +--echo Verify that example engine is not installed. +SELECT * FROM INFORMATION_SCHEMA.ENGINES WHERE ENGINE='EXAMPLE'; +# Wait for slave to catch up with master. +sync_slave_with_master; +# +# Cleanup +--source include/rpl_end.inc +--echo End of test diff --git a/mysql-test/suite/rpl/t/rpl_ps.test b/mysql-test/suite/rpl/t/rpl_ps.test new file mode 100644 index 00000000..45ab55bf --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_ps.test @@ -0,0 +1,94 @@ +# +# Test of replicating user variables +# +source include/master-slave.inc; + +#sync_slave_with_master; +#reset master; +#connection master; + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1(n char(30)); + +prepare stmt1 from 'insert into t1 values (?)'; +set @var1= "from-master-1"; +execute stmt1 using @var1; +set @var1= "from-master-2-'',"; +execute stmt1 using @var1; +SELECT * FROM t1 ORDER BY n; + +set @var2= 'insert into t1 values (concat("from-var-", ?))'; +prepare stmt2 from @var2; +set @var1='from-master-3'; +execute stmt2 using @var1; + +sync_slave_with_master; +SELECT * FROM t1 ORDER BY n; + +connection master; + +drop table t1; + +sync_slave_with_master; +stop slave; +source include/wait_for_slave_to_stop.inc; +# End of 4.1 tests + +# +# Bug #25843 Changing default database between PREPARE and EXECUTE of statement +# breaks binlog. +# +# There were actually two problems discovered by this bug: +# +# 1. Default (current) database is not fixed at the creation time. +# That leads to wrong output of DATABASE() function. +# +# 2. Database attributes (@@collation_database) are not fixed at the creation +# time. That leads to wrong resultset. +# +# Binlog breakage and Query Cache wrong output happened because of the first +# problem. +# + +--echo +--echo ######################################################################## +--echo # +--echo # BUG#25843: Changing default database between PREPARE and EXECUTE of +--echo # statement breaks binlog. +--echo # +--echo ######################################################################## + +############################################################################### + +--connection slave + +START SLAVE; + +--connection master + +CREATE DATABASE mysqltest1; +CREATE TABLE t1(db_name CHAR(32), db_col_name CHAR(32)); + +PREPARE stmt_d_1 FROM 'INSERT INTO t1 VALUES(DATABASE(), @@collation_database)'; + +EXECUTE stmt_d_1; + +use mysqltest1; + +EXECUTE stmt_d_1; + +--sync_slave_with_master + +SELECT * FROM t1; + +--connection master + +DROP DATABASE mysqltest1; + +use test; +DROP TABLE t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_query_cache.test b/mysql-test/suite/rpl/t/rpl_query_cache.test new file mode 100644 index 00000000..b23f2b20 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_query_cache.test @@ -0,0 +1,27 @@ +-- source include/have_binlog_format_row.inc +-- source include/have_innodb.inc +-- source include/master-slave.inc + +--connection slave +SET @qtype= @@global.query_cache_type; +SET GLOBAL query_cache_type= ON; +SET query_cache_type= ON; + +--connection master +create table t1 (i int) engine=innodb; +insert into t1 set i=1; + +--sync_slave_with_master +select * from t1; +--connection master +insert into t1 set i=2; + +--sync_slave_with_master +select * from t1; +select sql_no_cache * from t1; + +--connection master +DROP TABLE t1; +--sync_slave_with_master +SET GLOBAL query_cache_type= @qtype; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_rbr_monitor.test b/mysql-test/suite/rpl/t/rpl_rbr_monitor.test new file mode 100644 index 00000000..2bc1f9cd --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_rbr_monitor.test @@ -0,0 +1,76 @@ +# +# Mdev-7409 On RBR, extend the PROCESSLIST info to include at least the name of +# the recently used table +# This testcase create Write_rows_log_event , Update_rows_log_event and +# Delete_rows_log_event which is blocked on slave and we will check whether +# whether processinfo includes table name or not. +--source include/have_innodb.inc +--source include/have_binlog_format_row.inc +--source include/master-slave.inc +--enable_connect_log + +--connection master +create table t1(a int primary key) engine=innodb; + +--sync_slave_with_master +--connection slave1 +begin; +insert into t1(a) values(1); +--connection master +select * from t1; + +insert into t1(a) values(1); +--save_master_pos + +--echo #monitoring write rows +--connection slave + + +let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE DB = 'test' AND STATE LIKE "Write_rows_log_event::write_row(%) on table %"; +--source include/wait_condition.inc + + +--echo #monitoring update rows +--connection slave1 +rollback; +--sync_with_master +begin; +select a from t1 for update; + +--connection master +update t1 set a = a + 1 ; +--save_master_pos + +--connection slave +let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE DB = 'test' AND STATE LIKE "Update_rows_log_event::find_row(%) on table %"; +--source include/wait_condition.inc + +--echo #monitoring delete rows +--connection slave1 +rollback; +--sync_with_master +begin; +select * from t1 for update; + +--connection master +delete from t1; +--save_master_pos + +--connection slave +select * from t1; +let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE DB = 'test' AND STATE LIKE "Delete_rows_log_event::find_row(%) on table %"; +--source include/wait_condition.inc + +#CleanUp +--connection slave1 +rollback; +--sync_with_master + +--connection master +drop table t1; +--sync_slave_with_master + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_rbr_to_sbr.test b/mysql-test/suite/rpl/t/rpl_rbr_to_sbr.test new file mode 100644 index 00000000..1bc20c1e --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_rbr_to_sbr.test @@ -0,0 +1,31 @@ +-- source include/have_binlog_format_mixed.inc +-- source include/master-slave.inc + +# Test that the slave temporarily switches to ROW when seeing row +# events when it is in MIXED mode + +CREATE TABLE t1 (a INT, b LONG); +INSERT INTO t1 VALUES (1,1), (2,2); +INSERT INTO t1 VALUES (3,UUID()), (4,UUID()); +source include/show_binlog_events.inc; +sync_slave_with_master; +source include/show_binlog_events.inc; + +--exec $MYSQL_DUMP --compact --order-by-primary --skip-extended-insert --no-create-info test > $MYSQLTEST_VARDIR/tmp/rpl_rbr_to_sbr_master.sql +--exec $MYSQL_DUMP_SLAVE --compact --order-by-primary --skip-extended-insert --no-create-info test > $MYSQLTEST_VARDIR/tmp/rpl_rbr_to_sbr_slave.sql + +connection master; +DROP TABLE IF EXISTS t1; + +# Let's compare. Note: If they match test will pass, if they do not match +# the test will show that the diff statement failed and not reject file +# will be created. You will need to go to the mysql-test dir and diff +# the files your self to see what is not matching + +diff_files $MYSQLTEST_VARDIR/tmp/rpl_rbr_to_sbr_master.sql $MYSQLTEST_VARDIR/tmp/rpl_rbr_to_sbr_slave.sql; + +# If all is good, we can remove the files + +--remove_file $MYSQLTEST_VARDIR/tmp/rpl_rbr_to_sbr_master.sql +--remove_file $MYSQLTEST_VARDIR/tmp/rpl_rbr_to_sbr_slave.sql +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_read_new_relay_log_info.test b/mysql-test/suite/rpl/t/rpl_read_new_relay_log_info.test new file mode 100644 index 00000000..350071bf --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_read_new_relay_log_info.test @@ -0,0 +1,48 @@ +# ==== Purpose ==== +# +# - Verify that the post-WL#344 format of relay_log.info can be parsed. + +--source include/master-slave.inc + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1); +DROP TABLE t1; +--sync_slave_with_master + +--echo ==== Check that we can understand the new format of relay-log.info ==== +--source include/stop_slave.inc + +--let $master_use_gtid_option= No +--source include/reset_slave.inc +--let $MYSQLD_DATADIR= `select @@datadir` + +# the new version of relay_log.info comes in two versions: with path +# separator '/' (most systems) and with path separator '\' (windows) +if ($SYSTEM_PATH_SEPARATOR != /) { + --let $file_suffix= -win +} + +# MDEV-19801 changed the default Using_Gtid to Slave_Pos which doesn't +# automatically purge relay-log.info +--remove_file $MYSQLD_DATADIR/relay-log.info +--copy_file $MYSQL_TEST_DIR/std_data/new-format-relay-log$file_suffix.info $MYSQLD_DATADIR/relay-log.info + +--echo # Read relay-log.info +START SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_start.inc +--echo # Check that relay log coordinates are equal to those saved in new-format_relay-log.info +--let $master_file= query_get_value(SHOW SLAVE STATUS, Relay_Master_Log_File, 1) +--let $master_pos= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1) +--let $relay_log_file= query_get_value(SHOW SLAVE STATUS, Relay_Log_File, 1) +--let $relay_log_pos= query_get_value(SHOW SLAVE STATUS, Relay_Log_Pos, 1) +--echo $master_file= $master_file, $master_pos, $relay_log_file, $relay_log_pos +if (`SELECT "$master_file" != "" OR + "$master_pos" != "0" OR + "$relay_log_file" != "slave-relay-bin.000001" OR + "$relay_log_pos" != "4"`) { + --echo ERROR: log coordinates changed + --die log coordinates changed +} + +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_read_old_relay_log_info.test b/mysql-test/suite/rpl/t/rpl_read_old_relay_log_info.test new file mode 100644 index 00000000..d2206b5b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_read_old_relay_log_info.test @@ -0,0 +1,48 @@ +# ==== Purpose ==== +# +# - Verify that the pre-WL#344 format of relay_log.info can still be +# parsed. + +--source include/master-slave.inc + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1); +DROP TABLE t1; +--sync_slave_with_master + +--echo ==== Check that we still understand the old format of relay-log.info ==== +--source include/stop_slave.inc + +--let $master_use_gtid_option= No +--source include/reset_slave.inc +--let $MYSQLD_DATADIR= `select @@datadir` + +# the old version of relay_log.info comes in two versions: with path +# separator '/' (most systems) and with path separator '\' (windows) +if ($SYSTEM_PATH_SEPARATOR != /) { + --let $file_suffix= -win +} +# MDEV-19801 changed the default Using_Gtid to Slave_Pos which doesn't +# automatically purge relay-log.info +--remove_file $MYSQLD_DATADIR/relay-log.info +--copy_file $MYSQL_TEST_DIR/std_data/old-format-relay-log$file_suffix.info $MYSQLD_DATADIR/relay-log.info + +--echo # Read relay-log.info +START SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_start.inc +--echo # Check that relay log coordinates are equal to those we saved in old-format_relay-log.info +--let $master_file= query_get_value(SHOW SLAVE STATUS, Relay_Master_Log_File, 1) +--let $master_pos= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1) +--let $relay_log_file= query_get_value(SHOW SLAVE STATUS, Relay_Log_File, 1) +--let $relay_log_pos= query_get_value(SHOW SLAVE STATUS, Relay_Log_Pos, 1) +--echo $master_file= $master_file, $master_pos, $relay_log_file, $relay_log_pos +if (`SELECT "$master_file" != "" OR + "$master_pos" != "0" OR + "$relay_log_file" != "slave-relay-bin.000001" OR + "$relay_log_pos" != "4"`) { + --echo ERROR: log coordinates changed + --die log coordinates changed +} + +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_read_only.test b/mysql-test/suite/rpl/t/rpl_read_only.test new file mode 100644 index 00000000..62a8fa61 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_read_only.test @@ -0,0 +1,157 @@ +# Test case for BUG #11733 +-- source include/have_innodb.inc +-- source include/master-slave.inc + +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); + +# Create a test and replicate it to slave +connection master; +create user test; +grant all on test.* to test; +sync_slave_with_master; + +# Setting the master readonly : +# - the variable @@readonly is not replicated on the slave + +connect (master2,127.0.0.1,test,,test,$MASTER_MYPORT,); +connect (slave2,127.0.0.1,test,,test,$SLAVE_MYPORT,); + +connection master1; + +create table t1(a int) engine=InnoDB; +create table t2(a int) engine=MyISAM; +insert into t1 values(1001); +insert into t2 values(2001); + +connection master; +set global read_only=1; + +connection master1; +select @@read_only; +select * from t1; +select * from t2; + +sync_slave_with_master; +select @@read_only; +select * from t1; +select * from t2; + +# - replication of transactions +connection master; +set global read_only=0; + +connection master1; +BEGIN; + +connection master2; +BEGIN; + +connection master; +select @@read_only; +set global read_only=1; + +connection master1; +-- echo *** On SUPER USER connection *** +insert into t1 values(1002); +--disable_warnings +insert into t2 values(2002); +--enable_warnings + +connection master2; +-- echo *** On regular USER connection *** +--error ER_OPTION_PREVENTS_STATEMENT +insert into t1 values(1003); +--error ER_OPTION_PREVENTS_STATEMENT +insert into t2 values(2003); + +connection master1; +## works even with read_only=1, because master1 is root +-- echo *** SUPER USER COMMIT (must succeed) *** +COMMIT; + +connection master2; +-- echo *** regular USER COMMIT (must succeed - nothing to commit) *** +COMMIT; + +connection master; +select @@read_only; +set global read_only=0; + +connection master1; +insert into t1 values(1004); +insert into t2 values(2004); + +select * from t1; +select * from t2; + +sync_slave_with_master; +select * from t1; +select * from t2; + +# Setting the slave readonly : replication will pass +# +connection slave1; +set global read_only=1; + +connection slave; +select @@read_only; +# Make sure the replicated table is also transactional +show create table t1; +# Make sure the replicated table is not transactional +show create table t2; + +connection master; +insert into t1 values(1005); +insert into t2 values(2005); +select * from t1; +select * from t2; + +sync_slave_with_master; +connection slave; +select * from t1; +select * from t2; + +# Non root user can not write on the slave +connection slave2; +--error ER_OPTION_PREVENTS_STATEMENT +insert into t1 values(1006); +--error ER_OPTION_PREVENTS_STATEMENT +insert into t2 values(2006); + + +--echo # +--echo # MDEV-30978: On slave XA COMMIT/XA ROLLBACK fail to return an error in read-only mode +--echo # +--echo # Where a read-only server permits writes through replication, it +--echo # should not permit user connections to commit/rollback XA transactions +--echo # prepared via replication. This test ensure this behavior is prohibited +--echo # + +# Note: slave's read_only=1 is set prior to this test case + +connection master; +xa start '1'; +insert into t1 values (1007); +xa end '1'; +xa prepare '1'; +sync_slave_with_master; + +connection slave2; +--error ER_OPTION_PREVENTS_STATEMENT +xa commit '1'; +--error ER_OPTION_PREVENTS_STATEMENT +xa rollback '1'; + +connection master; +xa rollback '1'; + +## Cleanup +connection master; +drop user test; +drop table t1; +drop table t2; +sync_slave_with_master; +set global read_only=0; + + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_read_only2.test b/mysql-test/suite/rpl/t/rpl_read_only2.test new file mode 100644 index 00000000..da825c8f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_read_only2.test @@ -0,0 +1,30 @@ +--source include/have_binlog_format_statement.inc +--source include/master-slave.inc + +--echo # +--echo # Ensure that read-only slave logs temporary table statements under statement based +--echo # replication. This is related to MDEV-17863. +--echo # + +connection slave; +set global read_only=1; + +connection master; + +create table t1(a int) engine=MyISAM; +create temporary table tmp1 (a int) engine=MyISAM; +insert into t1 values(1); +insert into tmp1 values (2); +insert into t1 select * from tmp1; +insert into t1 values(3); +select * from t1; +analyze table t1; +drop table t1; +drop temporary table tmp1; + +sync_slave_with_master; +--source include/show_binlog_events.inc +set global read_only=0; +connection master; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_relay_max_extension.test b/mysql-test/suite/rpl/t/rpl_relay_max_extension.test new file mode 100644 index 00000000..acca2f69 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_relay_max_extension.test @@ -0,0 +1,111 @@ +# ==== Purpose ==== +# +# Test verifies that auto purging mechanism of relay logs works fine when the +# file extension grows beyond 999999. +# +# ==== Implementation ==== +# +# Steps: +# 0 - In master-slave setup clear all the relay logs on the slave server. +# 1 - Start the slave so that new relay logs starting from +# 'slave-relay-bin.000001' are created. +# 2 - Get the active relay-log file name by using SHOW SLAVE STATUS. +# Shutdown the slave server. +# 3 - Rename active relay log to '999997' in both 'relay-log.info' and +# 'slave-relay-bin.index' files. +# 4 - Restart the slave server by configuring 'slave_parallel_threads=1' +# and 'max_relay_log_size=100K'. +# 5 - Generate load on master such that few relay logs are generated on +# slave. The relay log sequence number will change to 7 digits. +# 6 - Sync slave with master to ensure that relay logs are applied on +# slave. They should have been automatically purged. +# 7 - Assert that there is no 'slave-relay-bin.999999' file in +# 'relay-log.info'. +# +# ==== References ==== +# +# MDEV-8134: The relay-log is not flushed after the slave-relay-log.999999 +# showed +# + +# MDEV-27721 rpl.rpl_relay_max_extension test is not FreeBSD-compatible +--source include/linux.inc +--source include/have_innodb.inc +--source include/have_binlog_format_row.inc +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +--connection server_2 +--source include/stop_slave.inc +RESET SLAVE; +--source include/start_slave.inc +--source include/stop_slave.inc +--let $relay_log=query_get_value(SHOW SLAVE STATUS, Relay_Log_File, 1) + +--echo # +--echo # Stop slave server +--echo # + +--let $datadir = `select @@datadir` +--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +--shutdown_server 10 +--source include/wait_until_disconnected.inc + +--exec sed -i "s/$relay_log/slave-relay-bin.999997/g" $datadir/relay-log.info +--exec sed -i "s/$relay_log/slave-relay-bin.999997/g" $datadir/slave-relay-bin.index + +--echo # +--echo # Simulate file number get close to 999997 +--echo # by renaming relay logs and modifying index/info files + +--move_file $datadir/$relay_log $datadir/slave-relay-bin.999997 + +--echo # +--echo # Restart slave server +--echo # + +--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +--enable_reconnect +--source include/wait_until_connected_again.inc +SET @save_slave_parallel_threads= @@GLOBAL.slave_parallel_threads; +SET @save_max_relay_log_size= @@GLOBAL.max_relay_log_size; + +SET GLOBAL slave_parallel_threads=1; +SET GLOBAL max_relay_log_size=100 * 1024; +--source include/start_slave.inc + +--connection server_1 +create table t1 (i int, c varchar(1024)); +--echo # +--echo # Insert some data to generate enough amount of binary logs +--echo # +--let $count = 1000 +--disable_query_log +while ($count) +{ + eval insert into t1 values (1001 - $count, repeat('a',1000)); + dec $count; +} +--enable_query_log +--save_master_pos + +--connection server_2 +--sync_with_master + +--let $relay_log=query_get_value(SHOW SLAVE STATUS, Relay_Log_File, 1) + +--echo # +--echo # Assert that 'slave-relay-bin.999999' is purged. +--echo # +let SEARCH_FILE=$datadir/slave-relay-bin.index; +let SEARCH_PATTERN=slave-relay-bin.999999; +source include/search_pattern_in_file.inc; + +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads= @save_slave_parallel_threads; +SET GLOBAL max_relay_log_size= @save_max_relay_log_size; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t1; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_relay_space_innodb.test b/mysql-test/suite/rpl/t/rpl_relay_space_innodb.test new file mode 100644 index 00000000..ccb1424a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_relay_space_innodb.test @@ -0,0 +1,3 @@ +-- source include/have_innodb.inc +let $engine_type=InnoDB; +-- source include/rpl_sv_relay_space.test diff --git a/mysql-test/suite/rpl/t/rpl_relay_space_myisam.test b/mysql-test/suite/rpl/t/rpl_relay_space_myisam.test new file mode 100644 index 00000000..6aa91dbc --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_relay_space_myisam.test @@ -0,0 +1,2 @@ +let $engine_type=MyISAM; +-- source include/rpl_sv_relay_space.test diff --git a/mysql-test/suite/rpl/t/rpl_relayrotate-slave.opt b/mysql-test/suite/rpl/t/rpl_relayrotate-slave.opt new file mode 100644 index 00000000..5cdfe28d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_relayrotate-slave.opt @@ -0,0 +1,2 @@ +--max_relay_log_size=16384 +--log-warnings diff --git a/mysql-test/suite/rpl/t/rpl_relayrotate.test b/mysql-test/suite/rpl/t/rpl_relayrotate.test new file mode 100644 index 00000000..4de554d3 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_relayrotate.test @@ -0,0 +1,18 @@ +# +# This include file is used by more than one test suite +# (currently rpl and binlog_encryption). +# Please check all dependent tests after modifying it +# + +####################################################### +# Wrapper for rpl_relayrotate.test to allow multi # +# Engines to reuse test code. By JBM 2006-02-15 # +####################################################### +-- source include/have_innodb.inc +# Slow test, don't run during staging part +-- source include/not_staging.inc +-- source include/master-slave.inc + +let $engine_type=innodb; +-- source suite/rpl/include/rpl_relayrotate.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_relayspace-slave.opt b/mysql-test/suite/rpl/t/rpl_relayspace-slave.opt new file mode 100644 index 00000000..06d96aa3 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_relayspace-slave.opt @@ -0,0 +1 @@ +--relay_log_space_limit=10 diff --git a/mysql-test/suite/rpl/t/rpl_relayspace.test b/mysql-test/suite/rpl/t/rpl_relayspace.test new file mode 100644 index 00000000..fc33d6bc --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_relayspace.test @@ -0,0 +1,52 @@ +# The slave is started with relay_log_space_limit=10 bytes, +# to force the deadlock after one event. + +source include/master-slave.inc; +--let $master_log_file= query_get_value(SHOW MASTER STATUS, File, 1) +connection slave; +--source include/stop_slave.inc +connection master; +# This will generate a master's binlog > 10 bytes +create table t1 (a int); +drop table t1; +create table t1 (a int); +drop table t1; +connection slave; +reset slave; +start slave io_thread; +# Give the I/O thread time to block. +let $slave_param= Slave_IO_State; +let $slave_param_value= Waiting for the slave SQL thread to free enough relay log space; +source include/wait_for_slave_param.inc; + +# A bug caused the I/O thread to refuse stopping. +--source include/stop_slave_io.inc +reset slave; +--source include/start_slave.inc + +# The I/O thread stops filling the relay log when it's >10b. And the +# SQL thread cannot purge this relay log as purge is done only when +# the SQL thread switches to another relay log, which does not exist +# here. So we should have a deadlock. If it is not resolved +# automatically we'll detect it with master_pos_wait that waits for +# farther than 1Ob; it will timeout after 300 seconds (which is inline +# with the default used for sync_slave_with_master and will protect us +# against slow test envs); also the slave will probably not cooperate +# to shutdown (as 2 threads are locked) +--let $outcome= `SELECT MASTER_POS_WAIT('$master_log_file',200,300) AS mpw;` + +# master_pos_wait returns: +# +# * >= 0, the number of events the slave had to wait to advance to the +# position +# +# * -1, if there was a timeout +# +# * NULL, if an error occurred, or the SQL thread was not started, +# slave master info is not initialized, the arguments are incorrect +--let $assert_text= Assert that master_pos_wait does not timeout nor it returns NULL +--let $assert_cond= $outcome IS NOT NULL AND $outcome <> -1 +--source include/assert.inc + +# End of 4.1 tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_reopen_temp_table.test b/mysql-test/suite/rpl/t/rpl_reopen_temp_table.test new file mode 100644 index 00000000..2396dc34 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_reopen_temp_table.test @@ -0,0 +1,43 @@ +--source include/have_innodb.inc +--source include/master-slave.inc + +# Clean up old slave's binlogs (see rpl_temporary.test for explanation). +save_master_pos; +connection slave; +sync_with_master; +reset master; + +--echo # +--echo # MDEV-5535: Cannot reopen temporary table +--echo # + +connection master; +--disable_query_log +CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); +--enable_query_log + +disable_warnings; +DROP TABLE IF EXISTS t1, t2, t3; +enable_warnings; + +CREATE TEMPORARY TABLE t1(c1 INT) ENGINE=INNODB; +INSERT INTO t1 VALUES (1), (2), (3), (4), (5); + +CREATE TEMPORARY TABLE t2 SELECT A.c1 a, B.c1 b FROM t1 AS A, t1 AS B; + +CREATE TABLE t3 SELECT * FROM t2; + +SELECT COUNT(*) = 5 FROM t1; +SELECT COUNT(*) = 25 FROM t2; +SELECT COUNT(*) = 25 FROM t3; + +sync_slave_with_master; + +SELECT COUNT(*) = 25 FROM t3; + +connection master; +DROP TABLE t1, t2, t3; + +sync_slave_with_master; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_replicate_do-slave.opt b/mysql-test/suite/rpl/t/rpl_replicate_do-slave.opt new file mode 100644 index 00000000..da345474 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_replicate_do-slave.opt @@ -0,0 +1 @@ +--replicate-do-table=test.t1 diff --git a/mysql-test/suite/rpl/t/rpl_replicate_do.test b/mysql-test/suite/rpl/t/rpl_replicate_do.test new file mode 100644 index 00000000..66ddf2df --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_replicate_do.test @@ -0,0 +1,65 @@ +# This test assumes we are ignoring updates on table t2, but doing +# updates on t1 +source include/master-slave.inc; +--disable_warnings +drop table if exists t11; +connection slave; +drop table if exists t11; +--enable_warnings + +create table t2 (n int); +insert into t2 values(4); +connection master; +create table t2 (s char(20)); +load data infile '../../std_data/words.dat' into table t2; +insert into t2 values('five'); +create table t1 (m int); +insert into t1 values(15),(16),(17); +update t1 set m=20 where m=16; +delete from t1 where m=17; +create table t11 select * from t1; +sync_slave_with_master; +select * from t1 ORDER BY m; +select * from t2; +--error 1146 +select * from t11; +connection master; +drop table if exists t1,t2,t11; +sync_slave_with_master; +# show slave status, just to see of it prints replicate-do-table +let $status_items= Replicate_Do_Table; +source include/show_slave_status.inc; + +# End of 4.1 tests + +# +# Bug#24478 DROP TRIGGER is not caught by replicate-*-table filters +# +connection master; +create table t1 (a int, b int); +create trigger trg1 before insert on t1 for each row set new.b=2; +create table t2 (a int, b int); +create trigger trg2 before insert on t2 for each row set new.b=2; +show tables; +--replace_column 6 # +show triggers; +sync_slave_with_master; +connection slave; +show tables; +--replace_column 6 # +show triggers; +connection master; +drop trigger trg1; +drop trigger trg2; +--replace_column 6 # +show triggers; +sync_slave_with_master; +connection slave; +show tables; +--replace_column 6 # +show triggers; +connection master; +drop table t1; +drop table t2; +sync_slave_with_master; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_replicate_ignore_db-slave.opt b/mysql-test/suite/rpl/t/rpl_replicate_ignore_db-slave.opt new file mode 100644 index 00000000..6e3aed44 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_replicate_ignore_db-slave.opt @@ -0,0 +1 @@ +--replicate_ignore_db=mysqltest1 diff --git a/mysql-test/suite/rpl/t/rpl_replicate_ignore_db.test b/mysql-test/suite/rpl/t/rpl_replicate_ignore_db.test new file mode 100644 index 00000000..f1907456 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_replicate_ignore_db.test @@ -0,0 +1,31 @@ +# see if --replicate-ignore-db works + +--source include/master-slave.inc + +--disable_warnings +drop database if exists mysqltest1; +drop database if exists mysqltest2; +--enable_warnings +create database mysqltest1; +create database mysqltest2; + +use mysqltest1; +create table t1 (a int); +insert into t1 values(1); +sync_slave_with_master; +--error 1146 +select * from mysqltest1.t1; + +connection master; +use mysqltest2; +create table t1 (a int); +insert into t1 values(1); +sync_slave_with_master; +select * from mysqltest2.t1; + +# cleanup +connection master; +drop database mysqltest1; +drop database mysqltest2; +sync_slave_with_master; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_report-slave.opt b/mysql-test/suite/rpl/t/rpl_report-slave.opt new file mode 100644 index 00000000..123e5c27 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_report-slave.opt @@ -0,0 +1,2 @@ +--report-host=127.0.0.1 --report-user='my_user' --report-password='my_password' --report-port=9308 + diff --git a/mysql-test/suite/rpl/t/rpl_report.test b/mysql-test/suite/rpl/t/rpl_report.test new file mode 100644 index 00000000..a7344291 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_report.test @@ -0,0 +1,22 @@ +# Verify that mysqld init time --report-{host,port,user,password} parameters +# are SHOW-able and SELECT-able FROM INFORMATION_SCHEMA.global_variables + +source include/master-slave.inc; + +connection slave; +select * from Information_schema.GLOBAL_VARIABLES where variable_name like 'report_host'; +select * from Information_schema.GLOBAL_VARIABLES where variable_name like 'report_port'; +select * from Information_schema.GLOBAL_VARIABLES where variable_name like 'report_user'; +select * from Information_schema.GLOBAL_VARIABLES where variable_name like 'report_password'; +query_vertical show global variables like 'report_host'; +query_vertical show global variables like 'report_port'; +query_vertical show global variables like 'report_user'; +query_vertical show global variables like 'report_password'; + +# to demonstrate that report global variables are read-only +error ER_INCORRECT_GLOBAL_LOCAL_VAR; +set @@global.report_host='my.new.address.net'; + + +--echo end of tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_report_port.test b/mysql-test/suite/rpl/t/rpl_report_port.test new file mode 100644 index 00000000..2a14d278 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_report_port.test @@ -0,0 +1,74 @@ +# +#BUG#13333431 : INCORRECT DEFAULT PORT IN 'SHOW SLAVE HOSTS' OUTPUT +# +# ==== Purpose ==== +# +# The test show the default value printed for the slave's port number if the +# --report-port= <some value> is not set on the slave. This is different from +# the present scenario which show 3306 as the default value if the report-port +# is not set on the slave. +# +#====Method==== +# +# Start replication with report port set to 9000 and restart the slave. +# In this case on doing SHOW SLAVE HOSTS on the master, we get the port number +# of the slave to be 9000. +# In the second case restart the slave server with report port not set. In this +# case on doing SHOW SLAVE HOSTS on the master, we get the actual port number +# of the slave (ie. SLAVE_PORT). + +source include/have_binlog_format_mixed.inc; +source include/master-slave.inc; + +connection master; + +# Start the server with some value being passed to the report_port= <option> +# this will be used incase we have to mask the value of the slave's port +# number in certain situations. + +--let $rpl_server_number= 2 +--let $rpl_server_parameters= --report-port=9000 +--source include/rpl_restart_server.inc + +connection slave; +--source include/start_slave.inc +--let $slave_param= Slave_IO_State +--let $slave_param_value= Waiting for master to send event +--source include/wait_for_slave_param.inc + +--echo [Slave restarted with the report-port set to some value] +connection master; + +# 9000 is the value of the port we should get. +--let $report_port= query_get_value(SHOW SLAVE HOSTS, Port, 1) +--let assert_text= The value shown for the slave's port number is user specified port number which is the value set for report-port. +--let assert_cond= $report_port = "9000" +--source include/assert.inc + +# Start the server with the report-port being passed with no value. So on SHOW SLAVE HOSTS +# on the master the value of slave's port should be the actual value of the slave port. +connection master; + +--let $rpl_server_number= 2 +--let $rpl_server_parameters= +--source include/rpl_restart_server.inc + +connection slave; +--source include/start_slave.inc +--let $slave_param= Slave_IO_State +--let $slave_param_value= Waiting for master to send event +--source include/wait_for_slave_param.inc + +connection master; +sync_slave_with_master; +--echo [Slave restarted with the report-port set to the value of slave's port number] + +connection master; + +# The value reported is the actual value of the slave's port. +--let $report_port= query_get_value(SHOW SLAVE HOSTS, Port, 1) +--let assert_text= The default value shown for the slave's port number is the actual port number of the slave. +--let assert_cond= $report_port = "$SLAVE_MYPORT" +--source include/assert.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_reset_slave_all_clears_filters.test b/mysql-test/suite/rpl/t/rpl_reset_slave_all_clears_filters.test new file mode 100644 index 00000000..7c01ce16 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_reset_slave_all_clears_filters.test @@ -0,0 +1,72 @@ +# +# Purpose: +# This test validates that after issuing the `SLAVE RESET ALL` command, +# any corresponding IGNORE_DOMAIN_IDS/DO_DOMAIN_IDS and IGNORE_SERVER_IDS +# values are cleared. +# +# +# Methodology: +# To ensure the filtering variables are properly cleared after issuing +# SLAVE RESET ALL, we categorize different combinations of allowable input +# into three different options, and ensure that the variables are cleared for +# each category. The categories are as follows: +# Category 1) DO_DOMAIN_IDS and IGNORE_SERVER_IDS specified together +# Category 2) IGNORE_DOMAIN_IDS and IGNORE_SERVER_IDS specified together +# Category 3) Null check - edge case with all empty lists to ensure a lack +# of specification doesn't break anything +# +# To specify the values, the variables are set in `CHANGE MASTER TO`. To +# ensure the slave state is correct, we test the domain/server id filtering +# variable values at the following times while testing each category. +# +# Before CHANGE MASTER TO the filtering variables are tested to all be +# empty. +# +# After CHANGE MASTER TO the variables are tested to ensure they reflect +# those set in the CHANGE MASTER command. +# +# After RESET SLAVE ALL the filtering variables are tested to all be +# empty. +# + +--source include/master-slave.inc +--source include/have_debug.inc + +--connection slave +--source include/stop_slave.inc + +--echo # +--echo # Category 1) DO_DOMAIN_IDS and IGNORE_SERVER_IDS specified together +--echo # +--let $_do_domain_ids= (1) +--let $_ignore_domain_ids= () +--let $_ignore_server_ids= (3) +--source include/rpl_reset_slave_all_check.inc + +--echo # +--echo # Category 2) IGNORE_DOMAIN_IDS and IGNORE_SERVER_IDS specified together +--echo # +--let $_do_domain_ids= () +--let $_ignore_domain_ids= (2) +--let $_ignore_server_ids= (3) +--source include/rpl_reset_slave_all_check.inc + +--echo # +--echo # Category 3) Null check - edge case with all empty lists to ensure a +--echo # lack of specification doesn't break anything +--echo # +--let $_do_domain_ids= () +--let $_ignore_domain_ids= () +--let $_ignore_server_ids= () +--source include/rpl_reset_slave_all_check.inc + + +--echo ############################ +--echo # Cleanup +--echo ############################ +--connection slave +--replace_result $MASTER_MYPORT MASTER_MYPORT +eval change master to master_port=$MASTER_MYPORT, master_host='127.0.0.1', master_user='root'; +--source include/start_slave.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_reset_slave_fail.test b/mysql-test/suite/rpl/t/rpl_reset_slave_fail.test new file mode 100644 index 00000000..5c7e6676 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_reset_slave_fail.test @@ -0,0 +1,91 @@ +############################################################################### +# Bug#24901077: RESET SLAVE ALL DOES NOT ALWAYS RESET SLAVE +# +# Problem: +# ======= +# If you have a relay log index file that has ended up with +# some relay log files that do not exists, then RESET SLAVE +# ALL is not enough to get back to a clean state. +############################################################################### +# Remove all slave-relay-bin.0* files (do not remove slave-relay-bin.index) +# During server restart rli initialization will fail as there are no +# relay logs. In case of bug RESET SLAVE will not do the required clean up +# as rli is not inited and subsequent START SLAVE will fail. +# Disable "Warning 1612 Being purged log ./slave-relay-bin.0* was not found" +# because it is different on Unix and Windows systems. + +--source include/have_binlog_format_mixed.inc +--source include/master-slave.inc + +--connection master +CREATE TABLE t1 (c1 INT); +INSERT INTO t1 (c1) VALUES (1); +--sync_slave_with_master + +--connection slave +--source include/stop_slave_sql.inc +--let $MYSQLD_SLAVE_DATADIR= `select @@datadir` + +--connection master +# Generate more relay logs on slave. +FLUSH LOGS; +FLUSH LOGS; +INSERT INTO t1 (c1) VALUES (2); + +--source include/sync_slave_io_with_master.inc +call mtr.add_suppression("File '.*slave-relay-bin."); +call mtr.add_suppression("Could not open log file"); +call mtr.add_suppression("Failed to open the relay log"); +call mtr.add_suppression("Failed to initialize the master info structure"); + +# Stop slave +--let $rpl_server_number= 2 +--source include/rpl_stop_server.inc + +# Delete file(s) +--echo # Removing $remove_pattern file(s) +--let $remove_pattern= slave-relay-bin.0* +--remove_files_wildcard $MYSQLD_SLAVE_DATADIR $remove_pattern + +# Start slave +--let $rpl_server_number= 2 +--source include/rpl_start_server.inc + +# Start slave must fail because of the removed file(s). +--error ER_MASTER_INFO +START SLAVE; + +# Try a second time, it must fail again. +--error ER_MASTER_INFO +START SLAVE; + +# Retrieve master executed position before reset slave. +--let $master_exec_file= query_get_value("SHOW SLAVE STATUS", Relay_Master_Log_File, 1) +--let $master_exec_pos= query_get_value("SHOW SLAVE STATUS", Exec_Master_Log_Pos, 1) + +# Reset slave. +# Disable "Warning 1612 Being purged log ./slave-relay-bin.0* was not found" +# because it is different on Unix and Windows systems. +--disable_warnings +--source include/reset_slave.inc +--enable_warnings +DROP TABLE t1; +--replace_result $master_exec_file MASTER_LOG_FILE $master_exec_pos MASTER_LOG_POS +--eval START SLAVE UNTIL MASTER_LOG_FILE= '$master_exec_file', MASTER_LOG_POS= $master_exec_pos; +--source include/wait_for_slave_sql_to_stop.inc +--source include/stop_slave_io.inc + +# Start slave. +--source include/start_slave.inc + +--connection master +--sync_slave_with_master +# Check consistency. +--let $diff_tables= master:t1, slave:t1 +--source include/diff_tables.inc + +# Cleanup +--connection master +DROP TABLE t1; +--sync_slave_with_master +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_rewrite_db_sys_vars-slave.opt b/mysql-test/suite/rpl/t/rpl_rewrite_db_sys_vars-slave.opt new file mode 100644 index 00000000..5a8f8233 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_rewrite_db_sys_vars-slave.opt @@ -0,0 +1,2 @@ +"--replicate-rewrite-db=primary_db1->replica_db1" +"--replicate-rewrite-db=x->y" diff --git a/mysql-test/suite/rpl/t/rpl_rewrite_db_sys_vars.test b/mysql-test/suite/rpl/t/rpl_rewrite_db_sys_vars.test new file mode 100644 index 00000000..b06899bb --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_rewrite_db_sys_vars.test @@ -0,0 +1,163 @@ +-- source include/have_binlog_format_mixed.inc +-- source include/master-slave.inc + +# Testing rpl option replicate_rewrite_db + +--echo # +--echo # MDEV-15530 Variable replicate_rewrite_db cannot be found +--echo # in "show global variables" +--echo # + +--echo # Create DBs and verify that slave has to be stopped before setting sys var + +connection slave; +--let $rpl_server_id= `select @@session.server_id` +select @@session.server_id; + +# These DBs will be rewrited from opt file +create database replica_db1; +create database y; +# This DB will be rewrited from test case +create database test_replica; +SELECT @@GLOBAL.replicate_rewrite_db; +let $rewrite_db_sss= query_get_value(SHOW SLAVE STATUS, Replicate_Rewrite_DB, 1); +--echo # Ensuring SHOW SLAVE STATUS produces correct value for Replicate_Rewrite_DB... +if (`SELECT strcmp(@@global.replicate_rewrite_db, "$rewrite_db_sss") != 0`) +{ + die SHOW SLAVE STATUS Replicate_Rewrite_DB value $rewrite_db_sss does not match variable @@GLOBAL.replicate_rewrite_db; +} +--echo # ...success + + +--echo # Create DBs and tables on primary +connection master; +--enable_warnings +create database primary_db1; +create database x; +use primary_db1; +create table my_table (t int); +insert into my_table values (2),(4); +use x; +create table my_table (t int); +insert into my_table values (654),(532); +--source include/save_master_gtid.inc + +--echo # Check replica +--connection slave +--source include/sync_with_master_gtid.inc +--let $diff_tables=master:primary_db1.my_table,slave:replica_db1.my_table +--source include/diff_tables.inc +--let $diff_tables=master:x.my_table,slave:y.my_table +--source include/diff_tables.inc +SELECT @@GLOBAL.replicate_rewrite_db; +show tables from replica_db1; +select * from replica_db1.my_table; +show tables from y; +select * from y.my_table; + +--echo # Set replica sys var replicate_rewrite_db +connection slave; +--error ER_SLAVE_MUST_STOP +SET @@GLOBAL.replicate_rewrite_db="test_master->test_replica"; +source include/stop_slave.inc; +SET @save_replicate_rewrite_db = @@GLOBAL.replicate_rewrite_db; +SELECT @@GLOBAL.replicate_rewrite_db; +SET @@GLOBAL.replicate_rewrite_db="test_master->test_replica"; +SELECT @@GLOBAL.replicate_rewrite_db; +SHOW DATABASES like 'test_replica'; +source include/start_slave.inc; +let $rewrite_db_sss= query_get_value(SHOW SLAVE STATUS, Replicate_Rewrite_DB, 1); +--echo # Ensuring SHOW SLAVE STATUS produces correct value for Replicate_Rewrite_DB... +if (`SELECT strcmp(@@global.replicate_rewrite_db, "$rewrite_db_sss") != 0`) +{ + die SHOW SLAVE STATUS Replicate_Rewrite_DB value $rewrite_db_sss does not match variable @@GLOBAL.replicate_rewrite_db; +} +--echo # ...success + +--echo # Create DB and tables on primary +connection master; +--enable_warnings +create database test_master; +use test_master; +create table my_table (t int); +insert into my_table values (1),(3); +--source include/save_master_gtid.inc + +--echo # Ensure that the replica receives all of the primary's events without +--echo # error +--connection slave +--source include/sync_with_master_gtid.inc +let $error= query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1); +--echo Last_SQL_Error = $error +let $errno= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1); +--echo Last_SQL_Errno = $errno + +SELECT @@GLOBAL.replicate_rewrite_db; +SHOW tables from test_replica; +select * from test_replica.my_table; + +# Additional check for tables +--let $diff_tables=master:test_master.my_table,slave:test_replica.my_table +--source include/diff_tables.inc + +--echo # Update of values on primary for DB not set in replication_rewrite_db +connection master; +use x; +insert into my_table values (314); +select * from my_table; +--source include/save_master_gtid.inc + +connection slave; +--source include/stop_slave.inc +--source include/reset_slave.inc +--source include/start_slave.inc +SELECT @@GLOBAL.replicate_rewrite_db; +--source include/sync_with_master_gtid.inc +# This shouldn't get the new values from x DB on master +select * from y.my_table; + +--echo # Dynamic updates to the replication filter should be lost after server restart +# Old value +connection slave; +SELECT @@GLOBAL.replicate_rewrite_db; + +connection master; +use x; +insert into my_table values (1000); +select * from my_table; +--source include/save_master_gtid.inc + +connection slave; +--source include/stop_slave.inc +--source include/reset_slave.inc +--let $rpl_server_number= 2 +--source include/rpl_restart_server.inc +--replace_result $MASTER_MYPORT MASTER_MYPORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root'; + +# New value +connection slave; +--source include/start_slave.inc +SELECT @@GLOBAL.replicate_rewrite_db; +--source include/sync_with_master_gtid.inc +# This should update values with 314 and 1000 from primary +select * from y.my_table; + +--echo # Cleanup +connection master; +drop database test_master; +drop database primary_db1; +drop database x; +--source include/save_master_gtid.inc + + +--connection slave +--source include/sync_with_master_gtid.inc +drop database test_replica; +drop database replica_db1; +drop database y; +source include/stop_slave.inc; +source include/start_slave.inc; + +--source include/rpl_end.inc +# end of 10.11 tests diff --git a/mysql-test/suite/rpl/t/rpl_rewrt_db-slave.opt b/mysql-test/suite/rpl/t/rpl_rewrt_db-slave.opt new file mode 100644 index 00000000..cb165442 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_rewrt_db-slave.opt @@ -0,0 +1,6 @@ +"--replicate-rewrite-db=test->rewrite" +"--replicate-rewrite-db=mysqltest1 -> test" +"--replicate-rewrite-db=x -> y" +"--replicate-rewrite-db=database_master_temp_01->database_slave_temp_01" +"--replicate-rewrite-db=database_master_temp_02->database_slave_temp_02" +"--replicate-rewrite-db=database_master_temp_03->database_slave_temp_03" diff --git a/mysql-test/suite/rpl/t/rpl_rewrt_db.test b/mysql-test/suite/rpl/t/rpl_rewrt_db.test new file mode 100644 index 00000000..aa0370c8 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_rewrt_db.test @@ -0,0 +1,250 @@ +# TBF - difference in row level logging +-- source include/have_binlog_format_mixed_or_statement.inc +-- source include/master-slave.inc + +--connection slave +set sql_log_bin=0; +create database y; +set sql_log_bin=1; + +--connection master +--disable_warnings +drop database if exists mysqltest1; +drop database if exists x; +--enable_warnings +create database mysqltest1; +set sql_log_bin=0; +create database x; +set sql_log_bin=1; + +use mysqltest1; +create table t1 (a int); +insert into t1 values(9); +use x; +create table t1 (a int); +insert into t1 values(9); +select * from mysqltest1.t1; +select * from x.t1; +sync_slave_with_master; +#TODO no it is no empty +show databases like 'mysqltest1'; # should be empty +select * from test.t1; +select * from y.t1; +# cleanup +connection master; +use mysqltest1; +drop table t1; +drop database mysqltest1; +sync_slave_with_master; + +# +# BUG#6353: +# Option --replicate-rewrite-db should work together with LOAD DATA INFILE +# + +connection slave; +--disable_warnings +drop database if exists rewrite; +--enable_warnings +create database rewrite; + +connection master; +use test; +create table t1 (a date, b date, c date not null, d date); +load data infile '../../std_data/loaddata1.dat' ignore into table t1 fields terminated by ','; +load data infile '../../std_data/loaddata1.dat' into table t1 fields terminated by ',' IGNORE 2 LINES; +sync_slave_with_master; + +connection slave; +select * from rewrite.t1; + +connection master; +truncate table t1; +load data infile '../../std_data/loaddata1.dat' ignore into table t1 fields terminated by ',' LINES STARTING BY ',' (b,c,d); +sync_slave_with_master; + +connection slave; +select * from rewrite.t1; + +connection master; +drop table t1; +create table t1 (a text, b text); +load data infile '../../std_data/loaddata2.dat' into table t1 fields terminated by ',' enclosed by ''''; +sync_slave_with_master; + +connection slave; +select concat('|',a,'|'), concat('|',b,'|') from rewrite.t1; + +connection master; +drop table t1; +create table t1 (a int, b char(10)); +load data infile '../../std_data/loaddata3.dat' into table t1 fields terminated by '' enclosed by '' ignore 1 lines; +sync_slave_with_master; + +connection slave; +select * from rewrite.t1; + +connection master; +truncate table t1; +load data infile '../../std_data/loaddata4.dat' into table t1 fields terminated by '' enclosed by '' lines terminated by '' ignore 1 lines; +sync_slave_with_master; + +connection slave; +# The empty line last comes from the end line field in the file +select * from rewrite.t1; + +set sql_log_bin= 0; +drop database rewrite; +set sql_log_bin= 1; + +connection master; +set sql_log_bin= 0; +drop table t1; +set sql_log_bin= 1; + +# End of 4.1 tests + +--echo +--echo **** +--echo **** Bug #46861 Auto-closing of temporary tables broken by replicate-rewrite-db +--echo **** +--echo + +--echo **** +--echo **** Preparing the environment +--echo **** +connection master; + +connect (con_temp_03,127.0.0.1,root,,test,$MASTER_MYPORT,); +connect (con_temp_02,127.0.0.1,root,,test,$MASTER_MYPORT,); +connect (con_temp_01,127.0.0.1,root,,test,$MASTER_MYPORT,); + +connection master; +SET sql_log_bin= 0; +CREATE DATABASE database_master_temp_01; +CREATE DATABASE database_master_temp_02; +CREATE DATABASE database_master_temp_03; +SET sql_log_bin= 1; + +connection slave; +SET sql_log_bin= 0; +CREATE DATABASE database_slave_temp_01; +CREATE DATABASE database_slave_temp_02; +CREATE DATABASE database_slave_temp_03; +SET sql_log_bin= 1; + +--echo +--echo **** +--echo **** Creating temporary tables on different databases with different connections +--echo **** +--echo **** con_temp_01 --> creates +--echo **** t_01_01_temp on database_master_temp_01 +--echo **** +--echo **** con_temp_02 --> creates +--echo **** t_01_01_temp on database_master_temp_01 +--echo **** t_02_01_temp, t_02_02_temp on database_master_temp_02 +--echo **** +--echo **** con_temp_02 --> creates +--echo **** t_01_01_temp on database_master_temp_01 +--echo **** t_02_01_temp, t_02_02_temp on database_master_temp_02 +--echo **** t_03_01_temp, t_03_02_temp, t_03_03_temp on database_master_temp_03 +--echo **** + +connection con_temp_01; +USE database_master_temp_01; +CREATE TEMPORARY TABLE t_01_01_temp(a int); +INSERT INTO t_01_01_temp VALUES(1); + +connection con_temp_02; +USE database_master_temp_01; +CREATE TEMPORARY TABLE t_01_01_temp(a int); +INSERT INTO t_01_01_temp VALUES(1); +USE database_master_temp_02; +CREATE TEMPORARY TABLE t_02_01_temp(a int); +INSERT INTO t_02_01_temp VALUES(1); +CREATE TEMPORARY TABLE t_02_02_temp(a int); +INSERT INTO t_02_02_temp VALUES(1); + +connection con_temp_03; +USE database_master_temp_01; +CREATE TEMPORARY TABLE t_01_01_temp(a int); +INSERT INTO t_01_01_temp VALUES(1); +USE database_master_temp_02; +CREATE TEMPORARY TABLE t_02_01_temp(a int); +INSERT INTO t_02_01_temp VALUES(1); +CREATE TEMPORARY TABLE t_02_02_temp(a int); +INSERT INTO t_02_02_temp VALUES(1); +USE database_master_temp_03; +CREATE TEMPORARY TABLE t_03_01_temp(a int); +INSERT INTO t_03_01_temp VALUES(1); +CREATE TEMPORARY TABLE t_03_02_temp(a int); +INSERT INTO t_03_02_temp VALUES(1); +CREATE TEMPORARY TABLE t_03_03_temp(a int); +INSERT INTO t_03_03_temp VALUES(1); + +--echo +--echo **** Dropping the connections +--echo **** We want to SHOW BINLOG EVENTS, to know what was logged. But there is no +--echo **** guarantee that logging of the terminated con1 has been done yet.a To be +--echo **** sure that logging has been done, we use a user lock. +--echo +connection master; +sync_slave_with_master; +connection slave; +show status like 'Slave_open_temp_tables'; + +connection master; +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +connection con_temp_01; +select get_lock("con_01",10); +connection master; +disconnect con_temp_01; +select get_lock("con_01",10); + +connection con_temp_02; +select get_lock("con_02",10); +connection master; +disconnect con_temp_02; +select get_lock("con_02",10); + +connection con_temp_03; +select get_lock("con_03",10); +connection master; +disconnect con_temp_03; +select get_lock("con_03",10); + +--echo +--echo **** Checking the binary log and temporary tables +--echo +connection master; +sync_slave_with_master; +connection slave; +show status like 'Slave_open_temp_tables'; + +connection master; +--source include/show_binlog_events.inc + +--echo **** +--echo **** Cleaning up the test case +--echo **** +connection master; +SET sql_log_bin= 0; +DROP DATABASE database_master_temp_01; +DROP DATABASE database_master_temp_02; +DROP DATABASE database_master_temp_03; +DROP DATABASE x; +SET sql_log_bin= 1; + +connection slave; +SET sql_log_bin= 0; +DROP DATABASE database_slave_temp_01; +DROP DATABASE database_slave_temp_02; +DROP DATABASE database_slave_temp_03; +DROP DATABASE y; +SET sql_log_bin= 1; + +connection master; +sync_slave_with_master; + +# end of 5.0 tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_rotate_logs.cnf b/mysql-test/suite/rpl/t/rpl_rotate_logs.cnf new file mode 100644 index 00000000..7e676dc2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_rotate_logs.cnf @@ -0,0 +1,6 @@ +!include ../rpl_1slave_base.cnf + +[mysqld.1] +max_binlog_size=4096 + + diff --git a/mysql-test/suite/rpl/t/rpl_rotate_logs.test b/mysql-test/suite/rpl/t/rpl_rotate_logs.test new file mode 100644 index 00000000..4dd58931 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_rotate_logs.test @@ -0,0 +1,203 @@ +# This test uses chmod, can't be run with root permissions +-- source include/not_as_root.inc + +-- source include/have_log_bin.inc + +# +# Test is run with max_binlog_size=2048 to force automatic rotation of the +# binary log +# Tests done: +# - Check that slaves reports correct failures if master.info has strange +# modes/information +# - Automatic binary log rotation +# - Ensure that temporary tables works over flush logs and binary log +# changes +# - Test creating a duplicate key error and recover from it + +# Requires statement logging +-- source include/have_binlog_format_mixed_or_statement.inc + +connect (master,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK); +connect (slave,localhost,root,,test,$SLAVE_MYPORT,$SLAVE_MYSOCK); + +# Reset the GTID position explicitly (since we're not using rpl_init.inc). +SET GLOBAL gtid_slave_pos= ""; + +# Create empty file +let $MYSQLD_SLAVE_DATADIR= `select @@datadir`; +write_file $MYSQLD_SLAVE_DATADIR/master.info; +EOF +chmod 0000 $MYSQLD_SLAVE_DATADIR/master.info; +connection slave; + +CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT."); +# START SLAVE will fail because it can't read the file (mode 000) +# (system error 13) +--replace_result $MYSQL_TEST_DIR TESTDIR +--error 1105,1105,29 +start slave; +chmod 0600 $MYSQLD_SLAVE_DATADIR/master.info; +# It will fail again because the file is empty so the slave cannot get valuable +# info about how to connect to the master from it (failure in +# init_strvar_from_file() in init_master_info()). +--error 1201 +start slave; +--replace_result $MASTER_MYPORT MASTER_PORT + +# CHANGE MASTER will fail because it first parses master.info before changing +# it (so when master.info is bad, people have to use RESET SLAVE first). +--error 1201 +eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root'; +reset slave; +--replace_result $MASTER_MYPORT MASTER_PORT +eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root'; +connection master; +reset master; +connection slave; +start slave; +--source include/wait_for_slave_to_start.inc +connection master; + +# +# Test FLUSH LOGS +# +create temporary table temp_table (a char(80) not null); +insert into temp_table values ("testing temporary tables"); +create table t1 (s text); +insert into t1 values('Could not break slave'),('Tried hard'); +sync_slave_with_master; +let $status_items= Master_Log_File, Relay_Master_Log_File; +source include/show_slave_status.inc; +source include/check_slave_is_running.inc; +select * from t1; +connection master; +flush logs; +create table t2(m int not null auto_increment primary key); +insert into t2 values (34),(67),(123); +flush logs; +source include/show_binary_logs.inc; +create table t3 select * from temp_table; + +sync_slave_with_master; + +select * from t3; +connection master; +drop table temp_table, t3; + +# +# Now lets make some duplicate key mess and see if we can recover from it +# + +# First insert a value on the slave +connection slave; +insert into t2 values(1234); + +#same value on the master +connection master; +set insert_id=1234; +insert into t2 values(NULL); +connection slave; +# 1062 = ER_DUP_ENTRY +call mtr.add_suppression("Slave SQL.*Error .Duplicate entry .1234. for key .PRIMARY.. on query.* error.* 1062"); +--let $slave_sql_errno= 1062 +--source include/wait_for_slave_sql_error_and_skip.inc + +connection master; + +#let slave catch up +sync_slave_with_master; +connection master; +purge master logs to 'master-bin.000002'; +source include/show_master_logs.inc; +# we just tests if synonyms are accepted +purge binary logs to 'master-bin.000002'; +source include/show_binary_logs.inc; +--source include/wait_for_binlog_checkpoint.inc + +# Set the purge time 1 second after the last modify time of master-bin.000002. +perl; +open F, ">>".$ENV{'MYSQLTEST_VARDIR'}.'/tmp/rpl_rotate_logs.tmp' or die "Tmp file rpl_rotate_logs.tmp not found"; +my $binlogpath = $ENV{'MYSQLTEST_VARDIR'}.'/mysqld.1/data/master-bin.000002'; +my @array = stat($binlogpath); +my $filemodifytime = $array[9]; +my @t = localtime $filemodifytime; +my $modifytime = sprintf "%04u-%02u-%02u %02u:%02u:%02u",$t[5]+1900,$t[4]+1,$t[3],$t[2],$t[1],$t[0]; +printf F ("let \$tmpval = %s;",$modifytime); +close F; +EOF + +--source $MYSQLTEST_VARDIR/tmp/rpl_rotate_logs.tmp +remove_file $MYSQLTEST_VARDIR/tmp/rpl_rotate_logs.tmp; + +--disable_result_log +--replace_result $tmpval tmpval +--eval SELECT @time_for_purge:=DATE_ADD('$tmpval', INTERVAL 1 SECOND) +--enable_result_log + +purge master logs before (@time_for_purge); +source include/show_binary_logs.inc; +insert into t2 values (65); +sync_slave_with_master; +source include/show_slave_status.inc; +source include/check_slave_is_running.inc; +select * from t2; + +# +# Test forcing the replication log to rotate +# + +connection master; +create temporary table temp_table (a char(80) not null); +insert into temp_table values ("testing temporary tables part 2"); + +# the nummber of produced logs is sensitive to whether checksum is NONE or CRC32 +# the value of 103 makes it even +let $1=103; + +create table t3 (n int); +disable_query_log; +while ($1) +{ +#eval means expand $ expressions + eval insert HIGH_PRIORITY into t3 values($1 + 4); + dec $1; +} +enable_query_log; +select count(*) from t3 where n >= 4; +create table t4 select * from temp_table; +source include/show_binary_logs.inc; +source include/show_master_status.inc; +sync_slave_with_master; +select * from t4; + +source include/show_slave_status.inc; +source include/check_slave_is_running.inc; +# because of concurrent insert, the table may not be up to date +# if we do not lock +lock tables t3 read; +select count(*) from t3 where n >= 4; +unlock tables; +#clean up +connection master; +drop table if exists t1,t2,t3,t4; +drop temporary table temp_table; +sync_slave_with_master; + +--echo End of 4.1 tests + +# +# Bug #29420: crash with show and purge binlogs +# +--error 1220 +show binlog events in 'non existing_binlog_file'; +purge master logs before now(); +--error 1220 +show binlog events in ''; +purge master logs before now(); + +--echo End of 5.0 tests +--echo #cleanup + +--remove_file $MYSQLD_SLAVE_DATADIR/master.info +--source include/stop_slave.inc +reset slave all; diff --git a/mysql-test/suite/rpl/t/rpl_rotate_purge_deadlock-master.opt b/mysql-test/suite/rpl/t/rpl_rotate_purge_deadlock-master.opt new file mode 100644 index 00000000..f71317fc --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_rotate_purge_deadlock-master.opt @@ -0,0 +1 @@ +--max-binlog-size=4k --expire-logs-days=1 diff --git a/mysql-test/suite/rpl/t/rpl_rotate_purge_deadlock.test b/mysql-test/suite/rpl/t/rpl_rotate_purge_deadlock.test new file mode 100644 index 00000000..6db4e2be --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_rotate_purge_deadlock.test @@ -0,0 +1,96 @@ +# +# Bug#11763573 - 56299: MUTEX DEADLOCK WITH COM_BINLOG_DUMP, BINLOG PURGE, AND PROCESSLIST/KILL +# +source include/have_debug_sync.inc; +source include/have_binlog_format_row.inc; +source include/have_innodb.inc; +source include/master-slave.inc; + +# +# Testing that execution of two concurrent INSERTing connections both +# triggering the binlog rotation is correct even though their execution +# is interleaved. +# The test makes the first connection to complete the rotation part +# and yields control to the second connection that rotates as well and +# gets first on purging. And the fact of interleaving does not create +# any issue. +# + +connection master; +source include/show_binary_logs.inc; +create table t1 (f text) engine=innodb; +SET DEBUG_SYNC = 'at_purge_logs_before_date WAIT_FOR rotated'; +SET DEBUG_SYNC = 'after_purge_logs_before_date SIGNAL continued'; +send insert into t1 set f=repeat('a', 4096); + +connection master1; + +let $wait_condition= + SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE STATE like "debug sync point: at_purge_logs_before_date%"; +--source include/wait_condition.inc + +--echo *** there must be two logs in the list *** +source include/show_binary_logs.inc; + +insert into t1 set f=repeat('b', 4096); + +--echo *** there must be three logs in the list *** +source include/show_binary_logs.inc; + +SET DEBUG_SYNC = 'now SIGNAL rotated'; +SET DEBUG_SYNC = 'now WAIT_FOR continued'; +SET DEBUG_SYNC = 'RESET'; + +# the first connection finally completes its INSERT +connection master; +reap; +SET DEBUG_SYNC = 'RESET'; + +sync_slave_with_master; + + +# +# Testing the reported deadlock involving DUMP, KILL and INSERT threads +# + +connection master; +SET DEBUG_SYNC = 'at_purge_logs_before_date WAIT_FOR rotated'; +SET DEBUG_SYNC = 'after_purge_logs_before_date SIGNAL continued'; +send insert into t1 set f=repeat('b', 4096); + +connection master1; + +# make sure INSERT reaches waiting point +let $wait_condition= + SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE STATE like "debug sync point: at_purge_logs_before_date%"; +--source include/wait_condition.inc + +# find and kill DUMP thread +let $_tid= `select id from information_schema.processlist where command = 'Binlog Dump' limit 1`; +--disable_query_log +eval kill query $_tid; +--enable_query_log + +# +# Now the proof is that the new DUMP thread has executed +# a critical section of the deadlock without any regression and is UP +# +let $wait_condition= + SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE command = 'Binlog Dump' and STATE like "Master has sent all binlog to slave%"; +--source include/wait_condition.inc + +SET DEBUG_SYNC = 'now SIGNAL rotated'; +SET DEBUG_SYNC = 'now WAIT_FOR continued'; +SET DEBUG_SYNC = 'RESET'; + +connection master; +reap; +SET DEBUG_SYNC = 'RESET'; +drop table t1; + +sync_slave_with_master; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_001.test b/mysql-test/suite/rpl/t/rpl_row_001.test new file mode 100644 index 00000000..887c0961 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_001.test @@ -0,0 +1,51 @@ +######################################################## +# By JBM 2005-02-15 Wrapped to allow reuse of test code# +######################################################## +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + +# Test if the slave SQL thread can be more than 16K behind the slave +# I/O thread (> IO_SIZE) + +# we'll use table-level locking to delay slave SQL thread +eval CREATE TABLE t1 (n INT); +sync_slave_with_master; +connection master; +RESET MASTER; +connection slave; +STOP SLAVE; +--source include/reset_slave.inc + +connection master; +let $1=5000; +# Generate 16K of relay log +disable_query_log; +while ($1) +{ + eval INSERT INTO t1 VALUES($1); + dec $1; +} +enable_query_log; +SELECT COUNT(*) FROM t1; +save_master_pos; + +# Try to cause a large relay log lag on the slave by locking t1 +connection slave; +LOCK TABLES t1 READ; +START SLAVE; +UNLOCK TABLES; +sync_with_master; +SELECT COUNT(*) FROM t1; + +connection master; +DROP TABLE t1; +CREATE TABLE t1 (n INT); +INSERT INTO t1 VALUES(3456); +sync_slave_with_master; +SELECT n FROM t1; + +connection master; +DROP TABLE t1; + +sync_slave_with_master; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_4_bytes-master.opt b/mysql-test/suite/rpl/t/rpl_row_4_bytes-master.opt new file mode 100644 index 00000000..3073fa4f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_4_bytes-master.opt @@ -0,0 +1,2 @@ +--loose-debug=d,"old_row_based_repl_4_byte_map_id_master" +--log-bin-use-v1-row-events=1 diff --git a/mysql-test/suite/rpl/t/rpl_row_4_bytes.test b/mysql-test/suite/rpl/t/rpl_row_4_bytes.test new file mode 100644 index 00000000..6130f749 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_4_bytes.test @@ -0,0 +1,34 @@ +# This test is to make sure that slaves can read a binlog containining +# table map ids stored in 4 bytes, even though we now store them in 6 +# bytes. This is for backward-compatibility. +# If the slave does not detect that the master stores the table map id +# in 4 bytes, slave will read 6 bytes, and so will read the 2 bytes of +# flags at the place where there actually is data, so the test should +# fail. + +-- source include/have_binlog_format_row.inc +-- source include/have_debug.inc +-- source include/master-slave.inc + +connection master; +--disable_warnings +drop database if exists mysqltest1; +create database mysqltest1; +--enable_warnings +use mysqltest1; +CREATE TABLE t1 (a char(3)); +CREATE TABLE t2 (a char(3)); +insert into t1 values("ANN"); +insert into t1 values("GUI"); +insert into t2 values("LIL"); +insert into t2 values("ABE"); +insert into t2 values("ANG"); +sync_slave_with_master; +use mysqltest1; +select * from t1 order by a; +select * from t2 order by a; + +connection master; +DROP DATABASE mysqltest1; +sync_slave_with_master; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_NOW.test b/mysql-test/suite/rpl/t/rpl_row_NOW.test new file mode 100644 index 00000000..d732c6e6 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_NOW.test @@ -0,0 +1,75 @@ +############################################################################# +# Original Author: JBM # +# Original Date: Aug/18/2005 # +# Updated 08/30/2005 Added dumps and diff # +############################################################################# +#TEST: Taken and modfied from http://bugs.mysql.com/bug.php?id=12480 # +############################################################################# + +# Includes +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + + +# Begin clean up test section +connection master; +--disable_warnings +create database if not exists mysqltest1; +DROP TABLE IF EXISTS mysqltest1.t1; +--enable_warnings + + +# Begin test section 1 +CREATE TABLE mysqltest1.t1 (n MEDIUMINT NOT NULL AUTO_INCREMENT, + a TIMESTAMP DEFAULT '2005-05-05 01:01:01', + b TIMESTAMP DEFAULT '2005-05-05 01:01:01', + PRIMARY KEY(n)); +delimiter |; +CREATE FUNCTION mysqltest1.f1() RETURNS TIMESTAMP +BEGIN + DECLARE v1 INT DEFAULT 300; + WHILE v1 > 0 DO + SET v1 = v1 - 1; + END WHILE; + RETURN NOW(); +END| +delimiter ;| + +INSERT INTO mysqltest1.t1 VALUES(NULL,NOW(),mysqltest1.f1()); + +delimiter |; +CREATE TRIGGER mysqltest1.trig1 BEFORE INSERT ON mysqltest1.t1 +FOR EACH ROW BEGIN + SET new.b = mysqltest1.f1(); +END| +delimiter ;| + +INSERT INTO mysqltest1.t1 SET n = NULL, a = now(); + +sync_slave_with_master; + +connection master; + +--exec $MYSQL_DUMP --compact --order-by-primary --skip-extended-insert --no-create-info mysqltest1 > $MYSQLTEST_VARDIR/tmp/NOW_master.sql +--exec $MYSQL_DUMP_SLAVE --compact --order-by-primary --skip-extended-insert --no-create-info mysqltest1 > $MYSQLTEST_VARDIR/tmp/NOW_slave.sql + +# lets cleanup +DROP TABLE IF EXISTS mysqltest1.t1; +DROP FUNCTION mysqltest1.f1; +DROP DATABASE mysqltest1; + +# Lets compare. Note: If they match test will pass, if they do not match +# the test will show that the diff statement failed and not reject file +# will be created. You will need to go to the mysql-test dir and diff +# the files your self to see what is not matching :-) The failed dump +# files will be located in $MYSQLTEST_VARDIR/tmp + +diff_files $MYSQLTEST_VARDIR/tmp/NOW_master.sql $MYSQLTEST_VARDIR/tmp/NOW_slave.sql; + +# If all is good, when can cleanup our dump files. +--remove_file $MYSQLTEST_VARDIR/tmp/NOW_master.sql +--remove_file $MYSQLTEST_VARDIR/tmp/NOW_slave.sql + +sync_slave_with_master; +# End of 5.1 test case +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_USER.test b/mysql-test/suite/rpl/t/rpl_row_USER.test new file mode 100644 index 00000000..405f609f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_USER.test @@ -0,0 +1,59 @@ +############################################################################# +# Original Author: JBM # +# Original Date: Aug/18/2005 # +############################################################################# +# TEST: To test the USER() and CURRENT_USER() in rbr # +############################################################################# +# Change Author: JBM +# Change Date: 2006-01-16 +########## + +# Includes +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc +set local sql_mode=""; + +# Begin clean up test section +connection master; +--disable_warnings +DROP DATABASE IF EXISTS mysqltest1; +CREATE DATABASE mysqltest1; +--enable_warnings + +# Section 1 test +CREATE USER tester IDENTIFIED BY 'test'; +GRANT ALL ON mysqltest1.* TO 'tester'@'%' IDENTIFIED BY 'test'; +GRANT ALL ON mysqltest1.* TO ''@'localhost%'; +FLUSH PRIVILEGES; +connect (m_1,localhost,tester,,mysqltest1); + +connection m_1; +CREATE TABLE mysqltest1.t1 (a INT, users VARCHAR(255), PRIMARY KEY(a)); +INSERT INTO mysqltest1.t1 VALUES(1,USER()); +INSERT INTO mysqltest1.t1 VALUES(2,CURRENT_USER()); +delimiter |; +create procedure mysqltest1.p1() +begin + INSERT INTO mysqltest1.t1 VALUES(3,USER()); + INSERT INTO mysqltest1.t1 VALUES(4,CURRENT_USER()); +end| +delimiter ;| + +CALL mysqltest1.p1(); +connection master; +SELECT * FROM mysqltest1.t1 ORDER BY a; +--sync_slave_with_master +SELECT * FROM mysqltest1.t1 ORDER BY a; + +connection master; +# Lets cleanup + +DROP DATABASE mysqltest1; +REVOKE ALL ON mysqltest1.* FROM 'tester'@'%'; +REVOKE ALL ON mysqltest1.* FROM ''@'localhost%'; +DROP USER tester@'%'; +DROP USER ''@'localhost%'; +FLUSH PRIVILEGES; +--sync_slave_with_master +# End of 5.0 test case +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_UUID.test b/mysql-test/suite/rpl/t/rpl_row_UUID.test new file mode 100644 index 00000000..8e1aa6d2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_UUID.test @@ -0,0 +1,8 @@ +######################################################## +# By JBM 2005-02-15 Wrapped to allow reuse of test code# +######################################################## +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc +let $engine_type=myisam; +--source include/rpl_row_UUID.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_annotate_do-slave.opt b/mysql-test/suite/rpl/t/rpl_row_annotate_do-slave.opt new file mode 100644 index 00000000..18de9bd1 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_annotate_do-slave.opt @@ -0,0 +1 @@ +--log-slave-updates --replicate-annotate-row-events --replicate-ignore-table=test1.xt1 --replicate-ignore-table=test1.xt2 diff --git a/mysql-test/suite/rpl/t/rpl_row_annotate_do.test b/mysql-test/suite/rpl/t/rpl_row_annotate_do.test new file mode 100644 index 00000000..ffaae314 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_annotate_do.test @@ -0,0 +1,16 @@ +############################################################################### +# WL47: Store in binlog text of statements that caused RBR events +# Wrapper for extra/rpl/rpl_row_annotate.test. +# Intended to test that if the --replicate-annotate-row-events option +# is switched on on slave then Annotate_events: +# - are reproduced on slave +# - are reproduced only once for "multi-table-maps" rbr queries +# - are not reproduced when the corresponding queries are filtered away +# on replication +# - are reproduced when the corresponding queries are filtered away partialy +# (e.g. in case of multi-delete) +# - are not generated on slave for queries that are not annotated on master. +############################################################################### + +--source include/have_binlog_format_row.inc +--source include/rpl_row_annotate.test diff --git a/mysql-test/suite/rpl/t/rpl_row_annotate_dont-slave.opt b/mysql-test/suite/rpl/t/rpl_row_annotate_dont-slave.opt new file mode 100644 index 00000000..feef43f7 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_annotate_dont-slave.opt @@ -0,0 +1 @@ +--log-slave-updates --skip-replicate-annotate-row-events --replicate-ignore-table=test1.xt1 --replicate-ignore-table=test1.xt2 diff --git a/mysql-test/suite/rpl/t/rpl_row_annotate_dont.test b/mysql-test/suite/rpl/t/rpl_row_annotate_dont.test new file mode 100644 index 00000000..24dd2a1c --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_annotate_dont.test @@ -0,0 +1,9 @@ +############################################################################### +# WL47: Store in binlog text of statements that caused RBR events +# Wrapper for extra/rpl/rpl_row_annotate.test. +# Intended to test that if the --replicate-annotate-row-events option +# is switched off on slave then Annotate_events are not reproduced. +############################################################################### + +--source include/have_binlog_format_row.inc +--source include/rpl_row_annotate.test diff --git a/mysql-test/suite/rpl/t/rpl_row_basic_11bugs-master.opt b/mysql-test/suite/rpl/t/rpl_row_basic_11bugs-master.opt new file mode 100644 index 00000000..bd772813 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_basic_11bugs-master.opt @@ -0,0 +1,2 @@ +--binlog_ignore_db=test_ignore --default-storage-engine=MyISAM + diff --git a/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test b/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test new file mode 100644 index 00000000..b875b97d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test @@ -0,0 +1,242 @@ +-- source include/have_query_cache.inc +--source include/have_binlog_format_row.inc +--source include/have_innodb.inc + +let $SERVER_VERSION=`select version()`; + +--source include/master-slave.inc + +# Add suppression for expected warning(s) in slaves error log +call mtr.add_suppression("Can't find record in 't.'"); + +# Bug#15942 (RBR ignores --binlog_ignore_db and tries to map to table +# on slave for writes) + +CREATE DATABASE test_ignore; # --binlog_ignore_db=mysqltest_ignore + +SHOW DATABASES; +USE test; +CREATE TABLE t1 (a INT, b INT); +SHOW TABLES; +INSERT INTO t1 VALUES (1,1), (2,2); +USE test_ignore; +CREATE TABLE t2 (a INT, b INT); +SHOW TABLES; +INSERT INTO t2 VALUES (3,3), (4,4); +source include/show_binlog_events.inc; +sync_slave_with_master; +SHOW DATABASES; +USE test; +SHOW TABLES; +--error 1049 +USE test_ignore; + +connection master; +DROP DATABASE test_ignore; +USE test; +DROP TABLE t1; +sync_slave_with_master; +USE test; + + +# Bug#19995: Extreneous table maps generated for statements that does +# not generate rows +--source include/rpl_reset.inc + +connection master; +CREATE TABLE t1 (a INT); +DELETE FROM t1; +INSERT INTO t1 VALUES (1),(2); +DELETE FROM t1 WHERE a = 0; +UPDATE t1 SET a=99 WHERE a = 0; +source include/show_binlog_events.inc; + +DROP TABLE t1; +--sync_slave_with_master + +# BUG#17620: Replicate (Row Based) Fails when Query Cache enabled on +# slave +--echo ================ Test for BUG#17620 ================ +--source include/rpl_reset.inc + +connection slave; +SET GLOBAL QUERY_CACHE_SIZE=0; +call mtr.add_suppression("Slave SQL.*Could not execute Update_rows event on table test.t1.* error.* 1032"); + +connection master; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2),(3); + +sync_slave_with_master; +SET GLOBAL QUERY_CACHE_SIZE=16*1024*1024; + +connection master; +INSERT INTO t1 VALUES (4),(5),(6); + +sync_slave_with_master; +SELECT * FROM t1; + +connection master; +INSERT INTO t1 VALUES (7),(8),(9); + +sync_slave_with_master; +SELECT * FROM t1; + +SET GLOBAL QUERY_CACHE_SIZE=default; +--connection master +DROP TABLE t1; + + +# Bug#22550: Replication of BIT columns failing +--echo ================ Test for BUG#22550 ================ +--source include/rpl_reset.inc + +connection master; +CREATE TABLE t1 (a BIT(1), b INT) ENGINE=MYISAM; +sync_slave_with_master; + +connection master; +INSERT INTO t1 VALUES(1,2); +SELECT HEX(a),b FROM t1; +sync_slave_with_master; +SELECT HEX(a),b FROM t1; + +connection master; +UPDATE t1 SET a=0 WHERE b=2; +SELECT HEX(a),b FROM t1; +sync_slave_with_master; +SELECT HEX(a),b FROM t1; + +connection master; +DROP TABLE IF EXISTS t1; +sync_slave_with_master; + +# BUG#22583: RBR between MyISAM and non-MyISAM tables containing a BIT +# field does not work + +--echo ================ Test for BUG#22583 ================ +--source include/rpl_reset.inc + +# disabling warnings temporarily for ENGINE=INNODB to work without InnoDB +--disable_warnings +connection master; +CREATE TABLE t1_myisam (k INT, a BIT(1), b BIT(9)) ENGINE=MYISAM; +CREATE TABLE t1_innodb (k INT, a BIT(1), b BIT(9)) ENGINE=INNODB; +CREATE TABLE t2_myisam (k INT, a BIT(1) NOT NULL, b BIT(4) NOT NULL) ENGINE=MYISAM; +CREATE TABLE t2_innodb (k INT, a BIT(1) NOT NULL, b BIT(4) NOT NULL) ENGINE=INNODB; +sync_slave_with_master; +ALTER TABLE t1_myisam ENGINE=INNODB; +ALTER TABLE t1_innodb ENGINE=MYISAM; +ALTER TABLE t2_myisam ENGINE=INNODB; +ALTER TABLE t2_innodb ENGINE=MYISAM; +--enable_warnings + +connection master; +INSERT INTO t1_myisam VALUES(1, b'0', 257); +INSERT INTO t1_myisam VALUES(2, b'1', 256); +INSERT INTO t1_innodb VALUES(1, b'0', 257); +INSERT INTO t1_innodb VALUES(2, b'1', 256); +SELECT k, HEX(a),HEX(b) FROM t1_myisam; +SELECT k, HEX(a),HEX(b) FROM t1_innodb; +INSERT INTO t2_myisam VALUES(1, b'0', 9); +INSERT INTO t2_myisam VALUES(2, b'1', 8); +INSERT INTO t2_innodb VALUES(1, b'0', 9); +INSERT INTO t2_innodb VALUES(2, b'1', 8); +SELECT k, HEX(a),HEX(b) FROM t2_myisam; +SELECT k, HEX(a),HEX(b) FROM t2_innodb; +sync_slave_with_master; +SELECT k, HEX(a),HEX(b) FROM t1_myisam; +SELECT k, HEX(a),HEX(b) FROM t1_innodb; +SELECT k, HEX(a),HEX(b) FROM t2_myisam; +SELECT k, HEX(a),HEX(b) FROM t2_innodb; + +connection master; +UPDATE t1_myisam SET a=0 WHERE k=2; +SELECT k, HEX(a),HEX(b) FROM t1_myisam; +UPDATE t1_innodb SET a=0 WHERE k=2; +SELECT k, HEX(a),HEX(b) FROM t1_innodb; +UPDATE t2_myisam SET a=0 WHERE k=2; +SELECT k, HEX(a),HEX(b) FROM t2_myisam; +UPDATE t2_innodb SET a=0 WHERE k=2; +SELECT k, HEX(a),HEX(b) FROM t2_innodb; +sync_slave_with_master; +SELECT k, HEX(a),HEX(b) FROM t1_myisam; +SELECT k, HEX(a),HEX(b) FROM t1_innodb; +SELECT k, HEX(a),HEX(b) FROM t2_myisam; +SELECT k, HEX(a),HEX(b) FROM t2_innodb; + +connection master; +DROP TABLE IF EXISTS t1_myisam, t1_innodb, t2_myisam, t2_innodb; +sync_slave_with_master; + +# +# Bug#27716 multi-update did partially and has not binlogged +# + +connection master; + +--disable_warnings +drop table if exists t1, t2; +--enable_warnings +CREATE TABLE `t1` ( + `a` int(11) NOT NULL auto_increment, + `b` int(11) default NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 ; + +CREATE TABLE `t2` ( + `a` int(11) NOT NULL auto_increment, + `b` int(11) default NULL, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 ; + +# testing multi_update::send_error() effective update +insert into t1 values (1,1),(2,2); +insert into t2 values (1,1),(4,4); + +connection master; +error ER_DUP_ENTRY; +UPDATE t2,t1 SET t2.a=t1.a+2; +select * from t2 /* must be (3,1), (4,4) */; +sync_slave_with_master; + +connection slave; +select * from t2 /* must be (3,1), (4,4) */; + +connection master; +drop table t1,t2; + +sync_slave_with_master; + +# +# BUG#31702: Missing row on slave causes assertion failure under +# row-based replication +# + +--source include/rpl_reset.inc + +connection master; +CREATE TABLE t1 (a INT PRIMARY KEY, b SET('master','slave')); +INSERT INTO t1 VALUES (1,'master,slave'), (2,'master,slave'); +sync_slave_with_master; +UPDATE t1 SET a = 5, b = 'slave' WHERE a = 1; +SELECT * FROM t1 ORDER BY a; +# since bug#31552/31609 idempotency is not default any longer. In +# order for the preceding test UPDATE t1 to pass, the mode is switched +# temprorarily +set @@global.slave_exec_mode= 'IDEMPOTENT'; +connection master; +UPDATE t1 SET a = 5, b = 'master' WHERE a = 1; +SELECT * FROM t1 ORDER BY a; +sync_slave_with_master; +set @@global.slave_exec_mode= default; +let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1); +disable_query_log; +eval SELECT "$last_error" AS Last_SQL_Error; +enable_query_log; + +SELECT * FROM t1 ORDER BY a; + +connection master; +DROP TABLE t1; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_basic_2myisam.test b/mysql-test/suite/rpl/t/rpl_row_basic_2myisam.test new file mode 100644 index 00000000..f1e836c6 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_basic_2myisam.test @@ -0,0 +1,11 @@ +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + +let $type= 'MYISAM' ; +let $extra_index= ; +-- source include/rpl_row_basic.test + +connection slave; +call mtr.add_suppression("Can't find record in 't1'"); + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_basic_3innodb.test b/mysql-test/suite/rpl/t/rpl_row_basic_3innodb.test new file mode 100644 index 00000000..b84a4c13 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_basic_3innodb.test @@ -0,0 +1,11 @@ +-- source include/have_innodb.inc +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + +connection slave; +let $bit_field_special = ALL_LOSSY; +let $type= 'INNODB' ; +let $extra_index= ; +-- source include/rpl_row_basic.test + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_basic_8partition.test b/mysql-test/suite/rpl/t/rpl_row_basic_8partition.test new file mode 100644 index 00000000..7a477056 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_basic_8partition.test @@ -0,0 +1,190 @@ +############################################################ +# Author: MATZ # +# Date: 2006-03-22 # +# Purpose: See if replication of partition tables work # +# Most of this test is copied from the rpl_xxx2yyy tests, # +# but here we just test some simple basic replication of # +# partition tables with same engine (MyISAM) in both ends. # +############################################################ + +--source include/have_binlog_format_row.inc +--source include/have_partition.inc +--source include/master-slave.inc +connection master; +--disable_warnings +DROP TABLE IF EXISTS t1; + +SET @@BINLOG_FORMAT = ROW; + +--echo **** Partition RANGE testing **** + +# Create table that is partitioned by range on year i.e. year(t) and +# replicate basice operations such at insert, update delete between 2 +# different storage engines Alter table and ensure table is handled +# Correctly on the slave +# Note that the storage engine should not be explicit: the default +# storage engine is used on master and slave. + +CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(255), + bc CHAR(255), d DECIMAL(10,4) DEFAULT 0, + f FLOAT DEFAULT 0, total BIGINT UNSIGNED, + y YEAR, t DATE) + PARTITION BY RANGE (YEAR(t)) + (PARTITION p0 VALUES LESS THAN (1901), + PARTITION p1 VALUES LESS THAN (1946), + PARTITION p2 VALUES LESS THAN (1966), + PARTITION p3 VALUES LESS THAN (1986), + PARTITION p4 VALUES LESS THAN (2005), + PARTITION p5 VALUES LESS THAN MAXVALUE); + +SHOW CREATE TABLE t1; + +sync_slave_with_master; +SHOW CREATE TABLE t1; + +--source include/rpl_multi_engine3.inc + +connection master; +# Check that simple Alter statements are replicated correctly +ALTER TABLE t1 MODIFY vc TEXT; + +SHOW CREATE TABLE t1; + +sync_slave_with_master; +SHOW CREATE TABLE t1; + +# Perform basic operation on master and ensure replicated correctly +--source include/rpl_multi_engine3.inc + +connection master; +DROP TABLE IF EXISTS t1; + +######################################################## + +--echo **** Partition LIST testing **** + +# Create table that is partitioned by list on id i.e. (2,4). Pretend +# that we missed one and alter to add. Then replicate basice +# operations such at insert, update delete between 2 different storage +# engines Alter table and ensure table is handled Correctly on the +# slave. + + +CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(255), + bc CHAR(255), d DECIMAL(10,4) DEFAULT 0, + f FLOAT DEFAULT 0, total BIGINT UNSIGNED, + y YEAR, t DATE) + PARTITION BY LIST(id) + (PARTITION p0 VALUES IN (2, 4), + PARTITION p1 VALUES IN (42, 142), + PARTITION p2 VALUES IN (412)); + +SHOW CREATE TABLE t1; + +sync_slave_with_master; +SHOW CREATE TABLE t1; + +# Perform basic operation on master and ensure replicated correctly +--source include/rpl_multi_engine3.inc + +connection master; +# Check that simple Alter statements are replicated correctly --- +ALTER TABLE t1 MODIFY vc TEXT; + +SHOW CREATE TABLE t1; + +sync_slave_with_master; +SHOW CREATE TABLE t1; + +# Perform basic operation on master and ensure replicated correctly +--source include/rpl_multi_engine3.inc + +connection master; +DROP TABLE IF EXISTS t1; + +######################################################## + +--echo **** Partition HASH testing **** + +# Create table that is partitioned by hash on year i.e. YEAR(t). Then +# replicate basice operations such at insert, update delete between 2 +# different storage engines Alter table and ensure table is handled +# Correctly on the slave + +CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(255), + bc CHAR(255), d DECIMAL(10,4) DEFAULT 0, + f FLOAT DEFAULT 0, total BIGINT UNSIGNED, + y YEAR, t DATE) + PARTITION BY HASH( YEAR(t) ) + PARTITIONS 4; + +SHOW CREATE TABLE t1; + +sync_slave_with_master; +SHOW CREATE TABLE t1; + +--source include/rpl_multi_engine3.inc + +# Check that simple Alter statements are replicated correctly +ALTER TABLE t1 MODIFY vc TEXT; + +SHOW CREATE TABLE t1; + +sync_slave_with_master; +SHOW CREATE TABLE t1; + +--source include/rpl_multi_engine3.inc + +connection master; +DROP TABLE IF EXISTS t1; + +######################################################## + +# This part does not work +--echo **** Partition by KEY **** + +# Create table that is partitioned by key on id with 4 parts. Then +# replicate basice operations such at insert, update delete between 2 +# different storage engines Alter table and ensure table is handled +# Correctly on the slave + +CREATE TABLE t1 (id MEDIUMINT NOT NULL, b1 BIT(8), vc VARCHAR(255), + bc CHAR(255), d DECIMAL(10,4) DEFAULT 0, + f FLOAT DEFAULT 0, total BIGINT UNSIGNED, + y YEAR, t DATE,PRIMARY KEY(id)) + PARTITION BY KEY() + PARTITIONS 4; + +SHOW CREATE TABLE t1; + +sync_slave_with_master; +SHOW CREATE TABLE t1; + +--source include/rpl_multi_engine3.inc + +connection master; +# Check that simple Alter statements are replicated correctly +ALTER TABLE t1 DROP PRIMARY KEY, ADD PRIMARY KEY(id, total); + +SHOW CREATE TABLE t1; + +sync_slave_with_master; +SHOW CREATE TABLE t1; + +--source include/rpl_multi_engine3.inc + +connection master; +# Check that simple Alter statements are replicated correctly +ALTER TABLE t1 MODIFY vc TEXT; + +SHOW CREATE TABLE t1; + +sync_slave_with_master; +SHOW CREATE TABLE t1; + +--source include/rpl_multi_engine3.inc + +DROP TABLE IF EXISTS t1; + +# End of 5.1 test case +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_big_table_id.opt b/mysql-test/suite/rpl/t/rpl_row_big_table_id.opt new file mode 100644 index 00000000..7c3d2411 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_big_table_id.opt @@ -0,0 +1 @@ +--verbose=1 diff --git a/mysql-test/suite/rpl/t/rpl_row_big_table_id.test b/mysql-test/suite/rpl/t/rpl_row_big_table_id.test new file mode 100644 index 00000000..15eadedb --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_big_table_id.test @@ -0,0 +1,58 @@ +################################################################## +# rpl_row_big_table_id +# +# MDEV-17803 Row-based event is not applied when +# table map id is greater 32 bit int +# +# This test is depending on that the server was restarted before test was run +# +# Verify row-based events applying when table map id value is about and greater +# than 1 << 32. +################################################################## +--source include/not_valgrind.inc +--source include/word_size.inc +--source include/have_debug.inc +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +SET @old_debug_dbug= @@debug_dbug; +SET @@debug_dbug="+d,simulate_big_table_id"; +CREATE TABLE t (a int); + +--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1) +--let $binlog_pos= query_get_value(SHOW MASTER STATUS, Position, 1) +INSERT INTO t SET a= 0; +ALTER TABLE t comment ''; +INSERT INTO t SET a= 1; +ALTER TABLE t comment ''; +INSERT INTO t SET a= 2; +ALTER TABLE t comment ''; +INSERT INTO t SET a= 3; + +# display simulated big table_id +--let $_in_from=in '$binlog_file' from $binlog_pos +--replace_result "$_in_from" "in <file> from <pos>" +--replace_column 2 # 5 # +--replace_regex /\/\* xid=.* \*\//\/* XID *\// /file_id=[0-9]+/file_id=#/ /GTID [0-9]+-[0-9]+-[0-9]+/GTID #-#-#/ +--eval show binlog events in '$binlog_file' from $binlog_pos + + +--sync_slave_with_master + +if (`SELECT sum(a) != 6 FROM t`) +{ + --echo *** unexpected result; check slave applier *** + --die +} + + +# Cleanup + +--connection master +SET debug_dbug=@old_debug_dbug; + +DROP TABLE t; + +--sync_slave_with_master + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_binlog_max_cache_size.test b/mysql-test/suite/rpl/t/rpl_row_binlog_max_cache_size.test new file mode 100644 index 00000000..a4db32cf --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_binlog_max_cache_size.test @@ -0,0 +1,8 @@ +--source include/have_innodb.inc +--source include/not_embedded.inc +--source include/not_windows.inc +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +--source include/rpl_binlog_max_cache_size.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_blob_innodb.test b/mysql-test/suite/rpl/t/rpl_row_blob_innodb.test new file mode 100644 index 00000000..57f3e91a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_blob_innodb.test @@ -0,0 +1,13 @@ +################################# +# Wrapper for rpl_row_blob.test# +################################# +######################################################## +# By JBM 2005-02-15 Wrapped to allow reuse of test code# +######################################################## +-- source include/have_innodb.inc +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc +let $engine_type=InnoDB; +-- source include/rpl_row_blob.test + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_blob_myisam.test b/mysql-test/suite/rpl/t/rpl_row_blob_myisam.test new file mode 100644 index 00000000..246d38f4 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_blob_myisam.test @@ -0,0 +1,12 @@ +################################# +# Wrapper for rpl_row_blob.test# +################################# +######################################################## +# By JBM 2005-02-15 Wrapped to allow reuse of test code# +######################################################## +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc +let $engine_type=myisam; +-- source include/rpl_row_blob.test + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_colSize.test b/mysql-test/suite/rpl/t/rpl_row_colSize.test new file mode 100644 index 00000000..21c68b55 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_colSize.test @@ -0,0 +1,173 @@ +################################################################## +# rpl_colSize # +# # +# This test is designed to test the changes included in WL#3228. # +# The changes include the ability to replicate with the master # +# having columns that are smaller (shorter) than the slave. # +################################################################## + +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + + +--echo **** Testing WL#3228 changes. **** +--echo *** Create "wider" table on slave *** +sync_slave_with_master; + +# +# Check each column type to verify error 1532 fires (BUG#22086) +# This check covers only those fields that require additional +# metadata from the master to be replicated to the slave. These +# field types are: +# MYSQL_TYPE_NEWDECIMAL: +# MYSQL_TYPE_FLOAT: +# MYSQL_TYPE_BIT: +# MYSQL_TYPE_SET: +# MYSQL_TYPE_STRING: +# MYSQL_TYPE_ENUM: +# MYSQL_TYPE_VARCHAR: +# MYSQL_TYPE_BLOB: + +# +# Test: Checking MYSQL_TYPE_NEWDECIMAL fields +# +--echo Checking MYSQL_TYPE_NEWDECIMAL fields +let $test_table_master = CREATE TABLE t1 (a DECIMAL(20, 10)); +let $test_table_slave = CREATE TABLE t1 (a DECIMAL(5,2)); +let $test_insert = INSERT INTO t1 VALUES (901251.90125); +source include/test_fieldsize.inc; + +let $test_table_master = CREATE TABLE t1 (a DECIMAL(27, 18)); +let $test_table_slave = CREATE TABLE t1 (a DECIMAL(27, 9)); +let $test_insert = INSERT INTO t1 VALUES (901251.90125); +source include/test_fieldsize.inc; + +let $test_table_master = CREATE TABLE t1 (a NUMERIC(20, 10)); +let $test_table_slave = CREATE TABLE t1 (a NUMERIC(5,2)); +let $test_insert = INSERT INTO t1 VALUES (901251.90125); +source include/test_fieldsize.inc; + +# +# Test: Checking MYSQL_TYPE_FLOAT fields +# +--echo Checking MYSQL_TYPE_FLOAT fields +let $test_table_master = CREATE TABLE t1 (a FLOAT(47)); +let $test_table_slave = CREATE TABLE t1 (a FLOAT(20)); +let $test_insert = INSERT INTO t1 VALUES (901251.90125); +source include/test_fieldsize.inc; + +# +# Test: Checking MYSQL_TYPE_BIT fields +# +--echo Checking MYSQL_TYPE_BIT fields +let $test_table_master = CREATE TABLE t1 (a BIT(64)); +let $test_table_slave = CREATE TABLE t1 (a BIT(5)); +let $test_insert = INSERT INTO t1 VALUES (B'10101'); +source include/test_fieldsize.inc; + +let $test_table_master = CREATE TABLE t1 (a BIT(12)); +let $test_table_slave = CREATE TABLE t1 (a BIT(11)); +let $test_insert = INSERT INTO t1 VALUES (B'10101'); +source include/test_fieldsize.inc; + +# +# Test: Checking MYSQL_TYPE_SET fields +# +--echo Checking MYSQL_TYPE_SET fields +let $test_table_master = CREATE TABLE t1 (a SET('1','2','3','4','5','6','7','8','9')); +let $test_table_slave = CREATE TABLE t1 (a SET('4')); +let $test_insert = INSERT INTO t1 VALUES ('4'); +source include/test_fieldsize.inc; + +# +# Test: Checking MYSQL_TYPE_STRING fields +# +--echo Checking MYSQL_TYPE_STRING fields +let $test_table_master = CREATE TABLE t1 (a CHAR(20)); +let $test_table_slave = CREATE TABLE t1 (a CHAR(10)); +let $test_insert = INSERT INTO t1 VALUES ('This is a test.'); +source include/test_fieldsize.inc; + +# +# Test: Checking MYSQL_TYPE_ENUM fields +# +--echo Checking MYSQL_TYPE_ENUM fields +let $test_table_master = CREATE TABLE t1 (a ENUM( + '01','02','03','04','05','06','07','08','09', + '11','12','13','14','15','16','17','18','19', + '21','22','23','24','25','26','27','28','29', + '31','32','33','34','35','36','37','38','39', + '41','42','43','44','45','46','47','48','49', + '51','52','53','54','55','56','57','58','59', + '61','62','63','64','65','66','67','68','69', + '71','72','73','74','75','76','77','78','79', + '81','82','83','84','85','86','87','88','89', + '91','92','93','94','95','96','97','98','99', + '101','102','103','104','105','106','107','108','109', + '111','112','113','114','115','116','117','118','119', + '121','122','123','124','125','126','127','128','129', + '131','132','133','134','135','136','137','138','139', + '141','142','143','144','145','146','147','148','149', + '151','152','153','154','155','156','157','158','159', + '161','162','163','164','165','166','167','168','169', + '171','172','173','174','175','176','177','178','179', + '181','182','183','184','185','186','187','188','189', + '191','192','193','194','195','196','197','198','199', + '201','202','203','204','205','206','207','208','209', + '211','212','213','214','215','216','217','218','219', + '221','222','223','224','225','226','227','228','229', + '231','232','233','234','235','236','237','238','239', + '241','242','243','244','245','246','247','248','249', + '251','252','253','254','255','256','257','258','259', + '261','262','263','264','265','266','267','268','269', + '271','272','273','274','275','276','277','278','279', + '281','282','283','284','285','286','287','288','289', + '291','292','293','294','295','296','297','298','299' + )); +let $test_table_slave = CREATE TABLE t1 (a ENUM('44','54')); +let $test_insert = INSERT INTO t1 VALUES ('44'); +source include/test_fieldsize.inc; + +# +# Test: Checking MYSQL_TYPE_VARCHAR fields +# +--echo Checking MYSQL_TYPE_VARCHAR fields +let $test_table_master = CREATE TABLE t1 (a VARCHAR(2000)); +let $test_table_slave = CREATE TABLE t1 (a VARCHAR(100)); +let $test_insert = INSERT INTO t1 VALUES ('This is a test.'); +source include/test_fieldsize.inc; + +let $test_table_master = CREATE TABLE t1 (a VARCHAR(200)); +let $test_table_slave = CREATE TABLE t1 (a VARCHAR(10)); +let $test_insert = INSERT INTO t1 VALUES ('This is a test.'); +source include/test_fieldsize.inc; + +let $test_table_master = CREATE TABLE t1 (a VARCHAR(2000)); +let $test_table_slave = CREATE TABLE t1 (a VARCHAR(1000)); +let $test_insert = INSERT INTO t1 VALUES ('This is a test.'); +source include/test_fieldsize.inc; + +# +# Test: Checking MYSQL_TYPE_BLOB fields +# +--echo Checking MYSQL_TYPE_BLOB fields +let $test_table_master = CREATE TABLE t1 (a LONGBLOB); +let $test_table_slave = CREATE TABLE t1 (a TINYBLOB); +let $test_insert = INSERT INTO t1 VALUES ('This is a test.'); +source include/test_fieldsize.inc; + +connection slave; +call mtr.add_suppression("Slave SQL.*Table definition on master and slave does not match: Column 0 ...e mismatch.* error.* 1535"); +call mtr.add_suppression("Slave SQL.*Column 0 of table .test.t1. cannot be converted from type.* error.* 1677"); + +--echo *** Cleanup *** +connection master; +DROP TABLE IF EXISTS t1; +sync_slave_with_master; +# END 5.1 Test Case + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_conflicts.test b/mysql-test/suite/rpl/t/rpl_row_conflicts.test new file mode 100644 index 00000000..adf37d99 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_conflicts.test @@ -0,0 +1,33 @@ +# See the top of mysql-test/include/rpl_conflicts.test for +# explanation of what this test does. +# +# This test file is for row-logging mode. It runs the test twice, with +# slave_exec_mode=STRICT and slave_exec_mode=IDEMPOTENT, respectively. + +source include/have_binlog_format_row.inc; +source include/master-slave.inc; + +connection slave; +call mtr.add_suppression("Slave: Can\'t find record in \'t1\' error.* .*"); +call mtr.add_suppression("Can't find record in 't.'"); + +connection slave; +SET @old_slave_exec_mode= @@global.slave_exec_mode; + + +--echo ######## Run with slave_exec_mode=STRICT ######## + +SET @@global.slave_exec_mode = 'STRICT'; +source include/rpl_conflicts.test; + +--source include/rpl_reset.inc + + +--echo ######## Run with slave_exec_mode=IDEMPOTENT ######## + +set @@global.slave_exec_mode= 'IDEMPOTENT'; +source include/rpl_conflicts.test; + + +SET @@global.slave_exec_mode= @old_slave_exec_mode; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_corruption-slave.opt b/mysql-test/suite/rpl/t/rpl_row_corruption-slave.opt new file mode 100644 index 00000000..da199510 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_corruption-slave.opt @@ -0,0 +1 @@ +--replicate-ignore-table=test.t2_11753004_ign diff --git a/mysql-test/suite/rpl/t/rpl_row_corruption.test b/mysql-test/suite/rpl/t/rpl_row_corruption.test new file mode 100644 index 00000000..d78df905 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_corruption.test @@ -0,0 +1,115 @@ +# +--source include/have_debug.inc +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +# BUG#11753004: 44360: REPLICATION FAILED + +## assert that we get an error when checking the +## identifiers at the slave (instead of a crash or +## different table being updated) + +--let $t1= t1_11753004 +--let $t2= t2_11753004 +--let $t2_ign= t2_11753004_ign + +## test #1: assert that we get an error raised when multiple +## tables in the same RBR statement are mapped with the +## same identifier + +--eval CREATE TABLE $t1 (c1 INT) +--eval CREATE TABLE $t2 (c1 INT) +--eval INSERT INTO $t1 VALUES (1) +--eval INSERT INTO $t2 VALUES (2) + +--sync_slave_with_master +call mtr.add_suppression(".*Found table map event mapping table id 0 which was already mapped but with different settings.*"); + +# stop the slave and inject corruption +--source include/stop_slave.inc +SET @saved_debug= @@global.debug_dbug; +SET @@global.debug_dbug="d,inject_tblmap_same_id_maps_diff_table"; +--source include/start_slave.inc +--connection master +# both tables get mapped to 0 (in a way, simulating scenario +# originated by BUG#56226) +--eval UPDATE $t1, $t2 SET $t1.c1=3, $t2.c1=4 WHERE $t1.c1=1 OR $t2.c1=2 +--connection slave + +# wait for error 1593 (ER_SLAVE_FATAL_ERROR) +--let $slave_sql_errno=1593 +--source include/wait_for_slave_sql_error.inc +--source include/stop_slave.inc + +# clean up +SET @@global.debug_dbug=@saved_debug; +--source include/start_slave.inc +--connection master +--source include/rpl_reset.inc +--eval DROP TABLE $t1, $t2 +--sync_slave_with_master + +## test #2: assert that ignored tables that may have been mapped +## with the same identifier are skipped, thus no error +## is raised. + +--connection slave +--source include/stop_slave.inc +SET @@global.debug_dbug="d,inject_tblmap_same_id_maps_diff_table"; +--source include/start_slave.inc +--source include/rpl_reset.inc +--connection master +--eval CREATE TABLE $t1 (c1 INT) +--eval CREATE TABLE $t2_ign (c1 INT) +--eval INSERT INTO $t1 VALUES (1) +--eval INSERT INTO $t2_ign VALUES (2) +--eval UPDATE $t1, $t2_ign SET $t1.c1=3, $t2_ign.c1=4 WHERE $t1.c1=1 OR $t2_ign.c1=2 + +# must not raise error as second table is filtered +--sync_slave_with_master + + +## test #3: check that BINLOG statements will also raise an +## error if containing table map events mapping different +## tables to same table identifier. + +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); + +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1); + +# FD event +BINLOG ' +SOgWTg8BAAAAbgAAAHIAAAAAAAQANS42LjMtbTUtZGVidWctbG9nAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAABI6BZOEzgNAAgAEgAEBAQEEgAAVgAEGggAAAAICAgCAAAAAAVAYI8= +'/*!*/; + +#110708 12:21:44 server id 1 end_log_pos 774 Table_map: `test`.`t1` mapped to number 66 +# at 774 +#110708 12:21:44 server id 1 end_log_pos 815 Table_map: `test`.`t2` mapped to number 67 +# at 815 +#110708 12:21:44 server id 1 end_log_pos 855 Update_rows: table id 66 +# at 855 +#110708 12:21:44 server id 1 end_log_pos 895 Update_rows: table id 67 flags: STMT_END_F +SET @@global.debug_dbug="d,inject_tblmap_same_id_maps_diff_table"; +--error ER_SLAVE_FATAL_ERROR +BINLOG ' +SOgWThMBAAAAKQAAAAYDAAAAAEIAAAAAAAEABHRlc3QAAnQxAAEDAAE= +SOgWThMBAAAAKQAAAC8DAAAAAEMAAAAAAAEABHRlc3QAAnQyAAEDAAE= +SOgWThgBAAAAKAAAAFcDAAAAAEIAAAAAAAAAAf///gEAAAD+AwAAAA== +SOgWThgBAAAAKAAAAH8DAAAAAEMAAAAAAAEAAf///gEAAAD+BAAAAA== +'/*!*/; + + +# clean up +DROP TABLE t1,t2; +--connection slave +SET @@global.debug_dbug=@saved_debug; +--connection master +--eval DROP TABLE $t1 +--eval DROP TABLE $t2_ign +--sync_slave_with_master +SET @@global.debug_dbug= @save_debug; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_create_select.test b/mysql-test/suite/rpl/t/rpl_row_create_select.test new file mode 100644 index 00000000..d870b68f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_create_select.test @@ -0,0 +1,30 @@ +# Testing table creations for row-based replication. + +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +--echo # +--echo # BUG#17994219: CREATE TABLE .. SELECT PRODUCES INVALID STRUCTURE, +--echo # BREAKS RBR +--echo # + +connection master; +--echo #After the patch, the display width is set to a default +--echo #value of 21. +SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR +CREATE TABLE t1 AS SELECT REPEAT('A', 1000) DIV 1 AS a; +SHOW CREATE TABLE t1; + +SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR +CREATE TABLE t2 AS SELECT CONVERT(REPEAT('A', 255) USING UCS2) DIV 1 AS a; +SHOW CREATE TABLE t2; + +--echo #After the patch, no error is reported. +sync_slave_with_master; + +connection master; +DROP TABLE t1; +DROP TABLE t2; + +--source include/rpl_end.inc + diff --git a/mysql-test/suite/rpl/t/rpl_row_create_table.test b/mysql-test/suite/rpl/t/rpl_row_create_table.test new file mode 100644 index 00000000..b62955e2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_create_table.test @@ -0,0 +1,285 @@ +# Testing table creations for row-based replication. + +--source include/have_binlog_format_row.inc +--source include/have_innodb.inc +--source include/master-slave.inc +connection slave; +--source include/have_innodb.inc +connection master; + +# Set the default storage engine to different values on master and +# slave. We need to stop the slave for the server variable to take +# effect, since the variable is only read on start-up. +sync_slave_with_master; +--disable_query_log +set @@default_storage_engine = @@global.default_storage_engine; +STOP SLAVE; +--source include/wait_for_slave_to_stop.inc +SET GLOBAL default_storage_engine=memory; +START SLAVE; +--source include/wait_for_slave_to_start.inc +--enable_query_log + +--source include/rpl_reset.inc + +connection master; +CREATE TABLE t1 (a INT); +CREATE OR REPLACE TABLE t1 (a INT, b INT); +CREATE TABLE t2 (a INT, b INT) ENGINE=Merge; +CREATE TABLE t3 (a INT, b INT) CHARSET=utf8; +CREATE TABLE t4 (a INT, b INT) ENGINE=Merge CHARSET=utf8; +--source include/show_binlog_events.inc +--query_vertical SHOW CREATE TABLE t1 +--query_vertical SHOW CREATE TABLE t2 +--query_vertical SHOW CREATE TABLE t3 +sync_slave_with_master; +--query_vertical SHOW CREATE TABLE t1 +--query_vertical SHOW CREATE TABLE t2 +--query_vertical SHOW CREATE TABLE t3 + +connection master; +CREATE TABLE t5 (b INT, c INT) SELECT * FROM t3; + +CREATE TEMPORARY TABLE tt3 (a INT, b INT); +INSERT INTO tt3 VALUES (1,2), (2,4), (3,6), (4,2), (5,10), (6,12); +CREATE TABLE t6 (b INT, c INT) SELECT * FROM tt3; +--query_vertical SHOW CREATE TABLE t5 +SELECT * FROM t5 ORDER BY a,b,c; +--query_vertical SHOW CREATE TABLE t6 +SELECT * FROM t6 ORDER BY a,b,c; +sync_slave_with_master; +--query_vertical SHOW CREATE TABLE t5 +SELECT * FROM t5 ORDER BY a,b,c; +--query_vertical SHOW CREATE TABLE t6 +SELECT * FROM t6 ORDER BY a,b,c; + +--source include/rpl_reset.inc + +connection master; +# Test for erroneous constructions +--error ER_DUP_ENTRY +CREATE TABLE t7 (UNIQUE(b)) SELECT a,b FROM tt3; +# Shouldn't be written to the binary log +--source include/show_binlog_events.inc + +# Test that INSERT-SELECT works the same way as for SBR. +CREATE TABLE t7 (a INT, b INT UNIQUE); +--error ER_DUP_ENTRY +INSERT INTO t7 SELECT a,b FROM tt3; +SELECT * FROM t7 ORDER BY a,b; +# Should be written to the binary log +--source include/show_binlog_events.inc +sync_slave_with_master; +SELECT * FROM t7 ORDER BY a,b; + +--source include/rpl_reset.inc + +connection master; +CREATE TEMPORARY TABLE tt4 (a INT, b INT); +INSERT INTO tt4 VALUES (4,8), (5,10), (6,12); +BEGIN; +INSERT INTO t7 SELECT a,b FROM tt4; +ROLLBACK; +--source include/show_binlog_events.inc +SELECT * FROM t7 ORDER BY a,b; +sync_slave_with_master; +SELECT * FROM t7 ORDER BY a,b; + +--source include/rpl_reset.inc + +connection master; +CREATE TABLE t8 LIKE t4; +CREATE TABLE t9 LIKE tt4; +CREATE TEMPORARY TABLE tt5 LIKE t4; +CREATE TEMPORARY TABLE tt6 LIKE tt4; +CREATE TEMPORARY TABLE tt7 SELECT 1; +--query_vertical SHOW CREATE TABLE t8 +--query_vertical SHOW CREATE TABLE t9 +--source include/show_binlog_events.inc +sync_slave_with_master; +--query_vertical SHOW CREATE TABLE t8 +--query_vertical SHOW CREATE TABLE t9 + +connection master; +DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8,t9; +sync_slave_with_master; +# Here we reset the value of the default storage engine +STOP SLAVE; +--source include/wait_for_slave_to_stop.inc +SET GLOBAL default_storage_engine=@@default_storage_engine; +START SLAVE; +--source include/wait_for_slave_to_start.inc +--enable_ps_protocol + +# BUG#22864 (Rollback following CREATE ... SELECT discards 'CREATE +# table' from log): +--echo ================ BUG#22864 ================ + +--source include/rpl_reset.inc + +connection master; +SET AUTOCOMMIT=0; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2),(3); + +CREATE TABLE t2 ENGINE=INNODB SELECT * FROM t1; +ROLLBACK; + +CREATE TABLE t3 ENGINE=INNODB SELECT * FROM t1; +INSERT INTO t3 VALUES (4),(5),(6); +ROLLBACK; + +CREATE TABLE t4 ENGINE=INNODB SELECT * FROM t1; +INSERT INTO t1 VALUES (4),(5),(6); +ROLLBACK; + +SHOW TABLES; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; +SELECT * FROM t4 ORDER BY a; +--source include/show_binlog_events.inc +sync_slave_with_master; +SHOW TABLES; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; +SELECT * FROM t4 ORDER BY a; + +connection master; +DROP TABLE IF EXISTS t1,t2,t3,t4; +SET AUTOCOMMIT=1; +sync_slave_with_master; + +# Some tests with temporary tables +--source include/rpl_reset.inc + +connection master; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2),(3); + +CREATE TABLE t2 (a INT) ENGINE=INNODB; + +BEGIN; +INSERT INTO t2 SELECT a*a FROM t1; +CREATE TEMPORARY TABLE tt1 +SELECT a+1 AS a + FROM t1 + WHERE a MOD 2 = 1; +INSERT INTO t2 SELECT a+2 FROM tt1; +COMMIT; + +SELECT * FROM t2 ORDER BY a; +--source include/show_binlog_events.inc +sync_slave_with_master; +SELECT * FROM t2 ORDER BY a; + +connection master; +TRUNCATE TABLE t2; +sync_slave_with_master; + +--source include/rpl_reset.inc + +connection master; +BEGIN; +INSERT INTO t2 SELECT a*a FROM t1; +CREATE TEMPORARY TABLE tt2 +SELECT a+1 AS a + FROM t1 + WHERE a MOD 2 = 1; +INSERT INTO t2 SELECT a+2 FROM tt2; +ROLLBACK; + +SELECT * FROM t2 ORDER BY a; +source include/show_binlog_events.inc; +sync_slave_with_master; +SELECT * FROM t2 ORDER BY a; + +connection master; +DROP TABLE t1,t2; +sync_slave_with_master; + +# +# bug#35762 Failing CREATE-SELECT produces bad binlog in row mode +# + +connection master; + +CREATE TABLE t1 (a INT); + +INSERT INTO t1 VALUES (1),(1); +--error ER_DUP_ENTRY +CREATE TABLE t2 (a INT UNIQUE) ENGINE=INNODB SELECT * FROM t1; +INSERT INTO t1 VALUES (2); + +sync_slave_with_master; +# connection slave; + +--echo *** the proof of the fix: +--echo select must show that the last insert performed on the slave *** +SELECT * FROM t1; + +connection master; +DROP TABLE t1; +sync_slave_with_master; + +# +# BUG#34707: Row based replication: slave creates table within wrong database +# + +--source include/rpl_reset.inc + +connection master; +--disable_warnings +DROP DATABASE IF EXISTS mysqltest1; +--enable_warnings +CREATE DATABASE mysqltest1; + +CREATE TABLE mysqltest1.without_select (f1 BIGINT); +CREATE TABLE mysqltest1.with_select AS SELECT 1 AS f1; +source include/show_binlog_events.inc; +sync_slave_with_master; + +connection master; +DROP DATABASE mysqltest1; +sync_slave_with_master; + +# +# BUG#48506: crash in CREATE TABLE <existing_view> IF NOT EXISTS LIKE +# <tmp_tbl> with RBL +# + +--source include/rpl_reset.inc + +connection master; +CREATE TEMPORARY TABLE t7(c1 INT); +CREATE TABLE t5(c1 INT); +CREATE TABLE t4(c1 INT); +CREATE VIEW bug48506_t1 AS SELECT 1; +CREATE VIEW bug48506_t2 AS SELECT * FROM t4; +CREATE VIEW bug48506_t3 AS SELECT t5.c1 AS A, t4.c1 AS B FROM t5, t4; +CREATE TABLE bug48506_t4(c1 INT); +--disable_warnings +sync_slave_with_master; +DROP VIEW bug48506_t1, bug48506_t2, bug48506_t3; +DROP TABLE bug48506_t4; + +connection master; +CREATE TABLE IF NOT EXISTS bug48506_t1 LIKE t7; +CREATE TABLE IF NOT EXISTS bug48506_t2 LIKE t7; +CREATE TABLE IF NOT EXISTS bug48506_t3 LIKE t7; +CREATE TABLE IF NOT EXISTS bug48506_t4 LIKE t7; +--enable_warnings +sync_slave_with_master; + +SHOW TABLES LIKE 'bug48506%'; + +connection master; +DROP VIEW IF EXISTS bug48506_t1, bug48506_t2, bug48506_t3; +DROP TEMPORARY TABLES t7; +DROP TABLES t4, t5; +DROP TABLES IF EXISTS bug48506_t4; + +--source include/rpl_end.inc + +--echo end of the tests diff --git a/mysql-test/suite/rpl/t/rpl_row_delayed_ins.test b/mysql-test/suite/rpl/t/rpl_row_delayed_ins.test new file mode 100644 index 00000000..603af398 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_delayed_ins.test @@ -0,0 +1,2 @@ +let $engine_type=myisam; +-- source include/rpl_row_delayed_ins.test diff --git a/mysql-test/suite/rpl/t/rpl_row_drop.test b/mysql-test/suite/rpl/t/rpl_row_drop.test new file mode 100644 index 00000000..4df6e2ad --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_drop.test @@ -0,0 +1,38 @@ +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + +# Bug#12415: DROP of temporary table on master stops slave +connection master; +CREATE TABLE t1 (a int); +CREATE TABLE t2 (a int); +CREATE TEMPORARY TABLE t2 (a int, b int); +SHOW TABLES; +sync_slave_with_master; +SHOW TABLES; +connection master; +DROP TABLE t2; # Dropping the temporary table +SHOW TABLES; +sync_slave_with_master; +SHOW TABLES; # There should be two tables on the slave + +connection master; +CREATE TEMPORARY TABLE t2 (a int, b int); +SHOW TABLES; +sync_slave_with_master; +SHOW TABLES; +connection master; +# Should drop the non-temporary table t1 and the temporary table t2 +DROP TABLE t1,t2; +source include/show_binlog_events.inc; +SHOW TABLES; +sync_slave_with_master; +SHOW TABLES; + +--disable_query_log +--disable_warnings +connection master; +DROP TABLE IF EXISTS t2; +sync_slave_with_master; +--enable_warnings +--enable_query_log +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_drop_create_temp_table.test b/mysql-test/suite/rpl/t/rpl_row_drop_create_temp_table.test new file mode 100644 index 00000000..bc5c6074 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_drop_create_temp_table.test @@ -0,0 +1,11 @@ +################################################################################### +# This test cases evaluates the mixture of non-transactional and transcational +# tables. Specifically when drop temporary tables and create temporary tables +# are used. +################################################################################### +--source include/have_binlog_format_row.inc +--source include/have_innodb.inc +--source include/master-slave.inc + +--source include/rpl_drop_create_temp_table.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_drop_temp_table.test b/mysql-test/suite/rpl/t/rpl_row_drop_temp_table.test new file mode 100644 index 00000000..ba3770d3 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_drop_temp_table.test @@ -0,0 +1,54 @@ +# ==== Purpose ==== +# +# Test verifies that plain DROP TEMPORARY TABLE IF EXISTS statements are not +# replicated during row based replication. +# +# ==== Implementation ==== +# +# Steps: +# 0 - Have a read_only master and slave. Binlog format should be "ROW". +# 1 - Create a procedure which executes DROP TEMPORARY TABLE IF EXISTS +# statements prior to CREATE TEMPORARY TABLE. +# 2 - Execute the procedure. +# 3 - Verify that the DROP TEMPORARY TABLE IF EXISTS statements within the +# procedure are not written to the binary log. +# +# ==== References ==== +# +# MDEV-20091: DROP TEMPORARY table is logged despite no CREATE was logged +# + +--source include/have_binlog_format_row.inc +--source include/have_innodb.inc +--source include/master-slave.inc + +connection slave; +SET GLOBAL read_only=1; + +connection master; +DELIMITER |; +CREATE PROCEDURE testproc() +BEGIN + DROP TEMPORARY TABLE IF EXISTS t1_tmp; + DROP TEMPORARY TABLE IF EXISTS t2_tmp; + CREATE TEMPORARY TABLE IF NOT EXISTS t1_tmp ( t1 varchar(400) DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8; + CREATE TEMPORARY TABLE IF NOT EXISTS t2_tmp ( t2 varchar(16) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +END| +DELIMITER ;| +SET GLOBAL read_only=1; +CALL testproc(); +--echo ******** None of the above DROP TEMPORARY TABLE statement should be found in binary log ******** +--source include/show_binlog_events.inc +--sync_slave_with_master +SELECT @@read_only; + +--echo ======== CLEAN UP ========= +connection master; +DROP TEMPORARY TABLE t1_tmp; +DROP TEMPORARY TABLE t2_tmp; +DROP PROCEDURE testproc; +SET GLOBAL read_only=0; +--sync_slave_with_master +SET GLOBAL read_only=0; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_end_of_statement_loss-master.opt b/mysql-test/suite/rpl/t/rpl_row_end_of_statement_loss-master.opt new file mode 100644 index 00000000..144bbca0 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_end_of_statement_loss-master.opt @@ -0,0 +1,2 @@ +--binlog-row-event-max-size=8192 + diff --git a/mysql-test/suite/rpl/t/rpl_row_end_of_statement_loss.test b/mysql-test/suite/rpl/t/rpl_row_end_of_statement_loss.test new file mode 100644 index 00000000..5b2d99f3 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_end_of_statement_loss.test @@ -0,0 +1,66 @@ +--source include/have_debug.inc +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +# Loss of STMT_END flagged event must error out the IO thread +--connection slave +call mtr.add_suppression("Slave IO thread did not receive an expected Rows-log end-of-statement"); +call mtr.add_suppression("Relay log write failure: could not queue event from master"); + +SET @save_debug= @@global.debug; +SET GLOBAL debug_dbug="+d,simulate_stmt_end_rows_event_loss"; +--source include/stop_slave.inc +--replace_result $MASTER_MYPORT MASTER_PORT +--eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $MASTER_MYPORT, MASTER_USE_GTID=SLAVE_POS + +--connection master +--let $max_row_size=8192 +--eval CREATE TABLE t (a INT, b text($max_row_size)); +--eval INSERT INTO t values (1, repeat('b', $max_row_size)), (1, repeat('b', $max_row_size)) + +# Prove that the missed STMT_END marked rows-event causes the io thread stop. +--connection slave +START SLAVE IO_THREAD; +--let $slave_io_errno=1595 +--source include/wait_for_slave_io_error.inc +SET GLOBAL debug_dbug="-d,simulate_stmt_end_rows_event_loss"; +--source include/start_slave.inc + +--connection master +sync_slave_with_master; + +# Compressed version of the above +--connection slave +--source include/stop_slave.inc + +--connection master +SET @save_log_bin_compress= @@GLOBAL.log_bin_compress; +SET @save_log_bin_compress_min_len= @@GLOBAL.log_bin_compress_min_len; + +SET @@GLOBAL.log_bin_compress=ON; +SET @@GLOBAL.log_bin_compress_min_len=10; + +--eval INSERT INTO t values (2, repeat('b', $max_row_size)), (2, repeat('b', $max_row_size)) + +# Prove that the missed STMT_END marked rows-event causes the io thread stop. +--connection slave +SET GLOBAL debug_dbug="+d,simulate_stmt_end_rows_event_loss"; +START SLAVE IO_THREAD; +--let $slave_io_errno=1595 +--source include/wait_for_slave_io_error.inc +SET GLOBAL debug_dbug="-d,simulate_stmt_end_rows_event_loss"; +--source include/start_slave.inc + +--connection master +sync_slave_with_master; + +# cleanup + +--connection master +SET @@GLOBAL.log_bin_compress= @save_log_bin_compress; +SET @@GLOBAL.log_bin_compress_min_len= @save_log_bin_compress_min_len; +DROP TABLE t; +sync_slave_with_master; +SET GLOBAL debug_dbug= @save_debug; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_err_daisychain-master.opt b/mysql-test/suite/rpl/t/rpl_row_err_daisychain-master.opt new file mode 100644 index 00000000..83ed8522 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_err_daisychain-master.opt @@ -0,0 +1 @@ +--binlog-format=row diff --git a/mysql-test/suite/rpl/t/rpl_row_err_daisychain-slave.opt b/mysql-test/suite/rpl/t/rpl_row_err_daisychain-slave.opt new file mode 100644 index 00000000..4cb7a31d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_err_daisychain-slave.opt @@ -0,0 +1 @@ +--binlog-format=statement --log-slave-updates diff --git a/mysql-test/suite/rpl/t/rpl_row_find_row.test b/mysql-test/suite/rpl/t/rpl_row_find_row.test new file mode 100644 index 00000000..444706ac --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_find_row.test @@ -0,0 +1,103 @@ +# BUG#47312: RBR: Disabling key on slave breaks replication: +# HA_ERR_WRONG_INDEX +# +# Description +# =========== +# +# This test case checks whether disabling a key on a slave breaks +# replication or not. +# +# Case #1, shows that while not using ALTER TABLE... DISABLE KEYS and +# the slave has no key defined while the master has one, replication +# won't break. +# +# Case #2, shows that before patch for BUG#47312, if defining key on +# slave table, and later disable it, replication would break. This +# has been fixed. +# + +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + +# +# Case #1: master has key, but slave has not. +# Replication does not break. +# + +SET SQL_LOG_BIN=0; +CREATE TABLE t (a int, b int, c int, key(b)); +SET SQL_LOG_BIN=1; + +-- connection slave + +CREATE TABLE t (a int, b int, c int); + +-- connection master + +INSERT INTO t VALUES (1,2,4); +INSERT INTO t VALUES (4,3,4); +DELETE FROM t; + +-- sync_slave_with_master + +-- connection master +DROP TABLE t; + +-- sync_slave_with_master + +# +# Case #2: master has key, slave also has one, +# but it gets disabled sometime. +# Replication does not break anymore. +# +--source include/rpl_reset.inc +-- connection master + +CREATE TABLE t (a int, b int, c int, key(b)); + +-- sync_slave_with_master + +ALTER TABLE t DISABLE KEYS; + +-- connection master + +INSERT INTO t VALUES (1,2,4); +INSERT INTO t VALUES (4,3,4); +DELETE FROM t; + +-- sync_slave_with_master + +-- connection master +DROP TABLE t; + +-- sync_slave_with_master + +# +# BUG#53893: RBR: nullable unique key can lead to out-of-sync slave +# + +# +# We insert two rows. Both with part of UNIQUE KEY set to null. +# Then we update the last row inserted. On master the correct +# row is updated. On the slave the wrong row would be updated +# because the engine would look it up by the NULL Unique KEY. +# As a consquence, the wrong row would be updated. +# + +-- source include/rpl_reset.inc +-- connection master + +CREATE TABLE t1 (c1 INT NOT NULL, c2 INT NOT NULL, c3 INT, UNIQUE KEY(c1,c3), KEY(c2)); +INSERT INTO t1(c1,c2) VALUES(1,1); +INSERT INTO t1(c1,c2) VALUES(1,2); +UPDATE t1 SET c1=1000 WHERE c2=2; +-- sync_slave_with_master + +-- let $diff_tables= master:t1, slave:t1 +-- source include/diff_tables.inc + +-- connection master +DROP TABLE t1; +-- sync_slave_with_master + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_find_row_debug.test b/mysql-test/suite/rpl/t/rpl_row_find_row_debug.test new file mode 100644 index 00000000..e3edabe2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_find_row_debug.test @@ -0,0 +1,57 @@ +# +# Bug#11760927: 53375: RBR + NO PK => HIGH LOAD ON SLAVE (TABLE SCAN/CPU) => SLAVE FAILURE +# +--source include/have_binlog_format_row.inc +--source include/have_debug.inc +--source include/master-slave.inc + +# SETUP +# - setup log_warnings and debug +--connection slave +--source include/stop_slave.inc +SET @saved_dbug = @@GLOBAL.debug_dbug; +--let $log_warnings_save= `SELECT @@GLOBAL.log_warnings` + +SET GLOBAL log_warnings = 2; + +let $log_error_= `SELECT @@GLOBAL.log_error`; +if(!$log_error_) +{ + # MySQL Server on windows is started with --console and thus + # does not know the location of its .err log, use default location + let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.2.err; +} + +# Assign env variable LOG_ERROR +let LOG_ERROR=$log_error_; + +# force printing the notes to the error log +SET GLOBAL debug_dbug="d,inject_long_find_row_note"; +--source include/start_slave.inc + +# test +--connection master +CREATE TABLE t1 (c1 INT); +--sync_slave_with_master +--connection master + +INSERT INTO t1 VALUES (1), (2); +UPDATE t1 SET c1= 1000 WHERE c1=2; +DELETE FROM t1; +DROP TABLE t1; +--sync_slave_with_master + +--echo # Check if any note related to long DELETE_ROWS and UPDATE_ROWS appears in the error log +--let SEARCH_FILE=$log_error_ +--let SEARCH_PATTERN=The slave is applying a ROW event on behalf of an UPDATE statement on table t1 and is currently taking a considerable amount +--source include/search_pattern_in_file.inc +--let SEARCH_PATTERN=The slave is applying a ROW event on behalf of a DELETE statement on table t1 and is currently taking a considerable amount +--source include/search_pattern_in_file.inc + +# cleanup +--source include/stop_slave.inc +SET @@GLOBAL.debug_dbug = @saved_dbug; +--eval SET GLOBAL log_warnings = $log_warnings_save +--source include/start_slave.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_flsh_tbls.test b/mysql-test/suite/rpl/t/rpl_row_flsh_tbls.test new file mode 100644 index 00000000..c10b3570 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_flsh_tbls.test @@ -0,0 +1,7 @@ +# depends on the binlog output +-- source include/have_binlog_format_row.inc +--source include/binlog_start_pos.inc + +let $rename_event_pos= `select @binlog_start_pos + 819`; + +-- source include/rpl_flsh_tbls.test diff --git a/mysql-test/suite/rpl/t/rpl_row_func001.test b/mysql-test/suite/rpl/t/rpl_row_func001.test new file mode 100644 index 00000000..2327ba9a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_func001.test @@ -0,0 +1,60 @@ +############################################################################# +# This test is being created to test out the non deterministic items with # +# row based replication. # +# Original Author: JBM # +# Original Date: Aug/10/2005 # +# Update: 08/29/2005 change name to initails # +############################################################################# + +# Includes +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + + +# Begin clean up test section +connection master; +--disable_warnings +--error 0,1305 +DROP FUNCTION test.f1; +DROP TABLE IF EXISTS test.t1; + + +--enable_warnings + +# Section 1 test from bug #12487 Uses stored function to insert rows to see what is replicated. + +create table test.t1 (a int, PRIMARY KEY(a)); + +delimiter //; +create function test.f1(i int) returns int +begin +insert into test.t1 values(i); +return 0; +end// +delimiter ;// + +--disable_ps2_protocol +select test.f1(1); +select test.f1(2); +--enable_ps2_protocol +select * from test.t1; + +save_master_pos; +sync_slave_with_master; +connection slave; +#show create table test.t1; +select * from test.t1; + +connection master; + +#Used for debugging +#show binlog events; + +# Cleanup + +DROP FUNCTION test.f1; +DROP TABLE test.t1; +sync_slave_with_master; + +# End of 5.0 test case +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_func002.test b/mysql-test/suite/rpl/t/rpl_row_func002.test new file mode 100644 index 00000000..2f4e3fdd --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_func002.test @@ -0,0 +1,105 @@ +############################################################################# +# This test is being created to test out the non deterministic items with # +# row based replication. # +# Original Author: JBM # +# Original Date: Aug/10/2005 # +# Update: 08/29/2005 Turn on diff # +############################################################################# +# Note: Many lines are commented out in this test case. These were used for # +# creating the test case and debugging and are being left for # +# debugging, but they can not be used for the regular testing as the # +# Time changes and is not deteministic, so instead we dump both the # +# master and slave and diff the dumps. If the dumps differ then the # +# test case will fail. To run during diff failuers, comment out the # +# diff. # +############################################################################# + +# Includes +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + + +# Begin clean up test section +connection master; +--disable_warnings +--error 0,1305 +DROP FUNCTION test.f1; +DROP TABLE IF EXISTS test.t1; +DROP TABLE IF EXISTS test.t2; + +--enable_warnings + +# Section 1 test from Peter G. This test changes uses a stored function to update rows and return the timestamp. We change the value of the time stamp on the master to see what is replicated. + +CREATE TABLE test.t1 (a INT NOT NULL AUTO_INCREMENT, t TIMESTAMP, t2 TIMESTAMP, PRIMARY KEY(a)); +CREATE TABLE test.t2 (a INT NOT NULL AUTO_INCREMENT, t TIMESTAMP, t2 TIMESTAMP, PRIMARY KEY(a)); + +delimiter //; +create function test.f1() RETURNS TIMESTAMP +BEGIN +UPDATE test.t1 SET t = CURRENT_TIMESTAMP; +RETURN CURRENT_TIMESTAMP; +END// +delimiter ;// + +INSERT INTO test.t2 VALUES (null,f1(),CURRENT_TIMESTAMP); +#select * from test.t1; +#save_master_pos; +#sync_slave_with_master; +#connection slave; +#select * from test.t1; +#connection master; + + +SET TIMESTAMP=2; +INSERT INTO test.t2 VALUES (null,f1(),CURRENT_TIMESTAMP); +#select * from test.t1; +#save_master_pos; +#sync_slave_with_master; +#connection slave; +#select * from test.t1; +#connection master; + +#sleep 3; +SET TIMESTAMP=1; +INSERT INTO test.t2 VALUES (null,f1(),CURRENT_TIMESTAMP); +#select * from test.t1; +#save_master_pos; +#sync_slave_with_master; +#connection slave; +#select * from test.t1; +#connection master; + + +SET TIMESTAMP=333300000; +INSERT INTO test.t2 VALUES (null,f1(),CURRENT_TIMESTAMP); + +# We need a sync to ensure that the slave has caught up before +# dumping the database. +sync_slave_with_master; + +connection master; +#Used for debugging +#show binlog events; + +# time to dump the databases and so we can see if they match + +--exec $MYSQL_DUMP --compact --order-by-primary --skip-extended-insert --no-create-info test > $MYSQLTEST_VARDIR/tmp/func002_master.sql +--exec $MYSQL_DUMP_SLAVE --compact --order-by-primary --skip-extended-insert --no-create-info test > $MYSQLTEST_VARDIR/tmp/func002_slave.sql + +# Cleanup +DROP FUNCTION test.f1; +DROP TABLE test.t1; +DROP TABLE test.t2; +sync_slave_with_master; + +# the test will show that the diff statement failed and no reject file +# will be created. You will need to go to the mysql-test dir and diff +# the files your self to see what is not matching :-). The files are located +# in mysql-test/var/tmp + +diff_files $MYSQLTEST_VARDIR/tmp/func002_master.sql $MYSQLTEST_VARDIR/tmp/func002_slave.sql; + +# End of 5.0 test case + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_func003.test b/mysql-test/suite/rpl/t/rpl_row_func003.test new file mode 100644 index 00000000..def987fa --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_func003.test @@ -0,0 +1,12 @@ +################################### +# Wrapper for rpl_row_func003.test# +################################### +######################################################## +# By JBM 2005-02-15 Wrapped to allow reuse of test code# +######################################################## +-- source include/have_innodb.inc +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc +let $engine_type=INNODB; +-- source include/rpl_row_func003.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_idempotency.test b/mysql-test/suite/rpl/t/rpl_row_idempotency.test new file mode 100644 index 00000000..85775832 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_idempotency.test @@ -0,0 +1,333 @@ +# Testing various forms of idempotency for replication. This file is +# for tests that should only be executed in row mode. + +source include/have_binlog_format_row.inc; +source include/master-slave.inc; +connection master; +source include/have_innodb.inc; +connection slave; +source include/have_innodb.inc; + +# Add suppression for expected warning(s) in slaves error log +call mtr.add_suppression("Can.t find record in .t[12].* error.* 1032"); +call mtr.add_suppression("Cannot delete or update a parent row: a foreign key constraint fails .* error.* 1451"); +call mtr.add_suppression("Cannot add or update a child row: a foreign key constraint fails .* error.* 1452"); +call mtr.add_suppression("Duplicate entry .1. for key .PRIMARY.* error.* 1062"); +call mtr.add_suppression("Can't find record in 't1'"); +call mtr.add_suppression("Can't find record in 't2'"); + + +# bug#31609 Not all RBR slave errors reported as errors +# bug#31552 Replication breaks when deleting rows from out-of-sync table +# without PK + +# The default for slave-exec-mode option and server +# variable slave_exec_mode is 'STRICT'. +# When 'STRICT' mode is set, the slave SQL thread will stop whenever +# the row to change is not found. In 'IDEMPOTENT' mode, the SQL thread +# will continue running and apply the row - replace if it's Write_rows event - +# or skip to the next event. + +# the previous part of the tests was with IDEMPOTENT slave's mode. + + +# +# Other than above idempotent errors dealing with foreign keys constraint +# +connection slave; + +set @old_slave_exec_mode= @@global.slave_exec_mode; +set @@global.slave_exec_mode= IDEMPOTENT; + +connection master; + +create table ti1 (b int primary key) engine = innodb; +create table ti2 (a int primary key, b int, foreign key (b) references ti1(b)) + engine = innodb; +set foreign_key_checks=1 /* ensure the check */; + +insert into ti1 values (1),(2),(3); +insert into ti2 set a=2, b=2; + +sync_slave_with_master; + +#connection slave; +select * from ti1 order by b /* must be (1),(2),(3) */; +insert into ti2 set a=1, b=1; +select * from ti2 order by b /* must be (1,1) (2,2) */; + +connection master; + +# from now on checking rbr specific idempotent errors +set @save_binlog_format= @@session.binlog_format; +set @@session.binlog_format= row; +delete from ti1 where b=1; + +select * from ti1 order by b /* must be (2),(3) */; + +# slave must catch up (expect some warnings in error.log) +sync_slave_with_master; + +#connection slave; +select * from ti1 order by b /* must stays as were on master (1),(2),(3) */; + +delete from ti1 where b=3; + +connection master; +insert into ti2 set a=3, b=3; + +# slave must catch up (expect some warnings in error.log) +sync_slave_with_master; + +#connection slave; +select * from ti2 order by b /* must be (1,1),(2,2) - not inserted */; + + +# +# Checking the new global sys variable +# + +connection slave; + +set global slave_exec_mode='IDEMPOTENT'; +set global slave_exec_mode='STRICT'; + +# checking mutual exclusion for the options +--error ER_WRONG_VALUE_FOR_VAR +set global slave_exec_mode='IDEMPOTENT,STRICT'; + +select @@global.slave_exec_mode /* must be STRICT */; + +# +# Checking stops. +# In the following sections strict slave sql thread is going to +# stop when faces an idempotent error. In order to proceed +# the mode is temporarily switched to indempotent. +# + +# +--echo *** foreign keys errors as above now forces to stop +# + +connection master; + +set foreign_key_checks=0; +drop table ti2, ti1; + +create table ti1 (b int primary key) engine = innodb; +create table ti2 (a int primary key, b int, foreign key (b) references ti1(b)) + engine = innodb; +set foreign_key_checks=1 /* ensure the check */; + +insert into ti1 values (1),(2),(3); +insert into ti2 set a=2, b=2; + +sync_slave_with_master; + +#connection slave; +select * from ti1 order by b /* must be (1),(2),(3) */; +--echo *** conspire future problem +insert into ti2 set a=1, b=1; +select * from ti2 order by b /* must be (1,1) (2,2) */; + +connection master; + +delete from ti1 where b=1 /* offending delete event */; +select * from ti1 order by b /* must be (2),(3) */; + +# foreign key: row is referenced + +--echo *** slave must stop (Trying to delete a referenced foreing key) +connection slave; +source include/wait_for_slave_sql_to_stop.inc; + +let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1); +disable_query_log; +eval SELECT "$last_error" AS Last_SQL_Error; +enable_query_log; + +select * from ti1 order by b /* must be (1),(2),(3) - not deleted */; +set foreign_key_checks= 0; +delete from ti2 where b=1; +set foreign_key_checks= 1; +set global slave_exec_mode='IDEMPOTENT'; +start slave sql_thread; +connection master; +sync_slave_with_master; +#connection slave; +set global slave_exec_mode='STRICT'; + +connection master; + +sync_slave_with_master; + +#connection slave; +--echo *** conspire the following insert failure +# foreign key: no referenced row + +--echo *** conspire future problem +delete from ti1 where b=3; + +connection master; +insert into ti2 set a=3, b=3 /* offending write event */; + +--echo *** slave must stop (Trying to insert an invalid foreign key) +connection slave; +source include/wait_for_slave_sql_to_stop.inc; + +let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1); +disable_query_log; +eval SELECT "$last_error" AS Last_SQL_Error; +enable_query_log; + +select * from ti2 order by b /* must be (2,2) */; +set foreign_key_checks= 0; +insert into ti1 set b=3; +set foreign_key_checks= 1; +set global slave_exec_mode='IDEMPOTENT'; +start slave sql_thread; +connection master; +sync_slave_with_master; +#connection slave; +set global slave_exec_mode='STRICT'; + +connection master; + +sync_slave_with_master; + +select * from ti2 order by b /* must be (2,2),(3,3) */; + +# +--echo *** other errors +# + +# dup key insert + +#connection slave; +--echo *** conspiring query +insert into ti1 set b=1; + +connection master; +insert into ti1 set b=1 /* offending write event */; + +--echo *** slave must stop (Trying to insert a dupliacte key) +connection slave; +source include/wait_for_slave_sql_to_stop.inc; + +let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1); +disable_query_log; +eval SELECT "$last_error" AS Last_SQL_Error; +enable_query_log; + +set foreign_key_checks= 0; +delete from ti1 where b=1; +set foreign_key_checks= 1; +set global slave_exec_mode='IDEMPOTENT'; +start slave sql_thread; +connection master; +sync_slave_with_master; +#connection slave; +set global slave_exec_mode='STRICT'; + +# key not found + +connection master; + +CREATE TABLE t1 (a INT PRIMARY KEY); +CREATE TABLE t2 (a INT); +INSERT INTO t1 VALUES (-1),(-2),(-3); +INSERT INTO t2 VALUES (-1),(-2),(-3); +sync_slave_with_master; + +#connection slave; +DELETE FROM t1 WHERE a = -2; +DELETE FROM t2 WHERE a = -2; +connection master; +DELETE FROM t1 WHERE a = -2; + +--echo *** slave must stop (Key was not found) +connection slave; +source include/wait_for_slave_sql_to_stop.inc; + +let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1); +disable_query_log; +eval SELECT "$last_error" AS Last_SQL_Error; +enable_query_log; + +set global slave_exec_mode='IDEMPOTENT'; +start slave sql_thread; +connection master; +sync_slave_with_master; +#connection slave; +set global slave_exec_mode='STRICT'; + +connection master; +DELETE FROM t2 WHERE a = -2; +--echo *** slave must stop (Key was not found) +connection slave; +source include/wait_for_slave_sql_to_stop.inc; + +let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1); +disable_query_log; +eval SELECT "$last_error" AS Last_SQL_Error; +enable_query_log; + +set global slave_exec_mode='IDEMPOTENT'; +start slave sql_thread; +connection master; +sync_slave_with_master; +#connection slave; +set global slave_exec_mode='STRICT'; + +UPDATE t1 SET a = 1 WHERE a = -1; +UPDATE t2 SET a = 1 WHERE a = -1; + +connection master; +UPDATE t1 SET a = 1 WHERE a = -1; + +--echo *** slave must stop (Key was not found) +connection slave; +source include/wait_for_slave_sql_to_stop.inc; + +let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1); +disable_query_log; +eval SELECT "$last_error" AS Last_SQL_Error; +enable_query_log; + +set global slave_exec_mode='IDEMPOTENT'; +start slave sql_thread; +connection master; +sync_slave_with_master; +#connection slave; +set global slave_exec_mode='STRICT'; + + +connection master; +UPDATE t2 SET a = 1 WHERE a = -1; + +--echo *** slave must stop (Key was not found) +connection slave; +source include/wait_for_slave_sql_to_stop.inc; + +let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1); +disable_query_log; +eval SELECT "$last_error" AS Last_SQL_Error; +enable_query_log; + +set global slave_exec_mode='IDEMPOTENT'; +start slave sql_thread; +connection master; +sync_slave_with_master; +#connection slave; +SET @@global.slave_exec_mode= @old_slave_exec_mode; + +# cleanup for bug#31609 tests + +connection master; + +drop table t1,t2,ti2,ti1; +sync_slave_with_master; +set @@global.slave_exec_mode= @old_slave_exec_mode; + +--echo *** end of tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_img.cnf b/mysql-test/suite/rpl/t/rpl_row_img.cnf new file mode 100644 index 00000000..ed9a4292 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_img.cnf @@ -0,0 +1,21 @@ +!include include/default_mysqld.cnf + +[mysqld.1] +log-slave-updates +innodb +innodb_flush_log_at_trx_commit= 0 + +[mysqld.2] +log-slave-updates +innodb +innodb_flush_log_at_trx_commit= 0 + +[mysqld.3] +log-slave-updates +innodb +innodb_flush_log_at_trx_commit= 0 + +[ENV] +SERVER_MYPORT_1= @mysqld.1.port +SERVER_MYPORT_2= @mysqld.2.port +SERVER_MYPORT_3= @mysqld.3.port diff --git a/mysql-test/suite/rpl/t/rpl_row_img_blobs.cnf b/mysql-test/suite/rpl/t/rpl_row_img_blobs.cnf new file mode 100644 index 00000000..d758d29f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_img_blobs.cnf @@ -0,0 +1 @@ +!include suite/rpl/t/rpl_row_img.cnf diff --git a/mysql-test/suite/rpl/t/rpl_row_img_blobs.test b/mysql-test/suite/rpl/t/rpl_row_img_blobs.test new file mode 100644 index 00000000..21f224f5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_img_blobs.test @@ -0,0 +1,59 @@ +#Want to skip this test from daily Valgrind execution +--source include/no_valgrind_without_big.inc + +# +# This file contains tests for WL#5096. +# + +--let $rpl_topology= 1->2->3 +--source include/rpl_init.inc +-- source include/have_binlog_format_row.inc + +-- connection server_1 +-- source include/have_innodb.inc +-- connection server_2 +-- source include/have_innodb.inc +-- connection server_3 +-- source include/have_innodb.inc +-- connection server_1 + +# +# WL#5096 Tests. +# + +# +# Tests combinations of binlog-row-image against mixes of MyISAM and InnoDB +# storage engines on all three servers. +# +# All the combinarions need not to be separated into their own files as +# the tests for indexes and engines mixes are, because noblobs test script +# does not take too long time, thence we do not risk triggering PB2 timeout +# on valgrind runs. +# + +## NOBLOB + +-- let $row_img_set=server_1:NOBLOB:N,server_2:NOBLOB:Y,server_3:NOBLOB:Y +-- source include/rpl_row_img_set.inc + +-- let $row_img_test_script= include/rpl_row_img_blobs.test +-- source include/rpl_row_img_general_loop.inc + +## MINIMAL + +-- let $row_img_set=server_1:MINIMAL:N,server_2:MINIMAL:Y,server_3:MINIMAL:Y +-- source include/rpl_row_img_set.inc + +-- let $row_img_test_script= include/rpl_row_img_blobs.test +-- source include/rpl_row_img_general_loop.inc + +## FULL + +-- let $row_img_set=server_1:FULL:N,server_2:FULL:Y,server_3:FULL:Y +-- source include/rpl_row_img_set.inc + +-- let $row_img_test_script= include/rpl_row_img_blobs.test +-- source include/rpl_row_img_general_loop.inc + + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_img_eng_min.cnf b/mysql-test/suite/rpl/t/rpl_row_img_eng_min.cnf new file mode 100644 index 00000000..d758d29f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_img_eng_min.cnf @@ -0,0 +1 @@ +!include suite/rpl/t/rpl_row_img.cnf diff --git a/mysql-test/suite/rpl/t/rpl_row_img_eng_min.test b/mysql-test/suite/rpl/t/rpl_row_img_eng_min.test new file mode 100644 index 00000000..06764fe8 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_img_eng_min.test @@ -0,0 +1,39 @@ +#Want to skip this test from daily Valgrind execution +--source include/no_valgrind_without_big.inc +# +# This file contains tests for WL#5096 and bug fixes. +# + +--let $rpl_topology= 1->2->3 +--source include/rpl_init.inc +-- source include/have_binlog_format_row.inc + +-- connection server_1 +-- source include/have_innodb.inc +-- connection server_2 +-- source include/have_innodb.inc +-- connection server_3 +-- source include/have_innodb.inc +-- connection server_1 + +# +# WL#5096 +# + +# +# Tests for different storage engines on each server, +# but same index structure on tables. The tests are conducted +# using MINIMAL binlog-row-image on all servers. +# + +-- let $row_img_set=server_1:MINIMAL:N,server_2:MINIMAL:Y,server_3:MINIMAL:Y +-- source include/rpl_row_img_set.inc + +-- let $row_img_test_script= include/rpl_row_img.test +-- source include/rpl_row_img_general_loop.inc + +-- let $row_img_set=server_1:FULL:N,server_2:FULL:Y,server_3:FULL:Y +-- source include/rpl_row_img_set.inc + + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_img_eng_noblob.cnf b/mysql-test/suite/rpl/t/rpl_row_img_eng_noblob.cnf new file mode 100644 index 00000000..d758d29f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_img_eng_noblob.cnf @@ -0,0 +1 @@ +!include suite/rpl/t/rpl_row_img.cnf diff --git a/mysql-test/suite/rpl/t/rpl_row_img_eng_noblob.test b/mysql-test/suite/rpl/t/rpl_row_img_eng_noblob.test new file mode 100644 index 00000000..7f4944b5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_img_eng_noblob.test @@ -0,0 +1,39 @@ +#Want to skip this test from daily Valgrind execution +--source include/no_valgrind_without_big.inc +# +# This file contains tests for WL#5096 and bug fixes. +# + +--let $rpl_topology= 1->2->3 +--source include/rpl_init.inc +-- source include/have_binlog_format_row.inc + +-- connection server_1 +-- source include/have_innodb.inc +-- connection server_2 +-- source include/have_innodb.inc +-- connection server_3 +-- source include/have_innodb.inc +-- connection server_1 + +# +# WL#5096 +# + +# +# Tests for different storage engines on each server, +# but same index structure on tables. The tests are conducted +# using NOBLOB binlog-row-image on all servers. +# + +-- let $row_img_set=server_1:NOBLOB:N,server_2:NOBLOB:Y,server_3:NOBLOB:Y +-- source include/rpl_row_img_set.inc + +-- let $row_img_test_script= include/rpl_row_img.test +-- source include/rpl_row_img_general_loop.inc + +-- let $row_img_set=server_1:FULL:N,server_2:FULL:Y,server_3:FULL:Y +-- source include/rpl_row_img_set.inc + + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_img_sequence_full.cnf b/mysql-test/suite/rpl/t/rpl_row_img_sequence_full.cnf new file mode 100644 index 00000000..7104b4e4 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_img_sequence_full.cnf @@ -0,0 +1,21 @@ +!include include/default_mysqld.cnf + +[mysqld.1] +log-slave-updates +innodb +gtid_domain_id=0 + +[mysqld.2] +log-slave-updates +innodb +gtid_domain_id=1 + +[mysqld.3] +log-slave-updates +innodb +gtid_domain_id=2 + +[ENV] +SERVER_MYPORT_1= @mysqld.1.port +SERVER_MYPORT_2= @mysqld.2.port +SERVER_MYPORT_3= @mysqld.3.port diff --git a/mysql-test/suite/rpl/t/rpl_row_img_sequence_full.test b/mysql-test/suite/rpl/t/rpl_row_img_sequence_full.test new file mode 100644 index 00000000..a0c6aa4d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_img_sequence_full.test @@ -0,0 +1,48 @@ +# +# Purpose: +# The rpl_row_img_sequence group of tests verify that sequence MDL updates, +# i.e. NEXTVAL and SETVAL, respect the binlog_row_image variable value when +# written into the binary log. In particular, it ensures that only changed +# columns are written with MINIMAL image mode, and all columns are written +# otherwise. This test focuses on validating the behavior of +# binlog_row_img=FULL. +# +# Methodology +# After issuing a sequence update, ensure that both 1) it was replicated +# correctly, and 2) it was binlogged respective to the binlog_row_image value. +# The sequence table does not use caching to ensure each update is immediately +# binlogged. Each command is binlogged into its own unique log file, and the +# entirety of the file is analyzed for correctness of its sequence event. +# Specifically, mysqlbinlog is used in verbose mode so it outputs the columns +# which belong to the event, and the columns are analyzed to ensure the correct +# ones were logged. rpl_row_img_general_loop.inc is used to test with multiple +# chained replicas, varying engines between InnoDB and MyISAM. +# +# References: +# MDEV-28487: sequences not respect value of binlog_row_image with select +# nextval(seq_gen) +# + +--let $rpl_topology= 1->2->3 +--source include/rpl_init.inc +--source include/have_binlog_format_row.inc + +--connection server_1 +--source include/have_innodb.inc +--connection server_2 +--source include/have_innodb.inc +--connection server_3 +--source include/have_innodb.inc +--connection server_1 + +--echo # +--echo # binlog_row_image=FULL should write all columns to the binary log +--echo # +--let $row_img_set=server_1:FULL:N,server_2:FULL:Y,server_3:FULL:Y +--source include/rpl_row_img_set.inc +--let $expected_columns=(1,2,3,4,5,6,7,8) +--let row_img_test_script= include/rpl_row_img_sequence.inc +--source include/rpl_row_img_general_loop.inc + +--source include/rpl_end.inc +--echo # End of tests diff --git a/mysql-test/suite/rpl/t/rpl_row_img_sequence_min.cnf b/mysql-test/suite/rpl/t/rpl_row_img_sequence_min.cnf new file mode 100644 index 00000000..7104b4e4 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_img_sequence_min.cnf @@ -0,0 +1,21 @@ +!include include/default_mysqld.cnf + +[mysqld.1] +log-slave-updates +innodb +gtid_domain_id=0 + +[mysqld.2] +log-slave-updates +innodb +gtid_domain_id=1 + +[mysqld.3] +log-slave-updates +innodb +gtid_domain_id=2 + +[ENV] +SERVER_MYPORT_1= @mysqld.1.port +SERVER_MYPORT_2= @mysqld.2.port +SERVER_MYPORT_3= @mysqld.3.port diff --git a/mysql-test/suite/rpl/t/rpl_row_img_sequence_min.test b/mysql-test/suite/rpl/t/rpl_row_img_sequence_min.test new file mode 100644 index 00000000..0a3b2827 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_img_sequence_min.test @@ -0,0 +1,52 @@ +# +# Purpose: +# The rpl_row_img_sequence group of tests verify that sequence MDL updates, +# i.e. NEXTVAL and SETVAL, respect the binlog_row_image variable value when +# written into the binary log. In particular, it ensures that only changed +# columns are written with MINIMAL image mode, and all columns are written +# otherwise. This test focuses on validating the behavior of +# binlog_row_img=MINIMAL. +# +# Methodology +# After issuing a sequence update, ensure that both 1) it was replicated +# correctly, and 2) it was binlogged respective to the binlog_row_image value. +# The sequence table does not use caching to ensure each update is immediately +# binlogged. Each command is binlogged into its own unique log file, and the +# entirety of the file is analyzed for correctness of its sequence event. +# Specifically, mysqlbinlog is used in verbose mode so it outputs the columns +# which belong to the event, and the columns are analyzed to ensure the correct +# ones were logged. rpl_row_img_general_loop.inc is used to test with multiple +# chained replicas, varying engines between InnoDB and MyISAM. +# +# References: +# MDEV-28487: sequences not respect value of binlog_row_image with select +# nextval(seq_gen) +# + +--let $rpl_topology= 1->2->3 +--source include/rpl_init.inc +--source include/have_binlog_format_row.inc + +--connection server_1 +--source include/have_innodb.inc +--connection server_2 +--source include/have_innodb.inc +--connection server_3 +--source include/have_innodb.inc +--connection server_1 + +--echo # +--echo # binlog_row_image=MINIMAL should write only columns 1 and 8 to the +--echo # binary log +--echo # +--let $row_img_set=server_1:MINIMAL:N,server_2:MINIMAL:Y,server_3:MINIMAL:Y +--source include/rpl_row_img_set.inc +--let $expected_columns=(1,8) +--let row_img_test_script= include/rpl_row_img_sequence.inc +--source include/rpl_row_img_general_loop.inc + +--let $row_img_set=server_1:FULL:N,server_2:FULL:Y,server_3:FULL:Y +--source include/rpl_row_img_set.inc + +--source include/rpl_end.inc +--echo # End of tests diff --git a/mysql-test/suite/rpl/t/rpl_row_img_sequence_noblob.cnf b/mysql-test/suite/rpl/t/rpl_row_img_sequence_noblob.cnf new file mode 100644 index 00000000..7104b4e4 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_img_sequence_noblob.cnf @@ -0,0 +1,21 @@ +!include include/default_mysqld.cnf + +[mysqld.1] +log-slave-updates +innodb +gtid_domain_id=0 + +[mysqld.2] +log-slave-updates +innodb +gtid_domain_id=1 + +[mysqld.3] +log-slave-updates +innodb +gtid_domain_id=2 + +[ENV] +SERVER_MYPORT_1= @mysqld.1.port +SERVER_MYPORT_2= @mysqld.2.port +SERVER_MYPORT_3= @mysqld.3.port diff --git a/mysql-test/suite/rpl/t/rpl_row_img_sequence_noblob.test b/mysql-test/suite/rpl/t/rpl_row_img_sequence_noblob.test new file mode 100644 index 00000000..38ff469f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_img_sequence_noblob.test @@ -0,0 +1,51 @@ +# +# Purpose: +# The rpl_row_img_sequence group of tests verify that sequence MDL updates, +# i.e. NEXTVAL and SETVAL, respect the binlog_row_image variable value when +# written into the binary log. In particular, it ensures that only changed +# columns are written with MINIMAL image mode, and all columns are written +# otherwise. This test focuses on validating the behavior of +# binlog_row_img=NOBLOB. +# +# Methodology +# After issuing a sequence update, ensure that both 1) it was replicated +# correctly, and 2) it was binlogged respective to the binlog_row_image value. +# The sequence table does not use caching to ensure each update is immediately +# binlogged. Each command is binlogged into its own unique log file, and the +# entirety of the file is analyzed for correctness of its sequence event. +# Specifically, mysqlbinlog is used in verbose mode so it outputs the columns +# which belong to the event, and the columns are analyzed to ensure the correct +# ones were logged. rpl_row_img_general_loop.inc is used to test with multiple +# chained replicas, varying engines between InnoDB and MyISAM. +# +# References: +# MDEV-28487: sequences not respect value of binlog_row_image with select +# nextval(seq_gen) +# + +--let $rpl_topology= 1->2->3 +--source include/rpl_init.inc +--source include/have_binlog_format_row.inc + +--connection server_1 +--source include/have_innodb.inc +--connection server_2 +--source include/have_innodb.inc +--connection server_3 +--source include/have_innodb.inc +--connection server_1 + +--echo # +--echo # binlog_row_image=NOBLOB should write all columns to the binary logs +--echo # +--let $row_img_set=server_1:NOBLOB:N,server_2:NOBLOB:Y,server_3:NOBLOB:Y +--source include/rpl_row_img_set.inc +--let $expected_columns=(1,2,3,4,5,6,7,8) +--let row_img_test_script= include/rpl_row_img_sequence.inc +--source include/rpl_row_img_general_loop.inc + +--let $row_img_set=server_1:FULL:N,server_2:FULL:Y,server_3:FULL:Y +--source include/rpl_row_img_set.inc + +--source include/rpl_end.inc +--echo # End of tests diff --git a/mysql-test/suite/rpl/t/rpl_row_implicit_commit_binlog.test b/mysql-test/suite/rpl/t/rpl_row_implicit_commit_binlog.test new file mode 100644 index 00000000..ba204b05 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_implicit_commit_binlog.test @@ -0,0 +1,12 @@ +################################################################################ +# Check file include/rpl_implicit_commit_binlog.test +################################################################################ +--source include/have_udf.inc +--source include/have_binlog_format_row.inc +--source include/have_innodb.inc +--source include/master-slave.inc + +--let $engine=Innodb +set session default_storage_engine=innodb; +--source include/rpl_implicit_commit_binlog.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_index_choice.test b/mysql-test/suite/rpl/t/rpl_row_index_choice.test new file mode 100644 index 00000000..958fa235 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_index_choice.test @@ -0,0 +1,243 @@ +--source include/have_binlog_format_row.inc +--source include/have_debug.inc +--source include/have_innodb.inc +--source include/master-slave.inc + +# Bug#58997: Row-based replication breaks on table with only fulltext index: +connection master; +CREATE TABLE t1 (a int, b varchar(100), fulltext(b)) engine=MyISAM; +INSERT INTO t1 VALUES (1,"a"), (2,"b"); +UPDATE t1 SET b='A' WHERE a=1; +DELETE FROM t1 WHERE a=2; + +sync_slave_with_master; + +connection slave; + +SELECT * FROM t1 ORDER BY a; + +connection master; +DROP TABLE t1; + + +# A utility table used to populate subsequent tables in various ways. +connection master; +CREATE TABLE t1 (d INT PRIMARY KEY) ENGINE=myisam; +INSERT INTO t1 VALUES (0); +INSERT INTO t1 SELECT d+1 FROM t1; +INSERT INTO t1 SELECT d+2 FROM t1; +INSERT INTO t1 SELECT d+4 FROM t1; +INSERT INTO t1 SELECT d+8 FROM t1; +INSERT INTO t1 SELECT d+16 FROM t1; +INSERT INTO t1 SELECT d+32 FROM t1; +INSERT INTO t1 SELECT d+64 FROM t1; +INSERT INTO t1 SELECT d+128 FROM t1; +INSERT INTO t1 SELECT d+256 FROM t1; +INSERT INTO t1 SELECT d+512 FROM t1; + +# Test that we pick the better multi-column index, even if the +# single-column index is more selective in the first column. +CREATE TABLE t2 (a INT, b INT, c INT, d INT, + KEY wrong_key(a), + KEY expected_key(b,c), + KEY wrong_key2(c)) ENGINE=myisam; +INSERT INTO t2 SELECT d DIV 10, d MOD 41, d MOD 37, d FROM t1; + +sync_slave_with_master; +connection slave; +ANALYZE TABLE t2; +--echo # Slave will crash if using the wrong or no index +SET @saved_dbug = @@GLOBAL.debug_dbug; +SET GLOBAL debug_dbug="+d,slave_crash_if_wrong_index,slave_crash_if_table_scan"; + +connection master; +UPDATE t2 SET d=10042 WHERE d=42; +DELETE FROM t2 WHERE d=53; + +sync_slave_with_master; +connection slave; +SET GLOBAL debug_dbug=""; +SELECT * FROM t2 WHERE d IN (10042,53); + +# Test that we don't pick a unique index with NULLS over a more selective +# non-unique index. +connection master; +DROP TABLE t2; +CREATE TABLE t2 (a INT, b INT, c INT, d INT NOT NULL, e INT, + UNIQUE wrong_key3(a,e), + KEY wrong_key4(b,c), + UNIQUE expected_key(d)) ENGINE=myisam; +INSERT INTO t2 SELECT d DIV 10, d MOD 41, d MOD 37, d, NULL FROM t1; + +sync_slave_with_master; +connection slave; +ANALYZE TABLE t2; +--echo # Slave will crash if using the wrong or no index +SET GLOBAL debug_dbug="+d,slave_crash_if_wrong_index,slave_crash_if_table_scan"; + +connection master; +UPDATE t2 SET d=10042 WHERE d=42; +DELETE FROM t2 WHERE d=53; + +sync_slave_with_master; +connection slave; +SET GLOBAL debug_dbug=""; +SELECT * FROM t2 WHERE d IN (10042,53); + +connection master; +DROP TABLE t2; + +# Test that we pick a reasonable index when there is no rec_per_key[] +# information (no ANALYZE TABLE). +CREATE TABLE t2 (a INT NOT NULL, b INT NOT NULL, c INT NOT NULL, d INT NOT NULL, + KEY wrong_key5(b), + UNIQUE expected_key(d), + KEY wrong_key6(c)) ENGINE=myisam; +INSERT INTO t2 SELECT d DIV 10, d MOD 41, d MOD 37, d FROM t1; + +sync_slave_with_master; +connection slave; +--echo # Slave will crash if using the wrong or no index +SET GLOBAL debug_dbug="+d,slave_crash_if_wrong_index,slave_crash_if_table_scan"; + +connection master; +UPDATE t2 SET d=10042 WHERE d=42; +DELETE FROM t2 WHERE d=53; + +sync_slave_with_master; +connection slave; +SET GLOBAL debug_dbug=""; +SELECT * FROM t2 WHERE d IN (10042,53); + +connection master; +DROP TABLE t2; + + +# Also test without ANALYZE when we pick the sub-optimal index. +# In this case the key on (d) is the best one, but without ANALYZE TABLE we +# have no information and will pick the first one on (b). +# (This test should be updated if we improve the index selection, of course). +CREATE TABLE t2 (a INT NOT NULL, b INT NOT NULL, c INT NOT NULL, d INT NOT NULL, + KEY expected_key(b), + KEY wrong_key7(d), + KEY wrong_key8(c)) ENGINE=myisam; +INSERT INTO t2 SELECT d DIV 10, d MOD 41, d MOD 37, d FROM t1; + +sync_slave_with_master; +connection slave; +--echo # Slave will crash if using the wrong or no index +SET GLOBAL debug_dbug="+d,slave_crash_if_wrong_index,slave_crash_if_table_scan"; + +connection master; +UPDATE t2 SET d=10042 WHERE d=42; +DELETE FROM t2 WHERE d=53; + +sync_slave_with_master; +connection slave; +SET GLOBAL debug_dbug=""; +SELECT * FROM t2 WHERE d IN (10042,53); + +connection master; +DROP TABLE t2; + + +# Test that we pick the primary key for InnoDB, if available. +CREATE TABLE t2 (a INT NOT NULL, b INT NOT NULL, c INT NOT NULL, d INT, + UNIQUE wrong_key9(d), + KEY wrong_key10(a), + PRIMARY KEY expected_key(c,b)) ENGINE=innodb; +INSERT INTO t2 SELECT d DIV 10, d MOD 41, d MOD 37, d FROM t1; + +sync_slave_with_master; +connection slave; +--echo # Slave will crash if using the wrong or no index +SET GLOBAL debug_dbug="+d,slave_crash_if_wrong_index,slave_crash_if_table_scan,slave_crash_if_index_scan"; + +connection master; +UPDATE t2 SET d=10042 WHERE d=42; +DELETE FROM t2 WHERE d=53; + +sync_slave_with_master; +connection slave; +SET GLOBAL debug_dbug=""; +SELECT * FROM t2 WHERE d IN (10042,53); + +connection master; +DROP TABLE t2; + + +# Test that we pick a good index for InnoDB when primary key is not available. +CREATE TABLE t2 (a INT NOT NULL, b INT NOT NULL, c INT NOT NULL, d INT, e INT, + UNIQUE wrong_key11(e), + KEY wrong_key12(a), + KEY expected_key(c,b)) ENGINE=innodb; +INSERT INTO t2 SELECT d DIV 10, d MOD 41, d MOD 37, d, IF(d<10, d, NULL) FROM t1; + +sync_slave_with_master; +connection slave; +ANALYZE TABLE t2; +--echo # Slave will crash if using the wrong or no index +SET GLOBAL debug_dbug="+d,slave_crash_if_wrong_index,slave_crash_if_table_scan"; + +connection master; +UPDATE t2 SET d=10042 WHERE d=42; +DELETE FROM t2 WHERE d=53; + +sync_slave_with_master; +connection slave; +SET GLOBAL debug_dbug=""; +SELECT * FROM t2 WHERE d IN (10042,53); + +connection master; +DROP TABLE t2; + + +# When there is no ANALYZE TABLE, InnoDB will just report "1" for index +# cardinality for all indexes in rec_per_key. So currently we cannot choose +# index to use intelligently. Just test that we work as expected (select +# first index, remember that unique keys are sorted first by server). +CREATE TABLE t2 (a INT NOT NULL, b INT NOT NULL, c INT NOT NULL, d INT, e INT, + KEY wrong_key13(a), + UNIQUE expected_key(e), + KEY wrong_key14(c,b)) ENGINE=innodb; +INSERT INTO t2 SELECT d DIV 10, d MOD 41, d MOD 37, d, IF(d<10, d, NULL) FROM t1; + +sync_slave_with_master; +connection slave; +--echo # Slave will crash if using the wrong or no index +SET GLOBAL debug_dbug="+d,slave_crash_if_wrong_index,slave_crash_if_table_scan"; + +connection master; +UPDATE t2 SET d=10042 WHERE d=42; +DELETE FROM t2 WHERE d=53; + +sync_slave_with_master; +connection slave; +SET GLOBAL debug_dbug=""; +SELECT * FROM t2 WHERE d IN (10042,53); + +connection master; +DROP TABLE t2; + + +# Finally, test behaviour when no indexes are available at all. +CREATE TABLE t2 (a INT NOT NULL, d INT) ENGINE=innodb; +INSERT INTO t2 SELECT d DIV 10, d FROM t1; + +UPDATE t2 SET d=10042 WHERE d=42; +DELETE FROM t2 WHERE d=53; + +sync_slave_with_master; +connection slave; +SELECT * FROM t2 WHERE d IN (10042,53); + +connection master; +DROP TABLE t2; + + +connection master; +DROP TABLE t1; +sync_slave_with_master; +connection slave; +SET @@GLOBAL.debug_dbug = @saved_dbug; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_inexist_tbl.test b/mysql-test/suite/rpl/t/rpl_row_inexist_tbl.test new file mode 100644 index 00000000..907e309a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_inexist_tbl.test @@ -0,0 +1,40 @@ +# ==== Purpose ==== +# +# Verify that slave gives an error message if master updates a table +# that slave does not have. +# +# ==== Method ==== +# +# Create a table on master, wait till it's on slave, remove it from +# slave. Then update the table on master. + +--source include/have_binlog_format_row.inc + +source include/master-slave.inc; + +--echo ==== Setup table on master but not on slave ==== +CREATE TABLE t1 (a INT); + +sync_slave_with_master; +DROP TABLE t1; + +--echo ==== Modify table on master ==== +connection master; +INSERT INTO t1 VALUES (1); + +--echo ==== Verify error on slave ==== +connection slave; +# slave should have stopped because can't find table t1 +# 1146 = ER_NO_SUCH_TABLE +call mtr.add_suppression("Slave SQL.*Error executing row event: .Table .test.t1. doesn.t exist., error.* 1146"); +--let $slave_sql_errno= 1146 +--source include/wait_for_slave_sql_error.inc + +--echo ==== Clean up ==== +source include/stop_slave_io.inc; +RESET SLAVE; + +connection master; +DROP TABLE t1; +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_lcase_tblnames-slave.opt b/mysql-test/suite/rpl/t/rpl_row_lcase_tblnames-slave.opt new file mode 100644 index 00000000..7624b013 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_lcase_tblnames-slave.opt @@ -0,0 +1 @@ +--replicate-do-db=bug_37656 --replicate-ignore-table=buG_37656.T1 --replicate-do-table=bUg_37656.T2 --replicate-do-table=bUg_37656.T3 --lower-case-table-names=1 diff --git a/mysql-test/suite/rpl/t/rpl_row_lcase_tblnames.test b/mysql-test/suite/rpl/t/rpl_row_lcase_tblnames.test new file mode 100644 index 00000000..7decd130 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_lcase_tblnames.test @@ -0,0 +1,12 @@ +# BUG#37656 +# +# For details look into extra/rpl_tests/rpl_lower_case_table_names.test +# + +-- source include/not_windows.inc +-- source include/have_innodb.inc +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + +-- let $engine=InnoDB +-- source include/rpl_lower_case_table_names.test diff --git a/mysql-test/suite/rpl/t/rpl_row_loaddata_concurrent.test b/mysql-test/suite/rpl/t/rpl_row_loaddata_concurrent.test new file mode 100644 index 00000000..c2cb2b4a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_loaddata_concurrent.test @@ -0,0 +1,13 @@ +-- source include/have_log_bin.inc +-- source include/have_binlog_format_row.inc + +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +CREATE TABLE t1 (c1 char(50)) engine=myisam; +LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE t1; +LOAD DATA CONCURRENT INFILE '../../std_data/words.dat' INTO TABLE t1; +-- source include/show_binlog_events.inc +DROP TABLE t1; + +let $lock_option= CONCURRENT; +let $engine_type=MyISAM; +-- source include/rpl_loaddata.test diff --git a/mysql-test/suite/rpl/t/rpl_row_log-master.opt b/mysql-test/suite/rpl/t/rpl_row_log-master.opt new file mode 100644 index 00000000..e0d075c3 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_log-master.opt @@ -0,0 +1 @@ +--skip-external-locking diff --git a/mysql-test/suite/rpl/t/rpl_row_log-slave.opt b/mysql-test/suite/rpl/t/rpl_row_log-slave.opt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_log-slave.opt @@ -0,0 +1 @@ + diff --git a/mysql-test/suite/rpl/t/rpl_row_log.test b/mysql-test/suite/rpl/t/rpl_row_log.test new file mode 100644 index 00000000..25fcc4f4 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_log.test @@ -0,0 +1,15 @@ +################################### +# Wrapper for rpl_row_log.test # +# Added wrapper so that MyISAM & # +# Innodb could all use the# +# Same test +################################### +######################################################## +# By JBM 2005-02-15 Wrapped to allow reuse of test code# +######################################################## +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc +let $engine_type=MyISAM; +-- source include/rpl_log.test + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_log_innodb-master.opt b/mysql-test/suite/rpl/t/rpl_row_log_innodb-master.opt new file mode 100644 index 00000000..773ec62b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_log_innodb-master.opt @@ -0,0 +1,2 @@ +--skip-external-locking +--default-storage-engine=MyISAM diff --git a/mysql-test/suite/rpl/t/rpl_row_log_innodb.test b/mysql-test/suite/rpl/t/rpl_row_log_innodb.test new file mode 100644 index 00000000..92fe0eb9 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_log_innodb.test @@ -0,0 +1,13 @@ +################################### +# Wrapper for rpl_row_log.test # +# Added wrapper so that MyISAM & # +# Innodb could all use the# +# Same test. +################################### +-- source include/have_binlog_format_row.inc +-- source include/have_innodb.inc +-- source include/master-slave.inc +let $engine_type=InnoDB; +-- source include/rpl_log.test + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_max_relay_size.test b/mysql-test/suite/rpl/t/rpl_row_max_relay_size.test new file mode 100644 index 00000000..0ec85244 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_max_relay_size.test @@ -0,0 +1,9 @@ +# Test of options max_binlog_size and max_relay_log_size and +# how they act (if max_relay_log_size == 0, use max_binlog_size +# for relay logs too). +# Test of manual relay log rotation with FLUSH LOGS. + +# Requires statement logging +source include/have_binlog_format_row.inc; + +source include/rpl_max_relay_size.test; diff --git a/mysql-test/suite/rpl/t/rpl_row_merge_engine.test b/mysql-test/suite/rpl/t/rpl_row_merge_engine.test new file mode 100644 index 00000000..c28d4a89 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_merge_engine.test @@ -0,0 +1,52 @@ +# +# BUG#47103 +# +# This test case checks whether the slave crashes or not when there is +# a merge table in use. +# +# Description +# =========== +# +# The test case creates two regular MyISAM tables on the master and +# one MERGE table. Then it populates the MyISAM tables, updates and +# deletes their contents through the merge table. Finally, the slave +# is synchronized with the master and (after the fix) it won't crash. +# +--source include/have_binlog_format_row.inc +--source include/master-slave.inc +--connection master + +CREATE TABLE t1 (a int) ENGINE=MyISAM; +CREATE TABLE t2 (a int) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1), (2), (3); +INSERT INTO t2 VALUES (4), (5), (6); +# Changed a little to check also an issue reported on BUG#20574550 +CREATE TEMPORARY TABLE IF NOT EXISTS tt1_merge LIKE t1; +ALTER TABLE tt1_merge ENGINE=MERGE UNION (t2, t1); +CREATE TABLE t1_merge LIKE tt1_merge; + +--sync_slave_with_master + +--let diff_tables=master:test.t1, slave:test.t1 +--source include/diff_tables.inc + +--let diff_tables=master:test.t2, slave:test.t2 +--source include/diff_tables.inc + +--connection master +UPDATE t1_merge SET a=10 WHERE a=1; +DELETE FROM t1_merge WHERE a=10; + +--sync_slave_with_master +--connection master + +--let diff_tables=master:test.t1, slave:test.t1 +--source include/diff_tables.inc + +--let diff_tables=master:test.t2, slave:test.t2 +--source include/diff_tables.inc + +DROP TABLE t1_merge, t1, t2; +--sync_slave_with_master + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_mixing_engines.test b/mysql-test/suite/rpl/t/rpl_row_mixing_engines.test new file mode 100644 index 00000000..5aa4f2c9 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_mixing_engines.test @@ -0,0 +1,14 @@ +################################################################################### +# This test cases evaluates the mixture of non-transactional and transcational +# tables. For further details, please, read WL#2687 and WL#5072. +################################################################################### +--source include/have_binlog_format_row.inc +--source include/have_innodb.inc +# MDEV-31790 FIXME: This test is extremely slow +--source include/not_msan.inc +--source include/master-slave.inc + +let $engine_type=Innodb; +let $database_name=test; +--source include/rpl_mixing_engines.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog-master.opt b/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog-master.opt new file mode 100644 index 00000000..07d12817 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog-master.opt @@ -0,0 +1 @@ +--max-binlog-size=1040384 diff --git a/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test b/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test new file mode 100644 index 00000000..9e10aaa6 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test @@ -0,0 +1,285 @@ +################################################################## +# Author: JBM # +# Date: 2006-02-22 # +# Purpose: To test changes to mysqlbinlog for row based bin logs # +# We are using .opt file since we need small binlog size # +################################################################## +-- source include/have_binlog_format_row.inc +-- source include/not_embedded.inc +-- source include/have_cp932.inc +-- source include/master-slave.inc + +--echo ---Setup Section -- + +# we need this for getting fixed timestamps inside of this test +set timestamp=1000000000; + +CREATE TABLE t1(word VARCHAR(20)); +CREATE TABLE t2(id INT AUTO_INCREMENT NOT NULL PRIMARY KEY); +--let position= query_get_value(SHOW MASTER STATUS, Position, 1) +CREATE TABLE t3(c1 INT NOT NULL PRIMARY KEY, c2 LONGBLOB, c3 TIMESTAMP, c4 TEXT, c5 FLOAT); +--let stop_position=query_get_value(SHOW MASTER STATUS, Position, 1) +--let stop_position1=`select $stop_position - 1` +--let binlog_start_pos=query_get_value(SHOW BINLOG EVENTS LIMIT 1, End_log_pos, 1) + +# Test Section +# Lets start by putting some data into the tables. + +INSERT INTO t1 VALUES ("abirvalg"); +LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE t1; +LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE t1; +LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE t1; +LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE t1; +LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE t1; + +# d1 length 3000 +set @d1 = 'dd1'; +set @d1 = concat(@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1); +set @d1 = concat(@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1); +set @d1 = concat(@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1); + +--disable_query_log +let count=500; +while ($count) +{ + INSERT INTO t2 VALUES (NULL); + eval INSERT INTO t3 VALUES ($count,@d1,'20060222000000','Tested in Texas',$count*2.2); + dec $count; +} +--enable_query_log + +--echo ---Test 1 check table load -- + +# Lets Check the tables on the Master +SELECT COUNT(*) from t1; +SELECT COUNT(*) from t2; +SELECT COUNT(*) from t3; +SELECT * FROM t1 ORDER BY word LIMIT 5; +SELECT * FROM t2 ORDER BY id LIMIT 5; +SELECT c1, c3, c4, c5 FROM t3 ORDER BY c1 LIMIT 5; + +# Should have the same on the slave; + +sync_slave_with_master; +SELECT COUNT(*) from t1; +SELECT COUNT(*) from t2; +SELECT COUNT(*) from t3; +SELECT * FROM t1 ORDER BY word LIMIT 5; +SELECT * FROM t2 ORDER BY id LIMIT 5; +SELECT c1, c3, c4, c5 FROM t3 ORDER BY c1 LIMIT 5; + +# Okay time to get busy, back to master + +connection master; + +# simple query to show more in second binlog +insert into t1 values ("Alas"); +flush logs; + +# delimiters are for easier debugging in future +--echo --- Test 1 Dump binlog to file -- + +# +# Prepare local temporary file to recreate what we have currently. +let MYSQLD_DATADIR= `select @@datadir;`; +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/master.sql + +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000002 >> $MYSQLTEST_VARDIR/tmp/master.sql + +# Now that we have our file, lets get rid of the current database. +# Cleanup the master and the slave and try to recreate. +--echo --- Test 1 delete tables, clean master and slave -- + +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; + +sync_slave_with_master; +stop slave; +--source include/wait_for_slave_to_stop.inc +connection master; +reset master; +connection slave; +--source include/reset_slave.inc +start slave; +--source include/wait_for_slave_to_start.inc +connection master; + +# We should be clean at this point, now we will run in the file from above. +--echo --- Test 1 Load from Dump binlog file -- + +--exec $MYSQL -e "source $MYSQLTEST_VARDIR/tmp/master.sql" + +--echo --- Test 1 Check Load Results -- + +# Lets Check the tables on the Master +SELECT COUNT(*) from t1; +SELECT COUNT(*) from t2; +SELECT COUNT(*) from t3; +SELECT * FROM t1 ORDER BY word LIMIT 5; +SELECT * FROM t2 ORDER BY id LIMIT 5; +SELECT c1, c3, c4, c5 FROM t3 ORDER BY c1 LIMIT 5; + +# Should have the same on the slave; + +sync_slave_with_master; +SELECT COUNT(*) from t1; +SELECT COUNT(*) from t2; +SELECT COUNT(*) from t3; +SELECT * FROM t1 ORDER BY word LIMIT 5; +SELECT * FROM t2 ORDER BY id LIMIT 5; +SELECT c1, c3, c4, c5 FROM t3 ORDER BY c1 LIMIT 5; +connection master; + +# We should be gold by the time, so I will get rid of our file. + +remove_file $MYSQLTEST_VARDIR/tmp/master.sql; + + +# this test for start-position option +# By setting this position to 416, we should only get the create of t3 +--echo --- Test 2 position test -- +--exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --start-position=$position --stop-position=$stop_position $MYSQLD_DATADIR/master-bin.000001 + +# These are tests for remote binlog. +# They should return the same as previous test. + +--echo --- Test 3 First Remote test -- + +# This is broken now +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --stop-position=$stop_position --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 + +--echo --- Test 4 Second Remote test -- +--exec $MYSQL_BINLOG --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT --to-last-log master-bin.000001 > $MYSQLTEST_VARDIR/tmp/remote.sql + +# Now that we have our file, lets get rid of the current database. +# Cleanup the master and the slave and try to recreate. + +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; + +sync_slave_with_master; + +stop slave; +--source include/wait_for_slave_to_stop.inc +connection master; +reset master; +connection slave; +--source include/reset_slave.inc +start slave; +--source include/wait_for_slave_to_start.inc +connection master; + +# We should be clean at this point, now we will run in the file from above. + +--exec $MYSQL -e "source $MYSQLTEST_VARDIR/tmp/remote.sql" + +# Lets Check the tables on the Master + +SELECT COUNT(*) from t1; +SELECT COUNT(*) from t2; +SELECT COUNT(*) from t3; +SELECT * FROM t1 ORDER BY word LIMIT 5; +SELECT * FROM t2 ORDER BY id LIMIT 5; +SELECT c1, c3, c4, c5 FROM t3 ORDER BY c1 LIMIT 5; + +# Should have the same on the slave; + +sync_slave_with_master; +SELECT COUNT(*) from t1; +SELECT COUNT(*) from t2; +SELECT COUNT(*) from t3; +SELECT * FROM t1 ORDER BY word LIMIT 5; +SELECT * FROM t2 ORDER BY id LIMIT 5; +SELECT c1, c3, c4, c5 FROM t3 ORDER BY c1 LIMIT 5; +connection master; + +# We should be gold by the time, so I will get rid of our file. + +--remove_file $MYSQLTEST_VARDIR/tmp/remote.sql +################### End Bug 17654 ###################### + +# What is the point of this test? It seems entirely pointless. It +# might make sense for statement-based replication, but for row-based +# replication the LOAD DATA INFILE is printed just as empty +# transactions. /Matz + +# LOAD DATA +--echo --- Test 5 LOAD DATA -- +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --stop-position=$binlog_start_pos --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000002 + +# Bug#7853 (mysqlbinlog does not accept input from stdin) + +--echo --- Test 6 reading stdin -- +--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +--exec $MYSQL_BINLOG --short-form --stop-position=$stop_position1 - < $MYSQLD_DATADIR/master-bin.000001 + +--echo --- Test 7 reading stdin w/position -- +--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +--exec $MYSQL_BINLOG --short-form --start-position=$position --stop-position=$stop_position - < $MYSQLD_DATADIR/master-bin.000001 + +# Bug#16217 (mysql client did not know how not switch its internal charset) +--echo --- Test 8 switch internal charset -- +sync_slave_with_master; + +stop slave; +--source include/wait_for_slave_to_stop.inc +connection master; +reset master; +connection slave; +--source include/reset_slave.inc +start slave; +--source include/wait_for_slave_to_start.inc +connection master; + +create table t4 (f text character set utf8); +create table t5 (f text character set cp932); +--exec $MYSQL --default-character-set=utf8 test -e "insert into t4 values(_utf8'ソ')" +--exec $MYSQL --default-character-set=cp932 test -e "insert into t5 values(_cp932'ƒ\');" +flush logs; +rename table t4 to t04, t5 to t05; +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 | $MYSQL --default-character-set=utf8 +# original and recovered data must be equal +select HEX(f) from t04; +select HEX(f) from t4; +select HEX(f) from t05; +select HEX(f) from t5; + +# slave should have same +sync_slave_with_master; +select HEX(f) from t04; +select HEX(f) from t4; +select HEX(f) from t05; +select HEX(f) from t5; + +--echo --- Test cleanup -- +# clean up +connection master; +sync_slave_with_master; + +connection master; +DROP TABLE t1, t2, t3, t04, t05, t4, t5; + +# BUG#17654 also test mysqlbinlog to ensure it can read the binlog from a remote server +# and ensure that the results are the same as if read from a file (the same file). + +CREATE TABLE t1 (a INT NOT NULL KEY, b INT); +INSERT INTO t1 VALUES(1,1); +SELECT * FROM t1; +FLUSH LOGS; + +--exec $MYSQL_BINLOG --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 > $MYSQLTEST_VARDIR/tmp/remote.sql +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/local.sql + +--diff_files $MYSQLTEST_VARDIR/tmp/local.sql $MYSQLTEST_VARDIR/tmp/remote.sql +--remove_file $MYSQLTEST_VARDIR/tmp/remote.sql +--remove_file $MYSQLTEST_VARDIR/tmp/local.sql +DROP TABLE t1; + +sync_slave_with_master; + +# End of 4.1 tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_rec_comp_innodb.test b/mysql-test/suite/rpl/t/rpl_row_rec_comp_innodb.test new file mode 100644 index 00000000..39149f6b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_rec_comp_innodb.test @@ -0,0 +1,11 @@ +-- source include/have_binlog_format_row.inc +-- source include/have_innodb.inc +-- source include/master-slave.inc + +# +# BUG#52868 Wrong handling of NULL value during update, replication out of sync +# + +-- let $engine= InnoDB +-- source include/rpl_record_compare.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_rec_comp_myisam.test b/mysql-test/suite/rpl/t/rpl_row_rec_comp_myisam.test new file mode 100644 index 00000000..d9c06d6b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_rec_comp_myisam.test @@ -0,0 +1,32 @@ +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc +-- let $engine= MyISAM + +# +# BUG#52868 Wrong handling of NULL value during update, replication out of sync +# + + +-- echo ## coverage purposes - Field_bits +-- echo ## 1 X bit + 2 Null bits + 5 bits => last_null_bit_pos==0 + +--source include/rpl_reset.inc +-- connection master + +-- eval CREATE TABLE t1 (c1 bigint(20) DEFAULT 0, c2 bit(5)) ENGINE=$engine DEFAULT CHARSET=latin1 + +INSERT INTO t1(c1,c2) VALUES (10, b'1'); +INSERT INTO t1(c1,c2) VALUES (NULL, b'1'); +UPDATE t1 SET c1= 0; +-- sync_slave_with_master + +-- let $diff_tables= master:t1, slave:t1 +-- source include/diff_tables.inc + +-- connection master +DROP TABLE t1; +-- sync_slave_with_master + +-- source include/rpl_record_compare.test + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_reset_slave.test b/mysql-test/suite/rpl/t/rpl_row_reset_slave.test new file mode 100644 index 00000000..284c6154 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_reset_slave.test @@ -0,0 +1,5 @@ +# TBF - difference in row level logging +# Temp tables are not replicated in rbr, but it is still good to hit rbr with everthing +-- source include/have_binlog_format_row.inc +-- source include/rpl_reset_slave.test + diff --git a/mysql-test/suite/rpl/t/rpl_row_rollback_to_savepoint.test b/mysql-test/suite/rpl/t/rpl_row_rollback_to_savepoint.test new file mode 100644 index 00000000..9bc812bb --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_rollback_to_savepoint.test @@ -0,0 +1,312 @@ +############################################################################### +# Bug#76727: SLAVE ASSERTION IN UNPACK_ROW WITH ROLLBACK TO +# SAVEPOINT IN ERROR HANDLER +# +# Problem: +# ======== +# "SAVEPOINT", "ROLLBACK TO savepoint" wipe out table map on slave during +# execution binary log events. For trigger the map is written to binary log once +# for all trigger body and if trigger contains "SAVEPOINT" or +# "ROLLBACK TO savepoint" statements any trigger's events after these +# statements will not have table map. This results in an assert on slave. +# +# Test: +# ===== +# Test case 1: +# Create a trigger with exception handler which rolls back to a savepoint. +# Test proves that there will not be any assert during execution of rolling +# back to savepoint. +# +# Test case 2: +# Create a trigger which calls a procedure which in turn calls an exception +# handler which rolls back to a savepoint. Prove that it doesn't cause any +# assertion during execution. +# +# Test case 3: +# Create a simple trigger which does SAVEPOINT and ROLLBACK TO SAVEPOINT +# and doesn't follow with any other DML statement. Prove that it doesn't cause +# any assertion during execution. +# +# Test case 4: +# Create a trigger with SAVEPOINT and follows with a DML without ROLLBACK TO +# savepoint. Ensure that data is replicated properly. +# +# Test case 5: +# Create a trigger with SAVEPOINT and it does nothing. Do few DMLs following +# the trigger ensure that the data is replicated properly +# +# Test case 6: +# Create a stored function which does SAVEPOINT and ROLLBACK TO +# SAVEPOINT. Do few inserts following the stored function call and ensure that +# no assert is generated on slave and all the rows are replicated to slave. +# +# Test case 7: +# Create a stored function which creates a SAVEPOINT alone and follows with +# DMLs without ROLLBACK TO savepoint. Ensure that data is replicated properly. +# +# Test case 8: +# Create a stored function which has SAVEPOINT inside it and does noting. It +# should follow with other DMLs. Ensure that data is replicated properly. +############################################################################### +--source include/have_binlog_format_row.inc +--source include/have_innodb.inc +--source include/master-slave.inc + +--echo #Test case 1: +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=INNODB; +CREATE TABLE t2 (f1 INTEGER PRIMARY KEY) ENGINE=INNODB; +CREATE TABLE t3 (f1 INTEGER PRIMARY KEY) ENGINE=INNODB; +DELIMITER |; + +CREATE TRIGGER tr1 AFTER INSERT ON t1 FOR EACH ROW +BEGIN + DECLARE EXIT HANDLER FOR SQLEXCEPTION + BEGIN + ROLLBACK TO event_logging_1; + INSERT t3 VALUES (1); + END; + SAVEPOINT event_logging_1; + INSERT INTO t2 VALUES (1); + RELEASE SAVEPOINT event_logging_1; +END| +DELIMITER ;| + +INSERT INTO t2 VALUES (1); +INSERT INTO t1 VALUES (1); + +--source include/show_binlog_events.inc + +--sync_slave_with_master + +connection master; + +DROP TRIGGER tr1; +DELETE FROM t1; +DELETE FROM t2; +DELETE FROM t3; + +--echo # Test case 2: + +DELIMITER |; + +CREATE PROCEDURE p1() +BEGIN + DECLARE EXIT HANDLER FOR SQLEXCEPTION + BEGIN + ROLLBACK TO event_logging_2; + INSERT t3 VALUES (3); + END; + SAVEPOINT event_logging_2; + INSERT INTO t2 VALUES (1); + RELEASE SAVEPOINT event_logging_2; +END| + +CREATE TRIGGER tr1 AFTER INSERT ON t1 FOR EACH ROW CALL p1()| + +DELIMITER ;| + +INSERT INTO t2 VALUES (1); +INSERT INTO t1 VALUES (1); + +--source include/show_binlog_events.inc + +--sync_slave_with_master + +connection master; + +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; + +DROP PROCEDURE p1; + +--echo # Test case 3: +--source include/rpl_reset.inc +connection master; + +CREATE TABLE t (f1 int(10) unsigned NOT NULL, PRIMARY KEY (f1)) ENGINE=InnoDB; + +--delimiter | +CREATE TRIGGER t_insert_trig AFTER INSERT ON t FOR EACH ROW +BEGIN + SAVEPOINT savepoint_1; + ROLLBACK TO savepoint_1; +END | +--delimiter ; + +INSERT INTO t VALUES (2); +INSERT INTO t VALUES (3); + +--source include/show_binlog_events.inc + +SELECT * FROM t; + +--source include/sync_slave_sql_with_master.inc + +SELECT * FROM t; + +connection master; +DROP TABLE t; + +--echo # Test case 4: +--source include/rpl_reset.inc +connection master; +CREATE TABLE t (f1 int(10) unsigned NOT NULL) ENGINE=InnoDB; +CREATE TABLE t1 (f1 int(10) unsigned NOT NULL) ENGINE=InnoDB; + +--delimiter | +CREATE TRIGGER t_insert_trig BEFORE INSERT ON t FOR EACH ROW +BEGIN + SAVEPOINT savepoint_1; + INSERT INTO t1 VALUES (5); +END | +--delimiter ; + +INSERT INTO t VALUES (2), (3); +INSERT INTO t1 VALUES (30); +--source include/show_binlog_events.inc + +SELECT * FROM t; +SELECT * FROM t1; +--source include/sync_slave_sql_with_master.inc + +SELECT * FROM t; +SELECT * FROM t1; + +connection master; +DROP TABLE t; +DROP TABLE t1; + +--echo # Test case 5: +--source include/rpl_reset.inc +connection master; +CREATE TABLE t (f1 int(10) unsigned NOT NULL) ENGINE=InnoDB; +CREATE TABLE t1 (f1 int(10) unsigned NOT NULL) ENGINE=InnoDB; + +--delimiter | +CREATE TRIGGER t_insert_trig BEFORE INSERT ON t +FOR EACH ROW +BEGIN + +SAVEPOINT savepoint_1; +END | + +--delimiter ; + +INSERT INTO t VALUES (2), (3); +INSERT INTO t1 VALUES (30); +--source include/show_binlog_events.inc + +SELECT * FROM t; +SELECT * FROM t1; +--source include/sync_slave_sql_with_master.inc + +SELECT * FROM t; +SELECT * FROM t1; + +connection master; +DROP TABLE t; +DROP TABLE t1; + +--echo # Test case 6: +--source include/rpl_reset.inc +connection master; +CREATE TABLE t1 (f1 INTEGER ) ENGINE=INNODB; +CREATE TABLE t2 (f1 INTEGER ) ENGINE=INNODB; + +--delimiter | + +CREATE FUNCTION f1() RETURNS INT +BEGIN + SAVEPOINT event_logging_2; + INSERT INTO t1 VALUES (1); + ROLLBACK TO event_logging_2; + RETURN 0; +END| + +--delimiter ; + +BEGIN; +INSERT INTO t2 VALUES (1), (f1()), (2), (4); +COMMIT; +INSERT INTO t2 VALUES (10); +--source include/show_binlog_events.inc + +connection master; +SELECT * FROM t2; +SELECT * FROM t1; +--source include/sync_slave_sql_with_master.inc +SELECT * FROM t2; +SELECT * FROM t1; + +connection master; +DROP TABLE t1; +DROP TABLE t2; +DROP FUNCTION f1; + +--echo # Test case 7: +--source include/rpl_reset.inc +connection master; +CREATE TABLE t1 (f1 INTEGER ) ENGINE=INNODB; +CREATE TABLE t2 (f1 INTEGER ) ENGINE=INNODB; + +--delimiter | + +CREATE FUNCTION f1() RETURNS INT +BEGIN + SAVEPOINT event_logging_2; + INSERT INTO t1 VALUES (1); + RETURN 0; +END| + +--delimiter ; + +BEGIN; +INSERT INTO t2 VALUES (1), (f1()), (2), (4); +COMMIT; +INSERT INTO t2 VALUES (10); +--source include/show_binlog_events.inc + +connection master; +SELECT * FROM t2; +SELECT * FROM t1; +--source include/sync_slave_sql_with_master.inc +SELECT * FROM t2; +SELECT * FROM t1; + +connection master; +DROP TABLE t1; +DROP TABLE t2; +DROP FUNCTION f1; + +--echo # Test case 8: +--source include/rpl_reset.inc +connection master; +CREATE TABLE t1 (f1 INTEGER ) ENGINE=INNODB; + +--delimiter | + +CREATE FUNCTION f1() RETURNS INT +BEGIN + SAVEPOINT event_logging_2; + RETURN 0; +END| + +--delimiter ; + +BEGIN; +INSERT INTO t1 VALUES (1), (f1()), (2), (4); +COMMIT; +INSERT INTO t1 VALUES (10); +--source include/show_binlog_events.inc + +connection master; +SELECT * FROM t1; +--source include/sync_slave_sql_with_master.inc +SELECT * FROM t1; + +connection master; +DROP TABLE t1; +DROP FUNCTION f1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_show_relaylog_events.test b/mysql-test/suite/rpl/t/rpl_row_show_relaylog_events.test new file mode 100644 index 00000000..3d4b8f1e --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_show_relaylog_events.test @@ -0,0 +1,19 @@ +# BUG#28777 SHOW BINLOG EVENTS does not work on relay log files +# +# GOAL +# ==== +# +# Test that SHOW BINLOG EVENTS and the new SHOW RELAYLOG EVENTS works after +# the patch, both on master and slave. +# +# HOW +# === +# +# This test issues SHOW [BINLOG|RELAYLOG] EVENTS both on master and slave after +# some statements have been issued. + +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + +-- source include/rpl_show_relaylog_events.inc +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_sp001.test b/mysql-test/suite/rpl/t/rpl_row_sp001.test new file mode 100644 index 00000000..99db5e7f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_sp001.test @@ -0,0 +1,145 @@ +############################################################################# +# This test is being created to test out the non deterministic items with # +# row based replication. # +# Original Author: JBM # +# Original Date: Aug/09/2005 # +# Updated: Aug/29/2005 +############################################################################# +# Test: Includes two stored procedure tests. First test uses SP to insert # +# values from RAND() and NOW() into a table. # +# The second test uses SP with CASE structure to decide what to text # +# to update a given table with. # +############################################################################ + +# Includes +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + +-- disable_query_log +-- disable_result_log + +# Begin clean up test section +connection master; +--disable_warnings +DROP PROCEDURE IF EXISTS test.p1; +DROP PROCEDURE IF EXISTS test.p2; +DROP TABLE IF EXISTS test.t1; +DROP TABLE IF EXISTS test.t2; + +-- enable_query_log +-- enable_result_log + +# Begin test section 1 for non deterministic SP +let $message=<Begin test section 1 (non deterministic SP)>; +--source include/show_msg.inc + +create table test.t1 (n MEDIUMINT NOT NULL AUTO_INCREMENT, f FLOAT, d DATETIME, PRIMARY KEY(n)); + +delimiter //; +create procedure test.p1() +begin + INSERT INTO test.t1 (f,d) VALUES (RAND(),NOW()); +end// +delimiter ;// + +# show binlog events; + +-- disable_query_log +-- disable_result_log +SET @wait_count=1; +let $1=10; +while ($1) +{ + call test.p1(); + let $wait_condition= SELECT COUNT(*) = @wait_count FROM test.t1; + -- source include/wait_condition.inc + -- disable_query_log + SET @wait_count = @wait_count + 1; + dec $1; +} +-- enable_result_log +-- enable_query_log + +## Used for debugging +#show binlog events; +#select * from test.t1; +#sync_slave_with_master; +#select * from test.t1; +#connection master; + +let $message=<End test section 1 (non deterministic SP)>; +--source include/show_msg.inc + + +CREATE TABLE test.t2 (a INT NOT NULL AUTO_INCREMENT, t CHAR(4), PRIMARY KEY(a)); + +delimiter //; +CREATE PROCEDURE test.p2(n int) +begin +CASE n +WHEN 1 THEN + UPDATE test.t2 set t ='Tex'; +WHEN 2 THEN + UPDATE test.t2 set t ='SQL'; +ELSE + UPDATE test.t2 set t ='NONE'; +END CASE; +end// +delimiter ;// + +INSERT INTO test.t2 VALUES(NULL,'NEW'),(NULL,'NEW'),(NULL,'NEW'),(NULL,'NEW'); + +SELECT * FROM t2 ORDER BY a; +sync_slave_with_master; +SELECT * FROM t2 ORDER BY a; + +connection master; +call test.p2(1); +SELECT * FROM t2 ORDER BY a; +sync_slave_with_master; +SELECT * FROM t2 ORDER BY a; + + +connection master; +call test.p2(2); +SELECT * FROM t2 ORDER BY a; +sync_slave_with_master; +SELECT * FROM t2 ORDER BY a; + +connection master; +call test.p2(3); +SELECT * FROM t2 ORDER BY a; +sync_slave_with_master; +SELECT * FROM t2 ORDER BY a; + +##Used for debugging +#show binlog events; + +# time to dump the databases and so we can see if they match + +--exec $MYSQL_DUMP --compact --order-by-primary --skip-extended-insert --no-create-info test > $MYSQLTEST_VARDIR/tmp/sp001_master.sql +--exec $MYSQL_DUMP_SLAVE --compact --order-by-primary --skip-extended-insert --no-create-info test > $MYSQLTEST_VARDIR/tmp/sp001_slave.sql + +# First lets cleanup + +connection master; +DROP PROCEDURE test.p1; +DROP PROCEDURE test.p2; +DROP TABLE test.t1; +DROP TABLE test.t2; +sync_slave_with_master; + +# Lets compare. Note: If they match test will pass, if they do not match +# the test will show that the diff statement failed and not reject file +# will be created. You will need to go to the mysql-test dir and diff +# the files your self to see what is not matching :-) Failed dump files +# will be located in $MYSQLTEST_VARDIR/tmp + +diff_files $MYSQLTEST_VARDIR/tmp/sp001_master.sql $MYSQLTEST_VARDIR/tmp/sp001_slave.sql; + +# If all is good, when can cleanup our dump files. +--remove_file $MYSQLTEST_VARDIR/tmp/sp001_master.sql +--remove_file $MYSQLTEST_VARDIR/tmp/sp001_slave.sql + +# End of 5.0 test case +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_sp002_innodb.test b/mysql-test/suite/rpl/t/rpl_row_sp002_innodb.test new file mode 100644 index 00000000..f096c157 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_sp002_innodb.test @@ -0,0 +1,3 @@ +-- source include/have_innodb.inc +let $engine_type=INNODB; +-- source include/rpl_row_sp002.test diff --git a/mysql-test/suite/rpl/t/rpl_row_sp003.test b/mysql-test/suite/rpl/t/rpl_row_sp003.test new file mode 100644 index 00000000..0a361202 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_sp003.test @@ -0,0 +1,16 @@ +################################# +# Wrapper for rpl_row_sp003.test# +################################# +######################################################## +# By JBM 2005-02-15 Wrapped to allow reuse of test code# +######################################################## +-- source include/have_innodb.inc +-- source include/have_binlog_format_row.inc +# Slow test, don't run during staging part +-- source include/not_staging.inc +--source include/long_test.inc +-- source include/master-slave.inc + +let $engine_type=INNODB; +-- source include/rpl_row_sp003.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_sp005.test b/mysql-test/suite/rpl/t/rpl_row_sp005.test new file mode 100644 index 00000000..865f2e94 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_sp005.test @@ -0,0 +1,102 @@ +############################################################################# +# Original Author: JBM # +# Original Date: Aug/15/2005 # +# Updated: Aug/29/2005: Removed sleeps # +############################################################################# +# Test: Tests SPs with cursors, flow logic, and alter sp. In addition the # +# tests SPs with insert and update operations. # +############################################################################# + +# Includes +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + + +# Begin clean up test section +connection master; +--disable_warnings +DROP PROCEDURE IF EXISTS test.p1; +DROP PROCEDURE IF EXISTS test.p2; +DROP TABLE IF EXISTS test.t2; +DROP TABLE IF EXISTS test.t1; +DROP TABLE IF EXISTS test.t3; +--enable_warnings +# End of cleanup + +# Begin test section 1 +CREATE TABLE IF NOT EXISTS test.t1(id INT, data CHAR(16),PRIMARY KEY(id)); +CREATE TABLE IF NOT EXISTS test.t2(id2 INT,PRIMARY KEY(id2)); +CREATE TABLE IF NOT EXISTS test.t3(id3 INT,PRIMARY KEY(id3), c CHAR(16)); + +delimiter |; +CREATE PROCEDURE test.p1() +BEGIN +DECLARE done INT DEFAULT 0; + DECLARE spa CHAR(16); + DECLARE spb,spc INT; + DECLARE cur1 CURSOR FOR SELECT id,data FROM test.t1 ORDER BY id; + DECLARE cur2 CURSOR FOR SELECT id2 FROM test.t2 ORDER BY id2; + DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1; + + OPEN cur1; + OPEN cur2; + + REPEAT + FETCH cur1 INTO spb, spa; + FETCH cur2 INTO spc; + IF NOT done THEN + IF spb < spc THEN + INSERT INTO test.t3 VALUES (spb,spa); + ELSE + INSERT INTO test.t3 VALUES (spc,spa); + END IF; + END IF; + UNTIL done END REPEAT; + + CLOSE cur1; + CLOSE cur2; +END| +CREATE PROCEDURE test.p2() +BEGIN + INSERT INTO test.t1 VALUES (4,'MySQL'),(20,'ROCKS'),(11,'Texas'),(10,'kyle'); + INSERT INTO test.t2 VALUES (4),(2),(1),(3); + UPDATE test.t1 SET id=id+4 WHERE id=4; +END| +delimiter ;| + +CALL test.p2(); +SELECT * FROM test.t1 ORDER BY id; +SELECT * FROM test.t2 ORDER BY id2; + +sync_slave_with_master; +SELECT * FROM test.t1 ORDER BY id; +SELECT * FROM test.t2 ORDER BY id2; + +connection master; +CALL test.p1(); + +let $wait_condition= SELECT COUNT(*) = 4 FROM t3; +--source include/wait_condition.inc +save_master_pos; +SELECT * FROM test.t3 ORDER BY id3; + +sync_slave_with_master; +SELECT * FROM test.t3 ORDER BY id3; + +connection master; + +ALTER PROCEDURE test.p1 MODIFIES SQL DATA; +#show binlog events; + +# Cleanup + +connection master; +DROP PROCEDURE IF EXISTS test.p1; +DROP PROCEDURE IF EXISTS test.p2; +DROP TABLE IF EXISTS test.t1; +DROP TABLE IF EXISTS test.t2; +DROP TABLE IF EXISTS test.t3; +sync_slave_with_master; + +# End of 5.0 test case +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_sp006_InnoDB.test b/mysql-test/suite/rpl/t/rpl_row_sp006_InnoDB.test new file mode 100644 index 00000000..c575a105 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_sp006_InnoDB.test @@ -0,0 +1,12 @@ +################################# +# Wrapper for rpl_row_sp006.test# +################################# +######################################################## +# By JBM 2005-02-15 Wrapped to allow reuse of test code# +######################################################## +-- source include/have_innodb.inc +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc +let $engine_type=InnoDB; +-- source include/rpl_row_sp006.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_sp007_innodb.test b/mysql-test/suite/rpl/t/rpl_row_sp007_innodb.test new file mode 100644 index 00000000..6eaafa8c --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_sp007_innodb.test @@ -0,0 +1,3 @@ +-- source include/have_innodb.inc +let $engine_type=INNODB; +-- source include/rpl_row_sp007.test diff --git a/mysql-test/suite/rpl/t/rpl_row_sp008.test b/mysql-test/suite/rpl/t/rpl_row_sp008.test new file mode 100644 index 00000000..74a988ee --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_sp008.test @@ -0,0 +1,52 @@ +############################################################################# +# Original Author: JBM # +# Original Date: Aug/15/2005 # +# Update: 08/29/2005 Remove sleep # +############################################################################# +# TEST: Use SQL_CALC_FOUND_ROWS and insert results into a table inside a sp # +############################################################################# + + +# Includes +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + +# Begin clean up test section +connection master; +--disable_warnings +DROP PROCEDURE IF EXISTS test.p1; +DROP TABLE IF EXISTS test.t2; +--enable_warnings +# End of cleanup + + + +# Begin test section 1 +CREATE TABLE test.t1 (a INT,PRIMARY KEY(a)); +CREATE TABLE test.t2 (a INT,PRIMARY KEY(a)); +INSERT INTO test.t1 VALUES(1),(2); + +delimiter |; +CREATE PROCEDURE test.p1() +BEGIN + SELECT SQL_CALC_FOUND_ROWS * FROM test.t1 LIMIT 1; + INSERT INTO test.t2 VALUES(FOUND_ROWS()); +END| +delimiter ;| + +CALL test.p1(); +SELECT * FROM test.t2; + +sync_slave_with_master; +SELECT * FROM test.t2; + +# Cleanup + +connection master; +DROP PROCEDURE IF EXISTS test.p1; +DROP TABLE IF EXISTS test.t1; +DROP TABLE IF EXISTS test.t2; +sync_slave_with_master; + +# End of 5.0 test case +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_sp009.test b/mysql-test/suite/rpl/t/rpl_row_sp009.test new file mode 100644 index 00000000..83d743b8 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_sp009.test @@ -0,0 +1,98 @@ +############################################################################# +# Original Author: JBM # +# Original Date: Aug/18/2005 # +# Updated: 08/29/2005 removed sleeps and added master pos save and snyc # +############################################################################# +#TEST: Taken and modfied from http://bugs.mysql.com/bug.php?id=12168 # +############################################################################# + +# Includes +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + + +# Begin clean up test section +connection master; +--disable_warnings +DROP PROCEDURE IF EXISTS test.p1; +DROP TABLE IF EXISTS test.t1; +DROP TABLE IF EXISTS test.t2; + + +# Begin test section 1 +CREATE TABLE test.t1 (a INT, PRIMARY KEY(a)); +INSERT INTO test.t1 VALUES (1),(2),(3),(4); +CREATE TABLE test.t2 (a INT, PRIMARY KEY(a)); + +delimiter |; +CREATE PROCEDURE test.p1 (arg1 CHAR(1)) +BEGIN + DECLARE b, c INT; + IF arg1 = 'a' THEN + BEGIN + DECLARE cur1 CURSOR FOR SELECT A FROM test.t1 WHERE a % 2; + DECLARE continue handler for not found set b = 1; + SET b = 0; + OPEN cur1; + c1_repeat: REPEAT + FETCH cur1 INTO c; + IF (b = 1) THEN + LEAVE c1_repeat; + END IF; + + INSERT INTO test.t2 VALUES (c); + UNTIL b = 1 + END REPEAT; + CLOSE cur1; + END; + END IF; + IF arg1 = 'b' THEN + BEGIN + DECLARE cur2 CURSOR FOR SELECT a FROM test.t1 WHERE NOT a % 2; + DECLARE continue handler for not found set b = 1; + SET b = 0; + OPEN cur2; + c2_repeat: REPEAT + FETCH cur2 INTO c; + IF (b = 1) THEN + LEAVE c2_repeat; + END IF; + + INSERT INTO test.t2 VALUES (c); + UNTIL b = 1 + END REPEAT; + CLOSE cur2; + END; + END IF; +END| +delimiter ;| + +CALL test.p1('a'); +SELECT * FROM test.t2 ORDER BY a; +sync_slave_with_master; +SELECT * FROM test.t2 ORDER BY a; +connection master; +truncate test.t2; + +# this next call fails, but should not +call test.p1('b'); +select * from test.t2 ORDER BY a; +sync_slave_with_master; +SELECT * FROM test.t2 ORDER BY a; + +connection master; +truncate test.t2; +SELECT * FROM test.t2 ORDER BY a; +sync_slave_with_master; +SELECT * FROM test.t2 ORDER BY a; + +# Cleanup +connection master; +#show binlog events; +DROP PROCEDURE test.p1; +DROP TABLE test.t1; +DROP TABLE test.t2; +sync_slave_with_master; + +# End of 5.0 test case +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_sp010.test b/mysql-test/suite/rpl/t/rpl_row_sp010.test new file mode 100644 index 00000000..aad7edcd --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_sp010.test @@ -0,0 +1,77 @@ +############################################################################# +# Original Author: JBM # +# Original Date: Aug/18/2005 # +# Update: 08/29/2005 remove sleep added master pos save and sync # +############################################################################# +#TEST: Taken and modfied from http://bugs.mysql.com/bug.php?id=11126 # +############################################################################# + +# Includes +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + + +# Begin clean up test section +connection master; +--disable_warnings +DROP PROCEDURE IF EXISTS test.p1; +DROP PROCEDURE IF EXISTS test.p2; +DROP PROCEDURE IF EXISTS test.p3; +DROP PROCEDURE IF EXISTS test.p4; +DROP TABLE IF EXISTS test.t1; +DROP TABLE IF EXISTS test.t2; + + +# Begin test section 1 +delimiter |; +CREATE PROCEDURE test.p1() +BEGIN + INSERT INTO test.t1 VALUES(2); +END| +CREATE PROCEDURE test.p2() +BEGIN + DROP TEMPORARY TABLE IF EXISTS test.t1; + CREATE TEMPORARY TABLE test.t1 (a int, PRIMARY KEY(a)); + INSERT INTO test.t1 VALUES(1); + CALL test.p1(); +END| +delimiter ;| +CALL test.p2(); +SELECT * FROM test.t1 ORDER BY a; + +sync_slave_with_master; +show tables; + +connection master; +delimiter |; +CREATE PROCEDURE test.p3() +BEGIN + INSERT INTO test.t2 VALUES(7); +END| +CREATE PROCEDURE test.p4() +BEGIN + DROP TABLE IF EXISTS test.t2; + CREATE TABLE test.t2 (a int, PRIMARY KEY(a)); + INSERT INTO test.t2 VALUES(6); + CALL test.p3(); +END| +delimiter ;| +CALL test.p4(); +SELECT * FROM test.t2 ORDER BY a; + +sync_slave_with_master; +SELECT * FROM test.t2 ORDER BY a; + +# Cleanup +connection master; +#show binlog events; +DROP PROCEDURE IF EXISTS test.p1; +DROP PROCEDURE IF EXISTS test.p2; +DROP PROCEDURE IF EXISTS test.p3; +DROP PROCEDURE IF EXISTS test.p4; +DROP TABLE IF EXISTS test.t1; +DROP TABLE IF EXISTS test.t2; +sync_slave_with_master; + +# End of 5.0 test case +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_sp011.test b/mysql-test/suite/rpl/t/rpl_row_sp011.test new file mode 100644 index 00000000..d2a323fa --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_sp011.test @@ -0,0 +1,112 @@ +############################################################################# +# Original Author: JBM # +# Original Date: Aug/18/2005 # +# Updated: 08/29/2005 turned on diff and commented out debug SQL statements# +############################################################################# +#TEST: SP to test alter table and nested SP calls # +############################################################################# + +# Includes +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + + +# Begin clean up test section +connection master; +--disable_warnings +DROP PROCEDURE IF EXISTS test.p1; +DROP PROCEDURE IF EXISTS test.p2; +DROP PROCEDURE IF EXISTS test.p3; +DROP PROCEDURE IF EXISTS test.p4; +DROP PROCEDURE IF EXISTS test.p5; +DROP PROCEDURE IF EXISTS test.p6; +DROP PROCEDURE IF EXISTS test.p7; +DROP TABLE IF EXISTS test.t1; +DROP TABLE IF EXISTS test.t2; + + +# Begin test section 1 +CREATE TABLE test.t1 (a int, PRIMARY KEY(a)); +INSERT INTO test.t1 VALUES (1); + +delimiter |; +CREATE PROCEDURE test.p1() +BEGIN + ALTER TABLE test.t1 ADD COLUMN b CHAR(4) AFTER a; + UPDATE test.t1 SET b = 'rbr' WHERE a = 1; + CALL test.p2(); +END| +CREATE PROCEDURE test.p2() +BEGIN + ALTER TABLE test.t1 ADD COLUMN f FLOAT AFTER b; + UPDATE test.t1 SET f = RAND() WHERE a = 1; + CALL test.p3(); +END| +CREATE PROCEDURE test.p3() +BEGIN + ALTER TABLE test.t1 RENAME test.t2; + CALL test.p4(); +END| +CREATE PROCEDURE test.p4() +BEGIN + ALTER TABLE test.t2 ADD INDEX (f); + ALTER TABLE test.t2 CHANGE a a INT UNSIGNED NOT NULL AUTO_INCREMENT; + INSERT INTO test.t2 VALUES (NULL,'TEST',RAND()); + CALL test.p5(); +END| +CREATE PROCEDURE test.p5() +BEGIN + ALTER TABLE test.t2 ORDER BY f; + INSERT INTO test.t2 VALUES (NULL,'STM',RAND()); + CALL test.p6(); +END| +CREATE PROCEDURE test.p6() +BEGIN + ALTER TABLE test.t2 ADD COLUMN b2 CHAR(4) FIRST; + ALTER TABLE test.t2 ADD COLUMN to_drop BIT(8) AFTER b2; + INSERT INTO test.t2 VALUES ('new',1,NULL,'STM',RAND()); + CALL test.p7(); +END| +CREATE PROCEDURE test.p7() +BEGIN + ALTER TABLE test.t2 DROP COLUMN to_drop; + INSERT INTO test.t2 VALUES ('gone',NULL,'STM',RAND()); +END| +delimiter ;| +CALL test.p1(); + +#SELECT * FROM test.t2; +sync_slave_with_master; +#SELECT * FROM test.t2; + +--exec $MYSQL_DUMP --compact --order-by-primary --skip-extended-insert --no-create-info test > $MYSQLTEST_VARDIR/tmp/sp011_master.sql +--exec $MYSQL_DUMP_SLAVE --compact --order-by-primary --skip-extended-insert --no-create-info test > $MYSQLTEST_VARDIR/tmp/sp011_slave.sql + +# Cleanup +connection master; +#show binlog events; +DROP PROCEDURE IF EXISTS test.p1; +DROP PROCEDURE IF EXISTS test.p2; +DROP PROCEDURE IF EXISTS test.p3; +DROP PROCEDURE IF EXISTS test.p4; +DROP PROCEDURE IF EXISTS test.p5; +DROP PROCEDURE IF EXISTS test.p6; +DROP PROCEDURE IF EXISTS test.p7; +DROP TABLE IF EXISTS test.t1; +DROP TABLE IF EXISTS test.t2; +sync_slave_with_master; + +# Lets compare. Note: If they match test will pass, if they do not match +# the test will show that the diff statement failed and not reject file +# will be created. You will need to go to the mysql-test dir and diff +# the files your self to see what is not matching :-) Failed test +# Will leave dump files in $MYSQLTEST_VARDIR/tmp + +diff_files $MYSQLTEST_VARDIR/tmp/sp011_master.sql $MYSQLTEST_VARDIR/tmp/sp011_slave.sql; + +# If all is good, when can cleanup our dump files. +--remove_file $MYSQLTEST_VARDIR/tmp/sp011_master.sql +--remove_file $MYSQLTEST_VARDIR/tmp/sp011_slave.sql + +# End of 5.0 test case +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_sp012.test b/mysql-test/suite/rpl/t/rpl_row_sp012.test new file mode 100644 index 00000000..2b8549bf --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_sp012.test @@ -0,0 +1,74 @@ +############################################################################# +# Original Author: JBM # +# Original Date: Aug/22/2005 # +# Update: 08/29/2005 Added save pos and sync # +############################################################################# +#TEST: SP to test security and current_user and user # +############################################################################# + + +# Includes +-- source include/have_binlog_format_row.inc +-- source include/not_embedded.inc +-- source include/master-slave.inc + + +# Begin clean up test section +connection master; +--disable_warnings +DROP PROCEDURE IF EXISTS test.p1; +DROP PROCEDURE IF EXISTS test.p2; +DROP PROCEDURE IF EXISTS test.p3; + + +# Begin test section 1 +# Create user user1 with no particular access rights +create user user1@localhost; +grant usage on *.* to user1@localhost; +flush privileges; + +SELECT CURRENT_USER(); +SELECT USER(); +CREATE PROCEDURE test.p1 () SQL SECURITY INVOKER SELECT CURRENT_USER(), USER(); +CREATE PROCEDURE test.p2 () SQL SECURITY DEFINER CALL test.p1(); +CREATE PROCEDURE test.p3 () SQL SECURITY INVOKER CALL test.p1(); +GRANT EXECUTE ON PROCEDURE p1 TO user1@localhost; +GRANT EXECUTE ON PROCEDURE p2 TO user1@localhost; +GRANT EXECUTE ON PROCEDURE p3 TO user1@localhost; +set sql_mode=default; + +# Need to wait for the rights to be applied at the slave +sync_slave_with_master; + +connect (muser1,localhost,user1,,); +connection muser1; +SELECT CURRENT_USER(); +SELECT USER(); +CALL test.p3(); +CALL test.p2(); + +connect (suser1,127.0.0.1,user1,,test,$SLAVE_MYPORT,); + +connection master; +save_master_pos; +connection suser1; +sync_with_master; + +SELECT CURRENT_USER(); +SELECT USER(); +CALL test.p3(); +CALL test.p2(); + +# Cleanup +connection master; +DROP PROCEDURE IF EXISTS test.p1; +DROP PROCEDURE IF EXISTS test.p3; +DROP PROCEDURE IF EXISTS test.p2; +DROP TABLE IF EXISTS test.t1; +DROP TABLE IF EXISTS test.t2; +DROP USER user1@localhost; +sync_slave_with_master; + +# End of 5.0 test case + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_spatial.test b/mysql-test/suite/rpl/t/rpl_row_spatial.test new file mode 100644 index 00000000..00c3dd7c --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_spatial.test @@ -0,0 +1,17 @@ +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +CREATE TABLE t1 (g POINT NOT NULL, SPATIAL INDEX(g)); +INSERT INTO t1 VALUES (ST_GEOMFROMTEXT('Point(1 1)')); +INSERT INTO t1 VALUES (ST_GEOMFROMTEXT('Point(2 1)')); +INSERT INTO t1 VALUES (ST_GEOMFROMTEXT('Point(1 2)')); +INSERT INTO t1 VALUES (ST_GEOMFROMTEXT('Point(2 2)')); +DELETE FROM t1 where MBREqual(g, ST_GEOMFROMTEXT('Point(1 2)')); + +--sync_slave_with_master +select count(*) from t1; + +--connection master +DELETE FROM t1; +drop table t1; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_tabledefs_2myisam.test b/mysql-test/suite/rpl/t/rpl_row_tabledefs_2myisam.test new file mode 100644 index 00000000..e1ecf702 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_tabledefs_2myisam.test @@ -0,0 +1,9 @@ + +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + +let $engine_type = 'MyISAM'; +-- source include/rpl_row_tabledefs.test + + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_tabledefs_3innodb.test b/mysql-test/suite/rpl/t/rpl_row_tabledefs_3innodb.test new file mode 100644 index 00000000..49abc84c --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_tabledefs_3innodb.test @@ -0,0 +1,10 @@ + +-- source include/have_binlog_format_row.inc +-- source include/have_innodb.inc +-- source include/master-slave.inc + +let $engine_type = 'InnoDB'; +-- source include/rpl_row_tabledefs.test + + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_tbl_metadata.test b/mysql-test/suite/rpl/t/rpl_row_tbl_metadata.test new file mode 100644 index 00000000..d3a115e9 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_tbl_metadata.test @@ -0,0 +1,338 @@ +# +# BUG#42749: infinite loop writing to row based binlog - processlist shows +# "freeing items" +# +# +# WHY +# === +# +# This bug would make table map event to report data_written one +# byte less than what would actually be written in its body. This +# would cause one byte shorter event end_log_pos. The ultimate +# impact was that it would make fixing the position in +# MYSQL_BIN_LOG::write_cache bogus or end up in an infinite loop. +# +# HOW +# === +# +# Checking that the patch fixes the problem is done as follows: +# +# i) one table with m_field_metadata sized at 290 +# ii) an insert is performed; +# iii) the logs are flushed; +# iv) mysqlbinlog is used to check if it succeeds. +# +# In step iv), before the bug was fixed, the test case would fail +# with mysqlbinlog reporting that it was unable to succeed in +# reading the event. + +-- source include/have_innodb.inc +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + +-- disable_warnings +DROP TABLE IF EXISTS `t1`; +-- enable_warnings + +-- echo ### TABLE with field_metadata_size == 290 +CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + `c2` varchar(30) NOT NULL, + `c3` varchar(30) DEFAULT NULL, + `c4` varchar(30) DEFAULT NULL, + `c5` varchar(30) DEFAULT NULL, + `c6` varchar(30) DEFAULT NULL, + `c7` varchar(30) DEFAULT NULL, + `c8` varchar(30) DEFAULT NULL, + `c9` varchar(30) DEFAULT NULL, + `c10` varchar(30) DEFAULT NULL, + `c11` varchar(30) DEFAULT NULL, + `c12` varchar(30) DEFAULT NULL, + `c13` varchar(30) DEFAULT NULL, + `c14` varchar(30) DEFAULT NULL, + `c15` varchar(30) DEFAULT NULL, + `c16` varchar(30) DEFAULT NULL, + `c17` varchar(30) DEFAULT NULL, + `c18` varchar(30) DEFAULT NULL, + `c19` varchar(30) DEFAULT NULL, + `c20` varchar(30) DEFAULT NULL, + `c21` varchar(30) DEFAULT NULL, + `c22` varchar(30) DEFAULT NULL, + `c23` varchar(30) DEFAULT NULL, + `c24` varchar(30) DEFAULT NULL, + `c25` varchar(30) DEFAULT NULL, + `c26` varchar(30) DEFAULT NULL, + `c27` varchar(30) DEFAULT NULL, + `c28` varchar(30) DEFAULT NULL, + `c29` varchar(30) DEFAULT NULL, + `c30` varchar(30) DEFAULT NULL, + `c31` varchar(30) DEFAULT NULL, + `c32` varchar(30) DEFAULT NULL, + `c33` varchar(30) DEFAULT NULL, + `c34` varchar(30) DEFAULT NULL, + `c35` varchar(30) DEFAULT NULL, + `c36` varchar(30) DEFAULT NULL, + `c37` varchar(30) DEFAULT NULL, + `c38` varchar(30) DEFAULT NULL, + `c39` varchar(30) DEFAULT NULL, + `c40` varchar(30) DEFAULT NULL, + `c41` varchar(30) DEFAULT NULL, + `c42` varchar(30) DEFAULT NULL, + `c43` varchar(30) DEFAULT NULL, + `c44` varchar(30) DEFAULT NULL, + `c45` varchar(30) DEFAULT NULL, + `c46` varchar(30) DEFAULT NULL, + `c47` varchar(30) DEFAULT NULL, + `c48` varchar(30) DEFAULT NULL, + `c49` varchar(30) DEFAULT NULL, + `c50` varchar(30) DEFAULT NULL, + `c51` varchar(30) DEFAULT NULL, + `c52` varchar(30) DEFAULT NULL, + `c53` varchar(30) DEFAULT NULL, + `c54` varchar(30) DEFAULT NULL, + `c55` varchar(30) DEFAULT NULL, + `c56` varchar(30) DEFAULT NULL, + `c57` varchar(30) DEFAULT NULL, + `c58` varchar(30) DEFAULT NULL, + `c59` varchar(30) DEFAULT NULL, + `c60` varchar(30) DEFAULT NULL, + `c61` varchar(30) DEFAULT NULL, + `c62` varchar(30) DEFAULT NULL, + `c63` varchar(30) DEFAULT NULL, + `c64` varchar(30) DEFAULT NULL, + `c65` varchar(30) DEFAULT NULL, + `c66` varchar(30) DEFAULT NULL, + `c67` varchar(30) DEFAULT NULL, + `c68` varchar(30) DEFAULT NULL, + `c69` varchar(30) DEFAULT NULL, + `c70` varchar(30) DEFAULT NULL, + `c71` varchar(30) DEFAULT NULL, + `c72` varchar(30) DEFAULT NULL, + `c73` varchar(30) DEFAULT NULL, + `c74` varchar(30) DEFAULT NULL, + `c75` varchar(30) DEFAULT NULL, + `c76` varchar(30) DEFAULT NULL, + `c77` varchar(30) DEFAULT NULL, + `c78` varchar(30) DEFAULT NULL, + `c79` varchar(30) DEFAULT NULL, + `c80` varchar(30) DEFAULT NULL, + `c81` varchar(30) DEFAULT NULL, + `c82` varchar(30) DEFAULT NULL, + `c83` varchar(30) DEFAULT NULL, + `c84` varchar(30) DEFAULT NULL, + `c85` varchar(30) DEFAULT NULL, + `c86` varchar(30) DEFAULT NULL, + `c87` varchar(30) DEFAULT NULL, + `c88` varchar(30) DEFAULT NULL, + `c89` varchar(30) DEFAULT NULL, + `c90` varchar(30) DEFAULT NULL, + `c91` varchar(30) DEFAULT NULL, + `c92` varchar(30) DEFAULT NULL, + `c93` varchar(30) DEFAULT NULL, + `c94` varchar(30) DEFAULT NULL, + `c95` varchar(30) DEFAULT NULL, + `c96` varchar(30) DEFAULT NULL, + `c97` varchar(30) DEFAULT NULL, + `c98` varchar(30) DEFAULT NULL, + `c99` varchar(30) DEFAULT NULL, + `c100` varchar(30) DEFAULT NULL, + `c101` varchar(30) DEFAULT NULL, + `c102` varchar(30) DEFAULT NULL, + `c103` varchar(30) DEFAULT NULL, + `c104` varchar(30) DEFAULT NULL, + `c105` varchar(30) DEFAULT NULL, + `c106` varchar(30) DEFAULT NULL, + `c107` varchar(30) DEFAULT NULL, + `c108` varchar(30) DEFAULT NULL, + `c109` varchar(30) DEFAULT NULL, + `c110` varchar(30) DEFAULT NULL, + `c111` varchar(30) DEFAULT NULL, + `c112` varchar(30) DEFAULT NULL, + `c113` varchar(30) DEFAULT NULL, + `c114` varchar(30) DEFAULT NULL, + `c115` varchar(30) DEFAULT NULL, + `c116` varchar(30) DEFAULT NULL, + `c117` varchar(30) DEFAULT NULL, + `c118` varchar(30) DEFAULT NULL, + `c119` varchar(30) DEFAULT NULL, + `c120` varchar(30) DEFAULT NULL, + `c121` varchar(30) DEFAULT NULL, + `c122` varchar(30) DEFAULT NULL, + `c123` varchar(30) DEFAULT NULL, + `c124` varchar(30) DEFAULT NULL, + `c125` varchar(30) DEFAULT NULL, + `c126` varchar(30) DEFAULT NULL, + `c127` varchar(30) DEFAULT NULL, + `c128` varchar(30) DEFAULT NULL, + `c129` varchar(30) DEFAULT NULL, + `c130` varchar(30) DEFAULT NULL, + `c131` varchar(30) DEFAULT NULL, + `c132` varchar(30) DEFAULT NULL, + `c133` varchar(30) DEFAULT NULL, + `c134` varchar(30) DEFAULT NULL, + `c135` varchar(30) DEFAULT NULL, + `c136` varchar(30) DEFAULT NULL, + `c137` varchar(30) DEFAULT NULL, + `c138` varchar(30) DEFAULT NULL, + `c139` varchar(30) DEFAULT NULL, + `c140` varchar(30) DEFAULT NULL, + `c141` varchar(30) DEFAULT NULL, + `c142` varchar(30) DEFAULT NULL, + `c143` varchar(30) DEFAULT NULL, + `c144` varchar(30) DEFAULT NULL, + `c145` varchar(30) DEFAULT NULL, + `c146` varchar(30) DEFAULT NULL, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB; + +LOCK TABLES `t1` WRITE; +INSERT INTO `t1`(c2) VALUES ('1'); +FLUSH LOGS; + +-- sync_slave_with_master +-- connection master + +-- echo ### assertion: the slave replicated event successfully and tables match +-- let $diff_tables= master:t1, slave:t1 +-- source include/diff_tables.inc + +DROP TABLE `t1`; + +-- connection master +-- sync_slave_with_master +-- connection master + +-- echo === Using mysqlbinlog to detect failure. Before the patch mysqlbinlog would find a corrupted event, thence would fail. + +-- let $MYSQLD_DATADIR= `SELECT @@datadir` +-- exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_bug42749.binlog +-- remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_bug42749.binlog + +############################################################# +# BUG#50018: binlog corruption when table has many columns +# +# Same test from BUG#42749, but now we generate some SQL which +# creates and inserts into tables with metadata size from 249 +# to 258. +# +# The test works as follows: +# 1. SQL for several CREATE TABLE and INSERTS are generated +# into a file. +# 2. This file is then "sourced" +# 3. The slave is synchronized with the master +# 4. FLUSH LOGS on master +# 5. Compare tables on master and slave. +# 6. run mysqlbinlog on master's binary log +# +# Steps #5 and #6 assert that binary log is not corrupted +# in both cases: when slave is replaying events and when +# mysqlbinlog is used to read the binary log + +--source include/rpl_reset.inc +-- connection master + +# Create several tables with field_metadata_size ranging +# from 249 to 258 (so that we cover 251 and 255 range). +# This should exercise the switch between using 1 or 3 +# bytes to pack m_field_metadata_size. +# +# Each varchar field takes up to 2 metadata bytes, see: +# +# Field_varstring::save_field_metadata (field.cc) +# +# The float field takes 1 byte, see: +# +# Field_float::save_field_metadata (field.cc) +# + +-- let $generated_sql= $MYSQLTEST_VARDIR/tmp/b50018.sql +-- let B50018_FILE= $generated_sql + +-- echo ### action: generating several tables with different metadata +-- echo ### sizes (resorting to perl) +-- perl +my $file= $ENV{'B50018_FILE'}; +open(FILE, ">", "$file") or die "Unable to open bug 50018 generated SQL file: $!" ; + +my $tables= ""; +my $ntables= 10; +my $base_ncols= 124; + +for my $i (1..$ntables) +{ + my $ncols= $base_ncols + $i; + my $metadata_size= $ncols_variable * 2 + 1; + + print FILE "-- echo ### testing table with " . ($base_ncols*2 + $i) . " field metadata size.\n"; + print FILE "CREATE TABLE t$i (\n"; + for my $n (1..$base_ncols) + { + print FILE "c$n VARCHAR(30) NOT NULL DEFAULT 'BUG#50018',\n"; + } + + for my $n (1..$i) + { + print FILE "c" . ($base_ncols+$n) . " FLOAT NOT NULL DEFAULT 0"; + if ($n < $i) + { + print FILE ",\n"; + } + } + + print FILE ") Engine=InnoDB;\n"; + + $tables.= " t$i WRITE"; + if ($i < $ntables) + { + $tables .=","; + } + + print FILE "LOCK TABLES t$i WRITE;\n"; + print FILE "INSERT INTO t$i(c". ($base_ncols+1) . ") VALUES (50018);\n"; + print FILE "UNLOCK TABLES;"; +} + +close(FILE); + +EOF + +## we don't need this in the result file +## however, for debugging purposes you +## may want to reactivate query logging +-- disable_query_log +-- source $generated_sql +-- enable_query_log + +-- sync_slave_with_master +-- connection master + +FLUSH LOGS; + +-- let $ntables=10 +while($ntables) +{ + -- echo ### assertion: the slave replicated event successfully and tables match for t$ntables + -- let $diff_tables= master:t$ntables, slave:t$ntables + -- source include/diff_tables.inc + + -- connection master + -- disable_query_log + -- eval DROP TABLE t$ntables + -- enable_query_log + -- sync_slave_with_master + -- connection master + + -- dec $ntables +} + +-- echo ### assertion: check that binlog is not corrupt. Using mysqlbinlog to +-- echo ### detect failure. Before the patch mysqlbinlog would find +-- echo ### a corrupted event, thence would fail. +-- let $MYSQLD_DATADIR= `SELECT @@datadir` +-- exec $MYSQL_BINLOG -v --hexdump $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_bug50018.binlog + +## clean up +## For debugging purposes you might want not to remove these +-- remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_bug50018.binlog +-- remove_file $generated_sql +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_to_stmt-master.opt b/mysql-test/suite/rpl/t/rpl_row_to_stmt-master.opt new file mode 100644 index 00000000..83ed8522 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_to_stmt-master.opt @@ -0,0 +1 @@ +--binlog-format=row diff --git a/mysql-test/suite/rpl/t/rpl_row_to_stmt-slave.opt b/mysql-test/suite/rpl/t/rpl_row_to_stmt-slave.opt new file mode 100644 index 00000000..af3a2119 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_to_stmt-slave.opt @@ -0,0 +1 @@ +--binlog-format=statement diff --git a/mysql-test/suite/rpl/t/rpl_row_to_stmt.test b/mysql-test/suite/rpl/t/rpl_row_to_stmt.test new file mode 100644 index 00000000..5ca583d8 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_to_stmt.test @@ -0,0 +1,23 @@ +# +# check that master starterd with log-format=ROW replication can replicate to +# slave started with log-format=STATEMENT +# + +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +use test; + +create table t1 (a int primary key); +insert into t1 values (1),(2),(3),(4),(5); +update t1 set a=a*10; + +sync_slave_with_master; +use test; +select * from t1; +source include/show_binlog_events.inc; + +connection master; +drop table t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_trig001.test b/mysql-test/suite/rpl/t/rpl_row_trig001.test new file mode 100644 index 00000000..39f2662b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_trig001.test @@ -0,0 +1,116 @@ +############################################################################# +# Original Author: JBM # +# Original Date: Aug/09/2005 # +############################################################################# +# TEST: Use after insert and before inset triggers and stored procdures to # +# Update and insert data # +############################################################################# + +# Includes +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + +-- disable_query_log +-- disable_result_log + +# Begin clean up test section +connection master; +--disable_warnings +DROP PROCEDURE IF EXISTS test.p2; +DROP PROCEDURE IF EXISTS test.p3; +--error 0,1360 +DROP TRIGGER test.t2_ai; +--error 0,1360 +DROP TRIGGER test.t3_bi_t2; +--error 0,1360 +DROP TABLE IF EXISTS test.t1; +DROP TABLE IF EXISTS test.t2; +DROP TABLE IF EXISTS test.t3; + + +# test section 1, lets add a trigger to the mix. Taken from bug #12280 +let $message=<Begin test section 1 (Tiggers & SP)>; +--source include/show_msg.inc + +CREATE TABLE test.t1 (n MEDIUMINT NOT NULL, d DATETIME, PRIMARY KEY(n)); +CREATE TABLE test.t2 (n MEDIUMINT NOT NULL AUTO_INCREMENT, f FLOAT, d DATETIME, PRIMARY KEY(n)); +CREATE TABLE test.t3 (n MEDIUMINT NOT NULL AUTO_INCREMENT, d DATETIME, PRIMARY KEY(n)); + +INSERT INTO test.t1 VALUES (1,NOW()); + +delimiter //; +CREATE TRIGGER test.t2_ai AFTER INSERT ON test.t2 FOR EACH ROW UPDATE test.t1 SET d=NOW() where n = 1// +CREATE PROCEDURE test.p3() +BEGIN + INSERT INTO test.t3 (d) VALUES (NOW()); +END// +CREATE TRIGGER test.t3_bi_t2 BEFORE INSERT ON test.t2 FOR EACH ROW CALL test.p3()// +CREATE PROCEDURE test.p2() +BEGIN + INSERT INTO test.t2 (f,d) VALUES (RAND(),NOW()); +END// +delimiter ;// + +# Make sure that all definition have propagated to the slave +sync_slave_with_master; + +connection master; +-- disable_query_log +-- disable_result_log +SET @wait_count = 1; +let $1=10; +while ($1) +{ + CALL test.p2(); + let $wait_condition= SELECT COUNT(*) = @wait_count FROM test.t3; + --source include/wait_condition.inc + --disable_query_log + SET @wait_count = @wait_count + 1; + dec $1; +} +-- enable_result_log +-- enable_query_log + +# Just a precaution to make sure all changes have made it over to the +# slave +connection master; +let $count = `select count(*) from t1`; +eval INSERT INTO test.t1 VALUES ($count+1, NOW()); +sync_slave_with_master; + +#show binlog events; +#select * from test.t2; +#select * from test.t3; +#connection slave; +#select * from test.t2; +#select * from test.t3; + +let $message=<End test section 2 (Tiggers & SP)>; +--source include/show_msg.inc + +# time to dump the databases and so we can see if they match + +--exec $MYSQL_DUMP --compact --order-by-primary --skip-extended-insert --no-create-info test > $MYSQLTEST_VARDIR/tmp/trig001_master.sql +--exec $MYSQL_DUMP_SLAVE --compact --order-by-primary --skip-extended-insert --no-create-info test > $MYSQLTEST_VARDIR/tmp/trig001_slave.sql + +# Cleanup +connection master; +DROP PROCEDURE test.p2; +DROP PROCEDURE test.p3; +DROP TRIGGER test.t2_ai; +DROP TRIGGER test.t3_bi_t2; +DROP TABLE test.t1; +DROP TABLE test.t2; +DROP TABLE test.t3; +sync_slave_with_master; + +# Lets compare. Note: If they match test will pass, if they do not match +# the test will show that the diff statement failed and not reject file +# will be created. You will need to go to the mysql-test dir and diff +# the files your self to see what is not matching :-) Failed tests +# will leave dump files in $MYSQLTEST_VARDIR/tmp + +diff_files $MYSQLTEST_VARDIR/tmp/trig001_master.sql $MYSQLTEST_VARDIR/tmp/trig001_slave.sql; + +# End of 5.0 test case +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_trig002.test b/mysql-test/suite/rpl/t/rpl_row_trig002.test new file mode 100644 index 00000000..f04d1e6d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_trig002.test @@ -0,0 +1,77 @@ +############################################################################# +# Original Author: JBM # +# Original Date: Aug/14/2005 # +# Updated: 08/29/2005 added save master pos and sync with master # +############################################################################# +# TEST: Taken and modified from BUG#12048 After Insert updates replication # +############################################################################# + +# Includes +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + +#-- disable_query_log +#-- disable_result_log + +# Begin clean up test section +connection master; +--disable_warnings +--error 0,1360 +DROP TRIGGER test.t2_ai; +DROP TABLE IF EXISTS test.t1; +DROP TABLE IF EXISTS test.t2; +DROP TABLE IF EXISTS test.t3; +--enable_warnings + +# test section 1, Taken from bug #12408 + +CREATE TABLE test.t2 (value CHAR(30),domain_id INT, mailaccount_id INT, program CHAR(30),keey CHAR(30),PRIMARY KEY(domain_id)); + +CREATE TABLE test.t3 (value CHAR(30),domain_id INT, mailaccount_id INT, program CHAR(30),keey CHAR(30),PRIMARY KEY(domain_id)); + +CREATE TABLE test.t1 (id INT,domain CHAR(30),PRIMARY KEY(id)); + +delimiter |; +CREATE TRIGGER test.t2_ai AFTER INSERT ON test.t2 FOR EACH ROW UPDATE test.t3 ms, test.t1 d SET ms.value='No' WHERE ms.domain_id = (SELECT max(id) FROM test.t1 WHERE domain='example.com') AND ms.mailaccount_id IS NULL AND ms.program='spamfilter' AND ms.keey='scan_incoming'| +delimiter ;| + +INSERT INTO test.t1 VALUES (1, 'example.com'),(2, 'mysql.com'),(3, 'earthmotherwear.com'), (4, 'yahoo.com'),(5, 'example.com'); + +SELECT * FROM test.t1 ORDER BY id; +#show binlog events; +sync_slave_with_master; +SELECT * FROM test.t1 ORDER BY id; +connection master; + +INSERT INTO test.t3 VALUES ('Yes', 5, NULL, 'spamfilter','scan_incoming'); +INSERT INTO test.t3 VALUES ('Yes', 1, NULL, 'spamfilter','scan_incoming'); +INSERT INTO test.t2 VALUES ('Yes', 1, NULL, 'spamfilter','scan_incoming'); + +select * from test.t2; +--sorted_result +select * from test.t3; +sync_slave_with_master; +select * from test.t2; +--sorted_result +select * from test.t3; +connection master; + +DELETE FROM test.t1 WHERE id = 1; + +SELECT * FROM test.t1 ORDER BY id; +connection master; +SELECT * FROM test.t1 ORDER BY id; +sync_slave_with_master; +SELECT * FROM test.t1 ORDER BY id; + +# Cleanup +connection master; +#show binlog events; +DROP TRIGGER test.t2_ai; +DROP TABLE test.t1; +DROP TABLE test.t2; +DROP TABLE test.t3; +sync_slave_with_master; + +# End of 5.0 test case +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_trig003.test b/mysql-test/suite/rpl/t/rpl_row_trig003.test new file mode 100644 index 00000000..e332fc91 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_trig003.test @@ -0,0 +1,155 @@ +############################################################################# +# Original Author: JBM # +# Original Date: Aug/16/2005 # +# Updated: 8/29/2005 Remove sleep calls add dump and diff # +############################################################################# +# TEST: This test includes all trigger types. BEFORE/AFTER INSERT, UPDATE & # +# DELETE. In addition, includes cursor, bit, varchar, flow control, # +# looping, ROUND(), NOW(), YEAR(), TIMESTAMP # +############################################################################# + +# Includes +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + +#-- disable_query_log +#-- disable_result_log + +# Begin clean up test section +connection master; +--disable_warnings +--error 0,1360 +DROP TRIGGER test.t1_bi; +--error 0,1360 +DROP TRIGGER test.t2_ai; +--error 0,1360 +DROP TRIGGER test.t1_bu; +--error 0,1360 +DROP TRIGGER test.t2_au; +--error 0,1360 +DROP TRIGGER test.t1_bd; +--error 0,1360 +DROP TRIGGER test.t2_ad; +DROP TABLE IF EXISTS test.t1; +DROP TABLE IF EXISTS test.t2; +DROP TABLE IF EXISTS test.t3; +--enable_warnings + +# test section 1 + +CREATE TABLE test.t1 (id MEDIUMINT NOT NULL AUTO_INCREMENT, b1 BIT(8), vc VARCHAR(255), bc CHAR(255), d DECIMAL(10,4) DEFAULT 0, f FLOAT DEFAULT 0, total BIGINT UNSIGNED, y YEAR, t TIMESTAMP,PRIMARY KEY(id)); +CREATE TABLE test.t2 (id MEDIUMINT NOT NULL AUTO_INCREMENT, b1 BIT(8), vc VARCHAR(255), bc CHAR(255), d DECIMAL(10,4) DEFAULT 0, f FLOAT DEFAULT 0, total BIGINT UNSIGNED, y YEAR, t TIMESTAMP,PRIMARY KEY(id)); +CREATE TABLE test.t3 (id MEDIUMINT NOT NULL AUTO_INCREMENT, b1 BIT(8), vc VARCHAR(255), bc CHAR(255), d DECIMAL(10,4) DEFAULT 0, f FLOAT DEFAULT 0, total BIGINT UNSIGNED, y YEAR, t TIMESTAMP,PRIMARY KEY(id)); + +# Note Most of these cause the slave to core or do not produce desired results. Currently commenting out the ones not working until they are fixed. + +delimiter |; +CREATE TRIGGER test.t1_bi BEFORE INSERT ON test.t1 FOR EACH ROW UPDATE test.t3 SET b1=1 and y=YEAR(NOW())| +CREATE TRIGGER test.t2_ai AFTER INSERT ON test.t2 FOR EACH ROW BEGIN + INSERT INTO test.t3 VALUES(NULL,0,'MySQL Replication team rocks!', 'Dark beer in prague is #1',12345.34,12.51,0,1965,NOW()); + UPDATE test.t3 SET f = ROUND(f); +END| +CREATE TRIGGER test.t1_bu BEFORE UPDATE on test.t1 FOR EACH ROW BEGIN + UPDATE test.t3 SET y = '2000'; + INSERT INTO test.t3 VALUES(NULL,1,'Testing MySQL databases before update ', 'Insert should work',621.43, 0105.21,0,1974,NOW()); +END| +CREATE TRIGGER test.t2_au AFTER UPDATE on test.t2 FOR EACH ROW BEGIN + DECLARE done INT DEFAULT 0; + DECLARE a DECIMAL(10,4); + DECLARE b FLOAT; + DECLARE num MEDIUMINT; + DECLARE cur1 CURSOR FOR SELECT t2.id, t2.d, t2.f FROM test.t2; + DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1; + + OPEN cur1; + + REPEAT + FETCH cur1 INTO num, a, b; + IF NOT done THEN + UPDATE test.t3 SET total =(a*b) WHERE ID = num; + END IF; + UNTIL done END REPEAT; + CLOSE cur1; +END| +CREATE TRIGGER test.t1_bd BEFORE DELETE on test.t1 FOR EACH ROW BEGIN + DECLARE done INT DEFAULT 0; + DECLARE a BIT(8); + DECLARE b VARCHAR(255); + DECLARE c CHAR(255); + DECLARE d DECIMAL(10,4); + DECLARE e FLOAT; + DECLARE f BIGINT UNSIGNED; + DECLARE g YEAR; + DECLARE h TIMESTAMP; + DECLARE cur1 CURSOR FOR SELECT t1.b1, t1.vc, t1.bc, t1.d, t1.f, t1.total, t1.y, t1.t FROM test.t1; + DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1; + + OPEN cur1; + + REPEAT + FETCH cur1 INTO a, b, c, d, e, f, g, h; + IF NOT done THEN + INSERT INTO test.t3 VALUES(NULL, a, b, c, d, e, f, g, h); + END IF; + UNTIL done END REPEAT; + CLOSE cur1; +END| +CREATE TRIGGER test.t2_ad AFTER DELETE ON test.t2 FOR EACH ROW + DELETE FROM test.t1| +delimiter ;| + +INSERT INTO test.t1 VALUES(NULL,1,'Testing MySQL databases is a cool ', 'Must make it bug free for the customer',654321.4321,15.21,0,1965,NOW()); +INSERT INTO test.t2 VALUES(NULL,0,'Testing MySQL databases is a cool ', 'MySQL Customers ROCK!',654321.4321,1.24521,0,YEAR(NOW()),NOW()); + +UPDATE test.t1 SET b1 = 0 WHERE b1 = 1; + +INSERT INTO test.t2 VALUES(NULL,1,'This is an after update test.', 'If this works, total will not be zero on the master or slave',1.4321,5.221,0,YEAR(NOW()),NOW()); +UPDATE test.t2 SET b1 = 0 WHERE b1 = 1; + +INSERT INTO test.t1 VALUES(NULL,1,'add some more test data test.', 'and hope for the best', 3.321,5.221,0,YEAR(NOW()),NOW()); + +# To make sure BUG#14698 is gone, we sleep before calling trigger +# (with the bug in, that caused differences in TIMESTAMP columns). +# We just need to let the machine's clock advance, it's not +# to do synchronization. + +let $wait_condition= SELECT SUM(f)= ROUND(SUM(f)) FROM t3; +--source include/wait_condition.inc + +DELETE FROM test.t1 WHERE id = 1; + +DELETE FROM test.t2 WHERE id = 1; + +sync_slave_with_master; +connection master; + +# time to dump the databases and so we can see if they match + +--exec $MYSQL_DUMP --compact --order-by-primary --skip-extended-insert --no-create-info test > $MYSQLTEST_VARDIR/tmp/trg003_master.sql +--exec $MYSQL_DUMP_SLAVE --compact --order-by-primary --skip-extended-insert --no-create-info test > $MYSQLTEST_VARDIR/tmp/trg003_slave.sql + +# cleanup +--disable_warnings +--error 0,1360 +DROP TRIGGER test.t1_bi; +--error 0,1360 +DROP TRIGGER test.t2_ai; +--error 0,1360 +DROP TRIGGER test.t1_bu; +--error 0,1360 +DROP TRIGGER test.t2_au; +--error 0,1360 +DROP TRIGGER test.t1_bd; +--error 0,1360 +DROP TRIGGER test.t2_ad; +DROP TABLE IF EXISTS test.t1; +DROP TABLE IF EXISTS test.t2; +DROP TABLE IF EXISTS test.t3; +--enable_warnings + +sync_slave_with_master; + +diff_files $MYSQLTEST_VARDIR/tmp/trg003_master.sql $MYSQLTEST_VARDIR/tmp/trg003_slave.sql; + +# End of 5.0 test case +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_trig004.test b/mysql-test/suite/rpl/t/rpl_row_trig004.test new file mode 100644 index 00000000..0cbdea33 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_trig004.test @@ -0,0 +1,15 @@ +############################################################################# +# Original Author: JBM # +# Original Date: Oct/18/2005 # +############################################################################# +# TEST: Use before insert triggers and has the second insert fail # +############################################################################# + +# Includes +-- source include/have_binlog_format_row.inc +-- source include/have_innodb.inc +-- source include/master-slave.inc +let $engine_type=INNODB; +-- source include/rpl_trig004.test + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_trigger_multi_db.test b/mysql-test/suite/rpl/t/rpl_row_trigger_multi_db.test new file mode 100644 index 00000000..0ade0090 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_trigger_multi_db.test @@ -0,0 +1,98 @@ +# +# This test ensures that a table share's database name is not freed when +# using row based replication with triggers that open different databases +# +# +# References: +# MDEV-29894: Calling a function from a different database in a slave side +# trigger crashes +# +--source include/master-slave.inc +--source include/have_binlog_format_row.inc + +--connection slave +--let $old_slave_run_triggers= `SELECT @@global.slave_run_triggers_for_rbr` +set global slave_run_triggers_for_rbr=1; + +--connection master +CREATE TABLE t1 (a int); +--sync_slave_with_master + +--connection slave +CREATE DATABASE db2; +CREATE FUNCTION db2.get_value(a INT) RETURNS int(2) RETURN 0; + +--echo # +--echo # Test Insert_rows_log_event + +--connection slave +DELIMITER //; +CREATE TRIGGER tr_ins BEFORE INSERT ON t1 FOR EACH ROW BEGIN +DECLARE a INT; +SET a = db2.get_value(1); +END// +DELIMITER ;// + +--connection master +INSERT INTO t1 VALUES (1); +--sync_slave_with_master + +--connection slave +DROP TRIGGER tr_ins; + + +--echo # +--echo # Test Update_rows_log_event +--connection master +--let $row_val=5 +--eval INSERT INTO t1 VALUES ($row_val) +--sync_slave_with_master + +--connection slave +DELIMITER //; +CREATE TRIGGER tr_upd BEFORE UPDATE ON t1 FOR EACH ROW BEGIN +DECLARE a INT; +SET a = db2.get_value(1); +END// +DELIMITER ;// + +--connection master +--eval UPDATE t1 SET a=a+1 WHERE a=$row_val +--sync_slave_with_master + +--connection slave +DROP TRIGGER tr_upd; + + +--echo # +--echo # Test Delete_rows_log_event +--connection master +--let $row_val=7 +--eval INSERT INTO t1 VALUES ($row_val) +--sync_slave_with_master + +--connection slave +DELIMITER //; +CREATE TRIGGER tr_del BEFORE DELETE ON t1 FOR EACH ROW BEGIN +DECLARE a INT; +SET a = db2.get_value(1); +END// +DELIMITER ;// + +--connection master +--eval DELETE FROM t1 WHERE a=$row_val +--sync_slave_with_master + +--connection slave +DROP TRIGGER tr_del; + + +--echo # +--echo # Cleanup +--connection slave +--eval SET GLOBAL slave_run_triggers_for_rbr=$old_slave_run_triggers +DROP DATABASE db2; +--connection master +DROP TABLE t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_triggers.test b/mysql-test/suite/rpl/t/rpl_row_triggers.test new file mode 100644 index 00000000..68002dbe --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_triggers.test @@ -0,0 +1,442 @@ +-- source include/have_binlog_format_row.inc +-- source include/have_innodb.inc +-- source include/master-slave.inc + +-- echo # Test of row replication with triggers on the slave side + +connection master; +CREATE TABLE t1 (C1 CHAR(1) primary key, C2 CHAR(1)) engine=innodb; +SELECT * FROM t1; + +sync_slave_with_master; + +connection slave; +SET @old_slave_exec_mode= @@global.slave_exec_mode; +SET @old_slave_run_triggers_for_rbr= @@global.slave_run_triggers_for_rbr; +SET @@global.slave_exec_mode= IDEMPOTENT; +SET @@global.slave_run_triggers_for_rbr= YES; +SELECT * FROM t1; +create table t2 (id char(2) primary key, cnt int, o char(1), n char(1)); +insert into t2 values + ('u0', 0, ' ', ' '),('u1', 0, ' ', ' '), + ('d0', 0, ' ', ' '),('d1', 0, ' ', ' '), + ('i0', 0, ' ', ' '),('i1', 0, ' ', ' '); +create trigger t1_cnt_b before update on t1 for each row + update t2 set cnt=cnt+1, o=old.C1, n=new.C1 where id = 'u0'; +create trigger t1_cnt_db before delete on t1 for each row + update t2 set cnt=cnt+1, o=old.C1, n=' ' where id = 'd0'; +create trigger t1_cnt_ib before insert on t1 for each row + update t2 set cnt=cnt+1, n=new.C1, o=' ' where id = 'i0'; +create trigger t1_cnt_a after update on t1 for each row + update t2 set cnt=cnt+1, o=old.C1, n=new.C1 where id = 'u1'; +create trigger t1_cnt_da after delete on t1 for each row + update t2 set cnt=cnt+1, o=old.C1, n=' ' where id = 'd1'; +create trigger t1_cnt_ia after insert on t1 for each row + update t2 set cnt=cnt+1, n=new.C1, o=' ' where id = 'i1'; +SELECT * FROM t2 order by id; + +connection master; +--echo # INSERT triggers test +insert into t1 values ('a','b'); + +sync_slave_with_master; + +connection slave; +SELECT * FROM t2 order by id; + +connection master; + +--echo # UPDATE triggers test +update t1 set C1= 'd'; + +sync_slave_with_master; + +connection slave; +SELECT * FROM t2 order by id; + +connection master; +--echo # DELETE triggers test +delete from t1 where C1='d'; + +sync_slave_with_master; + +connection slave; +SELECT * FROM t2 order by id; + +--echo # INSERT triggers causing DELETE + INSERT (on unique key conflict) +insert into t1 values ('0','1'); + +SELECT * FROM t2 order by id; + +connection master; + +insert into t1 values ('0','1'); + +sync_slave_with_master; + +connection slave; +SELECT * FROM t2 order by id; + + +--echo # INSERT triggers which cause also DELETE test +--echo # (insert duplicate row in table referenced by foreign key) +insert into t1 values ('1','1'); + +connection master; + +CREATE TABLE t3 (C1 CHAR(1) primary key, FOREIGN KEY (C1) REFERENCES t1(C1) ) engine=innodb; + +insert into t1 values ('1','1'); + +sync_slave_with_master; + +connection slave; +SELECT * FROM t2 order by id; + +connection master; + +drop table t3,t1; + +sync_slave_with_master; + +connection slave; +SET @@global.slave_exec_mode= @old_slave_exec_mode; +SET @@global.slave_run_triggers_for_rbr= @old_slave_run_triggers_for_rbr; +drop table t2; + +--connection master + +CREATE TABLE t1 (i INT) ENGINE=InnoDB; +CREATE TABLE t2 (i INT) ENGINE=InnoDB; + +--sync_slave_with_master + +SET @old_slave_run_triggers_for_rbr= @@global.slave_run_triggers_for_rbr; +SET GLOBAL slave_run_triggers_for_rbr=YES; + +CREATE TRIGGER tr AFTER INSERT ON t1 FOR EACH ROW + INSERT INTO t2 VALUES (new.i); + +--connection master + +BEGIN; +INSERT INTO t1 VALUES (1); +INSERT INTO t1 VALUES (2); +COMMIT; + +--sync_slave_with_master +select * from t2; +SET @@global.slave_run_triggers_for_rbr= @old_slave_run_triggers_for_rbr; + +--connection master +drop tables t2,t1; + +--sync_slave_with_master + +-- echo # Triggers on slave do not work if master has some + +connection master; +CREATE TABLE t1 (C1 CHAR(1) primary key, C2 CHAR(1)) engine=innodb; +SELECT * FROM t1; + +create trigger t1_dummy before delete on t1 for each row + set @dummy= 1; + +sync_slave_with_master; + +connection slave; +SET @old_slave_exec_mode= @@global.slave_exec_mode; +SET @old_slave_run_triggers_for_rbr= @@global.slave_run_triggers_for_rbr; +SET @@global.slave_exec_mode= IDEMPOTENT; +SET @@global.slave_run_triggers_for_rbr= YES; +SELECT * FROM t1; +create table t2 (id char(2) primary key, cnt int, o char(1), n char(1)); +insert into t2 values + ('u0', 0, ' ', ' '),('u1', 0, ' ', ' '), + ('d0', 0, ' ', ' '),('d1', 0, ' ', ' '), + ('i0', 0, ' ', ' '),('i1', 0, ' ', ' '); +create trigger t1_cnt_b before update on t1 for each row + update t2 set cnt=cnt+1, o=old.C1, n=new.C1 where id = 'u0'; +create trigger t1_cnt_ib before insert on t1 for each row + update t2 set cnt=cnt+1, n=new.C1, o=' ' where id = 'i0'; +create trigger t1_cnt_a after update on t1 for each row + update t2 set cnt=cnt+1, o=old.C1, n=new.C1 where id = 'u1'; +create trigger t1_cnt_da after delete on t1 for each row + update t2 set cnt=cnt+1, o=old.C1, n=' ' where id = 'd1'; +create trigger t1_cnt_ia after insert on t1 for each row + update t2 set cnt=cnt+1, n=new.C1, o=' ' where id = 'i1'; +SELECT * FROM t2 order by id; + +connection master; +--echo # INSERT triggers test +insert into t1 values ('a','b'); + +sync_slave_with_master; + +connection slave; +SELECT * FROM t2 order by id; + +connection master; + +--echo # UPDATE triggers test +update t1 set C1= 'd'; + +sync_slave_with_master; + +connection slave; +SELECT * FROM t2 order by id; + +connection master; +--echo # DELETE triggers test +delete from t1 where C1='d'; + +sync_slave_with_master; + +connection slave; +SELECT * FROM t2 order by id; + +--echo # INSERT triggers which cause also UPDATE test (insert duplicate row) +insert into t1 values ('0','1'); + +SELECT * FROM t2 order by id; + +connection master; + +insert into t1 values ('0','1'); + +sync_slave_with_master; + +connection slave; +SELECT * FROM t2 order by id; + + +--echo # INSERT triggers which cause also DELETE test +--echo # (insert duplicate row in table referenced by foreign key) +insert into t1 values ('1','1'); + +connection master; + +CREATE TABLE t3 (C1 CHAR(1) primary key, FOREIGN KEY (C1) REFERENCES t1(C1) ) engine=innodb; + +insert into t1 values ('1','1'); + +sync_slave_with_master; + +connection slave; +SELECT * FROM t2 order by id; + +connection master; + +drop table t3,t1; + +sync_slave_with_master; + +connection slave; +SET @@global.slave_exec_mode= @old_slave_exec_mode; +SET @@global.slave_run_triggers_for_rbr= @old_slave_run_triggers_for_rbr; +drop table t2; + +--echo # +--echo # MDEV-5513: Trigger is applied to the rows after first one +--echo # + +--connection master + +create table t1 (a int, b int); +create table tlog (a int); + +set sql_log_bin=0; +create trigger tr1 after insert on t1 for each row insert into tlog values (1); +set sql_log_bin=1; + +sync_slave_with_master; +--connection slave + +set @slave_run_triggers_for_rbr.saved = @@slave_run_triggers_for_rbr; +set global slave_run_triggers_for_rbr=1; +create trigger tr2 before insert on t1 for each row set new.b = new.a; + +--connection master + +insert into t1 values (1,10),(2,20),(3,30); + +--sync_slave_with_master + +select * from t1; + +# Cleanup + +set global slave_run_triggers_for_rbr = @slave_run_triggers_for_rbr.saved; + +--connection master + +drop table t1, tlog; + +sync_slave_with_master; + + +--echo # +--echo # MDEV-8411 Assertion `is_stat_field || !table || (!table->write_set || +--echo # bitmap_is_set(table->write_set, field_index) || +--echo # bitmap_is_set(table->vcol_set, field_index))' +--echo # failed in Field_timestamp::store_TIME_with_warning +--echo # +--echo # +--echo # Create table on master, replicate it on slave. +--echo # +--connection master +set @binlog_row_image.saved = @@binlog_row_image; +set binlog_row_image = MINIMAL; +create table t1 (pk int primary key, f int); + +--sync_slave_with_master +--echo # +--echo # Create a trigger on the slave. +--echo # +create trigger tr before update on t1 for each row set new.f = 1000; +set @old_slave_run_triggers_for_rbr = @@global.slave_run_triggers_for_rbr; +set global slave_run_triggers_for_rbr = YES; + +--connection master +--echo # +--echo # Update the table to have the trigger fire on the slave., +--echo # +insert into t1 values (1,1),(2,2); +update t1 set pk=pk+10; +select * from t1; + +--sync_slave_with_master +--echo # +--echo # Check to see if slave has the table updated. +--echo # +select * from t1; + +--echo # +--echo # Cleanup +--echo # + +set global slave_run_triggers_for_rbr = @old_slave_run_triggers_for_rbr; + +--connection master +set binlog_row_image = @binlog_row_image.saved; +drop table t1; + +--sync_slave_with_master + +--echo # +--echo # enterprise 10.4 tests start +--echo # + +--echo # +--echo # MENT-607 : Make slave_run_triggers_for_rbr enforce triggers to run +--echo # on slave, even when there are triggers on the master +--echo # + +--echo # Triggers on slave WILL work (with ENFORCE) if master has some + +connection master; +CREATE TABLE t1 (C1 CHAR(1) primary key, C2 CHAR(1)) engine=innodb; +SELECT * FROM t1; + +create trigger t1_dummy before delete on t1 for each row + set @dummy= 1; + +sync_slave_with_master; + +connection slave; +SET @old_slave_exec_mode= @@global.slave_exec_mode; +SET @old_slave_run_triggers_for_rbr= @@global.slave_run_triggers_for_rbr; +SET @@global.slave_exec_mode= IDEMPOTENT; +SET @@global.slave_run_triggers_for_rbr= ENFORCE; +SELECT * FROM t1; +create table t2 (id char(2) primary key, cnt int, o char(1), n char(1)); +insert into t2 values + ('u0', 0, ' ', ' '),('u1', 0, ' ', ' '), + ('d0', 0, ' ', ' '),('d1', 0, ' ', ' '), + ('i0', 0, ' ', ' '),('i1', 0, ' ', ' '); +create trigger t1_cnt_b before update on t1 for each row + update t2 set cnt=cnt+1, o=old.C1, n=new.C1 where id = 'u0'; +create trigger t1_cnt_ib before insert on t1 for each row + update t2 set cnt=cnt+1, n=new.C1, o=' ' where id = 'i0'; +create trigger t1_cnt_a after update on t1 for each row + update t2 set cnt=cnt+1, o=old.C1, n=new.C1 where id = 'u1'; +create trigger t1_cnt_da after delete on t1 for each row + update t2 set cnt=cnt+1, o=old.C1, n=' ' where id = 'd1'; +create trigger t1_cnt_ia after insert on t1 for each row + update t2 set cnt=cnt+1, n=new.C1, o=' ' where id = 'i1'; +SELECT * FROM t2 order by id; + +connection master; +--echo # INSERT triggers test +insert into t1 values ('a','b'); + +sync_slave_with_master; + +connection slave; +SELECT * FROM t2 order by id; + +connection master; + +--echo # UPDATE triggers test +update t1 set C1= 'd'; + +sync_slave_with_master; + +connection slave; +SELECT * FROM t2 order by id; + +connection master; +--echo # DELETE triggers test +delete from t1 where C1='d'; + +sync_slave_with_master; + +connection slave; +SELECT * FROM t2 order by id; + +--echo # INSERT triggers which cause also UPDATE test (insert duplicate row) +insert into t1 values ('0','1'); + +SELECT * FROM t2 order by id; + +connection master; + +insert into t1 values ('0','1'); + +sync_slave_with_master; + +connection slave; +SELECT * FROM t2 order by id; + + +--echo # INSERT triggers which cause also DELETE test +--echo # (insert duplicate row in table referenced by foreign key) +insert into t1 values ('1','1'); + +connection master; + +CREATE TABLE t3 (C1 CHAR(1) primary key, FOREIGN KEY (C1) REFERENCES t1(C1) ) engine=innodb; + +insert into t1 values ('1','1'); + +sync_slave_with_master; + +connection slave; +SELECT * FROM t2 order by id; + +connection master; + +drop table t3,t1; + +sync_slave_with_master; + +connection slave; +SET @@global.slave_exec_mode= @old_slave_exec_mode; +SET @@global.slave_run_triggers_for_rbr= @old_slave_run_triggers_for_rbr; +drop table t2; + +--echo # +--echo # enterprise 10.4 tests end +--echo # + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_trunc_temp.test b/mysql-test/suite/rpl/t/rpl_row_trunc_temp.test new file mode 100644 index 00000000..a8d7f77d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_trunc_temp.test @@ -0,0 +1,35 @@ +# +# Bug#48350 truncate temporary table crashes replication +# +# All statements operating on temporary tables should not be binlogged in RBR. +# However, before fix of bug#48350, 'TRUNCATE ...' statement on a temporary +# table was binlogged in RBR. +# + +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +#This statement is not binlogged in RBR. +CREATE TEMPORARY TABLE t1(c1 INTEGER); +CREATE TABLE t2(c1 INTEGER); +sync_slave_with_master; + +CREATE TABLE t1(c1 INTEGER); +INSERT INTO t1 VALUES(1), (2); +INSERT INTO t2 VALUES(1), (2); +SELECT * FROM t1; +SELECT * FROM t2; + +connection master; +TRUNCATE t1; +TRUNCATE t2; +sync_slave_with_master; +# t1 will have nothing, if 'TRUNCATE t1' has been replicate from master to +# slave. +SELECT * FROM t1; +SELECT * FROM t2; + +DROP TABLE t1; +connection master; +DROP TABLE t2; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_type_conv_err_msg.test b/mysql-test/suite/rpl/t/rpl_row_type_conv_err_msg.test new file mode 100644 index 00000000..2442f869 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_type_conv_err_msg.test @@ -0,0 +1,356 @@ +# ==== Purpose ==== +# +# Test verifies that when slave side type conversion fails in row based +# replication, more informative error message is displayed. It also verifies +# that in the case of blob fields appropriate type name is displayed in error +# message. +# +# ==== Implementation ==== +# +# Steps: +# Test case1: +# 1. Create a table on master with VARCHAR filed and charset +# 'utf8mb3'. +# 2. Create a table on slave with VARCHAR field and charset +# 'utf8mb4'. +# 3. Insert a tuple on master. +# 4. Verify that slave provides more informative error message with +# respect to difference in charsets. +# Test case2: Repeat same steps as above for CHAR field +# Test case3: +# 1. Create a table on master with LONGBLOB field. +# 2. Create a table on slave with TINYBLOB field. +# 3. Insert a tuple on master. +# 4. Verify that error message displayed on slave clearly states type +# conversion failure from 'longblob' to 'tinyblob'. +# 5. Also verify that error message doesn't show additional details +# of charset when not required. +# Test Case4: Verifies varbinary to binary type conversion failure specific +# error message. +# Test Case5: Verifies binary to varbinary type conversion failure specific +# error message. +# Test Case6: Verifies binary to binary type conversion failure specific +# error message. +# Test Case7: Verifies char to blob type conversion failure specific +# error message. +# Test Case8: Verifies char to text type conversion failure specific +# error message. +# ==== References ==== +# +# MDEV-19925: Column ... cannot be converted from type 'varchar(20)' to type +# 'varchar(20)' +# + +--source include/have_binlog_format_row.inc +# Inorder to grep a specific error pattern in error log a fresh error log +# needs to be generated. +--source include/force_restart.inc +--source include/master-slave.inc + +--echo #################################################################### +--echo # Test Case1: Improved error message with charset information +--echo #################################################################### +--connection master +SET SQL_LOG_BIN=0; +CREATE TABLE t1 (c1 VARCHAR(1) CHARACTER SET 'utf8mb3'); +SET SQL_LOG_BIN=1; + +--connection slave +CREATE TABLE t1 (c1 VARCHAR(1) CHARACTER SET 'utf8mb4'); + +--connection master +INSERT INTO t1 VALUES ('a'); + +--connection slave +--let $slave_sql_errno= 1677 +--source include/wait_for_slave_sql_error.inc + +# Check error log for correct messages. +let $log_error_= `SELECT @@GLOBAL.log_error`; +if(!$log_error_) +{ + # MySQL Server on windows is started with --console and thus + # does not know the location of its .err log, use default location + let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.2.err; +} + +# Error msg before: Column 0 of table 'test.t1' cannot be converted from type 'varchar(3)' to type 'varchar(1)' +# Error msg after : Column 0 of table 'test.t1' cannot be converted from type 'varchar(3 octets)' to type 'varchar(4 octets) character set utf8mb4' +--let SEARCH_FILE=$log_error_ +--let SEARCH_PATTERN=\'varchar\(3 octets\)\' to type \'varchar\(4 octets\) character set utf8mb4\' +--source include/search_pattern_in_file.inc + +--connection master +DROP TABLE t1; +--connection slave +DROP TABLE t1; +--let $rpl_only_running_threads= 1 +--source include/rpl_reset.inc + +--echo #################################################################### +--echo # Test Case2: Improved error message with charset information for CHAR +--echo # type +--echo #################################################################### +--connection master +SET SQL_LOG_BIN=0; +CREATE TABLE t1 (c1 CHAR(1) CHARACTER SET 'utf8mb3'); +SET SQL_LOG_BIN=1; + +--connection slave +CREATE TABLE t1 (c1 CHAR(1) CHARACTER SET 'utf8mb4'); + +--connection master +INSERT INTO t1 VALUES ('a'); + +--connection slave +--let $slave_sql_errno= 1677 +--source include/wait_for_slave_sql_error.inc + +# Error msg before: Column 0 of table 'test.t1' cannot be converted from type 'char(0)' to type 'char(1)' +# Error msg after : Column 0 of table 'test.t1' cannot be converted from type 'char(3 octets)' to type 'char(4 octets) character set utf8mb4)' +--let SEARCH_FILE=$log_error_ +--let SEARCH_PATTERN=\'char\(3 octets\)\' to type \'char\(4 octets\) character set utf8mb4\' +--source include/search_pattern_in_file.inc + +--connection master +DROP TABLE t1; +--connection slave +DROP TABLE t1; +--let $rpl_only_running_threads= 1 +--source include/rpl_reset.inc + +--echo #################################################################### +--echo # Test Case3: For BLOB type fileds, when type conversion failed on +--echo # slave, the errormessage had incorrect type names. +--echo #################################################################### +--connection master +SET SQL_LOG_BIN=0; +CREATE TABLE t1 (c1 LONGBLOB); +SET SQL_LOG_BIN=1; + +--connection slave +CREATE TABLE t1 (c1 TINYBLOB); + +--connection master +INSERT INTO t1 VALUES ('a'); + +--connection slave +--let $slave_sql_errno= 1677 +--source include/wait_for_slave_sql_error.inc + +# Error msg before: Column 0 of table 'test.t1' cannot be converted from type 'tinyblob' to type 'tinyblob' +# Error msg after : Column 0 of table 'test.t1' cannot be converted from type 'longblob' to type 'tinyblob' +--let SEARCH_FILE=$log_error_ +--let SEARCH_PATTERN=\'longblob\' to type \'tinyblob\' +--source include/search_pattern_in_file.inc + +--connection master +DROP TABLE t1; +--connection slave +DROP TABLE t1; +--let $rpl_only_running_threads= 1 +--source include/rpl_reset.inc + +--echo #################################################################### +--echo # Test Case4: Verifies varbinary to binary type conversion failure +--echo # specific error message. +--echo #################################################################### +--connection master +SET SQL_LOG_BIN=0; +CREATE TABLE t1 (c1 VARBINARY(10)); +SET SQL_LOG_BIN=1; + +--connection slave +CREATE TABLE t1 (c1 BINARY(10)); + +--connection master +INSERT INTO t1 VALUES ('a'); + +--connection slave +--let $slave_sql_errno= 1677 +--source include/wait_for_slave_sql_error.inc + +# Check error log for correct messages. +let $log_error_= `SELECT @@GLOBAL.log_error`; +if(!$log_error_) +{ + # MySQL Server on windows is started with --console and thus + # does not know the location of its .err log, use default location + let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.2.err; +} + +# Expected Error : Column 0 of table 'test.t1' cannot be converted from type 'varbinary(10)' to type 'binary(10)' +--let SEARCH_FILE=$log_error_ +--let SEARCH_PATTERN=\'varbinary\(10\)\' to type \'binary\(10\)\' +--source include/search_pattern_in_file.inc + +--connection master +DROP TABLE t1; +--connection slave +DROP TABLE t1; +--let $rpl_only_running_threads= 1 +--source include/rpl_reset.inc + +--echo #################################################################### +--echo # Test Case5: Verifies binary to varbinary type conversion failure +--echo # specific error message. +--echo #################################################################### +--connection master +SET SQL_LOG_BIN=0; +CREATE TABLE t1 (c1 BINARY(10)); +SET SQL_LOG_BIN=1; + +--connection slave +CREATE TABLE t1 (c1 VARBINARY(10)); + +--connection master +INSERT INTO t1 VALUES ('a'); + +--connection slave +--let $slave_sql_errno= 1677 +--source include/wait_for_slave_sql_error.inc + +# Check error log for correct messages. +let $log_error_= `SELECT @@GLOBAL.log_error`; +if(!$log_error_) +{ + # MySQL Server on windows is started with --console and thus + # does not know the location of its .err log, use default location + let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.2.err; +} + +# Expected Error : Column 0 of table 'test.t1' cannot be converted from type 'binary(10)' to type 'varbinary(10)' +--let SEARCH_FILE=$log_error_ +--let SEARCH_PATTERN=\'binary\(10\)\' to type \'varbinary\(10\)\' +--source include/search_pattern_in_file.inc + +--connection master +DROP TABLE t1; +--connection slave +DROP TABLE t1; +--let $rpl_only_running_threads= 1 +--source include/rpl_reset.inc + +--echo #################################################################### +--echo # Test Case6: Verifies binary to binary type conversion failure +--echo # specific error message. +--echo #################################################################### +--connection master +SET SQL_LOG_BIN=0; +CREATE TABLE t1 (c1 BINARY(1)); +SET SQL_LOG_BIN=1; + +--connection slave +CREATE TABLE t1 (c1 BINARY(10)); + +--connection master +INSERT INTO t1 VALUES ('a'); + +--connection slave +--let $slave_sql_errno= 1677 +--source include/wait_for_slave_sql_error.inc + +# Check error log for correct messages. +let $log_error_= `SELECT @@GLOBAL.log_error`; +if(!$log_error_) +{ + # MySQL Server on windows is started with --console and thus + # does not know the location of its .err log, use default location + let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.2.err; +} + +# Expected Error : Column 0 of table 'test.t1' cannot be converted from type 'binary(1)' to type 'binary(10)' +--let SEARCH_FILE=$log_error_ +--let SEARCH_PATTERN=\'binary\(1\)\' to type \'binary\(10\)\' +--source include/search_pattern_in_file.inc + +--connection master +DROP TABLE t1; +--connection slave +DROP TABLE t1; +--let $rpl_only_running_threads= 1 +--source include/rpl_reset.inc + +--echo #################################################################### +--echo # Test Case7: Verifies char to blob type conversion failure +--echo # specific error message. BLOB field on slave has no +--echo # associated character set hence the master side field +--echo # is also considered as binary. +--echo #################################################################### +--connection master +SET SQL_LOG_BIN=0; +CREATE TABLE t1 (c1 CHAR(1)); +SET SQL_LOG_BIN=1; + +--connection slave +CREATE TABLE t1 (c1 BLOB); + +--connection master +INSERT INTO t1 VALUES ('a'); + +--connection slave +--let $slave_sql_errno= 1677 +--source include/wait_for_slave_sql_error.inc + +# Check error log for correct messages. +let $log_error_= `SELECT @@GLOBAL.log_error`; +if(!$log_error_) +{ + # MySQL Server on windows is started with --console and thus + # does not know the location of its .err log, use default location + let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.2.err; +} + +# Expected Error : Column 0 of table 'test.t1' cannot be converted from type 'binary(1)' to type 'binary(10)' +--let SEARCH_FILE=$log_error_ +--let SEARCH_PATTERN=\'binary\(1\)\' to type \'blob\' +--source include/search_pattern_in_file.inc + +--connection master +DROP TABLE t1; +--connection slave +DROP TABLE t1; +--let $rpl_only_running_threads= 1 +--source include/rpl_reset.inc + +--echo #################################################################### +--echo # Test Case8: Verifies char to text type conversion failure +--echo # specific error message. +--echo #################################################################### +--connection master +SET SQL_LOG_BIN=0; +CREATE TABLE t1 (c1 CHAR(1)); +SET SQL_LOG_BIN=1; + +--connection slave +CREATE TABLE t1 (c1 TEXT); + +--connection master +INSERT INTO t1 VALUES ('a'); + +--connection slave +--let $slave_sql_errno= 1677 +--source include/wait_for_slave_sql_error.inc + +# Check error log for correct messages. +let $log_error_= `SELECT @@GLOBAL.log_error`; +if(!$log_error_) +{ + # MySQL Server on windows is started with --console and thus + # does not know the location of its .err log, use default location + let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.2.err; +} + +# Expected Error : Column 0 of table 'test.t1' cannot be converted from type 'binary(1)' to type 'binary(10)' +--let SEARCH_FILE=$log_error_ +--let SEARCH_PATTERN=\'char\(1 octets\)\' to type \'text\' +--source include/search_pattern_in_file.inc + +--connection master +DROP TABLE t1; +--connection slave +DROP TABLE t1; +--let $rpl_only_running_threads= 1 +--source include/rpl_reset.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_unsafe_funcs.test b/mysql-test/suite/rpl/t/rpl_row_unsafe_funcs.test new file mode 100644 index 00000000..31eea3a2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_unsafe_funcs.test @@ -0,0 +1,36 @@ +source include/have_binlog_format_mixed.inc; +source include/master-slave.inc; + +# +# Bug #30244: row_count/found_rows does not replicate well +# + +connection master; + +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT, b INT); + +INSERT INTO t1 SELECT 1; + +connection master1; +INSERT INTO t1 VALUES (2),(3),(4),(5),(6); + +connection master; +INSERT INTO t2 SELECT 1, ROW_COUNT(); + +INSERT INTO t1 VALUES (2),(3),(4); +INSERT INTO t2 SELECT 2, ROW_COUNT(); + +#must return 1 and 3 +SELECT b FROM t2 ORDER BY a; + +sync_slave_with_master; + +#must return 1 and 3 +SELECT b FROM t2 ORDER BY a; + +connection master; +DROP TABLE t1, t2; +sync_slave_with_master; +connection master; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_until.test b/mysql-test/suite/rpl/t/rpl_row_until.test new file mode 100644 index 00000000..d318e0d7 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_until.test @@ -0,0 +1,150 @@ +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + +############################################################################## +# The test is dependent on binlog positions. The test is divided into two +# sections. The first section checks START SLAVE UNTIL MASTER_LOG_FILE = +# 'log_name', MASTER_LOG_POS = log_pos followed by a couple of failure +# scenarios. The second section checks START SLAVE UNTIL RELAY_LOG_FILE = +# 'log_name', RELAY_LOG_POS = log_pos. +############################################################################## + +# Create some events on master +connection master; +CREATE TABLE t1(n INT NOT NULL AUTO_INCREMENT PRIMARY KEY); +INSERT INTO t1 VALUES (1),(2),(3),(4); +# Save master log position for query DROP TABLE t1 +let $master_pos_drop_t1= query_get_value(SHOW MASTER STATUS, Position, 1); +DROP TABLE t1; +# Save master log position for query DROP TABLE t1 +save_master_pos; +#let $master_pos_drop_t1= query_get_value(SHOW BINLOG EVENTS, Pos, 10); +let $master_log_file= query_get_value(SHOW BINLOG EVENTS, Log_name, 10); + +# Save master log position for query CREATE TABLE t2 +let $master_pos_create_t2= query_get_value(SHOW MASTER STATUS, Position, 1); +CREATE TABLE t2(n INT NOT NULL AUTO_INCREMENT PRIMARY KEY); +#show binlog events; + +INSERT INTO t2 VALUES (1),(2); +# Save master log position for query INSERT INTO t2 VALUES (1),(2); +let $master_pos_insert1_t2= query_get_value(SHOW MASTER STATUS, Position, 1); +INSERT INTO t2 VALUES (3),(4); +DROP TABLE t2; +# Save master log position for query DROP TABLE t2; +let $master_pos_drop_t2= query_get_value(SHOW MASTER STATUS, Position, 1); +sync_slave_with_master; +#show binlog events; + +--source include/stop_slave.inc +# Reset slave. +--source include/reset_slave.inc +--replace_result $MASTER_MYPORT MASTER_MYPORT +eval CHANGE MASTER TO MASTER_USER='root', MASTER_CONNECT_RETRY=1, MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT; + +# Try to replicate all queries until drop of t1 + +connection slave; +--replace_result $master_pos_drop_t1 master_pos_drop_t1 +eval START SLAVE UNTIL MASTER_LOG_FILE='$master_log_file', MASTER_LOG_POS=$master_pos_drop_t1; +--source include/wait_for_slave_sql_to_stop.inc + +# Here table should be still not deleted +SELECT * FROM t1; +--let $slave_param= Exec_Master_Log_Pos +--let $slave_param_value= $master_pos_drop_t1 +--source include/check_slave_param.inc + +# This should fail right after start +START SLAVE UNTIL MASTER_LOG_FILE='master-no-such-bin.000001', MASTER_LOG_POS=291; +--source include/wait_for_slave_sql_to_stop.inc +# again this table should be still not deleted +SELECT * FROM t1; + +--let $slave_param= Exec_Master_Log_Pos +--let $slave_param_value= $master_pos_drop_t1 +--source include/check_slave_param.inc + +# clean up +START SLAVE; +--source include/wait_for_slave_to_start.inc +connection master; +sync_slave_with_master; +--source include/stop_slave.inc + +# This should stop immediately as we are already there +--replace_result $master_pos_create_t2 master_pos_create_t2 +eval START SLAVE SQL_THREAD UNTIL MASTER_LOG_FILE='$master_log_file', MASTER_LOG_POS=$master_pos_create_t2; +let $slave_param= Until_Log_Pos; +let $slave_param_value= $master_pos_create_t2; +--source include/wait_for_slave_param.inc +--source include/wait_for_slave_sql_to_stop.inc +# here the sql slave thread should be stopped +--let $slave_param= Exec_Master_Log_Pos +--let $slave_param_value= $master_pos_drop_t2 +--source include/check_slave_param.inc + +#testing various error conditions +--replace_result 561 MASTER_LOG_POS +--error 1277 +START SLAVE UNTIL MASTER_LOG_FILE='master-bin', MASTER_LOG_POS=561; +--replace_result 561 MASTER_LOG_POS 12 RELAY_LOG_POS +--error 1277 +START SLAVE UNTIL MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=561, RELAY_LOG_POS=12; +--error 1277 +START SLAVE UNTIL MASTER_LOG_FILE='master-bin.000001'; +--error 1277 +START SLAVE UNTIL RELAY_LOG_FILE='slave-relay-bin.000009'; +--replace_result 561 MASTER_LOG_POS +--error 1277 +START SLAVE UNTIL RELAY_LOG_FILE='slave-relay-bin.000002', MASTER_LOG_POS=561; +--replace_result 740 MASTER_LOG_POS +START SLAVE UNTIL MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=740; + +--source include/stop_slave.inc +--source include/reset_slave.inc +--source include/start_slave.inc + +############################################################################## +# The second section - checks START SLAVE UNTIL RELAY_LOG_FILE =# 'log_name', +# RELAY_LOG_POS = log_pos. This section of the test does the following: +# 1) At master, create a table and inserts a value. Let slave replicate this. +# 2) Stop slave sql thread. +# 3) Insert some more values at master. Note that io thread copies this insert +# 4) Use start slave until to start the sql thread and check if it +# stops at the correct position. +############################################################################## + +--source include/rpl_reset.inc + +--connection master +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1); + +--sync_slave_with_master +--source include/stop_slave_sql.inc + +--connection master +INSERT INTO t1 VALUES (2); +--let $master_log_pos= query_get_value(SHOW MASTER STATUS, Position, 1) +INSERT INTO t1 VALUES (3); + +--source include/sync_slave_io_with_master.inc + +--let $relay_log_file= query_get_value(SHOW SLAVE STATUS, Relay_Log_File,1) +--source include/get_relay_log_pos.inc + +--replace_result $relay_log_pos relay_log_pos +--eval start slave until relay_log_file='$relay_log_file', relay_log_pos=$relay_log_pos +--source include/wait_for_slave_sql_to_stop.inc + +--let $assert_cond= COUNT(*) = 2 FROM t1 +--let $assert_text= table t1 should have two rows. +--source include/assert.inc + +#cleanup +--source include/start_slave.inc +--connection master +DROP TABLE t1; +--sync_slave_with_master +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_utf16.test b/mysql-test/suite/rpl/t/rpl_row_utf16.test new file mode 100644 index 00000000..d5dcdc42 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_utf16.test @@ -0,0 +1,26 @@ +-- source include/have_binlog_format_row.inc +-- source include/have_utf16.inc +-- source include/master-slave.inc + +# +# BUG#51716: Char column with utf16 character set gives wrong padding on slave +# + +CREATE TABLE t1(c1 CHAR(10) CHARACTER SET utf16 DEFAULT 'ola'); +INSERT INTO t1 VALUES ('abc'); # explicit value is inserted and encoded correctly +INSERT INTO t1 VALUES (); # default value is inserted and encoded correctly + +--query_vertical SELECT c1, hex(c1) from t1 + +-- sync_slave_with_master + +--query_vertical SELECT c1, hex(c1) FROM t1 + +# assertion: tables don't differ +-- let $diff_tables=master:t1,slave:t1 +-- source include/diff_tables.inc + +--connection master +DROP TABLE t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_utf32.test b/mysql-test/suite/rpl/t/rpl_row_utf32.test new file mode 100644 index 00000000..546cf07a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_utf32.test @@ -0,0 +1,113 @@ +-- source include/have_binlog_format_row.inc +-- source include/have_utf32.inc +-- source include/master-slave.inc + +# +# BUG#51787 Assertion `(n % 4) == 0' on slave upon INSERT into a table with UTF32 +# + +SET SQL_LOG_BIN=0; +CREATE TABLE t1 (c1 char(255) DEFAULT NULL, KEY c1 (c1)) DEFAULT CHARSET=utf32; +SET SQL_LOG_BIN=1; + +-- connection slave + +SET @saved_slave_type_conversions= @@global.slave_type_conversions; + +# +# Force test to cover conversion execution path in the +# slave, which also makes use of sql_type method, thence +# can ultimately trigger the assertion. +# +-- source include/stop_slave.inc +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_NON_LOSSY'; +-- source include/start_slave.inc + +SET SQL_LOG_BIN=0; +CREATE TABLE t1 ( c1 varchar(255) DEFAULT NULL, KEY c1 (c1)) DEFAULT CHARSET=utf32; +SET SQL_LOG_BIN=1; + +-- connection master + +INSERT INTO t1(c1) VALUES ('insert into t1'); +DROP TABLE t1; + +--sync_slave_with_master + +--echo # +--echo # MDEV-32249 strings/ctype-ucs2.c:2336: my_vsnprintf_utf32: Assertion `(n +--echo # + +--echo # +--echo # Testing with VARCHAR +--echo # + +-- connection slave +-- source include/stop_slave.inc +SET GLOBAL SLAVE_TYPE_CONVERSIONS= ''; +-- source include/start_slave.inc + +--connection master +CREATE TABLE t1 (a INT); + +--sync_slave_with_master +ALTER TABLE t1 MODIFY a VARCHAR(1) CHARACTER SET utf32; + +--connection master +INSERT INTO t1 VALUES (1); + +--connection slave +# ER_SLAVE_CONVERSION_FAILED +--let $slave_sql_errno= 1677 +--source include/wait_for_slave_sql_error.inc +SHOW CREATE TABLE t1; +SELECT * FROM t1 ORDER BY a; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1; +START SLAVE; + +--connection master +DROP TABLE t1; +--sync_slave_with_master + +--echo # +--echo # Testing with CHAR +--echo # + +-- connection slave +-- source include/stop_slave.inc +SET GLOBAL SLAVE_TYPE_CONVERSIONS= ''; +-- source include/start_slave.inc + +--connection master +CREATE TABLE t1 (a INT); + +--sync_slave_with_master +ALTER TABLE t1 MODIFY a CHAR(1) CHARACTER SET utf32; + +--connection master +INSERT INTO t1 VALUES (1); + +--connection slave +# ER_SLAVE_CONVERSION_FAILED +--let $slave_sql_errno= 1677 +--source include/wait_for_slave_sql_error.inc +SHOW CREATE TABLE t1; +SELECT * FROM t1 ORDER BY a; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1; +START SLAVE; + +--connection master +DROP TABLE t1; +--sync_slave_with_master + + +# assertion: the slave woul hit an/several assertions: +# before and during slave conversion procedure +# Now that is fixed, it wont. + +-- connection slave +SET GLOBAL SLAVE_TYPE_CONVERSIONS= @saved_slave_type_conversions; +-- source include/stop_slave.inc +-- source include/start_slave.inc +-- connection master +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_vcol_crash.test b/mysql-test/suite/rpl/t/rpl_row_vcol_crash.test new file mode 100644 index 00000000..84ee1497 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_vcol_crash.test @@ -0,0 +1,425 @@ +# ==== Purpose ==== +# +# Test verifies that, slave doesn't report any assert on UPDATE or DELETE of +# row which tries to update the virtual columns with associated KEYs. +# +# Test scenarios are listed below. +# 1) KEY on a virtual column with ON DELETE CASCADE +# 2) Verify "ON DELETE CASCADE" for parent->child->child scenario +# 3) KEY on a virtual column with ON UPDATE CASCADE +# 4) Define triggers on master, their results should be replicated +# as part of row events and they should be applied on slave with +# the default slave_run_triggers_for_rbr=NO +# 5) Define triggers + Foreign Keys on master, their results should be +# replicated as part of row events and master and slave should be in sync. +# 6) Triggers are present only on slave and 'slave_run_triggers_for_rbr=NO' +# 7) Triggers are present only on slave and 'slave_run_triggers_for_rbr=YES' +# 8) Triggers and Foreign Keys are present only on slave and +# 'slave_run_triggers_for_rbr=NO' +# 9) Triggers are Foreign Keys are present only on slave and +# 'slave_run_triggers_for_rbr=YES' +# +# ==== References ==== +# +# MDEV-23033: All slaves crash once in ~24 hours and loop restart with signal 11 +# + +--source include/have_binlog_format_row.inc +--source include/have_innodb.inc +--source include/master-slave.inc + + +--echo # +--echo # Test case 1: KEY on a virtual column with ON DELETE CASCADE +--echo # +CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1),(2),(3); + +CREATE TABLE t2 (id INT NOT NULL PRIMARY KEY, + t1_id INT NOT NULL, + v_col INT AS (t1_id+1) VIRTUAL, KEY (v_col), KEY (t1_id), + CONSTRAINT a FOREIGN KEY (t1_id) REFERENCES t1 (id) ON DELETE CASCADE +) ENGINE=InnoDB; + +INSERT INTO t2 VALUES (90,1,NULL); +INSERT INTO t2 VALUES (91,2,default); + +# Following query results in an assert on slave +DELETE FROM t1 WHERE id=1; +--sync_slave_with_master + +--echo # +--echo # Verify data consistency on slave +--echo # +--let $diff_tables= master:test.t1, slave:test.t1 +--source include/diff_tables.inc +--let $diff_tables= master:test.t2, slave:test.t2 +--source include/diff_tables.inc + +--connection master +DROP TABLE t2,t1; +--sync_slave_with_master + +--echo # +--echo # Test case 2: Verify "ON DELETE CASCADE" for parent->child->child scenario +--echo # Parent table: users +--echo # Child tables: matchmaking_groups, matchmaking_group_users +--echo # Parent table: matchmaking_groups +--echo # Child tables: matchmaking_group_users, matchmaking_group_maps +--echo # +--echo # Deleting a row from parent table should be reflected in +--echo # child tables. +--echo # matchmaking_groups->matchmaking_group_users->matchmaking_group_maps +--echo # users->matchmaking_group_users->matchmaking_group_maps +--echo # + +--connection master +CREATE TABLE users (id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(32) NOT NULL DEFAULT '' +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE matchmaking_groups ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + host_user_id INT UNSIGNED NOT NULL UNIQUE, + v_col INT AS (host_user_id+1) VIRTUAL, KEY (v_col), + CONSTRAINT FOREIGN KEY (host_user_id) REFERENCES users (id) + ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE matchmaking_group_users ( + matchmaking_group_id BIGINT UNSIGNED NOT NULL, + user_id INT UNSIGNED NOT NULL, + v_col1 int as (user_id+1) virtual, KEY (v_col1), + PRIMARY KEY (matchmaking_group_id,user_id), + UNIQUE KEY user_id (user_id), + CONSTRAINT FOREIGN KEY (matchmaking_group_id) + REFERENCES matchmaking_groups (id) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT FOREIGN KEY (user_id) + REFERENCES users (id) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE matchmaking_group_maps ( + matchmaking_group_id BIGINT UNSIGNED NOT NULL, + map_id TINYINT UNSIGNED NOT NULL, + v_col2 INT AS (map_id+1) VIRTUAL, KEY (v_col2), + PRIMARY KEY (matchmaking_group_id,map_id), + CONSTRAINT FOREIGN KEY (matchmaking_group_id) + REFERENCES matchmaking_groups (id) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +--sync_slave_with_master + +--connection master +INSERT INTO users VALUES (NULL,'foo'),(NULL,'bar'); +INSERT INTO matchmaking_groups VALUES (10,1,default),(11,2,default); +INSERT INTO matchmaking_group_users VALUES (10,1,default),(11,2,default); +INSERT INTO matchmaking_group_maps VALUES (10,55,default),(11,66,default); + +DELETE FROM matchmaking_groups WHERE id = 10; +--sync_slave_with_master + +--echo # +--echo # No rows should be returned as ON DELETE CASCASE should have removed +--echo # corresponding rows from child tables. There should not any mismatch +--echo # of 'id' field between parent->child. +--echo # +SELECT * FROM matchmaking_group_users WHERE matchmaking_group_id NOT IN (SELECT id FROM matchmaking_groups); +SELECT * FROM matchmaking_group_maps WHERE matchmaking_group_id NOT IN (SELECT id FROM matchmaking_groups); + +--echo # +--echo # Rows with id=11 should be present +--echo # +SELECT * FROM matchmaking_group_users; +SELECT * FROM matchmaking_group_maps; + +--connection master +DELETE FROM users WHERE id = 2; +--sync_slave_with_master + +--echo # +--echo # No rows should be present in both the child tables +--echo # +SELECT * FROM matchmaking_group_users; +SELECT * FROM matchmaking_group_maps; + +--connection master +DROP TABLE matchmaking_group_maps, matchmaking_group_users, matchmaking_groups, users; +--sync_slave_with_master + +--echo # +--echo # Test case 3: KEY on a virtual column with ON UPDATE CASCADE +--echo # + +--connection master +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b INT NOT NULL) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, 80); + +CREATE TABLE t2 (a INT KEY, b INT, + v_col int as (b+1) virtual, KEY (v_col), + CONSTRAINT b FOREIGN KEY (b) REFERENCES t1(a) ON UPDATE CASCADE +) ENGINE=InnoDB; +INSERT INTO t2 VALUES (51, 1, default); +--sync_slave_with_master + +--connection master +UPDATE t1 SET a = 50 WHERE a = 1; + +--echo # +--echo # Master: Verify that ON UPDATE CASCADE works fine +--echo # old_row: (51, 1, 2) ON UPDATE New_row: (51, 50, 51) +--echo # +SELECT * FROM t2 WHERE b=50; +--sync_slave_with_master + +--echo # +--echo # Slave: Verify that ON UPDATE CASCADE works fine +--echo # old_row: (51, 1, 2) ON UPDATE New_row: (51, 50, 51) +--echo # +SELECT * FROM t2 WHERE b=50; + +--connection master +DROP TABLE t2, t1; +--sync_slave_with_master + +--echo # +--echo # Test case 4: Define triggers on master, their results should be +--echo # replicated as part of row events and they should be +--echo # applied on slave with the default +--echo # slave_run_triggers_for_rbr=NO +--echo # + +# In row-based replication, the binary log contains row changes. It will have +# both the changes made by the statement itself, and the changes made by the +# triggers that were invoked by the statement. Slave server(s) do not need to +# run triggers for row changes they are applying. Hence verify that this +# property remains the same and data should be available as if trigger was +# executed. Please note by default slave_run_triggers_for_rbr=NO. + +--connection master +CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t2 (count INT NOT NULL) ENGINE=InnoDB; +CREATE TRIGGER trg AFTER INSERT ON t1 FOR EACH ROW INSERT INTO t2 VALUES (1); +INSERT INTO t1 VALUES (2),(3); +--sync_slave_with_master + +SHOW GLOBAL VARIABLES LIKE 'slave_run_triggers_for_rbr'; +--echo # +--echo # As two rows are inserted in table 't1', two rows should get inserted +--echo # into table 't2' as part of trigger. +--echo # +--let $assert_cond= COUNT(*) = 2 FROM t2 +--let $assert_text= Table t2 should have two rows. +--source include/assert.inc + +--connection master +DROP TABLE t1,t2; +--sync_slave_with_master + +--echo # +--echo # Test case 5: Define triggers + Foreign Keys on master, their results +--echo # should be replicated as part of row events and master +--echo # and slave should be in sync. +--echo # +--connection master +CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t2 (t1_id INT NOT NULL, + v_col INT AS (t1_id+1) VIRTUAL, KEY (v_col), KEY (t1_id), + CONSTRAINT a FOREIGN KEY (t1_id) REFERENCES t1 (id) ON DELETE CASCADE +) ENGINE=InnoDB; +CREATE TABLE t3 (count INT NOT NULL) ENGINE=InnoDB; +CREATE TRIGGER trg AFTER INSERT ON t1 FOR EACH ROW INSERT INTO t3 VALUES (1); + +INSERT INTO t1 VALUES (2),(3); +INSERT INTO t2 VALUES (2, default), (3, default); +--sync_slave_with_master + +--echo # +--echo # As two rows are inserted in table 't1', two rows should get inserted +--echo # into table 't3' as part of trigger. +--echo # +--let $assert_cond= COUNT(*) = 2 FROM t3 +--let $assert_text= Table t3 should have two rows. +--source include/assert.inc + +--echo # +--echo # Verify ON DELETE CASCASE correctness +--echo # +--connection master +DELETE FROM t1 WHERE id=2; +--sync_slave_with_master + +--connection master +--let $diff_tables= master:test.t1, slave:test.t1 +--source include/diff_tables.inc +--let $diff_tables= master:test.t2, slave:test.t2 +--source include/diff_tables.inc +--let $diff_tables= master:test.t3, slave:test.t3 +--source include/diff_tables.inc + +DROP TABLE t3,t2,t1; +--sync_slave_with_master + +# +# Test case: Triggers only on slave +# +--write_file $MYSQLTEST_VARDIR/tmp/trig_on_slave.inc PROCEDURE + if ($slave_run_triggers_for_rbr == '') { + --die !!!ERROR IN TEST: you must set $slave_run_triggers_for_rbr + } + +--connection slave +SET @save_slave_run_triggers_for_rbr= @@GLOBAL.slave_run_triggers_for_rbr; +--eval SET GLOBAL slave_run_triggers_for_rbr= $slave_run_triggers_for_rbr; +SHOW GLOBAL VARIABLES LIKE '%slave_run_triggers_for_rbr%'; + +--connection master +CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t2 (t1_id INT NOT NULL, + v_col INT AS (t1_id+1) VIRTUAL, KEY (v_col), + KEY (t1_id), CONSTRAINT a FOREIGN KEY (t1_id) REFERENCES t1 (id) ON DELETE CASCADE +) ENGINE=InnoDB; +CREATE TABLE t3 (count INT NOT NULL) ENGINE=InnoDB; +--sync_slave_with_master + +CREATE TRIGGER trg AFTER INSERT ON t2 FOR EACH ROW INSERT INTO t3 VALUES (1); + +--connection master +INSERT INTO t1 VALUES (2),(3); +INSERT INTO t2 VALUES (2, default), (3, default); +--sync_slave_with_master + +if ($slave_run_triggers_for_rbr == 'NO') { +--echo # +--echo # Count must be 0 +--echo # +--let $assert_cond= COUNT(*) = 0 FROM t3 +--let $assert_text= Table t3 should have zero rows. +--source include/assert.inc +} +if ($slave_run_triggers_for_rbr == 'YES') { +--echo # +--echo # Count must be 2 +--echo # +--let $assert_cond= COUNT(*) = 2 FROM t3 +--let $assert_text= Table t3 should have two rows. +--source include/assert.inc +} + +--connection master +DELETE FROM t1 WHERE id=2; +--sync_slave_with_master +SET GLOBAL slave_run_triggers_for_rbr= @save_slave_run_triggers_for_rbr; + +--echo # +--echo # Verify t1, t2 are consistent on slave. +--echo # +--let $diff_tables= master:test.t1, slave:test.t1 +--source include/diff_tables.inc +--let $diff_tables= master:test.t2, slave:test.t2 +--source include/diff_tables.inc + +--connection master +DROP TABLE t3,t2,t1; +--sync_slave_with_master +#END OF +PROCEDURE + +--echo # +--echo # Test case 6: Triggers are present only on slave and +--echo # 'slave_run_triggers_for_rbr=NO' +--echo # +--let $slave_run_triggers_for_rbr=NO +--source $MYSQLTEST_VARDIR/tmp/trig_on_slave.inc + +--echo # +--echo # Test case 7: Triggers are present only on slave and +--echo # 'slave_run_triggers_for_rbr=YES' +--echo # +--let $slave_run_triggers_for_rbr=YES +--source $MYSQLTEST_VARDIR/tmp/trig_on_slave.inc +--remove_file $MYSQLTEST_VARDIR/tmp/trig_on_slave.inc + +# +# Test case: Trigger and Foreign Key are present only on slave +# +--write_file $MYSQLTEST_VARDIR/tmp/trig_fk_on_slave.inc PROCEDURE + if ($slave_run_triggers_for_rbr == '') { + --die !!!ERROR IN TEST: you must set $slave_run_triggers_for_rbr + } + +--connection slave +SET @save_slave_run_triggers_for_rbr= @@GLOBAL.slave_run_triggers_for_rbr; +--eval SET GLOBAL slave_run_triggers_for_rbr= $slave_run_triggers_for_rbr; +SHOW GLOBAL VARIABLES LIKE '%slave_run_triggers_for_rbr%'; + +--connection master +CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY) ENGINE=InnoDB; +SET sql_log_bin=0; +CREATE TABLE t2 (t1_id INT NOT NULL,v_col INT AS (t1_id+1) VIRTUAL) ENGINE=INNODB; +SET sql_log_bin=1; +CREATE TABLE t3 (count INT NOT NULL) ENGINE=InnoDB; +--sync_slave_with_master + +# Have foreign key and trigger on slave. +CREATE TABLE t2 (t1_id INT NOT NULL, + v_col INT AS (t1_id+1) VIRTUAL, KEY (v_col), KEY (t1_id), + CONSTRAINT a FOREIGN KEY (t1_id) REFERENCES t1 (id) ON DELETE CASCADE +) ENGINE=InnoDB; +CREATE TRIGGER trg AFTER INSERT ON t2 FOR EACH ROW INSERT INTO t3 VALUES (1); + +--connection master +INSERT INTO t1 VALUES (2),(3); +INSERT INTO t2 VALUES (2, default), (3, default); +--sync_slave_with_master + +if ($slave_run_triggers_for_rbr == 'NO') { +--echo # +--echo # Count must be 0 +--echo # +--let $assert_cond= COUNT(*) = 0 FROM t3 +--let $assert_text= Table t3 should have zero rows. +--source include/assert.inc +} +if ($slave_run_triggers_for_rbr == 'YES') { +--echo # +--echo # Count must be 2 +--echo # +--let $assert_cond= COUNT(*) = 2 FROM t3 +--let $assert_text= Table t3 should have two rows. +--source include/assert.inc +} + +--connection master +DELETE FROM t1 WHERE id=2; +--echo # t1: Should have one row +SELECT * FROM t1; +--echo # t2: Should have two rows +SELECT * FROM t2; +--sync_slave_with_master +--echo # t1: Should have one row +SELECT * FROM t1; +--echo # t2: Should have one row on slave due to ON DELETE CASCASE +SELECT * FROM t2; +SET GLOBAL slave_run_triggers_for_rbr= @save_slave_run_triggers_for_rbr; + +--connection master +DROP TABLE t3,t2,t1; +--sync_slave_with_master +#END OF +PROCEDURE + +--echo # +--echo # Test case 8: Triggers and Foreign Keys are present only on slave and +--echo # 'slave_run_triggers_for_rbr=NO' +--echo # +--let $slave_run_triggers_for_rbr=NO +--source $MYSQLTEST_VARDIR/tmp/trig_fk_on_slave.inc + +--echo # +--echo # Test case 9: Triggers are Foreign Keys are present only on slave and +--echo # 'slave_run_triggers_for_rbr=YES' +--echo # +--let $slave_run_triggers_for_rbr=YES +--source $MYSQLTEST_VARDIR/tmp/trig_fk_on_slave.inc +--remove_file $MYSQLTEST_VARDIR/tmp/trig_fk_on_slave.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_view01.test b/mysql-test/suite/rpl/t/rpl_row_view01.test new file mode 100644 index 00000000..449196ae --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_view01.test @@ -0,0 +1,85 @@ +############################################################################# +# Original Author: JBM # +# Original Date: Aug/19/2005 # +# Updated: 08/29/2005 Remove sleeps # +############################################################################# +#TEST: row based replication of views # +############################################################################# +# Includes +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + +# Begin clean up test section +connection master; +--disable_warnings +create database if not exists mysqltest1; +DROP VIEW IF EXISTS mysqltest1.v1; +DROP VIEW IF EXISTS mysqltest1.v2; +DROP VIEW IF EXISTS mysqltest1.v3; +DROP VIEW IF EXISTS mysqltest1.v4; +DROP TABLE IF EXISTS mysqltest1.t3; +DROP TABLE IF EXISTS mysqltest1.t1; +DROP TABLE IF EXISTS mysqltest1.t2; +DROP TABLE IF EXISTS mysqltest1.t4; + +# Begin test section 1 +CREATE TABLE mysqltest1.t1 (a INT, c CHAR(6),PRIMARY KEY(a)); +CREATE TABLE mysqltest1.t2 (a INT, c CHAR(6),PRIMARY KEY(a)); +CREATE TABLE mysqltest1.t3 (a INT, c CHAR(6), c2 CHAR(6), PRIMARY KEY(a)); +CREATE TABLE mysqltest1.t4 (a INT, qty INT, price INT,PRIMARY KEY(a)); +CREATE TABLE mysqltest1.t5 (qty INT, price INT, total INT, PRIMARY KEY(qty)); +INSERT INTO mysqltest1.t1 VALUES (1,'Thank'),(2,'it'),(3,'Friday'); +INSERT INTO mysqltest1.t2 VALUES (1,'GOD'),(2,'is'),(3,'TGIF'); +INSERT INTO mysqltest1.t4 VALUES(1, 3, 50),(2, 18, 3),(4, 4, 4); + + +CREATE VIEW mysqltest1.v2 AS SELECT qty, price, qty*price AS value FROM mysqltest1.t4 ORDER BY qty; +CREATE VIEW mysqltest1.v1 AS SELECT t1.a, t1.c, t2.c as c2 FROM mysqltest1.t1 as t1, mysqltest1.t2 AS t2 WHERE mysqltest1.t1.a = mysqltest1.t2.a ORDER BY a; +CREATE VIEW mysqltest1.v3 AS SELECT * FROM mysqltest1.t1; +CREATE VIEW mysqltest1.v4 AS SELECT * FROM mysqltest1.v3 WHERE a > 1 WITH LOCAL CHECK OPTION; + + +SELECT * FROM mysqltest1.v2; +SELECT * FROM mysqltest1.v1; + +--sync_slave_with_master + +SELECT * FROM mysqltest1.v2; +SELECT * FROM mysqltest1.v1; +connection master; + +INSERT INTO mysqltest1.t5 SELECT * FROM mysqltest1.v2; +INSERT INTO mysqltest1.t3 SELECT * FROM mysqltest1.v1; + +SELECT * FROM mysqltest1.t5 ORDER BY qty; +SELECT * FROM mysqltest1.t3 ORDER BY a; +sync_slave_with_master; +SELECT * FROM mysqltest1.t5 ORDER BY qty; +SELECT * FROM mysqltest1.t3 ORDER BY a; +connection master; + +INSERT INTO mysqltest1.v4 VALUES (4,'TEST'); + +SELECT * FROM mysqltest1.t1 ORDER BY a; +SELECT * FROM mysqltest1.v4 ORDER BY a; +sync_slave_with_master; +SELECT * FROM mysqltest1.t1 ORDER BY a; +SELECT * FROM mysqltest1.v4 ORDER BY a; + +connection master; + +# lets cleanup +DROP VIEW IF EXISTS mysqltest1.v1; +DROP VIEW IF EXISTS mysqltest1.v2; +DROP VIEW IF EXISTS mysqltest1.v3; +DROP VIEW IF EXISTS mysqltest1.v4; +DROP TABLE IF EXISTS mysqltest1.t3; +DROP TABLE IF EXISTS mysqltest1.t1; +DROP TABLE IF EXISTS mysqltest1.t2; +DROP TABLE IF EXISTS mysqltest1.t4; +DROP DATABASE mysqltest1; +sync_slave_with_master; + +# End of 5.1 test case + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_virt.test b/mysql-test/suite/rpl/t/rpl_row_virt.test new file mode 100644 index 00000000..e79869cd --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_virt.test @@ -0,0 +1,27 @@ +--source include/have_binlog_format_row.inc +--source include/master-slave.inc +--source include/have_innodb.inc +connection master; + +create table t1 ( + id int auto_increment, + data varchar(32), + virt tinyint as (1), + primary key (id), + key virt (virt) +) engine=innodb default charset=utf8mb4; + +insert into t1 (data) values ('broken'); + +update t1 set data='more broken'; + +--sync_slave_with_master + +select * from t1; + +--connection master +drop table t1; + +--sync_slave_with_master + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_wide_table.test b/mysql-test/suite/rpl/t/rpl_row_wide_table.test new file mode 100644 index 00000000..01473f99 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_wide_table.test @@ -0,0 +1,340 @@ +################################################################## +# rpl_row_wide_table +# +# This test verifies that the table with number of attributes more +# than 250 is replicated. +# Related bugs: +# Bug #42977 RBR logs for rows with more than 250 column results +# in corrupt binlog +################################################################## + +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc + +--disable_warnings +DROP TABLE IF EXISTS t300; +--enable_warnings + +connection master; + +create table t300 ( +f1 int, +f2 int, +f3 int, +f4 int, +f5 int, +f6 int, +f7 int, +f8 int, +f9 int, +f10 int, +f11 int, +f12 int, +f13 int, +f14 int, +f15 int, +f16 int, +f17 int, +f18 int, +f19 int, +f20 int, +f21 int, +f22 int, +f23 int, +f24 int, +f25 int, +f26 int, +f27 int, +f28 int, +f29 int, +f30 int, +f31 int, +f32 int, +f33 int, +f34 int, +f35 int, +f36 int, +f37 int, +f38 int, +f39 int, +f40 int, +f41 int, +f42 int, +f43 int, +f44 int, +f45 int, +f46 int, +f47 int, +f48 int, +f49 int, +f50 int, +f51 int, +f52 int, +f53 int, +f54 int, +f55 int, +f56 int, +f57 int, +f58 int, +f59 int, +f60 int, +f61 int, +f62 int, +f63 int, +f64 int, +f65 int, +f66 int, +f67 int, +f68 int, +f69 int, +f70 int, +f71 int, +f72 int, +f73 int, +f74 int, +f75 int, +f76 int, +f77 int, +f78 int, +f79 int, +f80 int, +f81 int, +f82 int, +f83 int, +f84 int, +f85 int, +f86 int, +f87 int, +f88 int, +f89 int, +f90 int, +f91 int, +f92 int, +f93 int, +f94 int, +f95 int, +f96 int, +f97 int, +f98 int, +f99 int, +f100 int, +f101 int, +f102 int, +f103 int, +f104 int, +f105 int, +f106 int, +f107 int, +f108 int, +f109 int, +f110 int, +f111 int, +f112 int, +f113 int, +f114 int, +f115 int, +f116 int, +f117 int, +f118 int, +f119 int, +f120 int, +f121 int, +f122 int, +f123 int, +f124 int, +f125 int, +f126 int, +f127 int, +f128 int, +f129 int, +f130 int, +f131 int, +f132 int, +f133 int, +f134 int, +f135 int, +f136 int, +f137 int, +f138 int, +f139 int, +f140 int, +f141 int, +f142 int, +f143 int, +f144 int, +f145 int, +f146 int, +f147 int, +f148 int, +f149 int, +f150 int, +f151 int, +f152 int, +f153 int, +f154 int, +f155 int, +f156 int, +f157 int, +f158 int, +f159 int, +f160 int, +f161 int, +f162 int, +f163 int, +f164 int, +f165 int, +f166 int, +f167 int, +f168 int, +f169 int, +f170 int, +f171 int, +f172 int, +f173 int, +f174 int, +f175 int, +f176 int, +f177 int, +f178 int, +f179 int, +f180 int, +f181 int, +f182 int, +f183 int, +f184 int, +f185 int, +f186 int, +f187 int, +f188 int, +f189 int, +f190 int, +f191 int, +f192 int, +f193 int, +f194 int, +f195 int, +f196 int, +f197 int, +f198 int, +f199 int, +f200 int, +f201 int, +f202 int, +f203 int, +f204 int, +f205 int, +f206 int, +f207 int, +f208 int, +f209 int, +f210 int, +f211 int, +f212 int, +f213 int, +f214 int, +f215 int, +f216 int, +f217 int, +f218 int, +f219 int, +f220 int, +f221 int, +f222 int, +f223 int, +f224 int, +f225 int, +f226 int, +f227 int, +f228 int, +f229 int, +f230 int, +f231 int, +f232 int, +f233 int, +f234 int, +f235 int, +f236 int, +f237 int, +f238 int, +f239 int, +f240 int, +f241 int, +f242 int, +f243 int, +f244 int, +f245 int, +f246 int, +f247 int, +f248 int, +f249 int, +f250 int, +f251 int, +f252 int, +f253 int, +f254 int, +f255 int, +f256 int, +f257 int, +f258 int, +f259 int, +f260 int, +f261 int, +f262 int, +f263 int, +f264 int, +f265 int, +f266 int, +f267 int, +f268 int, +f269 int, +f270 int, +f271 int, +f272 int, +f273 int, +f274 int, +f275 int, +f276 int, +f277 int, +f278 int, +f279 int, +f280 int, +f281 int, +f282 int, +f283 int, +f284 int, +f285 int, +f286 int, +f287 int, +f288 int, +f289 int, +f290 int, +f291 int, +f292 int, +f293 int, +f294 int, +f295 int, +f296 int, +f297 int, +f298 int, +f299 int, +f300 int, + primary key (f1)); + +insert into t300 set f1= 1; + +sync_slave_with_master; + +# +# prove that slave processed the create as well as the insert +# +eval select f300 from t300; +select count(*) as one from t300; + +--echo *** Cleanup *** +connection master; +DROP TABLE t300; +sync_slave_with_master; + +# END of Test Case + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_savepoint.test b/mysql-test/suite/rpl/t/rpl_savepoint.test new file mode 100644 index 00000000..31af6151 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_savepoint.test @@ -0,0 +1,43 @@ +--source include/have_innodb.inc +--source include/master-slave.inc + +--echo # +--echo # Bug#50124 Rpl failure on DROP table with concurrent txn/non-txn +--echo # DML flow and SAVEPOINT +--echo # + +connection master; + +--disable_warnings +DROP TABLE IF EXISTS tt, nt; +--enable_warnings + +CREATE TABLE tt (i INT) ENGINE = InnoDB; +CREATE TABLE nt (i INT) ENGINE = MyISAM; +FLUSH LOGS; +START TRANSACTION; +INSERT INTO nt VALUES (1); +SAVEPOINT insert_statement; +INSERT INTO tt VALUES (1); + +connection master1; +--echo # Sending: +--send DROP TABLE tt + +connection master; +let $wait_condition= + SELECT COUNT(*) = 1 FROM information_schema.processlist + WHERE state = "Waiting for table metadata lock" AND info = "DROP TABLE tt"; +--source include/wait_condition.inc +ROLLBACK TO SAVEPOINT insert_statement; +COMMIT; + +connection master1; +--echo # Reaping: DROP TABLE tt +--reap +FLUSH LOGS; + +connection master; +DROP TABLE nt; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_seconds_behind_master_spike.test b/mysql-test/suite/rpl/t/rpl_seconds_behind_master_spike.test new file mode 100644 index 00000000..7c2e39dc --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_seconds_behind_master_spike.test @@ -0,0 +1,191 @@ +# +# Purpose: +# This test validates that a slave's relay log format description event is +# not used to calculate the Seconds_Behind_Master time displayed by +# SHOW SLAVE STATUS. +# +# Methodology: +# Ensure that a slave's reported Seconds_Behind_Master does not point before +# a time in which we can prove that it has progressed beyond. The slave's +# relay log events are created using the timestamp at which the IO thread was +# created. Therefore, after starting the slave's IO thread, we sleep so any +# proceeding events are forced to have later timestamps. After sleeping, we run +# MDL statements on the master and save the time at which they are binlogged. +# Once the slave executes these MDL commands, we have proven that the slave has +# caught up to this saved timestamp. At this point, if the value of +# Seconds_Behind_Master points before the time in which the MDL events were +# logged, it is invalid. +# +# References: +# MDEV-16091: Seconds_Behind_Master spikes to millions of seconds +# +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/have_innodb.inc +--source include/master-slave.inc + +--connection slave + +# Using_Gtid needs to start as NO before updating debug_dbug +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=NO; +--source include/start_slave.inc + +--source include/stop_slave.inc +SET @save_dbug= @@GLOBAL.debug_dbug; +SET @@global.debug_dbug="+d,pause_sql_thread_on_fde,negate_clock_diff_with_master"; +--source include/start_slave.inc + +--let $sleep_time=2 +--echo # Future events must be logged at least $sleep_time seconds after +--echo # the slave starts +--sleep $sleep_time + +--connection master +--echo # Write events to ensure slave will be consistent with master +create table t1 (a int); +insert into t1 values (1); +--let $t_master_events_logged= `SELECT UNIX_TIMESTAMP()` + +--echo # Flush logs on master forces slave to generate a Format description +--echo # event in its relay log +flush logs; + +--connection slave +--echo # Ignore FDEs that happen before the CREATE/INSERT commands +SET DEBUG_SYNC='now WAIT_FOR paused_on_fde'; +SET DEBUG_SYNC='now SIGNAL sql_thread_continue'; +SET DEBUG_SYNC='now WAIT_FOR paused_on_fde'; +SET DEBUG_SYNC='now SIGNAL sql_thread_continue'; + +--echo # On the next FDE, the slave should have the master CREATE/INSERT events +SET DEBUG_SYNC='now WAIT_FOR paused_on_fde'; +select count(*)=1 from t1; + +--echo # The relay log FDE has been processed - here we check to ensure it was +--echo # not considered in Seconds_Behind_Master calculation +--connection slave1 +let $sbm= query_get_value(SHOW SLAVE STATUS, Seconds_Behind_Master, 1); +--let $t_now= `SELECT UNIX_TIMESTAMP()` + +# Ensure Seconds_Behind_Master does not point beyond when we have proven the +# events we have proven to have executed. The extra second is needed as a +# buffer because the recorded times are not exact with when the events were +# recorded on the master. +if(`select $sbm > $t_now - $t_master_events_logged + 1`) +{ + die "A relay log event was incorrectly used to set Seconds_Behind_Master"; +} + +--echo # Safely resume slave SQL thread + +--let $dbug_wait_state="debug sync point: now" +--echo # Prove SQL thread is in state $dbug_wait_state +--let $wait_condition= SELECT STATE=$dbug_wait_state from information_schema.PROCESSLIST where COMMAND="Slave_SQL" +--source include/wait_condition.inc + +SET @@global.debug_dbug="-d,pause_sql_thread_on_fde"; +SET DEBUG_SYNC='now SIGNAL sql_thread_continue'; + +# We have to wait for the SQL thread to acknowledge the sql_thread_continue +# signal. Otherwise the below RESET command can overwrite the signal before +# the SQL thread is notified to proceed, causing it to "permanently" become +# stuck awaiting the signal (until timeout is reached). + +--echo # Wait for SQL thread to continue into normal execution +--let $wait_condition= SELECT STATE!= $dbug_wait_state from information_schema.PROCESSLIST where COMMAND="Slave_SQL" +--source include/wait_condition.inc + +# Reset last sql_thread_continue signal +SET DEBUG_SYNC='RESET'; + + +--echo # +--echo # MDEV-29639 +--echo # When receiving an event after the SQL Thread idles, +--echo # Seconds_Behind_Master should not update before it updates +--echo # last_master_timestamp + +--connection slave +--source include/stop_slave.inc +set @@global.debug_dbug="+d,pause_sql_thread_on_next_event"; +--source include/start_slave.inc + +--connection master +insert into t1 values(2); +--source include/save_master_gtid.inc + +# Each event after starting will trigger a pause, so continually send signal +# sql_thread_continue until caught up +--connection slave +--let $caught_up=0 +--let $tries= 0 +set debug_sync='now wait_for paused_on_event'; +--disable_query_log +while (!$caught_up) +{ + set debug_sync='now signal sql_thread_continue'; + --let $slave_gtid= `SELECT @@global.gtid_slave_pos` + if (`SELECT strcmp("$master_pos","$slave_gtid") = 0`) + { + --inc $caught_up + } + --inc $tries + # Wait 30s + if (`SELECT $tries > 300`) + { + --die Replica failed to sync with primary + } + sleep 0.1; +} +--enable_query_log + +--connection master +--echo # Sleeping 1s to create a visible SBM gap between events +sleep 1; +insert into t1 values(3); +--source include/save_master_gtid.inc + +--connection slave +set debug_sync='now wait_for paused_on_event'; +--let $sbm= query_get_value(SHOW SLAVE STATUS, Seconds_Behind_Master, 1) + +if ($sbm) +{ + --echo # Expected Seconds_Behind_Master to be 0 but was $sbm + --die Seconds_Behind_Master should not show updates before last_master_timestamp is updated +} + +# Continually send signal sql_thread_continue until caught up +--let $caught_up=0 +--let $tries= 0 +--disable_query_log +while (!$caught_up) +{ + set debug_sync='now signal sql_thread_continue'; + --let $slave_gtid= `SELECT @@global.gtid_slave_pos` + if (`SELECT strcmp("$master_pos","$slave_gtid") = 0`) + { + --inc $caught_up + } + --inc $tries + # Wait 30s + if (`SELECT $tries > 300`) + { + --die Replica failed to sync with primary + } + sleep 0.1; +} +--enable_query_log + +# Cleanup +--source include/stop_slave.inc +set debug_sync='RESET'; +SET @@global.debug_dbug=$save_dbug; +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc + +--connection master +DROP TABLE t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync.test b/mysql-test/suite/rpl/t/rpl_semi_sync.test new file mode 100644 index 00000000..720ec059 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync.test @@ -0,0 +1,532 @@ +# +# This include file is used by more than one test suite +# (currently rpl and binlog_encryption). +# Please check all dependent tests after modifying it +# + +source include/not_embedded.inc; +source include/have_innodb.inc; +source include/master-slave.inc; + +let $engine_type= InnoDB; + +# Suppress warnings that might be generated during the test +connection master; +call mtr.add_suppression("Timeout waiting for reply of binlog"); +call mtr.add_suppression("Read semi-sync reply"); +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT."); +call mtr.add_suppression("mysqld: Got an error reading communication packets"); +connection slave; +# While 'Current_Pos' exists as an option for Using_Gtd, keeping these +# events in the binlog will update gtid_binlog_pos, and the later calls to +# set `@@global.gtid_slave_pos= ""` will provide warning messages with +# inconsistent GTID values because the seq_nos are non-deterministic with +# the masters events coming in concurrently +set sql_log_bin=0; +call mtr.add_suppression("Master server does not support semi-sync"); +call mtr.add_suppression("Semi-sync slave .* reply"); +call mtr.add_suppression("Slave SQL.*Request to stop slave SQL Thread received while applying a group that has non-transactional changes; waiting for completion of the group"); +set sql_log_bin=1; +connection master; + +# wait for dying connections (if any) to disappear +let $wait_condition= select count(*) = 0 from information_schema.processlist where command='killed'; +--source include/wait_condition.inc + +# After fix of BUG#45848, semi-sync slave should not create any extra +# connections on master, save the count of connections before start +# semi-sync slave for comparison below. +let $_connections_normal_slave= query_get_value(SHOW STATUS LIKE 'Threads_connected', Value, 1); + +--echo # +--echo # Uninstall semi-sync plugins on master and slave +--echo # +connection slave; +source include/stop_slave.inc; +--source include/reset_slave.inc +set global rpl_semi_sync_master_enabled= 0; +set global rpl_semi_sync_slave_enabled= 0; + +connection master; +reset master; +set global rpl_semi_sync_master_enabled= 0; +set global rpl_semi_sync_slave_enabled= 0; + +--echo # +--echo # Main test of semi-sync replication start here +--echo # + +connection master; + +set global rpl_semi_sync_master_timeout= 60000; # 60s + +echo [ default state of semi-sync on master should be OFF ]; +show variables like 'rpl_semi_sync_master_enabled'; + +echo [ enable semi-sync on master ]; +set global rpl_semi_sync_master_enabled = 1; +show variables like 'rpl_semi_sync_master_enabled'; + +echo [ status of semi-sync on master should be ON even without any semi-sync slaves ]; +show status like 'Rpl_semi_sync_master_clients'; +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_yes_tx'; + +--echo # +--echo # BUG#45672 Semisync repl: ActiveTranx:insert_tranx_node: transaction node allocation failed +--echo # BUG#45673 Semisynch reports correct operation even if no slave is connected +--echo # + +# BUG#45672 When semi-sync is enabled on master, it would allocate +# transaction node even without semi-sync slave connected, and would +# finally result in transaction node allocation error. +# +# Semi-sync master will pre-allocate 'max_connections' transaction +# nodes, so here we do more than that much transactions to check if it +# will fail or not. +# select @@global.max_connections + 1; +let $i= `select @@global.max_connections + 1`; +disable_query_log; +eval create table t1 (a int) engine=$engine_type; +while ($i) +{ + eval insert into t1 values ($i); + dec $i; +} +drop table t1; +enable_query_log; + +# BUG#45673 +echo [ status of semi-sync on master should be OFF ]; +show status like 'Rpl_semi_sync_master_clients'; +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_yes_tx'; + +# reset master to make sure the following test will start with a clean environment +reset master; + +connection slave; + +echo [ default state of semi-sync on slave should be OFF ]; +show variables like 'rpl_semi_sync_slave_enabled'; + +echo [ enable semi-sync on slave ]; +set global rpl_semi_sync_slave_enabled = 1; +show variables like 'rpl_semi_sync_slave_enabled'; +source include/start_slave.inc; + +connection master; + +# NOTE: Rpl_semi_sync_master_client will only be updated when +# semi-sync slave has started binlog dump request +let $status_var= Rpl_semi_sync_master_clients; +let $status_var_value= 1; +source include/wait_for_status_var.inc; + +echo [ initial master state after the semi-sync slave connected ]; +show status like 'Rpl_semi_sync_master_clients'; +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_no_tx'; +show status like 'Rpl_semi_sync_master_yes_tx'; + +replace_result $engine_type ENGINE_TYPE; +eval create table t1(a int) engine = $engine_type; + +echo [ master state after CREATE TABLE statement ]; +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_no_tx'; +show status like 'Rpl_semi_sync_master_yes_tx'; + +# After fix of BUG#45848, semi-sync slave should not create any extra +# connections on master. +let $_connections_semisync_slave= query_get_value(SHOW STATUS LIKE 'Threads_connected', Value, 1); +replace_result $_connections_normal_slave CONNECTIONS_NORMAL_SLAVE $_connections_semisync_slave CONNECTIONS_SEMISYNC_SLAVE; +eval select $_connections_semisync_slave - $_connections_normal_slave as 'Should be 0'; + +echo [ insert records to table ]; +insert t1 values (10); +insert t1 values (9); +insert t1 values (8); +insert t1 values (7); +insert t1 values (6); +insert t1 values (5); +insert t1 values (4); +insert t1 values (3); +insert t1 values (2); +insert t1 values (1); + +echo [ master status after inserts ]; +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_no_tx'; +show status like 'Rpl_semi_sync_master_yes_tx'; + +sync_slave_with_master; + +echo [ slave status after replicated inserts ]; +show status like 'Rpl_semi_sync_slave_status'; + +select count(distinct a) from t1; +select min(a) from t1; +select max(a) from t1; + +--echo +--echo # BUG#50157 +--echo # semi-sync replication crashes when replicating a transaction which +--echo # include 'CREATE TEMPORARY TABLE `MyISAM_t` SELECT * FROM `Innodb_t` ; + +connection master; +SET SESSION AUTOCOMMIT= 0; +CREATE TABLE t2(c1 INT) ENGINE=innodb; +sync_slave_with_master; + +connection master; +BEGIN; +--echo +--echo # Even though it is in a transaction, this statement is binlogged into binlog +--echo # file immediately. +--disable_warnings +CREATE TEMPORARY TABLE t3 SELECT c1 FROM t2 where 1=1; +--enable_warnings +--echo +--echo # These statements will not be binlogged until the transaction is committed +INSERT INTO t2 VALUES(11); +INSERT INTO t2 VALUES(22); +COMMIT; + +DROP TABLE t2, t3; +SET SESSION AUTOCOMMIT= 1; +sync_slave_with_master; + + +--echo # +--echo # Test semi-sync master will switch OFF after one transaction +--echo # timeout waiting for slave reply. +--echo # +connection slave; +source include/stop_slave.inc; + +connection master; +--source include/kill_binlog_dump_threads.inc +set global rpl_semi_sync_master_timeout= 5000; + +# The first semi-sync check should be on because after slave stop, +# there are no transactions on the master. +echo [ master status should be ON ]; + +let $status_var= Rpl_semi_sync_master_status; +let $status_var_value= ON; +source include/wait_for_status_var.inc; + +let $status_var= Rpl_semi_sync_master_clients; +let $status_var_value= 0; +source include/wait_for_status_var.inc; + +show status like 'Rpl_semi_sync_master_no_tx'; +show status like 'Rpl_semi_sync_master_yes_tx'; + +echo [ semi-sync replication of these transactions will fail ]; +insert into t1 values (500); + +# Wait for the semi-sync replication of this transaction to timeout +let $status_var= Rpl_semi_sync_master_status; +let $status_var_value= OFF; +source include/wait_for_status_var.inc; + +# The second semi-sync check should be off because one transaction +# times out during waiting. +echo [ master status should be OFF ]; +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_no_tx'; +show status like 'Rpl_semi_sync_master_yes_tx'; + +# Semi-sync status on master is now OFF, so all these transactions +# will be replicated asynchronously. +delete from t1 where a=10; +delete from t1 where a=9; +delete from t1 where a=8; +delete from t1 where a=7; +delete from t1 where a=6; +delete from t1 where a=5; +delete from t1 where a=4; +delete from t1 where a=3; +delete from t1 where a=2; +delete from t1 where a=1; + +insert into t1 values (100); + +echo [ master status should be OFF ]; +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_no_tx'; +show status like 'Rpl_semi_sync_master_yes_tx'; + +--echo # +--echo # Test semi-sync status on master will be ON again when slave catches up +--echo # + +# Save the master position for later use. +save_master_pos; + +connection slave; + +echo [ slave status should be OFF ]; +show status like 'Rpl_semi_sync_slave_status'; +source include/start_slave.inc; +sync_with_master; + +echo [ slave status should be ON ]; +show status like 'Rpl_semi_sync_slave_status'; + +select count(distinct a) from t1; +select min(a) from t1; +select max(a) from t1; + +connection master; + +# The master semi-sync status should be on again after slave catches up. +echo [ master status should be ON again after slave catches up ]; + +let $status_var= Rpl_semi_sync_master_status; +let $status_var_value= ON; +source include/wait_for_status_var.inc; +show status like 'Rpl_semi_sync_master_no_tx'; +show status like 'Rpl_semi_sync_master_yes_tx'; +show status like 'Rpl_semi_sync_master_clients'; + +--echo # +--echo # Test disable/enable master semi-sync on the fly. +--echo # + +drop table t1; +sync_slave_with_master; + +source include/stop_slave.inc; + +--echo # +--echo # Flush status +--echo # +connection master; +echo [ Semi-sync master status variables before FLUSH STATUS ]; +SHOW STATUS LIKE 'Rpl_semi_sync_master_no_tx'; +SHOW STATUS LIKE 'Rpl_semi_sync_master_yes_tx'; +# Do not write the FLUSH STATUS to binlog, to make sure we'll get a +# clean status after this. +FLUSH NO_WRITE_TO_BINLOG STATUS; +echo [ Semi-sync master status variables after FLUSH STATUS ]; +SHOW STATUS LIKE 'Rpl_semi_sync_master_no_tx'; +SHOW STATUS LIKE 'Rpl_semi_sync_master_yes_tx'; + +connection master; + +source include/show_master_logs.inc; +show variables like 'rpl_semi_sync_master_enabled'; + +echo [ disable semi-sync on the fly ]; +set global rpl_semi_sync_master_enabled=0; +show variables like 'rpl_semi_sync_master_enabled'; +show status like 'Rpl_semi_sync_master_status'; + +echo [ enable semi-sync on the fly ]; +set global rpl_semi_sync_master_enabled=1; +show variables like 'rpl_semi_sync_master_enabled'; +show status like 'Rpl_semi_sync_master_status'; + +--echo # +--echo # Test RESET MASTER/SLAVE +--echo # + +connection slave; + +source include/start_slave.inc; + +connection master; + +replace_result $engine_type ENGINE_TYPE; +eval create table t1 (a int) engine = $engine_type; +drop table t1; + +sync_slave_with_master; + +echo [ test reset master ]; +connection master; + +reset master; + +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_no_tx'; +show status like 'Rpl_semi_sync_master_yes_tx'; + +connection slave; + +source include/stop_slave.inc; +--source include/reset_slave.inc + +# Kill the dump thread on master for previous slave connection and +--source include/kill_binlog_dump_threads.inc + +connection slave; +source include/start_slave.inc; + +connection master; + +# Wait for dump thread to start, Rpl_semi_sync_master_clients will be +# 1 after dump thread started. +let $status_var= Rpl_semi_sync_master_clients; +let $status_var_value= 1; +source include/wait_for_status_var.inc; + +replace_result $engine_type ENGINE_TYPE; +eval create table t1 (a int) engine = $engine_type; +insert into t1 values (1); +insert into t1 values (2), (3); + +sync_slave_with_master; + +select * from t1; + +connection master; + +echo [ master semi-sync status should be ON ]; +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_no_tx'; +show status like 'Rpl_semi_sync_master_yes_tx'; + +--echo # +--echo # Start semi-sync replication without SUPER privilege +--echo # +connection slave; +source include/stop_slave.inc; +--source include/reset_slave.inc +connection master; +reset master; + +# Kill the dump thread on master for previous slave connection and wait for it to exit +--source include/kill_binlog_dump_threads.inc + +# Do not binlog the following statement because it will generate +# different events for ROW and STATEMENT format +set sql_log_bin=0; +grant replication slave on *.* to rpl@127.0.0.1 identified by 'rpl_password'; +flush privileges; +set sql_log_bin=1; +connection slave; +grant replication slave on *.* to rpl@127.0.0.1 identified by 'rpl_password'; +flush privileges; +change master to master_user='rpl',master_password='rpl_password'; +source include/start_slave.inc; +show status like 'Rpl_semi_sync_slave_status'; +connection master; + +# Wait for the semi-sync binlog dump thread to start +let $status_var= Rpl_semi_sync_master_clients; +let $status_var_value= 1; +source include/wait_for_status_var.inc; +echo [ master semi-sync should be ON ]; +show status like 'Rpl_semi_sync_master_clients'; +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_no_tx'; +show status like 'Rpl_semi_sync_master_yes_tx'; +insert into t1 values (4); +insert into t1 values (5); +echo [ master semi-sync should be ON ]; +show status like 'Rpl_semi_sync_master_clients'; +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_no_tx'; +show status like 'Rpl_semi_sync_master_yes_tx'; + +--echo # +--echo # Test semi-sync slave connect to non-semi-sync master +--echo # + +# Disable semi-sync on master +connection slave; +source include/stop_slave.inc; +SHOW STATUS LIKE 'Rpl_semi_sync_slave_status'; + +connection master; + +# Kill the dump thread on master for previous slave connection and wait for it to exit +--source include/kill_binlog_dump_threads.inc + +echo [ Semi-sync status on master should be ON ]; +let $status_var= Rpl_semi_sync_master_clients; +let $status_var_value= 0; +source include/wait_for_status_var.inc; +show status like 'Rpl_semi_sync_master_status'; +let $status_var= Rpl_semi_sync_master_status; +let $status_var_value= ON; +source include/wait_for_status_var.inc; +set global rpl_semi_sync_master_enabled= 0; + +connection slave; +SHOW VARIABLES LIKE 'rpl_semi_sync_slave_enabled'; +source include/start_slave.inc; +connection master; +insert into t1 values (8); +let $status_var= Rpl_semi_sync_master_clients; +let $status_var_value= 1; +source include/wait_for_status_var.inc; +echo [ master semi-sync clients should be 1, status should be OFF ]; +show status like 'Rpl_semi_sync_master_clients'; +show status like 'Rpl_semi_sync_master_status'; +sync_slave_with_master; +show status like 'Rpl_semi_sync_slave_status'; + +# Uninstall semi-sync plugin on master +connection slave; +source include/stop_slave.inc; +connection master; +set global rpl_semi_sync_master_enabled= 0; + +connection slave; +SHOW VARIABLES LIKE 'rpl_semi_sync_slave_enabled'; +source include/start_slave.inc; + +connection master; +insert into t1 values (10); +sync_slave_with_master; + +--echo # +--echo # Test non-semi-sync slave connect to semi-sync master +--echo # + +connection master; +set global rpl_semi_sync_master_timeout= 5000; # 5s +set global rpl_semi_sync_master_enabled= 1; + +connection slave; +source include/stop_slave.inc; +SHOW STATUS LIKE 'Rpl_semi_sync_slave_status'; + +echo [ uninstall semi-sync slave plugin ]; +set global rpl_semi_sync_slave_enabled= 0; + +echo [ reinstall semi-sync slave plugin and disable semi-sync ]; +SHOW VARIABLES LIKE 'rpl_semi_sync_slave_enabled'; +SHOW STATUS LIKE 'Rpl_semi_sync_slave_status'; +source include/start_slave.inc; +SHOW STATUS LIKE 'Rpl_semi_sync_slave_status'; + +--echo # +--echo # Clean up +--echo # + +connection slave; +source include/stop_slave.inc; +set global rpl_semi_sync_slave_enabled= 0; + +connection master; +set global rpl_semi_sync_master_enabled= 0; + +connection slave; +change master to master_user='root',master_password=''; +source include/start_slave.inc; + +connection master; +drop table t1; +sync_slave_with_master; + +connection master; +drop user rpl@127.0.0.1; +flush privileges; +set global rpl_semi_sync_master_timeout= default; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_after_sync.test b/mysql-test/suite/rpl/t/rpl_semi_sync_after_sync.test new file mode 100644 index 00000000..2d91d2e4 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_after_sync.test @@ -0,0 +1,4 @@ +--source include/have_binlog_format_statement.inc +set global rpl_semi_sync_master_wait_point=AFTER_SYNC; +source rpl_semi_sync.test; +set global rpl_semi_sync_master_wait_point=default; diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_after_sync_row.test b/mysql-test/suite/rpl/t/rpl_semi_sync_after_sync_row.test new file mode 100644 index 00000000..47af6c34 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_after_sync_row.test @@ -0,0 +1,4 @@ +--source include/have_binlog_format_row.inc +set global rpl_semi_sync_master_wait_point=AFTER_SYNC; +source rpl_semi_sync.test; +set global rpl_semi_sync_master_wait_point=default; diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_crash.inc b/mysql-test/suite/rpl/t/rpl_semi_sync_crash.inc new file mode 100644 index 00000000..01b0d0e5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_crash.inc @@ -0,0 +1,112 @@ +if ($failover_to_slave) +{ + --let $server_to_crash=1 + --let $server_to_promote=2 + --let $new_master_port=$SERVER_MYPORT_2 + --let $client_port=$SERVER_MYPORT_1 + + --connect (conn_client,127.0.0.1,root,,test,$SERVER_MYPORT_1,) +} +if (!$failover_to_slave) +{ + --let $server_to_crash=2 + --let $server_to_promote=1 + --let $new_master_port=$SERVER_MYPORT_1 + --let $client_port=$SERVER_MYPORT_2 + + --connect (conn_client,127.0.0.1,root,,test,$SERVER_MYPORT_2,) +} + + +# Hold insert after write to binlog and before "run_commit_ordered" in engine + + +if ($case == 1) +{ + SET DEBUG_SYNC= "commit_after_release_LOCK_after_binlog_sync SIGNAL con1_ready WAIT_FOR con1_go"; + --send_eval $query_to_crash + --connection server_$server_to_crash + SET DEBUG_SYNC= "now WAIT_FOR con1_ready"; + --source include/kill_mysqld.inc +} + +# complicate recovery with an extra binlog file +if ($case == 2) +{ + SET DEBUG_SYNC= "commit_before_get_LOCK_commit_ordered SIGNAL con1_ready WAIT_FOR con1_go"; + --send_eval $query_to_crash + --connect (conn_client_2,127.0.0.1,root,,test,$SERVER_MYPORT_2,) + # use the same signal with $query_to_crash + SET DEBUG_SYNC= "now WAIT_FOR con1_ready"; + SET GLOBAL debug_dbug="d,Notify_binlog_EOF"; + --send_eval $query2_to_crash + --connection server_$server_to_crash + SET DEBUG_SYNC= "now WAIT_FOR eof_reached"; + --source include/kill_mysqld.inc +} + +# complicate recovery with an extra binlog file +if ($case == 3) +{ + SET DEBUG_SYNC= "commit_before_get_LOCK_commit_ordered SIGNAL con1_ready WAIT_FOR con1_go"; + --send_eval $query_to_crash + --connect (conn_client_3,127.0.0.1,root,,test,$SERVER_MYPORT_1,) + SET DEBUG_SYNC= "now WAIT_FOR con1_ready"; + # use the same signal with $query_to_crash + SET DEBUG_SYNC= "commit_before_update_binlog_end_pos SIGNAL con3_ready WAIT_FOR con1_go"; + --send_eval $query2_to_crash + --connection server_$server_to_crash + SET DEBUG_SYNC= "now WAIT_FOR con3_ready"; + --source include/kill_mysqld.inc +} + +--connection server_$server_to_promote +--let $slave_param= Slave_SQL_Running_State +--let $slave_param_value= Slave has read all relay log; waiting for more updates +source include/wait_for_slave_param.inc; + +--error 2003 +--source include/stop_slave.inc + +--let $assert_cond= COUNT(*) = $expected_rows_on_slave FROM t1 +--let $assert_text= Table t1 should have $expected_rows_on_slave rows. +--source include/assert.inc + +SELECT @@GLOBAL.gtid_current_pos; + +--let $restart_parameters=--skip-slave-start=1 --rpl-semi-sync-slave-enabled=1 +--let $allow_rpl_inited=1 +--source include/start_mysqld.inc +--connection server_$server_to_crash +--enable_reconnect +--source include/wait_until_connected_again.inc + +--let $assert_cond= COUNT(*) = $expected_rows_on_master FROM t1 +--let $assert_text= Table t1 should have $expected_rows_on_master rows. +--source include/assert.inc + +# Check error log for correct messages. +let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.$server_to_crash.err; +--let SEARCH_FILE=$log_error_ +--let SEARCH_PATTERN=$log_search_pattern +--source include/search_pattern_in_file.inc + +--disconnect conn_client + +# +# FAIL OVER now to new master +# +--connection server_$server_to_promote +set global rpl_semi_sync_master_enabled = 1; +set global rpl_semi_sync_master_wait_point=AFTER_SYNC; + +--connection server_$server_to_crash +--let $master_port=$SERVER_MYPORT_2 +if (`select $server_to_crash = 2`) +{ + --let $master_port=$SERVER_MYPORT_1 +} +evalp CHANGE MASTER TO master_host='127.0.0.1', master_port=$new_master_port, master_user='root', master_use_gtid=SLAVE_POS; +set global rpl_semi_sync_slave_enabled = 1; +set @@global.gtid_slave_pos=@@global.gtid_binlog_pos; +--source include/start_slave.inc diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_event-master.opt b/mysql-test/suite/rpl/t/rpl_semi_sync_event-master.opt new file mode 100644 index 00000000..4cfb5d53 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_event-master.opt @@ -0,0 +1 @@ +--max-connections=40 diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_event.test b/mysql-test/suite/rpl/t/rpl_semi_sync_event.test new file mode 100644 index 00000000..d4df9b40 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_event.test @@ -0,0 +1,91 @@ +source include/no_valgrind_without_big.inc; +source include/not_embedded.inc; +source include/have_innodb.inc; +source include/master-slave.inc; + +let $engine_type= InnoDB; + +# Suppress warnings that might be generated during the test +connection master; +call mtr.add_suppression("Timeout waiting for reply of binlog"); +call mtr.add_suppression("Semi-sync master .* waiting for slave reply"); +call mtr.add_suppression("Read semi-sync reply"); +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT."); +call mtr.add_suppression("mysqld: Got an error reading communication packets"); + +connection slave; +call mtr.add_suppression("Master server does not support semi-sync"); +call mtr.add_suppression("Semi-sync slave .* reply"); +call mtr.add_suppression("Slave SQL.*Request to stop slave SQL Thread received while applying a group that has non-transactional changes; waiting for completion of the group"); + +connection master; +set global rpl_semi_sync_master_enabled = 1; + +connection slave; +source include/stop_slave.inc; +set global rpl_semi_sync_slave_enabled = 1; + +source include/start_slave.inc; + +connection master; +SET GLOBAL event_scheduler = ON; + +replace_result $engine_type ENGINE_TYPE; +eval CREATE TABLE t1 (i INT NOT NULL AUTO_INCREMENT PRIMARY KEY, f varchar(8)) ENGINE=$engine_type; +INSERT INTO t1 (f) VALUES ('a'),('a'),('a'),('a'),('a'); +--disable_warnings +INSERT INTO t1 SELECT i+5, f FROM t1; +INSERT INTO t1 SELECT i+10, f FROM t1; +--enable_warnings +CREATE EVENT ev1 ON SCHEDULE EVERY 1 SECOND +DO INSERT INTO t1 VALUES (SLEEP(5),CONCAT('ev1_',CONNECTION_ID())); +CREATE EVENT ev2 ON SCHEDULE EVERY 1 SECOND +DO INSERT INTO t1 VALUES (SLEEP(5),CONCAT('ev2_',CONNECTION_ID())); + +connection slave; +STOP SLAVE IO_THREAD; + +connection master; +let $run = 20; +while ($run) +{ + connect (m$run,localhost,root,,); + connection m$run; + send; + eval UPDATE t1 SET f = CONCAT('up_',CONNECTION_ID()) WHERE i = $run; + connection master; + dec $run; +} + +connection master; +SET GLOBAL event_scheduler = OFF; + +let $run = 20; +while ($run) +{ + connection m$run; + reap; + disconnect m$run; + dec $run; +} + +# +# Clean up +# +connection slave; +source include/stop_slave.inc; +set global rpl_semi_sync_slave_enabled = 0; + +connection master; +set global rpl_semi_sync_master_enabled = 0; + +connection slave; +source include/start_slave.inc; + +connection master; + +DROP EVENT ev1; +DROP EVENT ev2; +DROP TABLE t1; +sync_slave_with_master; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_event_after_sync-master.opt b/mysql-test/suite/rpl/t/rpl_semi_sync_event_after_sync-master.opt new file mode 100644 index 00000000..4cfb5d53 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_event_after_sync-master.opt @@ -0,0 +1 @@ +--max-connections=40 diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_event_after_sync.test b/mysql-test/suite/rpl/t/rpl_semi_sync_event_after_sync.test new file mode 100644 index 00000000..527900fd --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_event_after_sync.test @@ -0,0 +1,3 @@ +set global rpl_semi_sync_master_wait_point=AFTER_SYNC; +source rpl_semi_sync_event.test; +set global rpl_semi_sync_master_wait_point=default; diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_fail_over.cnf b/mysql-test/suite/rpl/t/rpl_semi_sync_fail_over.cnf new file mode 100644 index 00000000..8c5e6362 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_fail_over.cnf @@ -0,0 +1,13 @@ +!include suite/rpl/rpl_1slave_base.cnf +!include include/default_client.cnf + + +[mysqld.1] +log-slave-updates +gtid-strict-mode=1 +sync-binlog=1 + +[mysqld.2] +log-slave-updates +gtid-strict-mode=1 +sync-binlog=1 diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_fail_over.test b/mysql-test/suite/rpl/t/rpl_semi_sync_fail_over.test new file mode 100644 index 00000000..6a691ae0 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_fail_over.test @@ -0,0 +1,221 @@ +# ==== References ==== +# +# MDEV-21117 recovery for --rpl-semi-sync-slave-enabled server +# MDEV-27760 event may non stop replicate in circular semisync setup +# + +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +# Initial slave +--connection server_2 +--source include/stop_slave.inc + +# Initial master +--connection server_1 +RESET MASTER; +SET @@global.max_binlog_size= 4096; + +--connection server_2 +RESET MASTER; +SET @@global.max_binlog_size= 4096; +set @@global.rpl_semi_sync_slave_enabled = 1; +set @@global.gtid_slave_pos = ""; +CHANGE MASTER TO master_use_gtid= slave_pos; +--source include/start_slave.inc + +--connection server_1 +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +set @@global.rpl_semi_sync_master_enabled = 1; +set @@global.rpl_semi_sync_master_wait_point=AFTER_SYNC; + +CREATE TABLE t1 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Innodb; +INSERT INTO t1 VALUES (1, 'dummy1'); +--save_master_pos + +--connection server_2 +--sync_with_master + +--connection server_1 +--let $case = 1 +--echo # +--echo # Case:$case +--echo # +--echo # CRASH the original master, and FAILOVER to the new +# value 1 for server id 1 -> 2 failover +--let $failover_to_slave=1 +--let $query_to_crash= INSERT INTO t1 VALUES (2, REPEAT("x", 4100)) +--echo # $query_to_crash +--echo # Row - 2 will be in master's binlog but not committed, gets replicated +--echo # to slave and applied. On crash master should have 1 row and slave +--echo # should have 2 rows. +--echo # +--echo # Expected State post crash: +--echo #================================================================= +--echo # Master | Slave | +--echo # 0-1-4 (Not committed) | 0-1-4 (Received through semi-sync | +--echo # | replication and applied) | +--echo #================================================================= +--let $log_search_pattern=truncated binlog file:.*master.*000001 +--let $expected_rows_on_master= 1 +--let $expected_rows_on_slave= 2 +--source rpl_semi_sync_crash.inc + +--echo # +--echo # Server_2 promoted as master will send 0-1-4 to new slave Server_1 +--echo # +--connection server_2 +--let $rows_so_far=3 +--eval INSERT INTO t1 VALUES ($rows_so_far, 'dummy3') +--save_master_pos +--echo # The gtid state on current master must be equal to ... +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +SHOW VARIABLES LIKE 'gtid_binlog_state'; +SHOW VARIABLES LIKE 'gtid_slave_pos'; + +--connection server_1 +--sync_with_master +--eval SELECT COUNT(*) = $rows_so_far as 'true' FROM t1 +--echo # ... the gtid states on the slave: +SHOW VARIABLES LIKE 'gtid_slave_pos'; +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +SHOW VARIABLES LIKE 'gtid_binlog_state'; + +--connection server_2 +--let $case = 2 +--echo # +--echo # Case:$case +--echo # +--echo # CRASH the new master, and FAILOVER back to the original +# value 0 for the reverse server id 2 -> 1 failover +--let $failover_to_slave=0 +# Additionally through "foreign" server_id verify MDEV-27760's acceptance +# policy on the recient (to be promoted into master) server. +--let $query_to_crash = SET STATEMENT server_id=1 FOR INSERT INTO t1 VALUES (4, REPEAT("x", 4100)) +--let $query2_to_crash= INSERT INTO t1 VALUES (5, REPEAT("x", 4100)) +--echo # $query_to_crash +--echo # $query2_to_crash +--echo # Rows 4 and 5 will be in master's binlog but not committed, they get +--echo # replicated to slave and applied. On crash master should have 3 rows +--echo # and slave should have 5 rows. +--echo # +--echo # Expected State post crash: +--echo #================================================================= +--echo # Master | Slave | +--echo # 0-1-6 (Not commited) | 0-1-6 (Received through semi-sync | +--echo # | replication and applied) | +--echo # 0-2-7 (Not commited) | 0-2-7 (Received through semi-sync | +--echo # | replication and applied) | +--echo #================================================================= +--let $log_search_pattern=truncated binlog file:.*slave.*000002.* to remove transactions starting from GTID 0-1-6 +--let $expected_rows_on_master= 3 +--let $expected_rows_on_slave= 5 +--source rpl_semi_sync_crash.inc + +--echo # +--echo # Server_1 promoted as master will send 0-1-6 and 0-2-7 to slave Server_2 +--echo # +--connection server_1 +--let $rows_so_far=6 +--eval INSERT INTO t1 VALUES ($rows_so_far, 'dummy6') +--save_master_pos +--echo # The gtid state on current master must be equal to ... +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +SHOW VARIABLES LIKE 'gtid_binlog_state'; +SHOW VARIABLES LIKE 'gtid_slave_pos'; + +--connection server_2 +--sync_with_master +--eval SELECT COUNT(*) = $rows_so_far as 'true' FROM t1 +--echo # ... the gtid states on the slave: +SHOW VARIABLES LIKE 'gtid_slave_pos'; +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +SHOW VARIABLES LIKE 'gtid_binlog_state'; + +--let $diff_tables=server_1:t1, server_2:t1 +--source include/diff_tables.inc + +--connection server_1 +--let $case = 3 +--echo # +--echo # Case:$case +--echo # +--echo # CRASH the master and FAILOVER to slave +--let $failover_to_slave=1 +--let $query_to_crash = INSERT INTO t1 VALUES (7, REPEAT("x", 4100)) +--let $query2_to_crash= INSERT INTO t1 VALUES (8, REPEAT("x", 4100)) +--echo # $query_to_crash +--echo # $query2_to_crash +--echo # Rows 7 and 8 will be in master's binlog but not committed, only 7 +--echo # gets replicated to slave and applied. On crash master should have 6 +--echo # rows and slave should have 7 rows. +--echo # +--echo # Expected State post crash: +--echo #================================================================= +--echo # Master | Slave | +--echo # 0-1-9 (Not commited) | 0-1-9 (Received through semi-sync | +--echo # | replication and applied) | +--echo # 0-1-10 (Not commited - | | +--echo # never sent to slave) | | +--echo #================================================================= +--let $log_search_pattern=truncated binlog file:.*master.*000002.* to remove transactions starting from GTID 0-1-9 +--let $expected_rows_on_master= 6 +--let $expected_rows_on_slave= 7 +--source rpl_semi_sync_crash.inc + +--echo # +--echo # Server_2 promoted as master will send 0-1-9 to slave Server_1 +--echo # +--connection server_2 +--let $rows_so_far=8 +--eval INSERT INTO t1 VALUES ($rows_so_far, 'Done') +--source include/save_master_gtid.inc +--echo # The gtid state on current master must be equal to ... +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +SHOW VARIABLES LIKE 'gtid_binlog_state'; +SHOW VARIABLES LIKE 'gtid_slave_pos'; + +--connection server_1 +--source include/sync_with_master_gtid.inc +--eval SELECT COUNT(*) = $rows_so_far as 'true' FROM t1 +--echo # ... the gtid states on the slave: +SHOW VARIABLES LIKE 'gtid_slave_pos'; +SHOW VARIABLES LIKE 'gtid_binlog_pos'; +SHOW VARIABLES LIKE 'gtid_binlog_state'; + +--echo # +--echo # Cleanup +--echo # + +--source include/stop_slave.inc +set global rpl_semi_sync_slave_enabled = 0; +set global rpl_semi_sync_master_enabled = 0; +set global rpl_semi_sync_master_wait_point=default; +RESET MASTER; +RESET SLAVE; + +--connection server_2 +RESET MASTER; +RESET SLAVE; +set @@global.rpl_semi_sync_master_enabled = 0; +set @@global.rpl_semi_sync_slave_enabled = 0; +set @@global.rpl_semi_sync_master_wait_point=default; +evalp CHANGE MASTER TO master_host='127.0.0.1', master_port=$SERVER_MYPORT_1, master_user='root', master_use_gtid=SLAVE_POS; +set @@global.gtid_slave_pos=@@global.gtid_binlog_pos; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t1; +--save_master_pos + +--connection server_2 +--sync_with_master + +connection default; +--enable_reconnect +--source include/wait_until_connected_again.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_gtid_reconnect.test b/mysql-test/suite/rpl/t/rpl_semi_sync_gtid_reconnect.test new file mode 100644 index 00000000..96f7e805 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_gtid_reconnect.test @@ -0,0 +1,74 @@ +source include/not_embedded.inc; +source include/have_binlog_format_mixed.inc; +source include/master-slave.inc; + +# +# Semisync initialization +# +--connection master +RESET MASTER; +--let $sav_enabled_master=`SELECT @@GLOBAL.rpl_semi_sync_master_enabled` +SET @@GLOBAL.rpl_semi_sync_master_enabled = 1; + +--connection slave +source include/stop_slave.inc; +--let $sav_enabled_slave=`SELECT @@GLOBAL.rpl_semi_sync_slave_enabled` +SET @@GLOBAL. rpl_semi_sync_slave_enabled = 1; +source include/start_slave.inc; + +# Prove fixes to +# MDEV-19376 Assert (!m_active_tranxs->is_tranx_end_pos(trx_wait_binlog_name...) +# +# +# Run few queries to replicate/execute on slave. +# Stop the slave applier. +# Replicate/not-executed few more. +# Restart the slave. +# +--connection master +CREATE TABLE t1 (a INT); +INSERT INTO t1 SET a = 1; +--source include/save_master_gtid.inc +--let $resume_gtid = $master_pos +FLUSH LOGS; +INSERT INTO t1 SET a = 2; + +--sync_slave_with_master +--connection slave +--source include/stop_slave_sql.inc + +--connection master +INSERT INTO t1 SET a = 3; + +# the sync connection is 'slave' by default +--source include/sync_slave_io_with_master.inc +--connection slave +--source include/stop_slave_io.inc + +--connection master +RESET MASTER; +--eval SET @@global.gtid_binlog_state = '$resume_gtid' + +# The resume gtid is set up to point to the very first binlog file +--connection slave +CHANGE MASTER TO MASTER_USE_GTID = slave_pos; +--eval SET @@global.gtid_slave_pos = '$resume_gtid' +# Yet the slave io first submits the last received binlog file name:pos. +--source include/start_slave.inc + +# Here goes the cracker. +--connection master +INSERT INTO t1 SET a = 4; + +# +# Clean up +# +--connection master +DROP TABLE t1; +--eval SET @@GLOBAL. rpl_semi_sync_master_enabled = $sav_enabled_master + +--sync_slave_with_master +source include/stop_slave.inc; +--eval SET @@GLOBAL. rpl_semi_sync_slave_enabled = $sav_enabled_slave +source include/start_slave.inc; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_master_shutdown.test b/mysql-test/suite/rpl/t/rpl_semi_sync_master_shutdown.test new file mode 100644 index 00000000..2224f78d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_master_shutdown.test @@ -0,0 +1,60 @@ +# MDEV-16812 Semisync slave io thread segfaults at STOP-SLAVE handling +# +# The test verifies that the semisync-enabled slave io thread +# finishes off as specified in particular trying to connect even to a shut down +# master for a semisync firewell routine. + +source include/not_embedded.inc; +source include/have_debug.inc; +source include/master-slave.inc; + +--connection master + +--let $sav_enabled_master=`SELECT @@GLOBAL.rpl_semi_sync_master_enabled ` +SET @@GLOBAL.rpl_semi_sync_master_enabled = 1; + +--connection slave +source include/stop_slave.inc; +--let $sav_enabled_slave=`SELECT @@GLOBAL.rpl_semi_sync_slave_enabled ` +SET @@GLOBAL. rpl_semi_sync_slave_enabled = 1; +source include/start_slave.inc; + +--connection master +CREATE TABLE t1 (a INT); +INSERT INTO t1 SET a=1; + +--sync_slave_with_master + +connection master; +--echo # Shutdown master +--let $rpl_server_number=1 +source include/rpl_stop_server.inc; + +--connection slave +--source include/stop_slave.inc + +#connection master; +--echo # Restart master +--let $rpl_server_number=1 +source include/rpl_start_server.inc; + +# +# Clean up +# +--connection slave +--source include/stop_slave.inc +--source include/start_slave.inc + +--connection master +SET @@GLOBAL.debug_dbug=""; +--eval SET @@GLOBAL. rpl_semi_sync_master_enabled = $sav_enabled_master + +--connection master +DROP TABLE t1; + +--sync_slave_with_master +source include/stop_slave.inc; +--eval SET @@GLOBAL. rpl_semi_sync_slave_enabled = $sav_enabled_slave + +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_shutdown_await_ack.cnf b/mysql-test/suite/rpl/t/rpl_semi_sync_shutdown_await_ack.cnf new file mode 100644 index 00000000..2cf1b178 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_shutdown_await_ack.cnf @@ -0,0 +1,14 @@ +!include ../my.cnf + +[mysqld.1] +log_warnings=9 + +[mysqld.2] +log_warnings=9 + +[mysqld.3] +log_warnings=9 + +[ENV] +SERVER_MYPORT_3= @mysqld.3.port +SERVER_MYSOCK_3= @mysqld.3.socket diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_shutdown_await_ack.inc b/mysql-test/suite/rpl/t/rpl_semi_sync_shutdown_await_ack.inc new file mode 100644 index 00000000..a232f685 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_shutdown_await_ack.inc @@ -0,0 +1,163 @@ +# +# Helper file to ensure that a primary waits for all ACKS (or timeout) from its +# replicas before shutting down. +# +# Parameters: +# server_1_dbug (string) Debug setting for primary (server 1) +# server_2_dbug (string) Debug setting to simulate delay or error on +# the first replica (server 2) +# server_3_dbug (string) Debug setting to simulate delay or error on +# the second replica (server 3) +# semisync_timeout (int) Rpl_semi_sync_master_timeout to use +# server_2_expect_row_count (int) The number of rows expected on the first +# replica after the shutdown +# server_3_expect_row_count (int) The number of rows expected on the second +# replica after the shutdown +# + +--connection server_1 +let $log_error_file= `SELECT @@GLOBAL.log_error`; + +--echo #-- +--echo #-- Semi-sync Setup + +--connection server_1 +--save_master_pos + +echo #-- Enable semi-sync on slaves +let slave_last= 3; +--let i= 2 +while (`SELECT $i <= $slave_last`) +{ + --connection server_$i + --sync_with_master + + set global rpl_semi_sync_slave_enabled = 1; + source include/stop_slave.inc; + source include/start_slave.inc; + show status like 'Rpl_semi_sync_slave_status'; + + --inc $i +} + +--echo #-- Enable semi-sync on master +--connection server_1 +SET @@GLOBAL.rpl_semi_sync_master_enabled = 1; +--eval set @@global.rpl_semi_sync_master_timeout= $semisync_timeout + +--echo #-- Wait for master to recognize semi-sync slaves +--connection server_1 +let $status_var= Rpl_semi_sync_master_clients; +let $status_var_value= 2; +source include/wait_for_status_var.inc; + +--echo #-- Master should have semi-sync enabled with 2 connections +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_clients'; + +--echo #-- Prepare servers to simulate delay or error +--connection server_1 +--eval SET @@GLOBAL.debug_dbug= $server_1_dbug +--connection server_2 +--eval SET @@GLOBAL.debug_dbug= $server_2_dbug +--connection server_3 +--eval SET @@GLOBAL.debug_dbug= $server_3_dbug + +--echo #-- +--echo #-- Test begins + +--connection server_1 +--echo #-- Begin semi-sync transaction +--send INSERT INTO t1 VALUES (1) + +--connection server_1_con2 +--echo #-- Wait until master recognizes a connection is awaiting semi-sync ACK +let $status_var= Rpl_semi_sync_master_wait_sessions; +let $status_var_value= 1; +source include/wait_for_status_var.inc; +show status like 'Rpl_semi_sync_master_wait_sessions'; + +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +wait +EOF + +--echo #-- Give enough time after timeout/ack received to query yes_tx/no_tx +SET @@GLOBAL.debug_dbug= "+d,delay_shutdown_phase_2_after_semisync_wait"; + +--echo #-- Begin master shutdown +--send SHUTDOWN WAIT FOR ALL SLAVES + +--connection server_1 +--reap +--echo #-- Ensure either ACK was received (yes_tx=1) or timeout (no_tx=1) +show status like 'Rpl_semi_sync_master_yes_tx'; +show status like 'Rpl_semi_sync_master_no_tx'; + +--connection server_1_con2 +--reap +--source include/wait_until_disconnected.inc + +--echo # Check logs to ensure shutdown was delayed +--let SEARCH_FILE=$log_error_file +--let SEARCH_PATTERN=Delaying shutdown to await semi-sync ACK +--source include/search_pattern_in_file.inc + +--echo # Validate slave data is in correct state +--connection server_2 +--eval select count(*)=$server_2_expect_row_count from t1 +--connection server_3 +--eval select count(*)=$server_3_expect_row_count from t1 + +--echo # +--echo #-- Re-synchronize slaves with master and disable semi-sync + +--echo #-- Stop slaves + +--connection server_2 +--eval SET @@GLOBAL.debug_dbug= "$sav_server_2_dbug" +--eval SET @@GLOBAL.rpl_semi_sync_slave_enabled= 0 +source include/stop_slave.inc; + +--connection server_3 +--eval SET @@GLOBAL.debug_dbug= "$sav_server_3_dbug" +--eval SET @@GLOBAL.rpl_semi_sync_slave_enabled= 0 +source include/stop_slave.inc; + +--echo #-- Bring the master back up +--connection server_1_con2 +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +restart +EOF + +--enable_reconnect +--source include/wait_until_connected_again.inc + +--connection default +--enable_reconnect +--source include/wait_until_connected_again.inc + +--connection server_1 +--enable_reconnect +--source include/wait_until_connected_again.inc + +--eval SET @@GLOBAL.debug_dbug= "$sav_master_dbug" +let $status_var= Rpl_semi_sync_master_clients; +let $status_var_value= 0; +source include/wait_for_status_var.inc; +--eval SET @@GLOBAL.rpl_semi_sync_master_enabled = 0 +show status like 'Rpl_semi_sync_master_status'; + +TRUNCATE TABLE t1; +--save_master_pos + +--echo #-- Bring slaves back up +--let i= 2 +while (`SELECT $i <= $slave_last`) +{ + --connection server_$i + source include/start_slave.inc; + show status like 'Rpl_semi_sync_slave_status'; + --sync_with_master + SELECT COUNT(*)=0 from t1; + --inc $i +} diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_shutdown_await_ack.test b/mysql-test/suite/rpl/t/rpl_semi_sync_shutdown_await_ack.test new file mode 100644 index 00000000..6c088c57 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_shutdown_await_ack.test @@ -0,0 +1,217 @@ +--source include/no_valgrind_without_big.inc + +# +# Purpose: +# This test validates that data is consistent between a primary and replica +# in semi-sync mode when the primary is issued `SHUTDOWN WAIT FOR SLAVES` +# during an active communication. More specifically, the primary should not +# kill the connection until it is sure a replica has received all binlog +# data, i.e. once the primary receives the ACK. If a primary is issued a +# shutdown before receiving an ACK, it should wait until either 1) the ACK is +# received, or 2) the configured timeout (rpl_semi_sync_master_timeout) is +# reached. +# +# Methodology: +# Using a topology consisting of one primary with two replicas, all in +# semi-sync mode, we use DEBUG_DBUG to simulate an error or delay on the +# replicas during an active communication while the primary is issued +# `SHUTDOWN WAIT FOR SLAVES`. We create four test cases to ensure the primary +# will correctly wait for the communication to finish, and use the semi-sync +# status variables Rpl_semi_sync_master_yes_tx and Rpl_semi_sync_master_no_tx +# to ensure the connection was not prematurely killed due to the shutdown. +# Test Case 1) If both replicas simulate a delay that is within the allowed +# timeout, the primary should delay killing the suspended thread +# until an ACK is received (Rpl_semi_sync_master_yes_tx should +# be 1). +# Test Case 2) If both replicas simulate an error before sending an ACK, the +# primary should delay killing the suspended thread until the +# the timeout is reached (Rpl_semi_sync_master_no_tx should be +# 1). +# Test Case 3) If one replica simulates a delay within the allowed timeout +# and the other simulates an error before sending an ACK, the +# primary should delay killing the suspended thread until it +# receives an ACK from the delayed slave +# (Rpl_semi_sync_master_yes_tx should be 1). +# Test Case 4) If a replica errors before sending an ACK, it will cause the +# IO thread to stop and handle the error. During error handling, +# if semi-sync is active, the replica will form a new connection +# with the primary to kill the active connection. However, if +# the primary is shutting down, it may kill the new connection, +# thereby leaving the active semi-sync connection in-tact. The +# slave should notice this, and not issue a `QUIT` command to +# the primary, which would otherwise be sent to kill an active +# connection. This test case validates that the slave does not +# send a `QUIT` in this case (Rpl_semi_sync_master_yes_tx should +# be 1 because server_3 will send the ACK within a valid +# timeout). +# +# References: +# MDEV-11853: semisync thread can be killed after sync binlog but before ACK +# in the sync state +# MDEV-28114: Semi-sync Master ACK Receiver Thread Can Error on COM_QUIT +# + +--echo ############################# +--echo # Common setup for all tests +--echo ############################# + +--echo # Note: Simulated slave delay is hardcoded to 800 milliseconds +--echo # Note: Simulated master shutdown delay is hardcoded to 500 milliseconds + +--source include/have_debug.inc +--let $rpl_topology=1->2, 1->3 +--source include/rpl_init.inc + +--connection server_1 + +--echo # Slaves which simulate an error will produce a timeout on the primary +call mtr.add_suppression("Timeout waiting"); +call mtr.add_suppression("did not exit"); +call mtr.add_suppression("Got an error reading communication packets"); + +--let $sav_master_timeout= `SELECT @@global.rpl_semi_sync_master_timeout` +--let $sav_enabled_master= `SELECT @@GLOBAL.rpl_semi_sync_master_enabled` +--let $sav_master_dbug= `SELECT @@GLOBAL.debug_dbug` + +--echo # Suppress slave errors related to the simulated error +--connection server_2 +call mtr.add_suppression("reply failed"); +call mtr.add_suppression("Replication event checksum verification"); +call mtr.add_suppression("Relay log write failure"); +call mtr.add_suppression("Failed to kill the active semi-sync connection"); +--let $sav_enabled_server_2=`SELECT @@GLOBAL.rpl_semi_sync_slave_enabled` +--let $sav_server_2_dbug= `SELECT @@GLOBAL.debug_dbug` + +--connection server_3 +call mtr.add_suppression("reply failed"); +call mtr.add_suppression("Replication event checksum verification"); +call mtr.add_suppression("Relay log write failure"); +call mtr.add_suppression("Failed to kill the active semi-sync connection"); +--let $sav_enabled_server_3=`SELECT @@GLOBAL.rpl_semi_sync_slave_enabled` +--let $sav_server_3_dbug= `SELECT @@GLOBAL.debug_dbug` + +--connection server_1 +CREATE TABLE t1 (a int); +--save_master_pos + +--let i= 2 +--let slave_last= 3 +while (`SELECT $i <= $slave_last`) +{ + --connection server_$i + --sync_with_master + --inc $i +} + +# Set up the connection used to issue the shutdown +--connect(server_1_con2, localhost, root,,) + + +--echo ############################# +--echo # Test cases +--echo ############################# + +--echo # +--echo # Test Case 1) If both replicas simulate a delay that is within the +--echo # allowed timeout, the primary should delay killing the suspended thread +--echo # until an ACK is received (Rpl_semi_sync_master_yes_tx should be 1). +--echo # +--let server_1_dbug= "" +--let server_2_dbug= "+d,simulate_delay_semisync_slave_reply" +--let server_3_dbug= "+d,simulate_delay_semisync_slave_reply" +--let semisync_timeout= 1600 +--let server_2_expect_row_count= 1 +--let server_3_expect_row_count= 1 +--source rpl_semi_sync_shutdown_await_ack.inc + +--echo # +--echo # Test Case 2) If both replicas simulate an error before sending an ACK, +--echo # the primary should delay killing the suspended thread until the +--echo # timeout is reached (Rpl_semi_sync_master_no_tx should be 1). +--echo # +--let server_1_dbug= "+d,mysqld_delay_kill_threads_phase_1" +--let server_2_dbug= "+d,corrupt_queue_event" +--let server_3_dbug= "+d,corrupt_queue_event" +--let semisync_timeout= 500 +--let server_2_expect_row_count= 0 +--let server_3_expect_row_count= 0 +--source rpl_semi_sync_shutdown_await_ack.inc + +--echo # +--echo # Test Case 3) If one replica simulates a delay within the allowed +--echo # timeout and the other simulates an error before sending an ACK, the +--echo # primary should delay killing the suspended thread until it receives an +--echo # ACK from the delayed slave (Rpl_semi_sync_master_yes_tx should be 1). +--echo # +--let server_1_dbug= "+d,mysqld_delay_kill_threads_phase_1" +--let server_2_dbug= "+d,corrupt_queue_event" +--let server_3_dbug= "+d,simulate_delay_semisync_slave_reply" +--let semisync_timeout= 1600 +--let server_2_expect_row_count= 0 +--let server_3_expect_row_count= 1 +--source rpl_semi_sync_shutdown_await_ack.inc + +--echo # +--echo # Test Case 4) If a replica errors before sending an ACK, it will cause +--echo # the IO thread to stop and handle the error. During error handling, if +--echo # semi-sync is active, the replica will form a new connection with the +--echo # primary to kill the active connection. However, if the primary is +--echo # shutting down, it may kill the new connection, thereby leaving the +--echo # active semi-sync connection in-tact. The slave should notice this, and +--echo # not issue a `QUIT` command to the primary, which would otherwise be +--echo # sent to kill an active connection. This test case validates that the +--echo # slave does not send a `QUIT` in this case (Rpl_semi_sync_master_yes_tx +--echo # should be 1 because server_3 will send the ACK within a valid timeout). +--echo # + +# mysqld_delay_kill_threads_phase1 ensures that server_2 will have enough time +# to start a new connection that has the intent to kill the active semi-sync +# connection +--let server_1_dbug= "+d,mysqld_delay_kill_threads_phase_1" + +# slave_delay_killing_semisync_connection ensures that the primary has force +# killed its current connection before it is able to issue `KILL` +--let server_2_dbug= "+d,corrupt_queue_event,slave_delay_killing_semisync_connection" +--let server_3_dbug= "+d,simulate_delay_semisync_slave_reply" +--let semisync_timeout= 1600 +--let server_2_expect_row_count= 0 +--let server_3_expect_row_count= 1 +--source rpl_semi_sync_shutdown_await_ack.inc + +--echo ############################# +--echo # Cleanup +--echo ############################# + +--connection server_2 +source include/stop_slave.inc; +source include/start_slave.inc; + +--disable_query_log +--eval SET @@GLOBAL.rpl_semi_sync_slave_enabled = $sav_enabled_server_2 +--eval SET @@GLOBAL.debug_dbug= "$sav_server_2_dbug" +--enable_query_log + +--connection server_3 +source include/stop_slave.inc; +source include/start_slave.inc; + +--disable_query_log +--eval SET @@GLOBAL.rpl_semi_sync_slave_enabled = $sav_enabled_server_3 +--eval SET @@GLOBAL.debug_dbug= "$sav_server_3_dbug" +--enable_query_log + + +--connection server_1 +let $status_var= Rpl_semi_sync_master_clients; +let $status_var_value= 0; +source include/wait_for_status_var.inc; + +--disable_query_log +--eval SET @@GLOBAL.rpl_semi_sync_master_timeout= $sav_master_timeout +--eval SET @@GLOBAL.rpl_semi_sync_master_enabled= $sav_enabled_master +--eval SET @@GLOBAL.debug_dbug= "$sav_master_dbug" +--enable_query_log + +drop table t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_skip_repl.test b/mysql-test/suite/rpl/t/rpl_semi_sync_skip_repl.test new file mode 100644 index 00000000..587e1290 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_skip_repl.test @@ -0,0 +1,66 @@ +# MDEV-14721 Big transaction events get lost on semisync master when +# replicate_events_marked_for_skip=FILTER_ON_MASTER +# +# When events of a big transaction are binlogged offsetting over 2GB from +# the beginning of the log the semisync master's dump thread +# lost such events. +# The test verifies the fixes' correctness simulating the 2GB offset. + +source include/not_embedded.inc; +source include/have_innodb.inc; +source include/have_debug.inc; +source include/master-slave.inc; + +--connection master +# Suppress warnings that might be generated during the test +call mtr.add_suppression("Timeout waiting for reply of binlog"); + +--let $sav_enabled_master=`SELECT @@GLOBAL.rpl_semi_sync_master_enabled` +--let $sav_timeout_master=`SELECT @@GLOBAL.rpl_semi_sync_master_timeout` +SET @@GLOBAL.rpl_semi_sync_master_enabled = 1; +SET @@GLOBAL.rpl_semi_sync_master_timeout=100; + +--connection slave +--let $sav_skip_marked_slave=`SELECT @@GLOBAL.replicate_events_marked_for_skip` +--let $sav_enabled_slave=`SELECT @@GLOBAL.rpl_semi_sync_slave_enabled` +source include/stop_slave.inc; +SET @@GLOBAL.replicate_events_marked_for_skip=FILTER_ON_MASTER; +SET @@GLOBAL.rpl_semi_sync_slave_enabled = 1; +source include/start_slave.inc; + +--connection master +CREATE TABLE t1 (a INT) ENGINE=innodb; + +# Make the following events as if they offset over 2GB from the beginning of binlog +SET @saved_dbug = @@GLOBAL.debug_dbug; +SET @@GLOBAL.debug_dbug="d,dbug_master_binlog_over_2GB"; +SET @@SESSION.skip_replication=1; +INSERT INTO t1 SET a=1; +SET @@SESSION.skip_replication=0; +INSERT INTO t1 SET a=0; +SET @@GLOBAL.debug_dbug=""; + +# The current binlog is inconsistent so let's rotate it away +# to clean up simulation results. +FLUSH LOGS; + +--sync_slave_with_master + +# +# Clean up +# +--connection master +SET @@GLOBAL.debug_dbug = @saved_dbug; +--eval SET @@GLOBAL.rpl_semi_sync_master_timeout = $sav_timeout_master +--eval SET @@GLOBAL.rpl_semi_sync_master_enabled = $sav_enabled_master + +--connection master +DROP TABLE t1; + +--sync_slave_with_master +source include/stop_slave.inc; +--eval SET @@GLOBAL.rpl_semi_sync_slave_enabled = $sav_enabled_slave +--eval SET @@GLOBAL.replicate_events_marked_for_skip = $sav_skip_marked_slave + +source include/start_slave.inc; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_slave_compressed_protocol-slave.opt b/mysql-test/suite/rpl/t/rpl_semi_sync_slave_compressed_protocol-slave.opt new file mode 100644 index 00000000..a1b687d6 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_slave_compressed_protocol-slave.opt @@ -0,0 +1 @@ +--slave_compressed_protocol diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_slave_compressed_protocol.test b/mysql-test/suite/rpl/t/rpl_semi_sync_slave_compressed_protocol.test new file mode 100644 index 00000000..bc05bec2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_slave_compressed_protocol.test @@ -0,0 +1,55 @@ +################################################################################ +# Bug#26027024 SLAVE_COMPRESSED_PROTOCOL DOESN'T WORK WITH SEMI-SYNC +# REPLICATION IN MYSQL-5.7 +# +# Steps to reproduce: +# 1) Set slave_compressed_protocol ON on Slave. +# 2) Do some sample work on Master +# 3) After the work is synced on Slave, check that there is no error +# (Read semi-sync reply magic number error) on Slave. +# 4) Cleanup +################################################################################ +# Test is independent of Binlog format. One of the three formats is enough +# for testing. Choosing 'Row' format. +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +--let $sav_enabled_master=`SELECT @@GLOBAL.rpl_semi_sync_master_enabled ` +SET @@GLOBAL.rpl_semi_sync_master_enabled = 1; + +--connection slave +source include/stop_slave.inc; +--let $sav_enabled_slave=`SELECT @@GLOBAL.rpl_semi_sync_slave_enabled ` +SET @@GLOBAL.rpl_semi_sync_slave_enabled = 1; +source include/start_slave.inc; + +--connection master +# Do some sample work on Master with slave_compressed_protocol ON. +# (slave_compressed_protocol is set to ON in -slave.opt file of this test.) +CREATE TABLE t1 (i INT); +DROP TABLE t1; + +# Make sure sync is done, so that next 'assert' step can be executed without +# any issues. +--source include/rpl_sync.inc + +# Without the fix, the test would have generated few +# errors in the error log. With the fix, test will +# pass without any errors in the error log. +--let $assert_text= Check that there is no 'Read semi-sync reply magic number error' in error log. +--let $assert_select=Read semi-sync reply magic number error +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let $assert_count= 0 +--let $assert_only_after = CURRENT_TEST:rpl.rpl_semi_sync_slave_compressed_protocol.test +--source include/assert_grep.inc + +--connection master +--evalp SET @@GLOBAL. rpl_semi_sync_master_enabled = $sav_enabled_master + +--connection slave +source include/stop_slave.inc; +--evalp SET @@GLOBAL. rpl_semi_sync_slave_enabled = $sav_enabled_slave +source include/start_slave.inc; + +# Cleanup +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_slave_reply_fail.test b/mysql-test/suite/rpl/t/rpl_semi_sync_slave_reply_fail.test new file mode 100644 index 00000000..94853799 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_slave_reply_fail.test @@ -0,0 +1,97 @@ +# ==== Purpose ==== +# +# Test verifies that slave IO thread doesn't report an error, when slave fails +# to send an acknowledgment to master with semi sync replication in use. +# +# ==== Implementation ==== +# +# Steps: +# 0 - Have semi synchronous replication in use. +# 1 - Enable a debug simulation point which simulates network flush failure +# at the time of slave reply operation. +# 2 - Do some operation on master and wait for it to be replicated. Master +# will timeout waiting for reply from slave. +# 3 - Check the slave error log for appropriate error message regarding +# net_flush operation failure. +# 4 - Remove the debug simulation and do some more DML operations on master +# and wait for them to be replicated. +# 5 - Slave will be able to replicate and data is consistent on both master +# and slave. Semi sync will be automatically turned on. +# +# ==== References ==== +# +# MDEV-20217: Semi_sync: Last_IO_Error: Fatal error: Failed to run +# 'after_queue_event' hook +# +--source include/have_debug.inc +--source include/master-slave.inc + +--connection slave +--source include/stop_slave.inc + +--connection master +call mtr.add_suppression("Timeout waiting for reply of binlog*"); +--let $sav_timeout_master=`SELECT @@GLOBAL.rpl_semi_sync_master_timeout` +set global rpl_semi_sync_master_enabled = ON; +SET @@GLOBAL.rpl_semi_sync_master_timeout=100; +create table t1 (i int); + +--connection slave +set global rpl_semi_sync_slave_enabled = ON; +CALL mtr.add_suppression("Semi-sync slave net_flush*"); +SET @save_debug= @@global.debug; +SET GLOBAL debug_dbug="+d,semislave_failed_net_flush"; +--source include/start_slave.inc + +--connection master +--sync_slave_with_master + +# Check error log for correct messages. +let $log_error_= `SELECT @@GLOBAL.log_error`; +if(!$log_error_) +{ + # MySQL Server on windows is started with --console and thus + # does not know the location of its .err log, use default location + let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.2.err; +} +--echo "Assert that the net_fulsh() reply failed is present in slave error log. +--let SEARCH_FILE=$log_error_ +--let SEARCH_PATTERN=Semi-sync slave net_flush\(\) reply failed +--source include/search_pattern_in_file.inc + +--echo "Assert that Slave IO thread is up and running." +SHOW STATUS LIKE 'Slave_running'; +let $status= query_get_value("show slave status", Slave_IO_Running, 1); +echo Slave_IO_Running= $status; + +--echo "Clear the network failure simulation." +SET GLOBAL debug_dbug= @save_debug; + +--connection master +insert into t1 values (10); +--sync_slave_with_master + +--connection slave +--echo # Compare the tables on master and slave. +--let $diff_tables= master:t1, slave:t1 +--source include/diff_tables.inc + +--connection master +set statement sql_log_bin=0 for call mtr.add_suppression("Read semi-sync reply magic number error"); +SET @save_debug_master= @@global.debug; +SET GLOBAL debug_dbug="+d,semisync_corrupt_magic"; +insert into t1 values (11); + +--sync_slave_with_master + +--connection master +SET GLOBAL debug_dbug= @save_debug_master; + +drop table t1; +--sync_slave_with_master +set global rpl_semi_sync_slave_enabled = OFF; + +--connection master +set global rpl_semi_sync_master_enabled = OFF; +--eval SET @@GLOBAL.rpl_semi_sync_master_timeout = $sav_timeout_master +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_wait_no_slave-master.opt b/mysql-test/suite/rpl/t/rpl_semi_sync_wait_no_slave-master.opt new file mode 100644 index 00000000..d84ebab5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_wait_no_slave-master.opt @@ -0,0 +1 @@ +--rpl_semi_sync_master_enabled=0 --rpl_semi_sync_master_wait_no_slave=0 diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_wait_no_slave.test b/mysql-test/suite/rpl/t/rpl_semi_sync_wait_no_slave.test new file mode 100644 index 00000000..fecd0e25 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_wait_no_slave.test @@ -0,0 +1,14 @@ +# The test verifies master crash of MDEV-18096 when the server starts with +# rpl_semi_sync_master_enabled = OFF rpl_semi_sync_master_wait_no_slave = OFF + +--source include/master-slave.inc +--source include/have_binlog_format_mixed.inc + +--connection master +CREATE TABLE t1 (a INT); +INSERT INTO t1 SET a=1; +DROP TABLE t1; + +--sync_slave_with_master + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_wait_point.opt b/mysql-test/suite/rpl/t/rpl_semi_sync_wait_point.opt new file mode 100644 index 00000000..e49ae455 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_wait_point.opt @@ -0,0 +1 @@ +--log_bin diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_wait_point.test b/mysql-test/suite/rpl/t/rpl_semi_sync_wait_point.test new file mode 100644 index 00000000..5eae91a5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_wait_point.test @@ -0,0 +1,251 @@ +source include/not_embedded.inc; +source include/have_innodb.inc; + +# +# This test the rpl_semi_sync_master_wait_point functionality +# and illustrates the differences between the two values AFTER_COMMIT and +# AFTER_SYNC +# + +--echo # +--echo # Preparation +--echo # + +CREATE TABLE t1 (i INT NOT NULL, PRIMARY KEY (i)) ENGINE=InnoDB; +RESET MASTER; + +let $save_timeout = `select @@global.rpl_semi_sync_master_timeout`; +let $save_wait_no_slave = `select @@global.rpl_semi_sync_master_wait_no_slave`; +let $save_wait_point = `select @@global.rpl_semi_sync_master_wait_point`; + +SET @@global.rpl_semi_sync_master_timeout = 60000; +SET @@global.rpl_semi_sync_master_wait_no_slave = 1; + +--echo # It's okay to see "Killed" but we should not see "Timeout" in the log. +call mtr.add_suppression("Killed waiting for reply of binlog"); + +--echo # +--echo # Test wait point = AFTER_COMMIT +--echo # +SET @@global.rpl_semi_sync_master_wait_point = AFTER_COMMIT; + +--echo # Make another connection to INSERT from. +connect (other,localhost,root,,); +connection other; +let $other_connection_id = `SELECT CONNECTION_ID()`; + +connection default; + +--disable_query_log +eval SET @other_connection_id = $other_connection_id; +--enable_query_log + +SET GLOBAL rpl_semi_sync_master_enabled = 1; + +--echo # Go ahead and send the INSERT; it should block. +connection other; +send INSERT INTO t1 (i) VALUES (1); + +connection default; + +let $wait_condition = + SELECT COUNT(*) > 0 AS should_be_true + FROM information_schema.processlist + WHERE id = @other_connection_id + AND state = "Waiting for semi-sync ACK from slave"; +--source include/wait_condition.inc + +--echo # The INSERT thread should now be waiting. +SELECT state AS should_be_waiting +FROM information_schema.processlist WHERE id = @other_connection_id; + +--echo # The insert should be visible to other threads +SELECT * FROM t1 ORDER BY 1; + +--echo # Kill the waiting thread; it should die immediately. +KILL @other_connection_id; + +--echo # Collect the error from the INSERT thread; it should be disconnected. +connection other; +--error 2013,ER_CONNECTION_KILLED +reap; + +connection default; + +--echo # Wait for INSERT thread to actually disappear (KILL closes connection +--echo # before thread actually finishes its processing). +let $wait_condition = + SELECT COUNT(*) = 0 AS should_be_true + FROM information_schema.processlist + WHERE id = @other_connection_id; +--source include/wait_condition.inc + +--echo # The INSERT thread should now be gone. +SELECT state AS should_be_empty_set +FROM information_schema.processlist WHERE id = @other_connection_id; + +--echo # The insert is still there +SELECT * FROM t1 ORDER BY 1; + +connection default; +disconnect other; + +--echo # Make another connection to INSERT from. +connect (other,localhost,root,,); +connection other; +let $other_connection_id = `SELECT CONNECTION_ID()`; +connection default; +--disable_query_log +eval SET @other_connection_id = $other_connection_id; +--enable_query_log + +--echo # Go ahead and send the INSERT; it should block. +connection other; +send INSERT INTO t1 (i) VALUES (2); + +connection default; + +let $wait_condition = + SELECT COUNT(*) > 0 AS should_be_true + FROM information_schema.processlist + WHERE id = @other_connection_id + AND state = "Waiting for semi-sync ACK from slave"; +--source include/wait_condition.inc + +--echo # The INSERT thread should now be waiting. +SELECT state AS should_be_waiting +FROM information_schema.processlist WHERE id = @other_connection_id; + +--echo # The insert should be visible to other threads +SELECT * FROM t1 ORDER BY 1; + +--echo # Now restart server +--source include/restart_mysqld.inc +--echo # Done restarting server + +--echo # Reset setting that were lost in restart +SET @@global.rpl_semi_sync_master_timeout = 60000; +SET @@global.rpl_semi_sync_master_wait_no_slave = 1; + +--echo # Check that row is still there +SELECT * FROM t1 ORDER BY 1; + +disconnect other; + +--echo # +--echo # Test wait point = AFTER_SYNC +--echo # +SET @@global.rpl_semi_sync_master_wait_point = AFTER_SYNC; + +--echo # Make another connection to INSERT from. +connect (other,localhost,root,,); +connection other; +let $other_connection_id = `SELECT CONNECTION_ID()`; + +connection default; + +--disable_query_log +eval SET @other_connection_id = $other_connection_id; +--enable_query_log + +SET GLOBAL rpl_semi_sync_master_enabled = 1; + +--echo # Go ahead and send the INSERT; it should block. +connection other; +send INSERT INTO t1 (i) VALUES (3); + +connection default; + +let $wait_condition = + SELECT COUNT(*) > 0 AS should_be_true + FROM information_schema.processlist + WHERE id = @other_connection_id + AND state = "Waiting for semi-sync ACK from slave"; +--source include/wait_condition.inc + +--echo # The INSERT thread should now be waiting. +SELECT state AS should_be_waiting +FROM information_schema.processlist WHERE id = @other_connection_id; + +--echo # The insert should NOT be visible to other threads +SELECT * FROM t1 ORDER BY 1; + +--echo # Kill the waiting thread; it should die immediately. +KILL @other_connection_id; + +--echo # Collect the error from the INSERT thread; it should be disconnected. +connection other; +--error 2013,ER_CONNECTION_KILLED +reap; + +connection default; + +--echo # Wait for INSERT thread to actually disappear (KILL closes connection +--echo # before thread actually finishes its processing). +let $wait_condition = + SELECT COUNT(*) = 0 AS should_be_true + FROM information_schema.processlist + WHERE id = @other_connection_id; +--source include/wait_condition.inc + +--echo # The INSERT thread should now be gone. +SELECT state AS should_be_empty_set +FROM information_schema.processlist WHERE id = @other_connection_id; + +--echo # The row inserted is there +SELECT * FROM t1 ORDER BY 1; + +connection default; +disconnect other; + +--echo # Make another connection to INSERT from. +connect (other,localhost,root,,); +connection other; +let $other_connection_id = `SELECT CONNECTION_ID()`; +connection default; +--disable_query_log +eval SET @other_connection_id = $other_connection_id; +--enable_query_log + +--echo # Go ahead and send the INSERT; it should block. +connection other; +send INSERT INTO t1 (i) VALUES (4); + +connection default; + +let $wait_condition = + SELECT COUNT(*) > 0 AS should_be_true + FROM information_schema.processlist + WHERE id = @other_connection_id + AND state = "Waiting for semi-sync ACK from slave"; +--source include/wait_condition.inc + +--echo # The INSERT thread should now be waiting. +SELECT state AS should_be_waiting +FROM information_schema.processlist WHERE id = @other_connection_id; + +--echo # The insert should NOT be visible to other threads +SELECT * FROM t1 ORDER BY 1; + +--echo # Now restart server +--source include/restart_mysqld.inc +--echo # Done restarting server + +--echo # Reset setting that were lost in restart +SET @@global.rpl_semi_sync_master_timeout = 60000; +SET @@global.rpl_semi_sync_master_wait_no_slave = 1; + +--echo # But the row inserted is there +SELECT * FROM t1 ORDER BY 1; + +disconnect other; + +--echo # +--echo # Cleanup +--echo # +SET GLOBAL rpl_semi_sync_master_enabled = 0; +DROP TABLE t1; + +eval SET @@global.rpl_semi_sync_master_timeout = $save_timeout; +eval SET @@global.rpl_semi_sync_master_wait_no_slave = $save_wait_no_slave; +eval SET @@global.rpl_semi_sync_master_wait_point = $save_wait_point; diff --git a/mysql-test/suite/rpl/t/rpl_semisync_ali_issues-master.opt b/mysql-test/suite/rpl/t/rpl_semisync_ali_issues-master.opt new file mode 100644 index 00000000..2672d4ff --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semisync_ali_issues-master.opt @@ -0,0 +1 @@ +--binlog_format=row diff --git a/mysql-test/suite/rpl/t/rpl_semisync_ali_issues-slave.opt b/mysql-test/suite/rpl/t/rpl_semisync_ali_issues-slave.opt new file mode 100644 index 00000000..2672d4ff --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semisync_ali_issues-slave.opt @@ -0,0 +1 @@ +--binlog_format=row diff --git a/mysql-test/suite/rpl/t/rpl_semisync_ali_issues.test b/mysql-test/suite/rpl/t/rpl_semisync_ali_issues.test new file mode 100644 index 00000000..5e6f350b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semisync_ali_issues.test @@ -0,0 +1,429 @@ +--source include/have_innodb.inc +--source include/have_debug_sync.inc +--source include/master-slave.inc + +CALL mtr.add_suppression("Failed to start semi-sync ACK receiver thread.*"); +CALL mtr.add_suppression("Failed to register slave to semi-sync ACK receiver thread.*"); +CALL mtr.add_suppression("Failed to stop ack receiver thread on pthread_join.*"); +CALL mtr.add_suppression("Got an error reading communication packets:*"); +CALL mtr.add_suppression("Timeout waiting for reply of binlog*"); +CALL mtr.add_suppression("slave_read_sync_header*"); +CALL mtr.add_suppression("Missing magic number for semi-sync*"); +CALL mtr.add_suppression("Got timeout reading communication packets*"); +CALL mtr.add_suppression("Failed to call*"); +CALL mtr.add_suppression("Execution failed on master*"); +CALL mtr.add_suppression("Failed on request_dump()*"); +CALL mtr.add_suppression("Semi-sync master failed on*"); +CALL mtr.add_suppression("Master command COM_BINLOG_DUMP failed*"); +CALL mtr.add_suppression("on master failed*"); +CALL mtr.add_suppression("Master server does not support semi-sync*"); +CALL mtr.add_suppression("Semi-sync slave net_flush*"); +CALL mtr.add_suppression("Failed to flush master info*"); +CALL mtr.add_suppression("Request to stop slave SQL Thread received while apply*"); + +connection master; +echo [ enable semi-sync on master ]; +set global rpl_semi_sync_master_enabled = 1; +show variables like 'rpl_semi_sync_master_enabled'; + +connection slave; +echo [ enable semi-sync on slave ]; +stop slave; +set global rpl_semi_sync_slave_enabled = 1; +start slave; +let $status_var= rpl_semi_sync_slave_status; +let $status_var_value= ON; +source include/wait_for_status_var.inc; +show status like 'rpl_semi_sync_slave%'; + + +connection master; +CREATE TABLE t1(a INT) ENGINE=InnoDB; +sync_slave_with_master; + +connection master; +connect(con1,localhost,root,,); +connect(con2,localhost,root,,); +connect(con3,localhost,root,,); + +show status like 'Rpl_semi_sync_master_clients'; +show status like "rpl_semi_sync_master_yes_tx"; + +--echo ######################################### +--echo # Test rpl_semi_sync_master_wait_point # +--echo ######################################### +--echo # Test after_sync and after_commit first. + +--echo #Test after_sync +connection con1; +# Let's set a very large timeout value for testing purpose. +SET GLOBAL rpl_semi_sync_master_timeout = 1000000; +SET GLOBAL rpl_semi_sync_master_wait_point= 'AFTER_SYNC'; +SET DEBUG_SYNC= "commit_before_get_LOCK_commit_ordered SIGNAL after_sync_done WAIT_FOR end"; +--send INSERT into t1 values (1); + +connection con2; +SET DEBUG_SYNC= "now WAIT_FOR after_sync_done"; + +sync_slave_with_master; +--echo #slave can see record (1) after sync slave with master +select * from t1; + +connection con2; +--echo #con2 shouldn't see record (1) +select * from t1; +SET DEBUG_SYNC= "now SIGNAL end"; + +connection con1; +reap; + +connection con1; +select * from t1; +truncate table t1; + +# MDEV-515 takes X-lock on the table +# So concurrent DML won't happen on the table +INSERT INTO t1 VALUES (100); + +sync_slave_with_master; + +# Test more threads in one semisync queue +connection con1; +SET DEBUG_SYNC= 'reset'; +SET DEBUG_SYNC= "commit_before_get_LOCK_log SIGNAL before_fetch_done WAIT_FOR more_queue"; +#SET DEBUG_SYNC= "before_semisync_fetch SIGNAL before_fetch_done WAIT_FOR more_queue"; +--send INSERT into t1 VALUES (1); + +connection con2; +SET DEBUG_SYNC= "now WAIT_FOR before_fetch_done"; +SET DEBUG_SYNC= "after_semisync_queue SIGNAL more_queue"; +INSERT INTO t1 VALUES (2); + +connection con1; +reap; + +# Test more threads in one semisync queue, but disable semisync before +# waiting. +connection con1; +SET DEBUG_SYNC= 'reset'; +SET DEBUG_SYNC= "commit_before_get_LOCK_log SIGNAL before_fetch_done WAIT_FOR disable_semisync"; +#SET DEBUG_SYNC= "before_semisync_fetch SIGNAL before_fetch_done WAIT_FOR more_queue"; +#SET DEBUG_SYNC= "before_semisync_fetch SIGNAL before_fetch_done WAIT_FOR disable_semisync"; +--send INSERT into t1 VALUES (3); + +connection con2; +SET DEBUG_SYNC= "now WAIT_FOR before_fetch_done"; +SET GLOBAL rpl_semi_sync_master_enabled= 0; +SET DEBUG_SYNC= "now SIGNAL disable_semisync"; + +connection con1; +reap; +SET GLOBAL rpl_semi_sync_master_enabled = 1; +show status like 'Rpl_semi_sync_master_clients'; + +--echo #Test after_commit +connection con1; +SET GLOBAL rpl_semi_sync_master_wait_point= 'AFTER_COMMIT'; +SET DEBUG_SYNC= "after_group_after_commit SIGNAL after_commit_done WAIT_FOR end"; +--send INSERT into t1 values (4); + +connection con2; +SET DEBUG_SYNC= "now WAIT_FOR after_commit_done"; + +sync_slave_with_master; +select * from t1; + +connection con2; +select * from t1; +SET DEBUG_SYNC= "now SIGNAL end"; + +connection con1; +reap; + +connection con1; +select * from t1; +truncate table t1; + +--echo ####################################################### +--echo # Test some other options in order to cover the patch # +--echo ####################################################### +connection slave; +--echo # Test rpl_semi_sync_slave_trace_level +SET GLOBAL rpl_semi_sync_slave_trace_level= 1; +SET GLOBAL rpl_semi_sync_slave_trace_level= 16; +SET GLOBAL rpl_semi_sync_slave_trace_level= 64; +SET GLOBAL rpl_semi_sync_slave_trace_level= 128; +SET GLOBAL rpl_semi_sync_slave_trace_level= 32; +connection master; +--echo # Test rpl_semi_sync_master_trace_level +SET GLOBAL rpl_semi_sync_master_trace_level= 1; +SET GLOBAL rpl_semi_sync_master_trace_level= 16; +SET GLOBAL rpl_semi_sync_master_trace_level= 64; +SET GLOBAL rpl_semi_sync_master_trace_level= 128; +SET GLOBAL rpl_semi_sync_master_trace_level= 32; +--echo # Test rpl_semi_sync_master_timeout +SET GLOBAL rpl_semi_sync_master_timeout= 1000; +SET GLOBAL rpl_semi_sync_master_timeout= 10000; +SET GLOBAL rpl_semi_sync_master_timeout = 1000000; + +--echo # Test rpl_semi_sync_slave_kill_conn_timeout +SET GLOBAL rpl_semi_sync_slave_kill_conn_timeout= 10; +SET GLOBAL rpl_semi_sync_slave_kill_conn_timeout= 20; +SET GLOBAL rpl_semi_sync_slave_kill_conn_timeout= 60; +SET GLOBAL rpl_semi_sync_slave_kill_conn_timeout= 5; + +--echo ############################################ +--echo # Test rpl_semi_sync_master_wait_no_slave # +--echo ############################################ +SET GLOBAL rpl_semi_sync_master_wait_no_slave = 1; +connection slave; +STOP SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_stop.inc + +connection con1; +SET GLOBAL rpl_semi_sync_master_timeout = 1000; +--send INSERT INTO t1 values (1); + +connection con1; +reap; +echo # Rpl_semi_sync_master_no_tx should be non-zero +SHOW STATUS LIKE 'Rpl_semi_sync_master_no_tx'; + +# test rpl_semi_sync_master_wait_no_slave = 0 +connection slave; +START SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_start.inc + +connection con1; +INSERT INTO t1 values (2); +sync_slave_with_master; +connection con1; +let $status_var= Rpl_semi_sync_master_clients; +let $status_var_value= 1; +source include/wait_for_status_var.inc; +let $status_var= Rpl_semi_sync_master_status; +let $status_var_value= ON; +source include/wait_for_status_var.inc; +show status like 'Rpl_semi_sync_master_clients'; +show status like 'Rpl_semi_sync_master_status'; + +connection slave; +STOP SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_stop.inc + +connection con1; +SET GLOBAL rpl_semi_sync_master_wait_no_slave= 0; +SET GLOBAL rpl_semi_sync_master_timeout= 1000000000; +INSERT INTO t1 values (3); +show status like 'Rpl_semi_sync_master_clients'; +show status like 'Rpl_semi_sync_master_status'; + + +connection slave; +START SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_start.inc + +connection con1; +--let $status_var= Rpl_semi_sync_master_status +--let $status_var_value=ON +--source include/wait_for_status_var.inc + +SET GLOBAL rpl_semi_sync_master_timeout= 10000000; +SET GLOBAL rpl_semi_sync_master_wait_no_slave= 1; +INSERT INTO t1 values (4); +sync_slave_with_master; + +connection con1; +show status like 'Rpl_semi_sync_master_status'; +show status like 'Rpl_semi_sync_master_clients'; + +--echo ########################################## +--echo # Test rpl_semi_sync_slave_delay_master # +--echo ########################################## + +connection slave; +SET GLOBAL rpl_semi_sync_slave_delay_master= 1; +START SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_start.inc + +connection con1; +INSERT INTO t1 values (3); +--source include/sync_slave_io_with_master.inc + +connection con1; +show status like 'Rpl_semi_sync_master_clients'; +show status like 'Rpl_semi_sync_master_status'; + +sync_slave_with_master; + +connection slave; +select * from t1 order by a; +connection con1; +select * from t1 order by a; + +connection slave; +SET GLOBAL rpl_semi_sync_slave_delay_master = 0; +STOP SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_stop.inc +START SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_start.inc + +--echo ########################################################## +--echo # Test rpl_semi_sync_master_enabled and new ACK thread # +--echo ######################################################### +connection con1; +SET GLOBAL rpl_semi_sync_master_enabled = 0; + +let $status_var= Rpl_semi_sync_master_clients; +let $status_var_value= 1; +source include/wait_for_status_var.inc; +show status like 'Rpl_semi_sync_master_clients'; + +INSERT INTO t1 VALUES (1); +SET GLOBAL rpl_semi_sync_master_enabled = 1; +INSERT INTO t1 VALUES (2); +show status like 'Rpl_semi_sync_master_clients'; + +--echo # Test failure of select error . +SET GLOBAL debug = 'd,rpl_semisync_simulate_select_error'; +# It can still receive ACK from semi-sync slave +INSERT INTO t1 VALUES(3); +sync_slave_with_master; + +connection con1; +--echo # Test failure of pthread_create +SET GLOBAL rpl_semi_sync_master_enabled = 0; +SET GLOBAL debug = 'd,rpl_semisync_simulate_create_thread_failure'; +SET GLOBAL rpl_semi_sync_master_enabled= ON; + +--let $wait_condition= SELECT @@global.rpl_semi_sync_master_enabled = 0 +--source include/wait_condition.inc + +# Todo: implement the thread join failure simulation +--echo # Test failure of pthread_join +#SET GLOBAL DEBUG = 'd,rpl_semisync_simulate_thread_join_failure'; +#SET GLOBAL rpl_semi_sync_master_enabled= ON; +# +#--let $wait_condition= SELECT @@global.rpl_semi_sync_master_enabled = 0 +#--source include/wait_condition.inc +SET GLOBAL rpl_semi_sync_master_enabled= OFF; + +--echo # +--echo # Failure on registering semisync slave +--echo # +SET GLOBAL debug= 'd,rpl_semisync_simulate_add_slave_failure'; +SET GLOBAL rpl_semi_sync_master_enabled= ON; + +connection slave; +STOP SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_stop.inc +START SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_start.inc + +connection con1; +#--echo # Should be Zero. +# Todo: implement the add_slave_failure simulation. Meanwhile +# the status will be 1. +# show status like 'Rpl_semi_sync_master_clients'; +SET GLOBAL debug=''; + +--let $status_var= Rpl_semi_sync_master_clients +--let $status_var_value= 1 +--let $status_type= GLOBAL +--source include/wait_for_status_var.inc + +connection slave; +--disable_warnings +START SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_start.inc +--enable_warnings + +connection con1; +sync_slave_with_master; + +show status like 'Rpl_semi_sync_master_clients'; + +--echo ################################################################## +--echo # Test fixing of BUG#70669 # +--echo #SLAVE CAN'T CONTINUE REPLICATION AFTER MASTER'S CRASH RECOVERY # +--echo ################################################################# +connection con1; +SET GLOBAL sync_binlog = 1; +CREATE TABLE t2 (c1 INT); +sync_slave_with_master; + +connection con1; +# Block the session before its events are synced to disk +#SET DEBUG_SYNC = 'before_sync_binlog_file SIGNAL before_sync_done WAIT_FOR continue'; +send INSERT INTO t2 values (1); + +connection slave; +--let $table= t2 +--let $count= 1 +--source include/wait_until_rows_count.inc + +connection con2; +#SET DEBUG_SYNC= "now WAIT_FOR before_sync_done"; +#SET DEBUG_SYNC = "now SIGNAL continue"; + +connection con1; +reap; + +sync_slave_with_master; +show tables like 't2'; +select * from t2; + +connection con1; +#SET DEBUG_SYNC= "before_update_pos SIGNAL leader_ready WAIT_FOR follower_ready"; +send INSERT INTO t2 VALUES (2); + +connection con2; +#SET DEBUG_SYNC= "now WAIT_FOR leader_ready"; +#SET DEBUG_SYNC= "after_sync_queue SIGNAL follower_ready"; +send INSERT INTO t2 VALUES (3); + +connection con1; +reap; +connection con2; +reap; + +connection con1; +#SET DEBUG_SYNC = 'before_sync_binlog_file SIGNAL before_sync_done WAIT_FOR continue'; +SET GLOBAL sync_binlog = 0; + +# Todo: fix this simulation and implement the intended sync protocol. +# As a workaround the DROP sender explicitly okays +# which naturally increments the binlog position. +#send DROP TABLE t2; +DROP TABLE t2; + +connection con2; +#SET DEBUG_SYNC= "now WAIT_FOR before_sync_done"; + +sync_slave_with_master; + +# t2 should be dropped +show tables like 't2'; + +connection con2; +#SET DEBUG_SYNC = "now SIGNAL continue"; + +# This block is commented out on purpose. See the todo/workaround above. +#connection con1; +#reap; + + +--echo #cleanup +connection master; +SET DEBUG_SYNC= 'reset'; +disconnect con1; +disconnect con2; +disconnect con3; +SET GLOBAL rpl_semi_sync_master_timeout= 10000; +SET GLOBAL rpl_semi_sync_master_enabled = 0; +DROP TABLE t1; +connection slave; +SET GLOBAL rpl_semi_sync_slave_enabled = 0; +stop slave;start slave; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_server_id1.test b/mysql-test/suite/rpl/t/rpl_server_id1.test new file mode 100644 index 00000000..90198a4a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_server_id1.test @@ -0,0 +1,22 @@ +# This test checks that the slave I/O thread refuses to start if slave +# and master have the same server id (because this is a useless setup, +# and otherwise SHOW SLAVE STATUS shows progress but all queries are +# ignored, which has caught our customers), unless +# --replicate-same-server-id. + +--let $rpl_topology= 2->2 +--let $rpl_skip_start_slave= 1 +--source include/rpl_init.inc + +--connection server_2 +START SLAVE; +# 1593 = ER_SLAVE_FATAL_ERROR +--let $slave_io_errno= 1593 +--let $show_slave_io_error= 1 +--source include/wait_for_slave_io_error.inc + +--source include/stop_slave_sql.inc +RESET SLAVE; + +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_server_id2-slave.opt b/mysql-test/suite/rpl/t/rpl_server_id2-slave.opt new file mode 100644 index 00000000..30288952 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_server_id2-slave.opt @@ -0,0 +1 @@ +--disable-log-slave-updates --replicate-same-server-id diff --git a/mysql-test/suite/rpl/t/rpl_server_id2.test b/mysql-test/suite/rpl/t/rpl_server_id2.test new file mode 100644 index 00000000..6dc2f791 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_server_id2.test @@ -0,0 +1,72 @@ +# This test checks that a slave DOES execute queries originating +# from itself, if running with --replicate-same-server-id. + +source include/master-slave.inc; + +connection slave; +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=NO; +--source include/start_slave.inc + +create table t1 (n int); +reset master; +# replicate ourselves +stop slave; +--source include/wait_for_slave_to_stop.inc +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval change master to master_port=$SLAVE_MYPORT; +start slave; +--source include/wait_for_slave_to_start.inc +insert into t1 values (1); +save_master_pos; +sync_with_master; +select * from t1; # check that indeed 2 were inserted +# We stop the slave before cleaning up otherwise we'll get +# 'drop table t1' executed twice, so an error in the slave.err +# (not critical). +stop slave; +--source include/wait_for_slave_to_stop.inc +drop table t1; + + +# +# Bug#38934 slave slave until does not work with --replicate-same-server-id +# +# Verifying that slave performs all events until the master_log_pos +# in presense of --replicate-same-server-id the slave is started with. + +connection master; +reset master; + +# setting the until position to correspond to the last position of +# create table which will make the event executed and the slave sql +# thread stopped right after that. + +create table t1(n int); +let $until_pos= query_get_value(SHOW MASTER STATUS, Position, 1); +dec $until_pos; +create table t2(n int); + +connection slave; +--replace_result $MASTER_MYPORT MASTER_PORT +eval change master to master_port=$MASTER_MYPORT; +--replace_result $until_pos UNTIL_POS +eval start slave until master_log_file='master-bin.000001', master_log_pos=$until_pos; +--source include/wait_for_slave_io_to_start.inc +--source include/wait_for_slave_sql_to_stop.inc + +--echo *** checking until position execution: must be only t1 in the list *** +show tables; + +# cleanup + +connection slave; +start slave sql_thread; + +connection master; +drop table t1; +drop table t2; +sync_slave_with_master; + +# End of tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_server_id_ignore-slave.opt b/mysql-test/suite/rpl/t/rpl_server_id_ignore-slave.opt new file mode 100644 index 00000000..30288952 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_server_id_ignore-slave.opt @@ -0,0 +1 @@ +--disable-log-slave-updates --replicate-same-server-id diff --git a/mysql-test/suite/rpl/t/rpl_server_id_ignore.test b/mysql-test/suite/rpl/t/rpl_server_id_ignore.test new file mode 100644 index 00000000..dbe7544b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_server_id_ignore.test @@ -0,0 +1,116 @@ +# This test checks that the slave rejects events originating +# by a server from the list of ignored originators (bug#27808 etc) +# +# phases of tests: +# +# 0. master_id new line in show slave status +# 1. syntax related: +# a. error reporting if options clash; +# b. overriding the old IGNORE_SERVER_IDS setup by the following +# CHANGE MASTER ... IGNORE_SERVER_IDS= (list); +# c. the old setup preserving by CHANGE MASTER w/o IGNORE_SERVER_IDS +# d. resetting the ignored server ids with the empty list arg to +# IGNORE_SERVER_IDS=() +# e. RESET SLAVE preserves the list +# 2. run time related: +# a. observing no processing events from a master listed in IGNORE_SERVER_IDS +# b. nullifying the list and resuming of taking binlog from the very beginning with +# executing events this time + +source include/have_binlog_format_mixed.inc; +source include/master-slave.inc; + +connection slave; + +# a new line for master_id +let $master_id= query_get_value(SHOW SLAVE STATUS, Master_Server_Id, 1); +echo master_id: $master_id; + +stop slave; +--echo *** --replicate-same-server-id and change master option can clash *** +--error ER_SLAVE_IGNORE_SERVER_IDS +change master to IGNORE_SERVER_IDS= (2, 1); +--echo *** must be empty due to the error *** +let $ignore_list= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Server_Ids, 1); +echo ignore server id list: $ignore_list; + +change master to IGNORE_SERVER_IDS= (10, 100); +--echo *** must be 10, 100 *** +let $ignore_list= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Server_Ids, 1); +echo ignore server id list: $ignore_list; +--source include/reset_slave.inc +--echo *** must be empty due to reset slave *** +let $ignore_list= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Server_Ids, 1); +echo ignore server id list: $ignore_list; +change master to IGNORE_SERVER_IDS= (10, 100); +--echo *** CHANGE MASTER with IGNORE_SERVER_IDS option overrides (does not increment) the previous setup *** +change master to IGNORE_SERVER_IDS= (5, 1, 4, 3, 1); +--echo *** must be 1, 3, 4, 5 due to overriding policy *** +let $ignore_list= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Server_Ids, 1); +echo ignore server id list: $ignore_list; +--echo *** ignore master (server 1) queries for a while *** +start slave; + +connection master; + +#connection slave; +sync_slave_with_master; +let $slave_relay_pos0= query_get_value(SHOW SLAVE STATUS, Relay_Log_Pos, 1); + +connection master; +create table t1 (n int); +let $master_binlog_end= query_get_value(SHOW MASTER STATUS, Position, 1); + +connection slave; +let $slave_param= Exec_Master_Log_Pos; +let $slave_param_value= $master_binlog_end; +source include/wait_for_slave_param.inc; +--echo *** must be empty as the event is to be filtered out *** +show tables; +--echo *** allowing events from master *** +let $slave_relay_pos1= query_get_value(SHOW SLAVE STATUS, Relay_Log_Pos, 1); +# +# checking stability of relay log pos +# +if (`select $slave_relay_pos1 - $slave_relay_pos0`) +{ + --echo Error: relay log position changed: $slave_relay_pos0, $slave_relay_pos1 + query_vertical show slave status; +} + +stop slave; +source include/wait_for_slave_to_stop.inc; +--source include/reset_slave.inc +change master to IGNORE_SERVER_IDS= (10, 100); +--echo *** the list must remain (10, 100) after reset slave *** +let $ignore_list= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Server_Ids, 1); + +change master to IGNORE_SERVER_IDS= (); +--echo *** must be empty due to IGNORE_SERVER_IDS empty list *** +let $ignore_list= query_get_value(SHOW SLAVE STATUS, Replicate_Ignore_Server_Ids, 1); +echo ignore server id list: $ignore_list; +--replace_result $MASTER_MYPORT MASTER_PORT +eval change master to master_host='127.0.0.1', master_port=$MASTER_MYPORT, master_user='root'; +start slave; + +connection master; + +#connection slave; +sync_slave_with_master; +--echo *** must have caught create table *** +show tables; + +# cleanup +connection master; +drop table t1; +#connection slave +sync_slave_with_master; + +--echo end of the tests + + + + + + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_session_var.test b/mysql-test/suite/rpl/t/rpl_session_var.test new file mode 100644 index 00000000..cf3faa65 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_session_var.test @@ -0,0 +1,61 @@ +# Replication of session variables. +# FOREIGN_KEY_CHECKS is tested in rpl_insert_id.test + +source include/master-slave.inc; + +disable_query_log; +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); +enable_query_log; + +drop table if exists t1; +create table t1(a varchar(100),b int); +set @@session.sql_mode=pipes_as_concat; +insert into t1 values('My'||'SQL', 1); +set @@session.sql_mode=default; +insert into t1 values('1'||'2', 2); +select * from t1 where b<3 order by a; +sync_slave_with_master; +select * from t1 where b<3 order by a; +connection master; +# if the slave does the next sync_with_master fine, then it means it accepts the +# two lines of ANSI syntax below, which is what we want to check. +set @@session.sql_mode=ignore_space; +insert into t1 values(password ('MySQL'), 3); +set @@session.sql_mode=ansi_quotes; +create table "t2" ("a" int); +drop table t1, t2; +set @@session.sql_mode=default; +create table t1(a int auto_increment primary key); +create table t2(b int, a int); +set @@session.sql_auto_is_null=1; +insert into t1 values(null); +insert into t2 select 1,a from t1 where a is null; +set @@session.sql_auto_is_null=0; +insert into t1 values(null); +insert into t2 select 2,a from t1 where a is null; +select * from t2 order by b; +sync_slave_with_master; +select * from t2 order by b; +connection master; +drop table t1,t2; +sync_slave_with_master; + +# +# Bug #29878 Garbage data generation when executing SESSION_USER() on a slave. +# + +connection master; +CREATE TABLE t1 ( + `id` int(11) NOT NULL auto_increment, + `data` varchar(100), + PRIMARY KEY (`id`) + ) ENGINE=MyISAM; +--disable_warnings +INSERT INTO t1(data) VALUES(SESSION_USER()); +--enable_warnings +sync_slave_with_master; +SELECT length(data) < 100 FROM t1; +connection master; +drop table t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_set_charset.test b/mysql-test/suite/rpl/t/rpl_set_charset.test new file mode 100644 index 00000000..72b89a13 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_set_charset.test @@ -0,0 +1,30 @@ +source include/master-slave.inc; +--disable_warnings +drop database if exists mysqltest1; +# 4.1 bases its conversion on the db's charset, +# while 4.0 uses the part of "SET CHARACTER SET" after "_". +# So for 4.1 we add a clause to CREATE DATABASE. +create database mysqltest1 /*!40100 character set latin2 */; +use mysqltest1; +drop table if exists t1; +--enable_warnings +create table t1 (a varchar(255) character set latin2, b varchar(4)); +SET CHARACTER SET cp1250_latin2; +INSERT INTO t1 VALUES ('ŠŒŽ','80'); +INSERT INTO t1 VALUES ('šœžŸ','90'); +INSERT INTO t1 VALUES ('£¥ª¯','A0'); +INSERT INTO t1 VALUES ('³¹º¼¾¿','B0'); +INSERT INTO t1 VALUES ('ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ','C0'); +INSERT INTO t1 VALUES ('ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß','D0'); +INSERT INTO t1 VALUES ('àáâãäåæçèéêëìíîï','E0'); +INSERT INTO t1 VALUES ('ðñòóôõö÷øùúûüýþÿ','F0'); +select hex(a),b from t1 order by b; +sync_slave_with_master; +use mysqltest1; +select hex(a),b from t1 order by b; +connection master; +drop database mysqltest1; +sync_slave_with_master; + +# End of 4.1 tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_set_null_innodb.test b/mysql-test/suite/rpl/t/rpl_set_null_innodb.test new file mode 100644 index 00000000..84f7adb3 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_set_null_innodb.test @@ -0,0 +1,7 @@ +-- source include/have_binlog_format_mixed_or_row.inc +-- source include/have_innodb.inc +-- source include/master-slave.inc + +-- let $engine= InnoDB +-- source include/rpl_set_null.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_set_null_myisam.test b/mysql-test/suite/rpl/t/rpl_set_null_myisam.test new file mode 100644 index 00000000..db1bd4b7 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_set_null_myisam.test @@ -0,0 +1,6 @@ +-- source include/have_binlog_format_mixed_or_row.inc +-- source include/master-slave.inc + +-- let $engine= MyISAM +-- source include/rpl_set_null.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_set_statement.test b/mysql-test/suite/rpl/t/rpl_set_statement.test new file mode 100644 index 00000000..5bc54e44 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_set_statement.test @@ -0,0 +1,61 @@ +--source include/master-slave.inc +--source include/have_binlog_format_statement.inc +set sql_mode=""; +connection slave; +set sql_mode=""; +connection master; + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +--enable_warnings + +call mtr.add_suppression("Unsafe statement written to the binary log*"); +CREATE TABLE t1 (a bigint unsigned not null); +CREATE TABLE t2 (a char(255) not null); + +--echo +--echo There are the following types of variables: +--echo 1) variables that are NOT replicated correctly when using STATEMENT mode; +--echo + +--let $rpl_ssvt_var_name=max_join_size +--let $rpl_ssvt_var_value=2 +--let $rpl_ssvt_table=t1 +--source suite/rpl/include/rpl_set_statement.inc + +--echo +--echo 2) variables thar ARE replicated correctly +--echo They must be replicated correctly with "SET STATEMENT" too. +--echo +--let $rpl_ssvt_var_name=auto_increment_increment +--let $rpl_ssvt_var_value=10 +--let $rpl_ssvt_table=t1 +--source suite/rpl/include/rpl_set_statement.inc + +--echo +--echo 3) sql_mode which is replicated correctly exept NO_DIR_IN_CREATE value; +--echo +--let $rpl_ssvt_var_name=sql_mode +--let $rpl_ssvt_var_value='ERROR_FOR_DIVISION_BY_ZERO' +--let $rpl_ssvt_table=t2 +--source suite/rpl/include/rpl_set_statement.inc +--let $rpl_ssvt_var_name=sql_mode +--let $rpl_ssvt_var_value='NO_DIR_IN_CREATE' +--let $rpl_ssvt_table=t2 +--source suite/rpl/include/rpl_set_statement.inc + +--echo +--echo 4) variables that are not replicated at all: +--echo default_storage_engine, storage_engine, max_heap_table_size +--echo +--let $rpl_ssvt_var_name=max_heap_table_size +--let $rpl_ssvt_var_value=16384 +--let $rpl_ssvt_table=t1 +--source suite/rpl/include/rpl_set_statement.inc + +connection master; +DROP TABLE t1; +DROP TABLE t2; +sync_slave_with_master; +source include/stop_slave.inc; diff --git a/mysql-test/suite/rpl/t/rpl_set_statement_default_master.test b/mysql-test/suite/rpl/t/rpl_set_statement_default_master.test new file mode 100644 index 00000000..106cb454 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_set_statement_default_master.test @@ -0,0 +1,34 @@ +--source include/master-slave.inc + +--connection slave + +--source include/stop_slave.inc +RESET SLAVE ALL; + +--echo # Does not work for CHANGE MASTER: +--replace_result $MASTER_MYPORT MASTER_MYPORT +eval SET STATEMENT default_master_connection = 'm1' FOR + CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root'; + + +--echo # +--echo # The first field, Connection_name, should say 'm1'... +--echo # +--let $status_items= Connection_name +--source include/show_all_slaves_status.inc +#query_vertical SHOW ALL SLAVES STATUS; + + +RESET SLAVE ALL; + +--replace_result $MASTER_MYPORT MASTER_MYPORT +eval CHANGE MASTER 'm1' TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root'; +SET STATEMENT default_master_connection = 'm1' FOR START SLAVE; + +set default_master_connection = 'm1'; +stop slave; +--source include/wait_for_slave_to_stop.inc +reset slave all; +set default_master_connection = ''; +--disconnect slave +--connection default diff --git a/mysql-test/suite/rpl/t/rpl_show_slave_hosts.cnf b/mysql-test/suite/rpl/t/rpl_show_slave_hosts.cnf new file mode 100644 index 00000000..288f0132 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_show_slave_hosts.cnf @@ -0,0 +1,20 @@ +!include ../my.cnf + +[mysqld.1] +server_id=1 + +[mysqld.2] +server_id=2 +report-host= +report-user= + +[mysqld.3] +server_id=3 +report-host=slave2 +slave-net-timeout=5 + +[ENV] +SLAVE_MYPORT2= @mysqld.3.port +SLAVE_MYSOCK2= @mysqld.3.socket + + diff --git a/mysql-test/suite/rpl/t/rpl_show_slave_hosts.test b/mysql-test/suite/rpl/t/rpl_show_slave_hosts.test new file mode 100644 index 00000000..84c5c215 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_show_slave_hosts.test @@ -0,0 +1,52 @@ +############################################################################### +# Bug#13963 SHOW SLAVE HOSTS is unreliable +# +# Slaves only appear in the output of SHOW SLAVE HOSTS when report-host option +# is set. If an expected slave does not appear in the list, nobody knows +# whether the slave does not connect or has started without the "report-host" +# option. +# +# Remove the "Rpl_recovery_rank" column from SHOW SLAVE HOSTS, It is not +# implemented. +####################################################################### +source include/master-slave.inc; +connect (slave2,127.0.0.1,root,,test,$SLAVE_MYPORT2,); + +connection slave2; +RESET SLAVE; +--replace_result $MASTER_MYPORT MASTER_PORT +--eval CHANGE MASTER TO master_host='127.0.0.1',master_port=$MASTER_MYPORT,master_user='root' +START SLAVE IO_THREAD; +source include/wait_for_slave_io_to_start.inc; + +connection master; +let $show_statement= SHOW SLAVE HOSTS; +let $field= Server_id; +# 3 is server_id of slave2. +let $condition= ='3'; +source include/wait_show_condition.inc; +# Make sure that the other slave also had time to register. Otherwise we get +# occasional spurious failures where server_id=2 is missing from SHOW SLAVE +# HOSTS, when that slave is much slower to register due to thread scheduling. +let $condition= ='2'; +source include/wait_show_condition.inc; +--replace_column 3 'SLAVE_PORT' +--replace_result $SLAVE_MYPORT SLAVE_PORT $DEFAULT_MASTER_PORT DEFAULT_PORT +SHOW SLAVE HOSTS; + +connection slave2; +--source include/stop_slave_io.inc + +connection master; +let $show_statement= SHOW SLAVE HOSTS; +let $field= Server_id; +# 3 is server_id of slave2. +let $condition= <> '3'; +# All rows of 'SHOW SLAVE HOSTS' are not equal to 3. It mean that master has +# knew the leave of slave2 and has unregistered it. +let $wait_for_all= 1; +source include/wait_show_condition.inc; +--replace_result $SLAVE_MYPORT SLAVE_PORT +SHOW SLAVE HOSTS; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_show_slave_running.test b/mysql-test/suite/rpl/t/rpl_show_slave_running.test new file mode 100644 index 00000000..cb4a8819 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_show_slave_running.test @@ -0,0 +1,83 @@ +# +# Bug #30703 SHOW STATUS LIKE 'Slave_running' is not compatible with `SHOW SLAVE STATUS' +# The test verifies that SHOW STATUS LIKE 'Slave_running' displays ON +# if and only if `SHOW SLAVE STATUS' displays YES for Slave_IO_Running and Slave_SQL_Running +# +source include/have_debug.inc; +source include/have_debug_sync.inc; +source include/master-slave.inc; + +connection slave; + +SET DEBUG_SYNC= 'RESET'; +source include/stop_slave.inc; +SET @saved_dbug = @@GLOBAL.debug_dbug; +set global debug_dbug= 'd,dbug.before_get_running_status_yes'; # to block due-started IO + +# Test 1. Slave is stopped + +--echo Slave_running, Slave_IO_Running, Slave_SQL_Running, must be OFF, NO, NO in three following queries + +SHOW STATUS LIKE 'Slave_running'; +let $status= query_get_value("show slave status", Slave_IO_Running, 1); +echo Slave_IO_Running= $status; +let $status= query_get_value("show slave status", Slave_SQL_Running, 1); +echo Slave_SQL_Running= $status; + +# Test 2. The slave IO thread is started but not yet got connected to master +# and SQL thread is not started + +start slave io_thread; + +# +# Notice a difference between versions in showing p.2: +# 5.1 has two OFF,ON IO-thread state running state whereas later versions +# have three: OFF,Connecting,ON. +# Hence, 5.1 must display OFF NO NO where as 5.1+ OFF Connecting NO +# +--echo Slave_running, Slave_IO_Running, Slave_SQL_Running must be OFF Connecting NO in three following queries + +SHOW STATUS LIKE 'Slave_running'; +let $status= query_get_value("show slave status", Slave_IO_Running, 1); +echo Slave_IO_Running= $status; +let $status= query_get_value("show slave status", Slave_SQL_Running, 1); +echo Slave_SQL_Running= $status; + +# Test 3. The slave IO thread is started and got connected to master +# and SQL thread is still not started + +SET DEBUG_SYNC='now SIGNAL signal.io_thread_let_running'; # unblock IO thread now +let $slave_param= Slave_IO_Running; +let $slave_param_value= YES; +source include/wait_for_slave_param.inc; + +--echo Slave_running, Slave_IO_Running, Slave_SQL_Running must be OFF YES NO in three following queries + +SHOW STATUS LIKE 'Slave_running'; +let $status= query_get_value("show slave status", Slave_IO_Running, 1); +echo Slave_IO_Running= $status; +let $status= query_get_value("show slave status", Slave_SQL_Running, 1); +echo Slave_SQL_Running= $status; + +# Test 4. The slave IO thread is started and got connected to master +# and SQL thread is started + +start slave sql_thread; +source include/wait_for_slave_sql_to_start.inc; + +--echo Slave_running, Slave_IO_Running, Slave_SQL_Running must be ON, YES, YES in three following queries + +SHOW STATUS LIKE 'Slave_running'; +let $status= query_get_value("show slave status", Slave_IO_Running, 1); +echo Slave_IO_Running= $status; +let $status= query_get_value("show slave status", Slave_SQL_Running, 1); +echo Slave_SQL_Running= $status; + +# cleanup + +connection slave; + +SET @@GLOBAL.debug_dbug = @saved_dbug; +SET DEBUG_SYNC= 'RESET'; +--echo End of tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_shutdown_wait_semisync_slaves.cnf b/mysql-test/suite/rpl/t/rpl_shutdown_wait_semisync_slaves.cnf new file mode 100644 index 00000000..8ff9df03 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_shutdown_wait_semisync_slaves.cnf @@ -0,0 +1,16 @@ +!include ../my.cnf + +[mysqld.1] +log_warnings=3 +[mysqld.2] + +[mysqld.3] + +[mysqld.4] + +[ENV] +SERVER_MYPORT_3= @mysqld.3.port +SERVER_MYSOCK_3= @mysqld.3.socket + +SERVER_MYPORT_4= @mysqld.4.port +SERVER_MYSOCK_4= @mysqld.4.socket diff --git a/mysql-test/suite/rpl/t/rpl_shutdown_wait_semisync_slaves.test b/mysql-test/suite/rpl/t/rpl_shutdown_wait_semisync_slaves.test new file mode 100644 index 00000000..2c63df30 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_shutdown_wait_semisync_slaves.test @@ -0,0 +1,46 @@ +# +# MDEV-18450 "Slow" shutdown to wait for slaves that are to be fed +# with everything in the master binlog before shutdown completes. +# +# This is a semisync version of basic tests. +--source include/have_innodb.inc +--source include/have_debug.inc +--let $rpl_topology=1->2, 1->3, 1->4 +--source include/rpl_init.inc + +--connection server_1 +call mtr.add_suppression("Timeout waiting for reply of binlog"); +--let $sav_enabled_master=`SELECT @@GLOBAL.rpl_semi_sync_master_enabled` +SET @@GLOBAL.rpl_semi_sync_master_enabled = 1; + +--let slaves= 3 +--let i= 2 +while (`SELECT $i <= $slaves`) +{ + --connection server_$i + --let $sav_enabled_slave=`SELECT @@GLOBAL.rpl_semi_sync_slave_enabled` + set global rpl_semi_sync_slave_enabled = 1; + + source include/stop_slave.inc; + source include/start_slave.inc; + set global rpl_semi_sync_slave_enabled = 1; + + --inc $i +} + +--source include/rpl_shutdown_wait_slaves.inc +--let i= 2 +while (`SELECT $i <= $slaves`) +{ + --connection server_$i + source include/stop_slave.inc; + source include/start_slave.inc; + --eval SET @@GLOBAL.rpl_semi_sync_slave_enabled = $sav_enabled_slave; + + --inc $i +} + +--connection server_1 +--eval SET @@GLOBAL.rpl_semi_sync_master_enabled = $sav_enabled_master + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_shutdown_wait_slaves.cnf b/mysql-test/suite/rpl/t/rpl_shutdown_wait_slaves.cnf new file mode 100644 index 00000000..8ff9df03 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_shutdown_wait_slaves.cnf @@ -0,0 +1,16 @@ +!include ../my.cnf + +[mysqld.1] +log_warnings=3 +[mysqld.2] + +[mysqld.3] + +[mysqld.4] + +[ENV] +SERVER_MYPORT_3= @mysqld.3.port +SERVER_MYSOCK_3= @mysqld.3.socket + +SERVER_MYPORT_4= @mysqld.4.port +SERVER_MYSOCK_4= @mysqld.4.socket diff --git a/mysql-test/suite/rpl/t/rpl_shutdown_wait_slaves.test b/mysql-test/suite/rpl/t/rpl_shutdown_wait_slaves.test new file mode 100644 index 00000000..97363206 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_shutdown_wait_slaves.test @@ -0,0 +1,11 @@ +# +# MDEV-18450 "Slow" shutdown to wait for slaves that are to be fed +# with everything in the master binlog before shutdown completes. +# +--source include/have_innodb.inc +--source include/have_debug.inc +--let $rpl_topology=1->2, 1->3, 1->4 +--source include/rpl_init.inc + +--source include/rpl_shutdown_wait_slaves.inc +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_skip_error-slave.opt b/mysql-test/suite/rpl/t/rpl_skip_error-slave.opt new file mode 100644 index 00000000..208da1fa --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_skip_error-slave.opt @@ -0,0 +1 @@ +--slave-skip-errors=1062 diff --git a/mysql-test/suite/rpl/t/rpl_skip_error.test b/mysql-test/suite/rpl/t/rpl_skip_error.test new file mode 100644 index 00000000..d3ef834e --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_skip_error.test @@ -0,0 +1,175 @@ +# ==== Purpose ==== +# +# Verify that --slave-skip-errors works correctly. The error messages +# specified by --slave-skip-errors on slave should be ignored. If +# such errors occur, they should not be reported and not cause the +# slave to stop. +# +# ==== Method ==== +# +# We run the slave with --slave-skip-errors=1062 (the code for +# duplicate key). Then we have two set of tests. In the first +# set, we insert value 1 in a table on the slave, and then, on +# master, we insert value 1 in the table. In the second set, we +# insert several values on the master, disable the binlog and +# delete one of the values and re-enable the binlog. Right after, +# we perform an update on the set of values in order to generate +# a duplicate key on the slave. The errors should be ignored on +# the slave. +# +# ==== Related bugs ==== +# +# BUG#28839: Errors in strict mode silently stop SQL thread if --slave-skip-errors exists +# bug in this test: BUG#30594: rpl.rpl_skip_error is nondeterministic: +# BUG#39393: slave-skip-errors does not work when using ROW based replication + +source include/have_innodb.inc; +source include/master-slave.inc; + +--connection slave +let $initial_skipped_error= query_get_value(show global status like "Slave_skipped_errors", Value, 1); + +connection master; +--echo ==== Test Without sql_mode=strict_trans_tables ==== + +create table t1 (n int not null primary key); + +sync_slave_with_master; +insert into t1 values (1); + +connection master; +# Here we expect (ignored) error, since 1 is already in slave table +insert into t1 values (1); +# These should work fine +insert into t1 values (2),(3); + +sync_slave_with_master; +select * from t1 order by n; + +--echo ==== Test With sql_mode=strict_trans_tables ==== +insert into t1 values (7),(8); +connection master; +set sql_mode=strict_trans_tables; +insert into t1 values (7), (8), (9); +sync_slave_with_master; +select * from t1 order by n; +source include/check_slave_is_running.inc; + +--echo ==== Clean Up ==== +connection master; +drop table t1; +sync_slave_with_master; +# End of 4.1 tests + +# +# #28839 Errors in strict mode silently stop SQL thread if --slave-skip-errors exists +# +connection master; +create table t1(a int primary key); +insert into t1 values (1),(2); +SET SQL_LOG_BIN=0; +delete from t1; +SET SQL_LOG_BIN=1; +set sql_mode=strict_trans_tables; +insert into t1 values (1), (2), (3); + +sync_slave_with_master; +select * from t1; +source include/check_slave_is_running.inc; + + +--echo ==== Clean Up ==== + +connection master; +drop table t1; +sync_slave_with_master; +# End of 5.0 tests + +# +# BUG#39393: slave-skip-errors does not work when using ROW based replication +# +--echo ==== Using Innodb ==== + +connection master; + +SET SQL_LOG_BIN=0; +CREATE TABLE t1(id INT NOT NULL PRIMARY KEY, data INT) Engine=InnoDB; +SHOW CREATE TABLE t1; +SET SQL_LOG_BIN=1; + +connection slave; + +call mtr.add_suppression("Slave SQL.*Could not execute .*te_rows event on table test.t.; Duplicate entry.* error.* 1062"); + +CREATE TABLE t1(id INT NOT NULL PRIMARY KEY, data INT) Engine=InnoDB; +SHOW CREATE TABLE t1; + +connection master; + +INSERT INTO t1 VALUES(1, 1); +INSERT INTO t1 VALUES(2, 1); +INSERT INTO t1 VALUES(3, 1); +INSERT INTO t1 VALUES(4, 1); + +SET SQL_LOG_BIN=0; +DELETE FROM t1 WHERE id = 4; +SET SQL_LOG_BIN=1; +UPDATE t1 SET id= id + 3, data = 2; + +sync_slave_with_master; + +let $error= query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1); +echo $error; + +--echo **** We cannot execute a select as there are differences in the +--echo **** behavior between STMT and RBR. + +--echo ==== Using MyIsam ==== + +connection master; + +SET SQL_LOG_BIN=0; +CREATE TABLE t2(id INT NOT NULL PRIMARY KEY, data INT) Engine=MyIsam; +SHOW CREATE TABLE t2; +SET SQL_LOG_BIN=1; + +connection slave; + +CREATE TABLE t2(id INT NOT NULL PRIMARY KEY, data INT) Engine=MyIsam; +SHOW CREATE TABLE t2; +let $current_skipped_error= query_get_value(show global status like "Slave_skipped_errors", Value, 1); +--let $delta_skipped_error= `select $current_skipped_error - $initial_skipped_error from dual` +--echo # Slave_skipped_errros = $delta_skipped_error +connection master; + +INSERT INTO t2 VALUES(1, 1); +INSERT INTO t2 VALUES(2, 1); +INSERT INTO t2 VALUES(3, 1); +INSERT INTO t2 VALUES(5, 1); + +SET SQL_LOG_BIN=0; +DELETE FROM t2 WHERE id = 5; +SET SQL_LOG_BIN=1; +UPDATE t2 SET id= id + 3, data = 2; + +sync_slave_with_master; + +let $error= query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1); +echo $error; + +let $current_skipped_error= query_get_value(show global status like "Slave_skipped_errors", Value, 1); +--let $delta_skipped_error= `select $current_skipped_error - $initial_skipped_error from dual` +--echo # Slave_skipped_errros = $delta_skipped_error + +--echo **** We cannot execute a select as there are differences in the +--echo **** behavior between STMT and RBR. + +--echo ==== Clean Up ==== + +connection master; + +DROP TABLE t1; +DROP TABLE t2; + +sync_slave_with_master; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_skip_incident-master.opt b/mysql-test/suite/rpl/t/rpl_skip_incident-master.opt new file mode 100644 index 00000000..912801de --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_skip_incident-master.opt @@ -0,0 +1 @@ +--loose-debug=+d,incident_database_resync_on_replace diff --git a/mysql-test/suite/rpl/t/rpl_skip_incident-slave.opt b/mysql-test/suite/rpl/t/rpl_skip_incident-slave.opt new file mode 100644 index 00000000..a223f2e0 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_skip_incident-slave.opt @@ -0,0 +1 @@ +--slave-skip-errors=1590 diff --git a/mysql-test/suite/rpl/t/rpl_skip_incident.test b/mysql-test/suite/rpl/t/rpl_skip_incident.test new file mode 100644 index 00000000..704854ae --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_skip_incident.test @@ -0,0 +1,42 @@ +--source include/have_debug.inc +--source include/master-slave.inc + +connection master; +SET GLOBAL BINLOG_CHECKSUM=NONE; +connection slave; +SET GLOBAL BINLOG_CHECKSUM=NONE; +connection master; + +--echo **** On Master **** +CREATE TABLE t1 (a INT); + +INSERT INTO t1 VALUES (1),(2),(3); +SELECT * FROM t1; + +# This will generate an incident log event and store it in the binary +# log before the replace statement. +REPLACE INTO t1 VALUES (4); + +--sync_slave_with_master + +# Now, we should have inserted the row into the table and the slave +# should be running. We should also have rotated to a new binary log. + +SELECT * FROM t1; +source include/check_slave_is_running.inc; + +connection master; + +--echo Should have two binary logs here +--source include/show_binary_logs.inc +DROP TABLE t1; +--sync_slave_with_master + + +connection master; +SET GLOBAL BINLOG_CHECKSUM=default; +connection slave; +SET GLOBAL BINLOG_CHECKSUM=default; +connection master; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_skip_replication.test b/mysql-test/suite/rpl/t/rpl_skip_replication.test new file mode 100644 index 00000000..d1044c4b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_skip_replication.test @@ -0,0 +1,408 @@ +# +# This include file is used by more than one test suite +# (currently rpl and binlog_encryption). +# Please check all dependent tests after modifying it. +# +# Usage: +# +# --let $use_remote_mysqlbinlog= 1 # optional +# --source suite/rpl/include/rpl_skip_replication.inc +# +# The script uses MYSQLBINLOG to verify certain results. +# By default, it uses binary logs directly. If it is undesirable, +# this behavior can be overridden by setting $use_remote_binlog +# as shown above. +# The value will be unset after every execution of the script, +# so if it is needed, it should be set explicitly before each call. +# + +--source include/have_innodb.inc +--source include/master-slave.inc + +--connection slave +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=NO; +--source include/start_slave.inc +--connection master + +connection slave; +# Test that SUPER is required to change @@replicate_events_marked_for_skip. +CREATE USER 'nonsuperuser'@'127.0.0.1'; +GRANT ALTER,CREATE,DELETE,DROP,EVENT,INSERT,PROCESS,REPLICATION SLAVE, + SELECT,UPDATE ON *.* TO 'nonsuperuser'@'127.0.0.1'; +connect(nonpriv, 127.0.0.1, nonsuperuser,, test, $SLAVE_MYPORT,); +connection nonpriv; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_MASTER; +disconnect nonpriv; +connection slave; +DROP USER'nonsuperuser'@'127.0.0.1'; + +SELECT @@global.replicate_events_marked_for_skip; +--error ER_SLAVE_MUST_STOP +SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_SLAVE; +SELECT @@global.replicate_events_marked_for_skip; +STOP SLAVE; +--error ER_GLOBAL_VARIABLE +SET SESSION replicate_events_marked_for_skip=FILTER_ON_MASTER; +SELECT @@global.replicate_events_marked_for_skip; +SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_MASTER; +SELECT @@global.replicate_events_marked_for_skip; +START SLAVE; + +connection master; +SELECT @@skip_replication; +--error ER_LOCAL_VARIABLE +SET GLOBAL skip_replication=1; +SELECT @@skip_replication; + +CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=myisam; +CREATE TABLE t2 (a INT PRIMARY KEY, b INT) ENGINE=innodb; +INSERT INTO t1(a) VALUES (1); +INSERT INTO t2(a) VALUES (1); + + +# Test that master-side filtering works. +SET skip_replication=1; + +CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=myisam; +INSERT INTO t1(a) VALUES (2); +INSERT INTO t2(a) VALUES (2); + +# Inject a rotate event in the binlog stream sent to slave (otherwise we will +# fail sync_slave_with_master as the last event on the master is not present +# on the slave). +FLUSH NO_WRITE_TO_BINLOG LOGS; + +sync_slave_with_master; +connection slave; +SHOW TABLES; +SELECT * FROM t1; +SELECT * FROM t2; + +connection master; +DROP TABLE t3; + +FLUSH NO_WRITE_TO_BINLOG LOGS; +sync_slave_with_master; + + +# Test that slave-side filtering works. +connection slave; +STOP SLAVE; +SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_SLAVE; +START SLAVE; + +connection master; +SET skip_replication=1; +CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=myisam; +INSERT INTO t1(a) VALUES (3); +INSERT INTO t2(a) VALUES (3); + +# Inject a rotate event in the binlog stream sent to slave (otherwise we will +# fail sync_slave_with_master as the last event on the master is not present +# on the slave). +FLUSH NO_WRITE_TO_BINLOG LOGS; + +sync_slave_with_master; +connection slave; +SHOW TABLES; +SELECT * FROM t1; +SELECT * FROM t2; + +connection master; +DROP TABLE t3; + +FLUSH NO_WRITE_TO_BINLOG LOGS; +sync_slave_with_master; +connection slave; +STOP SLAVE; +SET GLOBAL replicate_events_marked_for_skip=REPLICATE; +START SLAVE; + + +# Test that events with @@skip_replication=1 are not filtered when filtering is +# not set on slave. +connection master; +SET skip_replication=1; +CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=myisam; +INSERT INTO t3(a) VALUES(2); +sync_slave_with_master; +connection slave; +SELECT * FROM t3; +connection master; +DROP TABLE t3; + +# +# Test that the slave will preserve the @@skip_replication flag in its +# own binlog. +# + +TRUNCATE t1; +sync_slave_with_master; +connection slave; +RESET MASTER; + +connection master; +SET skip_replication=0; +INSERT INTO t1 VALUES (1,0); +SET skip_replication=1; +INSERT INTO t1 VALUES (2,0); +SET skip_replication=0; +INSERT INTO t1 VALUES (3,0); + +sync_slave_with_master; +connection slave; +# Since slave has @@replicate_events_marked_for_skip=REPLICATE, it should have +# applied all events. +SELECT * FROM t1 ORDER by a; + +STOP SLAVE; +SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_MASTER; +let $SLAVE_DATADIR= `select @@datadir`; + +connection master; +TRUNCATE t1; + +# Now apply the slave binlog to the master, to check that both the slave +# and mysqlbinlog will preserve the @@skip_replication flag. + +--let $mysqlbinlog_args= $SLAVE_DATADIR/slave-bin.000001 +if ($use_remote_mysqlbinlog) +{ + --let $mysqlbinlog_args= --read-from-remote-server --protocol=tcp --host=127.0.0.1 --port=$SLAVE_MYPORT -uroot slave-bin.000001 + --let $use_remote_mysqlbinlog= 0 +} +--exec $MYSQL_BINLOG $mysqlbinlog_args > $MYSQLTEST_VARDIR/tmp/rpl_skip_replication.binlog +--exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/rpl_skip_replication.binlog + +# The master should have all three events. +SELECT * FROM t1 ORDER by a; + +# The slave should be missing event 2, which is marked with the +# @@skip_replication flag. + +connection slave; +START SLAVE; + +connection master; +sync_slave_with_master; + +connection slave; +SELECT * FROM t1 ORDER by a; + +# +# Test that @@sql_slave_skip_counter does not count skipped @@skip_replication +# events. +# + +connection master; +TRUNCATE t1; + +sync_slave_with_master; +connection slave; +STOP SLAVE; +# We will skip two INSERTs (in addition to any skipped due to +# @@skip_replication). Since from 5.5 every statement is wrapped in +# BEGIN ... END, we need to skip 6 events for this. +SET GLOBAL sql_slave_skip_counter=6; +SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_SLAVE; +START SLAVE; + +connection master; +# Need to fix @@binlog_format to get consistent event count. +SET @old_binlog_format= @@binlog_format; +SET binlog_format= statement; +SET skip_replication=0; +INSERT INTO t1 VALUES (1,5); +SET skip_replication=1; +INSERT INTO t1 VALUES (2,5); +SET skip_replication=0; +INSERT INTO t1 VALUES (3,5); +INSERT INTO t1 VALUES (4,5); +SET binlog_format= @old_binlog_format; + +sync_slave_with_master; +connection slave; + +# The slave should have skipped the first three inserts (number 1 and 3 due +# to @@sql_slave_skip_counter=2, number 2 due to +# @@replicate_events_marked_for_skip=FILTER_ON_SLAVE). So only number 4 +# should be left. +SELECT * FROM t1; + + +# +# Check that BINLOG statement preserves the @@skip_replication flag. +# +connection slave; +# Need row @@binlog_format for BINLOG statements containing row events. +--source include/stop_slave.inc +SET @old_slave_binlog_format= @@global.binlog_format; +SET GLOBAL binlog_format= row; +--source include/start_slave.inc + +connection master; +TRUNCATE t1; + +SET @old_binlog_format= @@binlog_format; +SET binlog_format= row; +# Format description log event. +BINLOG 'wlZOTw8BAAAA8QAAAPUAAAAAAAQANS41LjIxLU1hcmlhREItZGVidWctbG9nAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAA2QAEGggAAAAICAgCAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAA371saA=='; +# INSERT INTO t1 VALUES (1,8) # with @@skip_replication=1 +BINLOG 'wlZOTxMBAAAAKgAAAGMBAAAAgCkAAAAAAAEABHRlc3QAAnQxAAIDAwAC +wlZOTxcBAAAAJgAAAIkBAAAAgCkAAAAAAAEAAv/8AQAAAAgAAAA='; +# INSERT INTO t1 VALUES (2,8) # with @@skip_replication=0 +BINLOG 'wlZOTxMBAAAAKgAAADwCAAAAACkAAAAAAAEABHRlc3QAAnQxAAIDAwAC +wlZOTxcBAAAAJgAAAGICAAAAACkAAAAAAAEAAv/8AgAAAAgAAAA='; +SET binlog_format= @old_binlog_format; + +SELECT * FROM t1 ORDER BY a; +sync_slave_with_master; +connection slave; +# Slave should have only the second insert, the first should be ignored due to +# the @@skip_replication flag. +SELECT * FROM t1 ORDER by a; + +--source include/stop_slave.inc +SET GLOBAL binlog_format= @old_slave_binlog_format; +--source include/start_slave.inc + + +# Test that it is not possible to change @@skip_replication inside a +# transaction or statement, thereby replicating only parts of statements +# or transactions. +connection master; +SET skip_replication=0; + +BEGIN; +--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SKIP_REPLICATION +SET skip_replication=0; +--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SKIP_REPLICATION +SET skip_replication=1; +ROLLBACK; +SET skip_replication=1; +BEGIN; +--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SKIP_REPLICATION +SET skip_replication=0; +--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SKIP_REPLICATION +SET skip_replication=1; +COMMIT; +SET autocommit=0; +INSERT INTO t2(a) VALUES(100); +--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SKIP_REPLICATION +SET skip_replication=1; +ROLLBACK; +SET autocommit=1; + +SET skip_replication=1; +--delimiter | +CREATE FUNCTION foo (x INT) RETURNS INT BEGIN SET SESSION skip_replication=x; RETURN x; END| +CREATE PROCEDURE bar(x INT) BEGIN SET SESSION skip_replication=x; END| +CREATE FUNCTION baz (x INT) RETURNS INT BEGIN CALL bar(x); RETURN x; END| +--delimiter ; +--error ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION +SELECT foo(0); +--error ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION +SELECT baz(0); +--error ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION +SET @a= foo(1); +--error ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION +SET @a= baz(1); +--error ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION +UPDATE t2 SET b=foo(0); +--error ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION +UPDATE t2 SET b=baz(0); +--error ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION +INSERT INTO t1 VALUES (101, foo(1)); +--error ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION +INSERT INTO t1 VALUES (101, baz(0)); +SELECT @@skip_replication; +CALL bar(0); +SELECT @@skip_replication; +CALL bar(1); +SELECT @@skip_replication; +DROP FUNCTION foo; +DROP PROCEDURE bar; +DROP FUNCTION baz; + + +# Test that master-side filtering happens on the master side, and that +# slave-side filtering happens on the slave. + +# First test that events do not reach the slave when master-side filtering +# is configured. Do this by replicating first with only the IO thread running +# and master-side filtering; then change to no filtering and start the SQL +# thread. This should still skip the events, as master-side filtering +# means the events never reached the slave. +connection master; +SET skip_replication= 0; +TRUNCATE t1; +sync_slave_with_master; +connection slave; +STOP SLAVE; +SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_MASTER; +START SLAVE IO_THREAD; +connection master; +SET skip_replication= 1; +INSERT INTO t1(a) VALUES (1); +SET skip_replication= 0; +INSERT INTO t1(a) VALUES (2); +--source include/save_master_pos.inc +connection slave; +--source include/sync_io_with_master.inc +STOP SLAVE IO_THREAD; +SET GLOBAL replicate_events_marked_for_skip=REPLICATE; +START SLAVE; +connection master; +sync_slave_with_master; +connection slave; +# Now only the second insert of (2) should be visible, as the first was +# filtered on the master, so even though the SQL thread ran without skipping +# events, it will never see the event in the first place. +SELECT * FROM t1; + +# Now tests that when slave-side filtering is configured, events _do_ reach +# the slave. +connection master; +SET skip_replication= 0; +TRUNCATE t1; +sync_slave_with_master; +connection slave; +STOP SLAVE; +SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_SLAVE; +START SLAVE IO_THREAD; +connection master; +SET skip_replication= 1; +INSERT INTO t1(a) VALUES (1); +SET skip_replication= 0; +INSERT INTO t1(a) VALUES (2); +--source include/save_master_pos.inc +connection slave; +--source include/sync_io_with_master.inc +STOP SLAVE IO_THREAD; +SET GLOBAL replicate_events_marked_for_skip=REPLICATE; +START SLAVE; +connection master; +sync_slave_with_master; +connection slave; +# Now both inserts should be visible. Since filtering was configured to be +# slave-side, the event is in the relay log, and when the SQL thread ran we +# had disabled filtering again. +SELECT * FROM t1 ORDER BY a; + + +# Clean up. +connection master; +SET skip_replication=0; +DROP TABLE t1,t2; +connection slave; +STOP SLAVE; +SET GLOBAL replicate_events_marked_for_skip=REPLICATE; +START SLAVE; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_slave_alias_replica.test b/mysql-test/suite/rpl/t/rpl_slave_alias_replica.test new file mode 100644 index 00000000..06cf12ab --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_slave_alias_replica.test @@ -0,0 +1,103 @@ +# ==== Purpose ==== +# +# Test verifies that SQL statements which use keyword 'REPLICA' a synonym for +# 'SLAVE' work as expected. +# +# ==== Implementation ==== +# +# List of commands being verified are +# On Master: SHOW REPLICA HOSTS +# : Privilege "REPLICA" +# +# On Slave: START REPLICA +# START REPLICA UNTIL +# STOP REPLICA +# SHOW REPLICA STATUS +# RESET REPLICA ALL +# REPLICA_POS +# +# ==== References ==== +# +# MDEV-20601: Make REPLICA a synonym for SLAVE in SQL statements +# + +--source include/have_innodb.inc +--source include/master-slave.inc + +--echo "Command: STOP SLAVE --> STOP REPLICA" +--connection slave +STOP REPLICA; +--source include/wait_for_slave_io_to_stop.inc +--source include/wait_for_slave_sql_to_stop.inc + +--connection master +CREATE USER 'repl_user'; +--echo "Privilege: SLAVE --> REPLICA" +GRANT REPLICATION REPLICA on *.* TO repl_user; +FLUSH PRIVILEGES; + +--connection slave +--echo "SHOW SLAVE STATUS --> SHOW REPLICA STATUS" +--let $master_user= query_get_value(SHOW REPLICA STATUS, Master_User, 1) +CHANGE MASTER TO MASTER_USER= 'repl_user'; +--echo "Command: START SLAVE --> START REPLICA" +START REPLICA; +--source include/wait_for_slave_io_to_start.inc +--source include/wait_for_slave_sql_to_start.inc + +--connection master +--sync_slave_with_master + +--connection master +--echo "Command: SHOW SLAVE HOSTS --> SHOW REPLICA HOSTS" +let $show_statement= SHOW REPLICA HOSTS; +let $field= Server_id; +# Slave's server_id 2 +let $condition= ='2'; +source include/wait_show_condition.inc; +DROP USER 'repl_user'; +--sync_slave_with_master + +--echo "Command: SHOW SLAVE IO/SQL THREAD --> SHOW REPLICA IO/SQL THREAD" +STOP REPLICA IO_THREAD; +STOP REPLICA SQL_THREAD; +--source include/wait_for_slave_io_to_stop.inc +--source include/wait_for_slave_sql_to_stop.inc +--echo "Command: RESET SLAVE ALL --> RESET REPLICA ALL" +RESET REPLICA ALL; +set @@global.gtid_slave_pos= ""; + +--connection master +RESET MASTER; +CREATE TABLE t(f INT) ENGINE=INNODB; +INSERT INTO t VALUES (10); +let $master_log_file= query_get_value(SHOW MASTER STATUS, File, 1); +let $master_pos= query_get_value(SHOW MASTER STATUS, Position, 1); +DROP TABLE t; + +--connection slave +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1',MASTER_PORT=$MASTER_MYPORT,MASTER_USER='$master_user'; +--echo "Command: START SLAVE UNTIL --> START REPLICA UNTIL" +--replace_result $master_log_file MASTER_LOG_FILE $master_pos MASTER_POS +--eval START REPLICA UNTIL MASTER_LOG_FILE='$master_log_file', MASTER_LOG_POS=$master_pos +--source include/wait_for_slave_sql_to_stop.inc +--source include/stop_slave_io.inc + +SELECT * FROM t; +--let $slave_param= Exec_Master_Log_Pos +--let $slave_param_value= $master_pos +--source include/check_slave_param.inc + +--replace_result $MASTER_MYPORT MASTER_PORT +--echo "MASTER_USE_GTID=SLAVE_POS --> MASTER_USE_GTID=REPLICA_POS" +--replace_result $MASTER_MYPORT MASTER_PORT +--eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $MASTER_MYPORT, MASTER_USE_GTID=REPLICA_POS +--source include/start_slave.inc + +--connection master +CREATE TABLE t2 (f INT PRIMARY KEY) ENGINE=INNODB; +INSERT INTO t2 VALUES (10); +DROP TABLE t2; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_slave_grp_exec.test b/mysql-test/suite/rpl/t/rpl_slave_grp_exec.test new file mode 100644 index 00000000..5b08b2cd --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_slave_grp_exec.test @@ -0,0 +1,186 @@ +############################################################# +# Author: Serge Kozlov <skozlov@mysql.com> +# Date: 03/21/2008 +# Purpose: +# WL#3734 Test: slave group execution +# Testing slave group execution: stop in middle of the group +# (of events) should be immpossible on slave. +# Group of events means set of statements between BEGIN/COMMIT +# for transactional engines or a statement for +# non-transactional engines that fires triggers and +# affects to another tables. +# Implementation of slave stop in middle of the group: +# Delete the table on slave before start of the group +# on master where this table is participant of the group. +# So sql thread will failed inside of the group. +# Expected results: +# 1. For non-transactional engines w/o PK slave should trying +# to complete executing of the group. +# 2. For non-transactional engines slave should stop on +# start position of the group. +############################################################# +--source include/have_innodb.inc +--source include/master-slave.inc +--echo + +# Create tables and data +--echo *** Preparing data *** +--connection master +CREATE TABLE t1 (a INT NOT NULL, b VARCHAR(10)) ENGINE=MyISAM; +CREATE TABLE t2 LIKE t1; +CREATE TABLE t3 LIKE t1; + +DELIMITER |; +CREATE TRIGGER tr1 BEFORE UPDATE ON t1 + FOR EACH ROW BEGIN + UPDATE t2 SET b='YY' WHERE a=NEW.a; + END| +CREATE TRIGGER tr2 AFTER UPDATE ON t1 + FOR EACH ROW BEGIN + UPDATE t3 SET b='ZZ' WHERE a=NEW.a; + END| +DELIMITER ;| +--echo + +# Test non-transactional group with MyISAM tables w/o PK. +# Data for t1,t2 should be replicated for SBR even t3 +# doesn't exist on slave +--echo *** Test non-transactional group w/o PK *** + +--connection master +INSERT INTO t3 VALUES(1, 'AA'); +INSERT INTO t2 VALUES(1, 'AA'); +INSERT INTO t1 VALUES(1, 'AA'); +--sync_slave_with_master + +RENAME TABLE t3 TO t3_bak; + +--connection master +UPDATE t1 SET b = 'XX' WHERE a = 1; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; + +--connection slave +# 1146 = ER_NO_SUCH_TABLE +call mtr.add_suppression("Slave SQL.*Table .test.t3. doesn.t exist.* error.* 1146"); +call mtr.add_suppression("At line *"); +--let $slave_sql_errno= 1146 +--source include/wait_for_slave_sql_error.inc +SHOW TABLES LIKE 't%'; +if (`SELECT @@BINLOG_FORMAT = 'ROW'`) { +--replace_regex /AA/AA_for_row_or_XX_for_stmt_mixed/ + SELECT * FROM t1 ORDER BY a; +--replace_regex /AA/AA_for_row_or_YY_for_stmt_mixed/ + SELECT * FROM t2 ORDER BY a; +} +if (!`SELECT @@BINLOG_FORMAT = 'ROW'`) { +--replace_regex /XX/AA_for_row_or_XX_for_stmt_mixed/ + SELECT * FROM t1 ORDER BY a; +--replace_regex /YY/AA_for_row_or_YY_for_stmt_mixed/ + SELECT * FROM t2 ORDER BY a; +} + +--source include/stop_slave_io.inc +RENAME TABLE t3_bak TO t3; +--source include/start_slave.inc + +--connection master +TRUNCATE t1; +TRUNCATE t2; +TRUNCATE t3; +--sync_slave_with_master +--echo + + +# Test non-transactional group with MyISAM tables and PK. +# No data replicated because update based on PK +--echo *** Test non-transactional group w/ PK *** + +--connection master +ALTER TABLE t1 ADD PRIMARY KEY (a); +ALTER TABLE t2 ADD PRIMARY KEY (a); +ALTER TABLE t3 ADD PRIMARY KEY (a); + +--sync_slave_with_master +RENAME TABLE t3 TO t3_bak; + +--connection master +INSERT INTO t3 VALUES(2, 'B'); +INSERT INTO t2 VALUES(2, 'B'); +INSERT INTO t1 VALUES(2, 'B'); +UPDATE t1 SET b = 'X' WHERE a = 2; + +--connection slave +# 1146 = ER_NO_SUCH_TABLE +--let $slave_sql_errno= 1146 +--source include/wait_for_slave_sql_error.inc + +--connection master +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; + +--connection slave +SHOW TABLES LIKE 't%'; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +--source include/stop_slave_io.inc +RENAME TABLE t3_bak TO t3; +--source include/start_slave.inc + +--connection master +TRUNCATE t1; +TRUNCATE t2; +TRUNCATE t3; +--sync_slave_with_master +--echo + + +# Test transactional group with InnoDB tables with PK +# No data replicated if errors happens inside transaction +--echo *** Test transactional group w/ PK *** + +--connection master +ALTER TABLE t1 ENGINE=InnoDB; +ALTER TABLE t2 ENGINE=InnoDB; +ALTER TABLE t3 ENGINE=InnoDB; + +--sync_slave_with_master +RENAME TABLE t3 TO t3_bak; + +--connection master +BEGIN; +INSERT INTO t1 VALUES (3, 'C'), (4, 'D'); +INSERT INTO t2 VALUES (3, 'C'), (4, 'D'); +INSERT INTO t3 VALUES (3, 'C'), (4, 'D'); +COMMIT; + +--connection slave +# 1146 = ER_NO_SUCH_TABLE +--let $slave_sql_errno= 1146 +--source include/wait_for_slave_sql_error.inc + +--connection master +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; + +--connection slave +SHOW TABLES LIKE 't%'; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +source include/stop_slave_io.inc; +RENAME TABLE t3_bak TO t3; +source include/start_slave.inc; + +# Clean up +--echo *** Clean up *** +--connection master +DROP TABLE t1,t2,t3; +--sync_slave_with_master + +# End of 5.1 test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_slave_invalid_external_user.test b/mysql-test/suite/rpl/t/rpl_slave_invalid_external_user.test new file mode 100644 index 00000000..5099d7ee --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_slave_invalid_external_user.test @@ -0,0 +1,42 @@ +# ==== Purpose ==== +# +# Test verifies that when applier thread tries to access 'variable_name' of +# INFORMATION_SCHEMA.SESSION_VARIABLES table through triggers it successfully +# retrieves all the session variables. +# +# ==== Implementation ==== +# +# Steps: +# 0 - Create two tables t1 and t2. +# 1 - Create a trigger such that it reads the names of all session variables +# from INFORMATION_SCHEMA.SESSION_VARIABLES table and populates one of the +# tables. +# 2 - Do a DML on master and wait for it to be replicated and ensure that +# slave is in sync with master and it is up and running. +# +# ==== References ==== +# +# MDEV-14784: Slave crashes in show_status_array upon running a trigger with +# select from I_S + +--source include/master-slave.inc +--source include/have_binlog_format_mixed.inc +--enable_connect_log +CREATE USER test_user@localhost; +SET PASSWORD FOR test_user@localhost = password('PWD'); +GRANT ALL ON *.* TO test_user@localhost WITH GRANT OPTION; +connect(conn_test,localhost,test_user,PWD,test,$MASTER_MYPORT,$MASTER_MYSOCK); + +--connection conn_test +CREATE TABLE t1 (f1 INT); +CREATE TABLE t2 (f2 VARCHAR(64)); +CREATE TRIGGER tr_before BEFORE INSERT ON t1 FOR EACH ROW INSERT INTO t2 SELECT variable_name FROM INFORMATION_SCHEMA.SESSION_VARIABLES; +CREATE DEFINER='root'@'localhost' TRIGGER tr_after AFTER INSERT ON t1 FOR EACH ROW INSERT INTO t2 SELECT variable_name FROM INFORMATION_SCHEMA.SESSION_VARIABLES; + +INSERT INTO t1 VALUES (1); +--disable_connect_log +# Cleanup +--connection master +DROP USER 'test_user'@'localhost'; +DROP TABLE t1, t2; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_slave_load_in.test b/mysql-test/suite/rpl/t/rpl_slave_load_in.test new file mode 100644 index 00000000..80a27479 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_slave_load_in.test @@ -0,0 +1,49 @@ +########################################################################## +# This test verifies if a slave is able to process a "LOAD DATA INFILE" +# event while the "--secure-file-priv" option is set. +# +# The test is divided in two steps: +# 1 - Creates tables and populates them through "LOAD DATA INFILE". +# 2 - Compares the master and slave. +########################################################################## +--source include/have_innodb.inc +--source include/master-slave.inc + +########################################################################## +# Loading data +########################################################################## +connection master; + +create table t1(a int not null auto_increment, b int, primary key(a)); +create table t2(a int not null auto_increment, b int, primary key(a)) engine=innodb; + +load data infile '../../std_data/rpl_loaddata.dat' into table t1; + +start transaction; + insert into t2(b) values (1); + insert into t2(b) values (2); + load data infile '../../std_data/rpl_loaddata.dat' into table t2; + load data infile '../../std_data/rpl_loaddata.dat' into table t2; +commit; + +########################################################################## +# Checking Consistency +########################################################################## +sync_slave_with_master; + +let $diff_tables= master:t1, slave:t1; +source include/diff_tables.inc; + +let $diff_tables= master:t2, slave:t2; +source include/diff_tables.inc; + +########################################################################## +# Clean up +########################################################################## +connection master; + +drop table t1; +drop table t2; + +sync_slave_with_master; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_slave_load_remove_tmpfile.test b/mysql-test/suite/rpl/t/rpl_slave_load_remove_tmpfile.test new file mode 100644 index 00000000..10051408 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_slave_load_remove_tmpfile.test @@ -0,0 +1,80 @@ +# ==== Purpose ==== +# +# This test verifies if the slave fails gracefully when the temporary +# file used to load data is removed while it is about to be used. +# Similar errors are caught if the temporary directory is removed. +# +# ==== Implementation ==== +# +# Steps: +# 0 - Set debug variable remove_slave_load_file_before_write. This +# causes the slave to remove the file. +# 1 - Creates a table and populates it through "LOAD DATA INFILE". +# 2 - Catches error. +# +# ==== References ==== +# +# BUG#42861: Assigning invalid directories to --slave-load-tmpdir crashes the slave +# BUG#11872422: rpl_slave_load_remove_tmpfile fails sporadically in pb2 + +--source include/have_binlog_format_statement.inc +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/not_embedded.inc +--source include/not_var_link.inc +--source include/master-slave.inc + +########################################################################## +# Loading data +########################################################################## + +connection slave; +SET @saved_dbug = @@GLOBAL.debug_dbug; +SET @@global.debug_dbug= '+d,remove_slave_load_file_before_write'; + +connection master; + +create table t1(a int not null auto_increment, b int, primary key(a)) engine=innodb; + +start transaction; + insert into t1(b) values (1); + insert into t1(b) values (2); + load data infile '../../std_data/rpl_loaddata.dat' into table t1; +commit; + +########################################################################## +# Catch Error +########################################################################## +connection slave; + +# windows and linux different error numbers here: +# Windows: +# - Last_Errno 29 (File not found) +# Unix like OS: +# - Last_Errno 13 (Can't stat file) +--let $slave_sql_errno= 29, 13 +--source include/wait_for_slave_sql_error.inc + +########################################################################## +# Clean up +########################################################################## +connection master; + +drop table t1; + +--source include/sync_slave_io_with_master.inc +--source include/stop_slave_io.inc +RESET SLAVE; + +drop table t1; + +call mtr.add_suppression("Slave: Can't get stat of .*"); +call mtr.add_suppression("Slave SQL: Error .Can.t get stat of.* error.* 13"); +call mtr.add_suppression("Slave: File.* not found.*"); +call mtr.add_suppression("Slave SQL: Error .File.* not found.* error.* 29"); +--let $rpl_only_running_threads= 1 + +SET @@GLOBAL.debug_dbug = @saved_dbug; + +--source include/rpl_end.inc + diff --git a/mysql-test/suite/rpl/t/rpl_slave_load_tmpdir_not_exist-slave.opt b/mysql-test/suite/rpl/t/rpl_slave_load_tmpdir_not_exist-slave.opt new file mode 100644 index 00000000..c4f91e97 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_slave_load_tmpdir_not_exist-slave.opt @@ -0,0 +1 @@ +--slave-load-tmpdir=../../../error diff --git a/mysql-test/suite/rpl/t/rpl_slave_load_tmpdir_not_exist.test b/mysql-test/suite/rpl/t/rpl_slave_load_tmpdir_not_exist.test new file mode 100644 index 00000000..16dcd8ec --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_slave_load_tmpdir_not_exist.test @@ -0,0 +1,22 @@ +########################################################################## +# This test verifies if the start slave fails gracefuly when an +# invalid directory is used to set --slave-load-tmpdir. +########################################################################## +--source include/have_log_bin.inc +--source include/not_embedded.inc + +--let $rpl_skip_start_slave= 1 +--source include/master-slave.inc + +--connection slave +START SLAVE; +call mtr.add_suppression("Slave SQL.*Unable to use slave.s temporary directory"); +# 12 = EE_CANT_MKDIR +--let $slave_sql_errno= 12 +source include/wait_for_slave_sql_error.inc; + +--source include/stop_slave_io.inc +RESET SLAVE; + +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_slave_max_statement_time.test b/mysql-test/suite/rpl/t/rpl_slave_max_statement_time.test new file mode 100644 index 00000000..b600c843 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_slave_max_statement_time.test @@ -0,0 +1,110 @@ +# +# Purpose: +# This test ensures that the slave can limit the execution time of its +# events via the global system variable @@slave_max_statement_time. +# +# Methodology: +# This test uses the following test cases to ensure that a slave will +# correctly limit the execution time of its events: +# 1) Using a serial slave, the SQL thread should time out when its underlying +# event executes for longer than @@slave_max_statement_time. +# 2) Using a parallel slave, a worker thread should time out when its +# underlying event executes for longer than @@slave_max_statement_time. +# 3) Load-based log events (from LOAD DATA INFILE) should time out if their +# execution time exceeds @@slave_max_statement_time +# 4) Locally executed long running statements should not time out due to +# @@slave_max_statement_time. +# +# References: +# MDEV-27161: Add option for SQL thread to limit maximum execution time per +# query replicated +# +--source include/have_innodb.inc +--source include/master-slave.inc + +--echo # +--echo # Set up +--echo # +--connection master +SET STATEMENT sql_log_bin=0 FOR CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format"); +SET STATEMENT sql_log_bin=0 FOR CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format"); +--connection slave +SET STATEMENT sql_log_bin=0 FOR CALL mtr.add_suppression("Slave log event execution was interrupted"); +SET STATEMENT sql_log_bin=0 FOR CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format"); +SET @save_slave_max_statement_time=@@GLOBAL.slave_max_statement_time; + +--let $with_lock= 1 + +--echo # +--echo # Test Case 1) Using a serial slave, the SQL thread should time out when +--echo # its underlying event executes for longer than @@slave_max_statement_time. +--echo # +--source include/rpl_slave_max_statement_time.inc + + +--echo # +--echo # Test Case 2) Using a parallel slave, a worker thread should time out +--echo # when its underlying event executes for longer than +--echo # @@slave_max_statement_time +--echo # + +--source include/stop_slave.inc +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode; +SET GLOBAL slave_parallel_threads=2; +SET GLOBAL slave_parallel_mode='optimistic'; +--source include/start_slave.inc + +--source include/rpl_slave_max_statement_time.inc + +--source include/stop_slave.inc +SET GLOBAL slave_parallel_mode=@old_parallel_mode; +SET GLOBAL slave_parallel_threads=@old_parallel_threads; +--source include/start_slave.inc + + +--echo # +--echo # Test Case 3) Load-based log events (from LOAD DATA INFILE) should time +--echo # out if their execution time exceeds @@slave_max_statement_time +--echo # +--let $use_load_data= 1 +--source include/rpl_slave_max_statement_time.inc +--let $use_load_data= + + +--echo # +--echo # Test Case 4) Locally executed long running statements should not time +--echo # out due to @@slave_max_statement_time +--echo # + +--connection slave +--source include/stop_slave.inc +SET @old_slave_max_statement_time=@@GLOBAL.slave_max_statement_time; +SET @old_gtid_domain_id=@@GLOBAL.gtid_domain_id; +SET @@GLOBAL.slave_max_statement_time=0.75; +SET @@GLOBAL.gtid_domain_id=1; +--source include/start_slave.inc + +CREATE TABLE t2 (a int); +SET STATEMENT sql_log_bin=0 FOR INSERT INTO t2 SELECT SLEEP(1); +--let $t2_count= `SELECT COUNT(*) FROM t2` +if ($t2_count != 1) +{ + --die Local long running insert statement should have completed +} +DROP TABLE t2; + +--source include/stop_slave.inc +SET GLOBAL gtid_domain_id=@old_gtid_domain_id; +SET GLOBAL slave_max_statement_time=@old_slave_max_statement_time; +--source include/start_slave.inc + + +--echo # Cleanup +--source include/stop_slave.inc +SET GLOBAL slave_max_statement_time=@save_slave_max_statement_time; +--source include/start_slave.inc + +--source include/rpl_end.inc + +--echo # End of rpl_slave_max_statement_time.test diff --git a/mysql-test/suite/rpl/t/rpl_slave_shutdown_mdev20821.cnf b/mysql-test/suite/rpl/t/rpl_slave_shutdown_mdev20821.cnf new file mode 100644 index 00000000..1e7cdee5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_slave_shutdown_mdev20821.cnf @@ -0,0 +1,19 @@ +!include suite/rpl/rpl_1slave_base.cnf +!include include/default_client.cnf + +[mysqld.1] +log-slave-updates +gtid-domain-id=1 + +[mysqld.2] +log-slave-updates +gtid-domain-id=2 + +[mysqld.3] +log-slave-updates +gtid-domain-id=3 +slave_parallel_threads=2 + +[ENV] +SERVER_MYPORT_3= @mysqld.3.port +SERVER_MYSOCK_3= @mysqld.3.socket diff --git a/mysql-test/suite/rpl/t/rpl_slave_shutdown_mdev20821.test b/mysql-test/suite/rpl/t/rpl_slave_shutdown_mdev20821.test new file mode 100644 index 00000000..6f73de98 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_slave_shutdown_mdev20821.test @@ -0,0 +1,171 @@ +# MDEV-20821 parallel slave server shutdown hang +# +# Test the bug condition of a parallel slave server shutdown +# hang when the parallel workers were idle. +# The bug reported scenario is extented to cover the multi-sources case as well as +# checking is done for both the idle and busy workers cases. +# +# MDEV-25336 Parallel replication causes failed assert while restarting +# Since this test case involves slave restart this will help in testing +# Mdev-25336 too. + +--source include/have_innodb.inc +--source include/have_binlog_format_mixed.inc +--let $rpl_topology= 1->3 +--source include/rpl_init.inc + +# +# A. idle workers. +# +--connection server_3 +set default_master_connection = ''; +--source include/start_slave.inc + +set default_master_connection = 'm2'; +--replace_result $SERVER_MYPORT_2 SERVER_MYPORT_2 +eval change master to master_host='127.0.0.1', master_port=$SERVER_MYPORT_2, master_user='root', master_use_gtid=slave_pos; +--source include/start_slave.inc + +select @@global.slave_parallel_workers as two; + +# At this point worker threads have no assignement. +# Shutdown must not hang. +# In 10.2/10.3 there should not be any assert failure `prev != 0 && next != 0' +--connection server_3 +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.3.expect +wait +EOF +--send SHUTDOWN +--reap +--source include/wait_until_disconnected.inc + +--connection server_3 +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.3.expect +restart +EOF + +# No hang is *proved* to occur when this point is reached. +--connection server_3 +--enable_reconnect +--source include/wait_until_connected_again.inc + +# +# B. resting workers after some busy time +# +--connection server_1 +create table t1 (i int primary key) engine=Innodb; + +--connection server_2 +create table t2 (i int primary key) engine=Innodb; + +--connection server_3 +set default_master_connection = ''; +--source include/start_slave.inc + +set default_master_connection = 'm2'; +--source include/start_slave.inc + +--connection server_2 +insert into t2 values (1); +--save_master_pos + +--connection server_3 +--sync_with_master 0,'m2' + +--connection server_1 +insert into t1 values (1); +--save_master_pos + +--connection server_3 +--sync_with_master 0,'' + +# In 10.2/10.3 there should not be any assert failure `prev != 0 && next != 0' +# At this point worker threads have no assignement. +# Shutdown must not hang. + +--connection server_3 +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.3.expect +wait +EOF +--send SHUTDOWN +--reap +--source include/wait_until_disconnected.inc + +--connection server_3 +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.3.expect +restart +EOF + +# No hang is *proved* to occur when this point is reached. +--connection server_3 +--enable_reconnect +--source include/wait_until_connected_again.inc + +# +# C. busy workers +# +--connection server_3 +set default_master_connection = ''; +--source include/start_slave.inc + +set default_master_connection = 'm2'; +--source include/start_slave.inc + +--connect (conn_block_server3, 127.0.0.1, root,, test, $SERVER_MYPORT_3,) +begin; + insert into t1 values (2); + insert into t2 values (2); + +--connection server_1 +insert into t1 values (2); +--connection server_2 +insert into t2 values (2); + + +# In 10.2/10.3 there should not be any assert failure `prev != 0 && next != 0' +# At this point there's a good chance the worker threads are busy. +# SHUTDOWN must proceed without any delay as above. +--connection server_3 +--write_file $MYSQLTEST_VARDIR/tmp/mysqld.3.expect +wait +EOF +--send SHUTDOWN +--reap +--source include/wait_until_disconnected.inc + +--connection server_3 +--append_file $MYSQLTEST_VARDIR/tmp/mysqld.3.expect +restart +EOF + +# No hang is *proved* to occur when this point is reached. +--connection server_3 +--enable_reconnect +--source include/wait_until_connected_again.inc + + +# Cleanup + +--connection server_3 +set default_master_connection = ''; +--source include/start_slave.inc + +set default_master_connection = 'm2'; +--source include/start_slave.inc + +--connection server_1 +drop table t1; + +--connection server_2 +drop table t2; +--save_master_pos + +# (!) The following block is critical to avoid check-mysqld_3.reject by mtr: +--connection server_3 +--sync_with_master 0,'m2' +set default_master_connection = 'm2'; +--source include/stop_slave.inc +RESET SLAVE ALL; +set default_master_connection = ''; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_slave_skip.test b/mysql-test/suite/rpl/t/rpl_slave_skip.test new file mode 100644 index 00000000..933e7d14 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_slave_skip.test @@ -0,0 +1,293 @@ +# Every statement in this test is either executing under ROW or +# STATEMENT format, which requires the slave thread to be able to apply +# both statement and row events. Hence, we only need to execute this +# test for MIXED mode. +source include/have_binlog_format_mixed.inc; + +source include/have_innodb.inc; +source include/master-slave.inc; + +connection slave; +source include/have_innodb.inc; +STOP SLAVE; +--source include/wait_for_slave_to_stop.inc + +connection master; +SET SESSION BINLOG_FORMAT=ROW; + +CREATE TABLE t1 (a INT, b INT) ENGINE=MyISAM; +CREATE TABLE t2 (c INT, d INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1,1),(2,4),(3,9); +INSERT INTO t2 VALUES (1,1),(2,8),(3,27); +let $master_log_pos= query_get_value(SHOW MASTER STATUS, Position, 1); +UPDATE t1,t2 SET b = d, d = b * 2 WHERE a = c; +source include/show_binlog_events.inc; + +# These tables should be changed +SELECT * FROM t1; +SELECT * FROM t2; +save_master_pos; +connection slave; + +# Stop when reaching the the first table map event. +--replace_result $master_log_pos MASTER_LOG_POS +eval START SLAVE UNTIL MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=$master_log_pos; +source include/wait_for_slave_sql_to_stop.inc; +let $slave_param= Exec_Master_Log_Pos; +let $slave_param_value= $master_log_pos; +source include/check_slave_param.inc; +source include/check_slave_no_error.inc; + +# Now we skip *one* table map event. If the execution starts right +# after that table map event, *one* of the involved tables will be +# changed. +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +--source include/wait_for_slave_to_start.inc +sync_with_master; + +# These values should be what was inserted, not what was +# updated. Since we are skipping the first table map of the group +# representing the UPDATE statement above, we should skip the entire +# group and not start executing at the first table map. +SELECT * FROM t1; +SELECT * FROM t2; + +STOP SLAVE; +--source include/wait_for_slave_to_stop.inc +--source include/reset_slave.inc +connection master; +RESET MASTER; + +SET SESSION BINLOG_FORMAT=STATEMENT; +SET @foo = 12; +let $master_log_pos= query_get_value(SHOW MASTER STATUS, Position, 1); +INSERT INTO t1 VALUES(@foo, 2*@foo); +save_master_pos; +source include/show_binlog_events.inc; + +connection slave; +--replace_result $master_log_pos MASTER_LOG_POS +eval START SLAVE UNTIL MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=$master_log_pos; +source include/wait_for_slave_sql_to_stop.inc; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +--source include/wait_for_slave_to_start.inc +sync_with_master; + +connection master; +DROP TABLE t1, t2; +sync_slave_with_master; + +# +# More tests for BUG#28618 +# +# Case 1. +# ROW binlog format and non-transactional tables. +# Create the group of events via triggers and try to skip +# some items of that group. +# + +connection master; +SET SESSION BINLOG_FORMAT=ROW; +SET AUTOCOMMIT=0; + +CREATE TABLE t1 (a INT, b VARCHAR(20)) ENGINE=myisam; +CREATE TABLE t2 (a INT, b VARCHAR(20)) ENGINE=myisam; +CREATE TABLE t3 (a INT, b VARCHAR(20)) ENGINE=myisam; + +INSERT INTO t1 VALUES (1,'master/slave'); +INSERT INTO t2 VALUES (1,'master/slave'); +INSERT INTO t3 VALUES (1,'master/slave'); + +DELIMITER |; + +CREATE TRIGGER tr1 AFTER UPDATE on t1 FOR EACH ROW +BEGIN + INSERT INTO t2 VALUES (NEW.a,NEW.b); + DELETE FROM t2 WHERE a < NEW.a; +END| + +CREATE TRIGGER tr2 AFTER INSERT on t2 FOR EACH ROW +BEGIN + UPDATE t3 SET a =2, b = 'master only'; +END| + +DELIMITER ;| + +sync_slave_with_master; +source include/stop_slave.inc; + +connection master; +UPDATE t1 SET a = 2, b = 'master only' WHERE a = 1; +DROP TRIGGER tr1; +DROP TRIGGER tr2; +INSERT INTO t1 VALUES (3,'master/slave'); +INSERT INTO t2 VALUES (3,'master/slave'); +INSERT INTO t3 VALUES (3,'master/slave'); +COMMIT; + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; + +save_master_pos; + +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +source include/start_slave.inc; +sync_with_master; + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; + +connection master; +DROP TABLE t1, t2, t3; +sync_slave_with_master; + +--echo **** Case 2: Row binlog format and transactional tables **** + +# Create the transaction and try to skip some +# queries from one. + +connection master; +CREATE TABLE t4 (a INT, b VARCHAR(20)) ENGINE=innodb; +CREATE TABLE t5 (a INT, b VARCHAR(20)) ENGINE=innodb; +CREATE TABLE t6 (a INT, b VARCHAR(20)) ENGINE=innodb; + +sync_slave_with_master; +source include/stop_slave.inc; + +connection master; +BEGIN; +INSERT INTO t4 VALUES (2, 'master only'); +INSERT INTO t5 VALUES (2, 'master only'); +INSERT INTO t6 VALUES (2, 'master only'); +COMMIT; + +BEGIN; +INSERT INTO t4 VALUES (3, 'master/slave'); +INSERT INTO t5 VALUES (3, 'master/slave'); +INSERT INTO t6 VALUES (3, 'master/slave'); +COMMIT; + +SELECT * FROM t4 ORDER BY a; +SELECT * FROM t5 ORDER BY a; +SELECT * FROM t6 ORDER BY a; + +save_master_pos; + +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +source include/start_slave.inc; +sync_with_master; + +SELECT * FROM t4 ORDER BY a; +SELECT * FROM t5 ORDER BY a; +SELECT * FROM t6 ORDER BY a; + +# Test skipping two groups + +connection slave; +source include/stop_slave.inc; + +connection master; +BEGIN; +INSERT INTO t4 VALUES (6, 'master only'); +INSERT INTO t5 VALUES (6, 'master only'); +INSERT INTO t6 VALUES (6, 'master only'); +COMMIT; + +BEGIN; +INSERT INTO t4 VALUES (7, 'master only'); +INSERT INTO t5 VALUES (7, 'master only'); +INSERT INTO t6 VALUES (7, 'master only'); +COMMIT; + +SELECT * FROM t4 ORDER BY a; +SELECT * FROM t5 ORDER BY a; +SELECT * FROM t6 ORDER BY a; + +save_master_pos; + +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=12; +source include/start_slave.inc; +sync_with_master; + +SELECT * FROM t4 ORDER BY a; +SELECT * FROM t5 ORDER BY a; +SELECT * FROM t6 ORDER BY a; + +# +# And the same, but with autocommit = 0 +# +connection slave; +source include/stop_slave.inc; + +connection master; +SET AUTOCOMMIT=0; + +INSERT INTO t4 VALUES (4, 'master only'); +INSERT INTO t5 VALUES (4, 'master only'); +INSERT INTO t6 VALUES (4, 'master only'); +COMMIT; + +INSERT INTO t4 VALUES (5, 'master/slave'); +INSERT INTO t5 VALUES (5, 'master/slave'); +INSERT INTO t6 VALUES (5, 'master/slave'); +COMMIT; + +SELECT * FROM t4 ORDER BY a; +SELECT * FROM t5 ORDER BY a; +SELECT * FROM t6 ORDER BY a; + +save_master_pos; + +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +source include/start_slave.inc; +sync_with_master; + +SELECT * FROM t4 ORDER BY a; +SELECT * FROM t5 ORDER BY a; +SELECT * FROM t6 ORDER BY a; + +connection master; +DROP TABLE t4, t5, t6; +sync_slave_with_master; + +--echo **** Case 3: Statement logging format and LOAD DATA with non-transactional table **** + +# LOAD DATA creates two events in binary log for statement binlog format. +# Try to skip the first. + +connection master; +CREATE TABLE t10 (a INT, b VARCHAR(20)) ENGINE=myisam; + +sync_slave_with_master; +source include/stop_slave.inc; + +connection master; +SET SESSION BINLOG_FORMAT=STATEMENT; + +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/std_data/rpl_bug28618.dat' INTO TABLE t10 FIELDS TERMINATED BY '|'; + +SELECT * FROM t10 ORDER BY a; + +save_master_pos; + +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +source include/start_slave.inc; +sync_with_master; + +SELECT * FROM t10 ORDER BY a; + +connection master; +DROP TABLE t10; +sync_slave_with_master; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_slave_status.test b/mysql-test/suite/rpl/t/rpl_slave_status.test new file mode 100644 index 00000000..63e37216 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_slave_status.test @@ -0,0 +1,81 @@ +# ==== Purpose ==== +# +# Verify that a slave without replication privileges has +# Slave_IO_Running = No +# Check that relay_log_status doesn't change by CHANGE MASTER +# ==== Method ==== +# +# We do the following steps: +# - Create a new replication user on master +# - Connect to slave and start replication as this user. +# - Verify that slave can replicate well, by creating a table and +# inserting a row into it. +# - Delete the user from the master. +# - Stop and start the slave (this should fail). +# - Check the Slave_IO_Running column of SHOW SLAVE STATUS. +# +# ==== Related bugs ==== +# +# BUG#10780: slave can't connect to master - IO and SQL threads running + +--source include/master-slave.inc + +--echo ==== Create new replication user ==== +connection master; +GRANT REPLICATION SLAVE ON *.* TO rpl@127.0.0.1 IDENTIFIED BY 'rpl'; + +sync_slave_with_master; +source include/stop_slave.inc; + +# Test that relay_log_purge doesn't change because of CHANGE MASTER +set @save_relay_log_purge=@@global.relay_log_purge; +set @@global.relay_log_purge=0; +CHANGE MASTER TO master_user='rpl', master_password='rpl'; +select @@global.relay_log_purge; +set @@global.relay_log_purge=1; +CHANGE MASTER TO master_user='rpl', master_password='rpl'; +select @@global.relay_log_purge; +set @@global.relay_log_purge=@save_relay_log_purge; + +CHANGE MASTER TO master_user='rpl', master_password='rpl'; +source include/start_slave.inc; + +--echo ==== Do replication as new user ==== +connection master; +CREATE TABLE t1 (n INT); +INSERT INTO t1 VALUES (1); +sync_slave_with_master; +SELECT * FROM t1; + +--echo ==== Delete new replication user ==== +connection master; +DROP USER rpl@127.0.0.1; +FLUSH PRIVILEGES; + +sync_slave_with_master; + +--echo ==== Restart slave without privileges ===== +# (slave.err will contain access denied error for this START SLAVE command) +source include/stop_slave.inc; +START SLAVE; +source include/wait_for_slave_sql_to_start.inc; +source include/wait_for_slave_io_to_stop.inc; + +--echo ==== Verify that Slave IO thread stopped with error ==== +# 1045 = ER_ACCESS_DENIED_ERROR +--let $slave_io_errno= 1045 +--source include/wait_for_slave_io_error.inc + +--echo ==== Cleanup (Note that slave IO thread is not running) ==== + +# cleanup: slave io thread has is stopped so we reset replication +--source include/stop_slave_sql.inc +CHANGE MASTER TO MASTER_USER = 'root', MASTER_PASSWORD = ''; +# clear Slave_IO_Errno +--let $rpl_only_running_threads= 1 +--source include/rpl_reset.inc + +connection master; +DROP TABLE t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_slow_query_log-slave.opt b/mysql-test/suite/rpl/t/rpl_slow_query_log-slave.opt new file mode 100644 index 00000000..43911726 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_slow_query_log-slave.opt @@ -0,0 +1 @@ +--log-slow-slave-statements --slow-query-log diff --git a/mysql-test/suite/rpl/t/rpl_slow_query_log.test b/mysql-test/suite/rpl/t/rpl_slow_query_log.test new file mode 100644 index 00000000..2d5d08a4 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_slow_query_log.test @@ -0,0 +1,345 @@ +# +# BUG#23300: Slow query log on slave does not log slow replicated statements +# +# Description: +# The slave should log slow queries replicated from master when +# --log-slow-slave-statements is used. +# +# Test is implemented as follows: +# i) stop slave +# ii) On slave, set long_query_time to a small value. +# ii) start slave so that long_query_time variable is picked by sql thread +# iii) On master, do one short time query and one long time query, on slave +# and check that slow query is logged to slow query log but fast query +# is not. +# iv) On slave, check that slow queries go into the slow log and fast don't, +# when issued through a regular client connection +# v) On slave, check that slow queries go into the slow log and fast don't +# when we use SET TIMESTAMP= 1 on a regular client connection. +# vi) check that when setting slow_query_log= OFF in a connection 'extra2' +# prevents logging slow queries in a connection 'extra' +# +# OBS: +# This test only runs for statement binlogging format because on row format +# slow queries do not get slow query logged. +# Note that due to the sleep() command the insert is written to the binary +# log in row format. + +source include/have_binlog_format_statement.inc; +source include/master-slave.inc; + +CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); +call mtr.add_suppression("Slave SQL.*Request to stop slave SQL Thread received while applying a group that has non-transactional changes; waiting for completion of the group"); + +# Prepare slave for different long_query_time we need to stop the slave +# and restart it as long_query_time variable is dynamic and, after +# setting it, it only takes effect on new connections. +# +# Reference: +# http://dev.mysql.com/doc/refman/6.0/en/set-option.html +connection slave; + +source include/stop_slave.inc; + +SET @old_log_output= @@log_output; +SET GLOBAL log_output= 'TABLE'; +SET @old_long_query_time= @@long_query_time; +SET GLOBAL long_query_time= 2; +TRUNCATE mysql.slow_log; + +source include/start_slave.inc; + +--disable_ps2_protocol +connection master; +CREATE TABLE t1 (a int, b int); + +# test: +# check that slave logs the slow query to the slow log, but not the fast one. + +let $slow_query= INSERT INTO t1 values(1, sleep(3)); +let $fast_query= INSERT INTO t1 values(1, 1); + +eval $fast_query; +--disable_warnings +eval $slow_query; +--enable_warnings +sync_slave_with_master; + +let $found_fast_query= `SELECT count(*) = 1 FROM mysql.slow_log WHERE sql_text like '$fast_query'`; +let $found_slow_query= `SELECT count(*) = 1 FROM mysql.slow_log WHERE sql_text like '$slow_query'`; + +if ($found_fast_query) +{ + SELECT * FROM mysql.slow_log; + die "Assertion failed! Fast query FOUND in slow query log. Bailing out!"; +} + +if (!$found_slow_query) +{ + SELECT * FROM mysql.slow_log; + die "Assertion failed! Slow query NOT FOUND in slow query log. Bailing out!"; +} +TRUNCATE mysql.slow_log; + +# regular checks for slow query log (using a new connection - 'extra' - to slave) + +# test: +# when using direct connections to the slave, check that slow query is logged +# but not the fast one. + +connect(extra,127.0.0.1,root,,test,$SLAVE_MYPORT); +connection extra; + +let $fast_query= SELECT 1; +let $slow_query= SELECT 1, sleep(3); + +eval $slow_query; +eval $fast_query; + +let $found_fast_query= `SELECT count(*) = 1 FROM mysql.slow_log WHERE sql_text like '$fast_query'`; +let $found_slow_query= `SELECT count(*) = 1 FROM mysql.slow_log WHERE sql_text like '$slow_query'`; + +if ($found_fast_query) +{ + SELECT * FROM mysql.slow_log; + die "Assertion failed! Fast query FOUND in slow query log. Bailing out!"; +} + +if (!$found_slow_query) +{ + SELECT * FROM mysql.slow_log; + die "Assertion failed! Slow query NOT FOUND in slow query log. Bailing out!"; +} +TRUNCATE mysql.slow_log; + +# test: +# when using direct connections to the slave, check that when setting timestamp to 1 the +# slow query is logged but the fast one is not. + +let $fast_query= SELECT 2; +let $slow_query= SELECT 2, sleep(3); + +SET TIMESTAMP= 1; +eval $slow_query; +eval $fast_query; + +let $found_fast_query= `SELECT count(*) = 1 FROM mysql.slow_log WHERE sql_text like '$fast_query'`; +let $found_slow_query= `SELECT count(*) = 1 FROM mysql.slow_log WHERE sql_text like '$slow_query'`; + +if ($found_fast_query) +{ + SELECT * FROM mysql.slow_log; + die "Assertion failed! Fast query FOUND in slow query log. Bailing out!"; +} + +if (!$found_slow_query) +{ + SELECT * FROM mysql.slow_log; + die "Assertion failed! Slow query NOT FOUND in slow query log. Bailing out!"; +} +TRUNCATE mysql.slow_log; + +# test: +# check that when setting the slow_query_log= OFF on connection 'extra2' +# prevents connection 'extra' from logging to slow query log. + +let $fast_query= SELECT 3; +let $slow_query= SELECT 3, sleep(3); + +connect(extra2,127.0.0.1,root,,test,$SLAVE_MYPORT); +connection extra2; + +SET @old_slow_query_log= @@slow_query_log; +SET GLOBAL slow_query_log= 'OFF'; + +connection extra; + +eval $slow_query; +eval $fast_query; + +let $found_fast_query= `SELECT count(*) = 1 FROM mysql.slow_log WHERE sql_text like '$fast_query'`; +let $found_slow_query= `SELECT count(*) = 1 FROM mysql.slow_log WHERE sql_text like '$slow_query'`; + +if ($found_fast_query) +{ + SELECT * FROM mysql.slow_log; + die "Assertion failed! Fast query FOUND in slow query log when slow_query_log= OFF. Bailing out!"; +} + +if ($found_slow_query) +{ + SELECT * FROM mysql.slow_log; + die "Assertion failed! Slow query FOUND in slow query log when slow_query_log= OFF. Bailing out!"; +} +TRUNCATE mysql.slow_log; + +# clean up: drop tables, reset the variables back to the previous value, +# disconnect extra connections +connection extra2; + +SET GLOBAL slow_query_log= @old_slow_query_log; + +connection master; +DROP TABLE t1; +sync_slave_with_master; + +source include/stop_slave.inc; + +SET GLOBAL long_query_time= @old_long_query_time; +SET GLOBAL log_output= @old_log_output; + +source include/start_slave.inc; + +disconnect extra; +disconnect extra2; + +# +# BUG#50620: Adding an index to a table prevents slave from logging into slow log +# + +--source include/rpl_reset.inc + +-- connection master +SET @old_log_output= @@log_output; +SET GLOBAL log_output= 'TABLE'; +SET GLOBAL long_query_time= 2; +SET @old_long_query_time= @@long_query_time; +SET SESSION long_query_time= 2; +TRUNCATE mysql.slow_log; +-- connection slave + +-- source include/stop_slave.inc +SET @old_log_output= @@log_output; +SET GLOBAL log_output= 'TABLE'; +SET @old_long_query_time= @@long_query_time; +SET GLOBAL long_query_time= 2; +TRUNCATE mysql.slow_log; +-- source include/start_slave.inc + +let $slow_query= INSERT INTO t1 values(1, sleep(3)); + +-- connection master +CREATE TABLE t1 (a int, b int); + +-- echo ******************************************************************** +-- echo **** INSERT one row that exceeds long_query_time +-- echo **** Outcome: query ends up in both master and slave slow log +-- echo ******************************************************************** + +-- disable_warnings +-- eval $slow_query +-- enable_warnings + +let $master_slow_query= `SELECT count(*) = 1 FROM mysql.slow_log WHERE sql_text like '$slow_query'`; +-- sync_slave_with_master +let $slave_slow_query= `SELECT count(*) = 1 FROM mysql.slow_log WHERE sql_text like '$slow_query'`; + +if ($master_slow_query != $slave_slow_query) +{ + -- connection master + -- echo *********************************************** + -- echo ** DUMPING MASTER SLOW LOG CONTENTS + -- echo *********************************************** + SELECT * FROM mysql.slow_log; + + -- connection slave + -- echo *********************************************** + -- echo ** DUMPING SLAVE SLOW LOG CONTENTS + -- echo *********************************************** + SELECT * FROM mysql.slow_log; + + -- die "Assertion failed! Master and slave slow log contents differ. Bailing out!" +} + +if ($master_slow_query == $slave_slow_query) +{ + -- echo ### Assertion is good. Both Master and Slave exhibit the + -- echo ### same number of queries in slow log: $master_slow_query +} + +TRUNCATE mysql.slow_log; +-- connection master +TRUNCATE mysql.slow_log; + +-- echo ******************************************************************** +-- echo **** Now do inserts again, but first add an index to the table. +-- echo **** Outcome: Note that the slave contains the same one entry (as +-- echo **** the master does) whereas before the patch it did not. +-- echo ******************************************************************** + +ALTER TABLE t1 ADD INDEX id1(a); + +-- disable_warnings +-- eval $slow_query +-- enable_warnings + +let $master_slow_query= `SELECT count(*) = 1 FROM mysql.slow_log WHERE sql_text like '$slow_query'`; +-- sync_slave_with_master +let $slave_slow_query= `SELECT count(*) = 1 FROM mysql.slow_log WHERE sql_text like '$slow_query'`; + +if ($master_slow_query != $slave_slow_query) +{ + -- connection master + -- echo *********************************************** + -- echo ** DUMPING MASTER SLOW LOG CONTENTS + -- echo *********************************************** + SELECT * FROM mysql.slow_log; + + -- connection slave + -- echo *********************************************** + -- echo ** DUMPING SLAVE SLOW LOG CONTENTS + -- echo *********************************************** + SELECT * FROM mysql.slow_log; + + -- die "Assertion failed! Master and slave slow log contents differ. Bailing out!" +} + +if ($master_slow_query == $slave_slow_query) +{ + -- echo ### Assertion is good. Both Master and Slave exhibit the + -- echo ### same number of queries in slow log: $master_slow_query +} + +-- echo ******************************************************************** +-- echo **** TRUNCATE the slow log then check whether runtime changes of +-- echo **** log_slow_slave_statements work without slave restart. +-- echo ******************************************************************** + +SET @old_log_slow_slave_statements= @@global.log_slow_slave_statements; +SET @@global.log_slow_slave_statements = off; +TRUNCATE mysql.slow_log; + +-- connection master + +--disable_warnings +-- eval $slow_query; +--enable_warnings +sync_slave_with_master; + +-- connection slave + +eval SELECT sql_text FROM mysql.slow_log WHERE sql_text like '$slow_query'; + +SET @@global.log_slow_slave_statements = on; + +-- connection master + +--disable_warnings +-- eval $slow_query; +--enable_warnings +sync_slave_with_master; + +-- connection slave + +eval SELECT sql_text FROM mysql.slow_log WHERE sql_text like '$slow_query'; + +-- connection master +SET @@global.log_output= @old_log_output; +SET @@global.long_query_time= @old_long_query_time; +DROP TABLE t1; + +-- sync_slave_with_master +SET @@global.log_output= @old_log_output; +SET @@global.long_query_time= @old_long_query_time; +--source include/rpl_end.inc +--enable_ps2_protocol diff --git a/mysql-test/suite/rpl/t/rpl_sp-master.opt b/mysql-test/suite/rpl/t/rpl_sp-master.opt new file mode 100644 index 00000000..18c5c969 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_sp-master.opt @@ -0,0 +1 @@ +--log_bin_trust_function_creators=0 diff --git a/mysql-test/suite/rpl/t/rpl_sp-slave.opt b/mysql-test/suite/rpl/t/rpl_sp-slave.opt new file mode 100644 index 00000000..18c5c969 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_sp-slave.opt @@ -0,0 +1 @@ +--log_bin_trust_function_creators=0 diff --git a/mysql-test/suite/rpl/t/rpl_sp.test b/mysql-test/suite/rpl/t/rpl_sp.test new file mode 100644 index 00000000..12619a00 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_sp.test @@ -0,0 +1,732 @@ +# row-based and statement have expected binlog difference in result files + +# Test of replication of stored procedures (WL#2146 for MySQL 5.0) +# Modified by WL#2971. + +source include/have_binlog_format_mixed.inc; +source include/master-slave.inc; + +set local sql_mode=''; +# we need a db != test, where we don't have automatic grants +--disable_warnings +drop database if exists mysqltest1; +--enable_warnings +create database mysqltest1; +use mysqltest1; +create table t1 (a varchar(100)); +sync_slave_with_master; +use mysqltest1; + +# ********************** PART 1 : STORED PROCEDURES *************** + +# Does the same proc as on master get inserted into mysql.proc ? +# (same definer, same properties...) + +connection master; + +delimiter |; + +# Stored procedures don't have the limitations that functions have +# regarding binlogging: it's ok to create a procedure as not +# deterministic and updating data, while it's not ok to create such a +# function. We test this. + +create procedure foo() +begin + declare b int; + set b = 8; + insert into t1 values (b); + insert into t1 values (unix_timestamp()); +end| +delimiter ;| + +# we replace columns having times +# (even with fixed timestamp displayed time may changed based on TZ) +--replace_result localhost.localdomain localhost 127.0.0.1 localhost +--replace_column 13 # 14 # +select * from mysql.proc where name='foo' and db='mysqltest1'; +sync_slave_with_master; +# You will notice in the result that the definer does not match what +# it is on master, it is a known bug on which Alik is working +--replace_result localhost.localdomain localhost 127.0.0.1 localhost +--replace_column 13 # 14 # +select * from mysql.proc where name='foo' and db='mysqltest1'; + +connection master; +# see if timestamp used in SP on slave is same as on master +set timestamp=1000000000; +call foo(); +select * from t1; +sync_slave_with_master; +select * from t1; + +# Now a SP which is not updating tables + +connection master; +delete from t1; +create procedure foo2() + select * from mysqltest1.t1; +call foo2(); + +# check that this is allowed (it's not for functions): +alter procedure foo2 contains sql; + +# SP with definer's right + +drop table t1; +create table t1 (a int); +create table t2 like t1; + +create procedure foo3() + deterministic + insert into t1 values (15); + +# let's create a non-privileged user +grant CREATE ROUTINE, EXECUTE on mysqltest1.* to "zedjzlcsjhd"@127.0.0.1; +grant SELECT on mysqltest1.t1 to "zedjzlcsjhd"@127.0.0.1; +grant SELECT, INSERT on mysqltest1.t2 to "zedjzlcsjhd"@127.0.0.1; + +# ToDo: BUG#14931: There is a race between the last grant binlogging, and +# the binlogging in the new connection made below, causing sporadic test +# failures due to switched statement order in binlog. To fix this we do +# SELECT 1 in the first connection before starting the second, ensuring +# that binlogging is done in the expected order. +# Please remove this SELECT 1 when BUG#14931 is fixed. +SELECT 1; + +connect (con1,127.0.0.1,zedjzlcsjhd,,mysqltest1,$MASTER_MYPORT,); +connection con1; + +# this routine will fail in the second INSERT because of privileges +delimiter |; +create procedure foo4() + deterministic + begin + insert into t2 values(3); + insert into t1 values (5); + end| + +delimiter ;| + +# I add ,0 so that it does not print the error in the test output, +# because this error is hostname-dependent +--error 1142,0 +call foo4(); # invoker has no INSERT grant on table t1 => failure + +connection master; +call foo3(); # success (definer == root) +show warnings; + +--error 1142,0 +call foo4(); # definer's rights => failure + +# we test replication of ALTER PROCEDURE +alter procedure foo4 sql security invoker; +call foo4(); # invoker's rights => success +show warnings; + +# Note that half-failed procedure calls are ok with binlogging; +# if we compare t2 on master and slave we see they are identical: + +select * from t1; +select * from t2; +sync_slave_with_master; +select * from t1; +select * from t2; + +# Let's check another failing-in-the-middle procedure +connection master; +delete from t2; +alter table t2 add unique (a); + +drop procedure foo4; +delimiter |; +create procedure foo4() + deterministic + begin + insert into t2 values(20),(20); + end| + +delimiter ;| + +--error ER_DUP_ENTRY +call foo4(); +show warnings; + +select * from t2; +sync_slave_with_master; +# check that this failed-in-the-middle replicated right: +select * from t2; + +# Test of DROP PROCEDURE + +--replace_result localhost.localdomain localhost 127.0.0.1 localhost +--replace_column 13 # 14 # +select * from mysql.proc where name="foo4" and db='mysqltest1'; +connection master; +drop procedure foo4; +select * from mysql.proc where name="foo4" and db='mysqltest1'; +sync_slave_with_master; +select * from mysql.proc where name="foo4" and db='mysqltest1'; + +# ********************** PART 2 : FUNCTIONS *************** + +connection master; +drop procedure foo; +drop procedure foo2; +drop procedure foo3; + +delimiter |; +# check that needs "deterministic" +--error 1418 +create function fn1(x int) + returns int +begin + insert into t1 values (x); + return x+2; +end| +create function fn1(x int) + returns int + deterministic +begin + insert into t1 values (x); + return x+2; +end| + +delimiter ;| +delete t1,t2 from t1,t2; +--disable_ps2_protocol +select fn1(20); +--enable_ps2_protocol +insert into t2 values(fn1(21)); +--sorted_result +select * from t1; +select * from t2; +sync_slave_with_master; +--sorted_result +select * from t1; +select * from t2; + +connection master; +delimiter |; + +drop function fn1| + +create function fn1() + returns int + no sql +begin + return unix_timestamp(); +end| + +delimiter ;| +# check that needs "deterministic" +--error 1418 +alter function fn1 contains sql; + +delete from t1; +set timestamp=1000000000; +insert into t1 values(fn1()); + +connection con1; + +delimiter |; +--error 1419 # only full-global-privs user can create a function +create function fn2() + returns int + no sql +begin + return unix_timestamp(); +end| +delimiter ;| +connection master; +set @old_log_bin_trust_function_creators= @@global.log_bin_trust_function_creators; +set global log_bin_trust_function_creators=0; +set global log_bin_trust_function_creators=1; +# slave needs it too otherwise will not execute what master allowed: +connection slave; +set @old_log_bin_trust_function_creators= @@global.log_bin_trust_function_creators; +set global log_bin_trust_function_creators=1; + +connection con1; + +delimiter |; +create function fn2() + returns int + no sql +begin + return unix_timestamp(); +end| +delimiter ;| + +connection master; + +# Now a function which is supposed to not update tables +# as it's "reads sql data", so should not give error even if +# non-deterministic. + +delimiter |; +create function fn3() + returns int + not deterministic + reads sql data +begin + return 0; +end| +delimiter ;| + +select fn3(); +--replace_result localhost.localdomain localhost 127.0.0.1 localhost +--replace_column 13 # 14 # +select * from mysql.proc where db='mysqltest1'; +select * from t1; + +sync_slave_with_master; +use mysqltest1; +select * from t1; +--replace_result localhost.localdomain localhost 127.0.0.1 localhost +--replace_column 13 # 14 # +select * from mysql.proc where db='mysqltest1'; + +# Let's check a failing-in-the-middle function +connection master; +delete from t2; +alter table t2 add unique (a); + +drop function fn1; + +delimiter |; +create function fn1(x int) + returns int +begin + insert into t2 values(x),(x); + return 10; +end| + +delimiter ;| + +do fn1(100); + +--error ER_DUP_ENTRY +select fn1(20); + +select * from t2; +sync_slave_with_master; + +# check that this failed-in-the-middle replicated right: +select * from t2; + +# ********************** PART 3 : TRIGGERS *************** + +connection con1; +# now fails due to missing trigger grant (err 1142 i/o 1227) due to new +# check in sql_trigger.cc (v1.44) by anozdrin on 2006/02/01 --azundris +--error ER_TABLEACCESS_DENIED_ERROR +create trigger trg before insert on t1 for each row set new.a= 10; + +connection master; +delete from t1; +# TODO: when triggers can contain an update, test that this update +# does not go into binlog. +# I'm not setting user vars in the trigger, because replication of user vars +# would take care of propagating the user var's value to slave, so even if +# the trigger was not executed on slave it would not be discovered. +create trigger trg before insert on t1 for each row set new.a= 10; +insert into t1 values (1); +select * from t1; +sync_slave_with_master; +select * from t1; + +connection master; +delete from t1; +drop trigger trg; +insert into t1 values (1); +select * from t1; +sync_slave_with_master; +select * from t1; + + +# ********************** PART 4 : RELATED FIXED BUGS *************** + + +# +# Test for bug #13969 "Routines which are replicated from master can't be +# executed on slave". +# +connection master; +create procedure foo() + not deterministic + reads sql data + select * from t1; +sync_slave_with_master; +# This should not fail +call foo(); +connection master; +drop procedure foo; +sync_slave_with_master; + + +# Clean up +connection master; +drop function fn1; +drop database mysqltest1; +drop user "zedjzlcsjhd"@127.0.0.1; +use test; +sync_slave_with_master; +use test; + +# +# Bug#14077 "Failure to replicate a stored function with a cursor": +# verify that stored routines with cursors work on slave. +# +connection master; +--disable_warnings +drop function if exists f1; +--enable_warnings +delimiter |; +create function f1() returns int reads sql data +begin + declare var integer; + declare c cursor for select a from v1; + open c; + fetch c into var; + close c; + return var; +end| +delimiter ;| +create view v1 as select 1 as a; +create table t1 (a int); +insert into t1 (a) values (f1()); +select * from t1; +drop view v1; +drop function f1; +sync_slave_with_master; +connection slave; +select * from t1; + +# +# Bug#16621 "INSERTs in Stored Procedures causes data corruption in the Binary +# Log for 5.0.18" +# + +# Prepare environment. + +connection master; + +--disable_warnings +DROP PROCEDURE IF EXISTS p1; +DROP TABLE IF EXISTS t1; +--enable_warnings + +# Test case. + +CREATE TABLE t1(col VARCHAR(10)); + +CREATE PROCEDURE p1(arg VARCHAR(10)) + INSERT INTO t1 VALUES(arg); + +CALL p1('test'); + +SELECT * FROM t1; + +sync_slave_with_master; +SELECT * FROM t1; + +# Cleanup +connection master; +DROP PROCEDURE p1; + + +# +# BUG#20438: CREATE statements for views, stored routines and triggers can be +# not replicable. +# + +--echo +--echo ---> Test for BUG#20438 + +# Prepare environment. + +--echo +--echo ---> Preparing environment... +--connection master + +--disable_warnings +DROP PROCEDURE IF EXISTS p1; +DROP FUNCTION IF EXISTS f1; +--enable_warnings + +--echo +--echo ---> Synchronizing slave with master... + +--sync_slave_with_master + +--connection master + +# Test. + +--echo +--echo ---> Creating procedure... + +/*!50003 CREATE PROCEDURE p1() SET @a = 1 */; + +/*!50003 CREATE FUNCTION f1() RETURNS INT RETURN 0 */; + +--echo +--echo ---> Checking on master... + +SHOW CREATE PROCEDURE p1; +SHOW CREATE FUNCTION f1; + +--echo +--echo ---> Synchronizing slave with master... + +--sync_slave_with_master + +--echo +--echo ---> Checking on slave... + +SHOW CREATE PROCEDURE p1; +SHOW CREATE FUNCTION f1; + +# Cleanup. + +--connection master + +--echo +--echo ---> Cleaning up... + +DROP PROCEDURE p1; +DROP FUNCTION f1; + +--sync_slave_with_master +--connection master + + +# cleanup +connection master; +drop table t1; +sync_slave_with_master; + +# +# Bug22043: MySQL don't add "USE <DATABASE>" before "DROP PROCEDURE IF EXISTS" +# + +connection master; +--disable_warnings +drop database if exists mysqltest; +drop database if exists mysqltest2; +--enable_warnings +create database mysqltest; +create database mysqltest2; +use mysqltest2; +create table t ( t integer ); +create procedure mysqltest.test() begin end; +insert into t values ( 1 ); +--error ER_BAD_DB_ERROR +create procedure `\\`.test() begin end; + +# +# BUG#19725: Calls to stored function in other database are not +# replicated correctly in some cases +# + +connection master; +delimiter |; +create function f1 () returns int +begin + insert into t values (1); + return 0; +end| +delimiter ;| +sync_slave_with_master; +# Let us test if we don't forget to binlog the function's database +connection master; +use mysqltest; +set @a:= mysqltest2.f1(); +sync_slave_with_master; +connection master; + +# Final inspection which verifies how all statements of this test file +# were written to the binary log. +--source include/show_binlog_events.inc + + +# Restore log_bin_trust_function_creators to its original value. +# This is a cleanup for all parts above where we tested stored +# functions and triggers. +connection slave; +set @@global.log_bin_trust_function_creators= @old_log_bin_trust_function_creators; +connection master; +set @@global.log_bin_trust_function_creators= @old_log_bin_trust_function_creators; + +# Clean up +drop database mysqltest; +drop database mysqltest2; +sync_slave_with_master; + +# +# Bug#36570: Parse error of CREATE PROCEDURE stmt with comments on slave +# +connection master; +use test; +delimiter |; + +/*!50001 create procedure `mysqltestbug36570_p1`() */ +begin + select 1; +end| + +use mysql| +create procedure test.` mysqltestbug36570_p2`(/*!50001 a int*/)`label`: +begin + select a; +end| + +/*!50001 create function test.mysqltestbug36570_f1() */ + returns int + /*!50001 deterministic */ +begin + return 3; +end| +use test| + +delimiter ;| + +--replace_column 5 t 6 t +show procedure status like '%mysqltestbug36570%'; +show create procedure ` mysqltestbug36570_p2`; + +sync_slave_with_master; +connection slave; + +--replace_column 5 t 6 t +show procedure status like '%mysqltestbug36570%'; +show create procedure ` mysqltestbug36570_p2`; +call ` mysqltestbug36570_p2`(42); + +--replace_column 5 t 6 t +show function status like '%mysqltestbug36570%'; + +connection master; +flush logs; +let $MYSQLD_DATADIR= `select @@datadir`; +--replace_regex /$MYSQL_TEST_DIR/MYSQL_TEST_DIR/ /TIMESTAMP=[0-9]*/TIMESTAMP=t/ +--exec $MYSQL_BINLOG --short-form $MYSQLD_DATADIR/master-bin.000001 +use test; +drop procedure mysqltestbug36570_p1; +drop procedure ` mysqltestbug36570_p2`; +drop function mysqltestbug36570_f1; +--echo End of 5.0 tests +--echo # End of 5.1 tests +--echo # +--echo # Test Bug#30977 Concurrent statement using stored +--echo # function and DROP FUNCTION breaks SBR. +--echo # +--echo # Demonstrate that stored function DDL can not go through, +--echo # or, worse yet, make its way into the binary log, while +--echo # the stored function is in use. +--echo # For that, try to insert a result of a stored function +--echo # into a table. Block the insert in the beginning, waiting +--echo # on a table lock. While insert is blocked, attempt to +--echo # drop the routine. Verify that this attempt +--echo # blocks and waits for INSERT to complete. Commit and +--echo # reap the chain of events. Master and slave must contain +--echo # identical data. Statements in the binrary log must be +--echo # consistent with data in the table. +--echo # +connection default; +--disable_warnings +drop table if exists t1, t2; +drop function if exists t1; +--enable_warnings +create table t1 (a int); +create table t2 (a int) as select 1 as a; +create function f1() returns int deterministic return (select max(a) from t2); +lock table t2 write; +connection master; +--echo # Sending 'insert into t1 (a) values (f1())'... +--send insert into t1 (a) values (f1()) +connection master1; +--echo # Waitng for 'insert into t1 ...' to get blocked on table lock... +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='Waiting for table metadata lock' and + info='insert into t1 (a) values (f1())'; +--source include/wait_condition.inc +--echo # Sending 'drop function f1'. It will wait till insert finishes. +--send drop function f1; +connection default; +--echo # Check that 'drop function f1' gets blocked. +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='Waiting for stored function metadata lock' and info='drop function f1'; +--source include/wait_condition.inc +--echo # Now let's let 'insert' go through... +unlock tables; +connection master; +--echo # Reaping 'insert into t1 (a) values (f1())'... +--reap +connection master1; +--echo # Reaping 'drop function f1' +--reap +connection master; +select * from t1; +sync_slave_with_master; +connection slave; +select * from t1; +# Cleanup +connection master; +drop table t1, t2; +--error ER_SP_DOES_NOT_EXIST +drop function f1; + + +--echo # +--echo # Bug #11918 Can't use a declared variable in LIMIT clause +--echo # +--source include/rpl_reset.inc + +create table t1 (c1 int); +insert into t1 (c1) values +(1), (2), (3), (4), (5), (6), (7), (8), (9), (10); + +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); + +create procedure p1(p1 integer) + delete from t1 limit p1; + +set @save_binlog_format=@@session.binlog_format; +set @@session.binlog_format=STATEMENT; + +--disable_warnings +call p1(NULL); +call p1(0); +call p1(1); +call p1(2); +call p1(3); +--enable_warnings + +select * from t1; +sync_slave_with_master; +connection slave; +select * from t1; +connection master; +--disable_warnings +call p1(-1); +--enable_warnings +select * from t1; +sync_slave_with_master; +connection slave; +select * from t1; +connection master; + +--echo # Cleanup +set @@session.binlog_format=@save_binlog_format; +drop table t1; +drop procedure p1; + +--echo # End of 5.5 tests. + + +# Cleanup +sync_slave_with_master; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_sp004.test b/mysql-test/suite/rpl/t/rpl_sp004.test new file mode 100644 index 00000000..31e4ce37 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_sp004.test @@ -0,0 +1,92 @@ +############################################################################# +# Original Author: JBM # +# Original Date: Aug/14/2005 # +############################################################################# +# Test: This test contains two sp that create and drop tables, insert and # +# updated data and uses the NOW() function. # +############################################################################# + + +# Includes +-- source include/master-slave.inc + + +# Begin clean up test section +connection master; +--disable_warnings +DROP PROCEDURE IF EXISTS test.p1; +DROP PROCEDURE IF EXISTS test.p2; +DROP TABLE IF EXISTS test.t2; +DROP TABLE IF EXISTS test.t1; +DROP TABLE IF EXISTS test.t3; +--enable_warnings +# End of cleanup + +# Begin test section 1 + +delimiter |; +CREATE PROCEDURE test.p1() +BEGIN + CREATE TABLE IF NOT EXISTS test.t1(a INT,PRIMARY KEY(a)); + CREATE TABLE IF NOT EXISTS test.t2(a INT,PRIMARY KEY(a)); + INSERT INTO test.t1 VALUES (4),(2),(1),(3); + UPDATE test.t1 SET a=a+4 WHERE a=4; + INSERT INTO test.t2 (a) SELECT t1.a FROM test.t1; + UPDATE test.t1 SET a=a+4 WHERE a=8; + CREATE TABLE IF NOT EXISTS test.t3(n MEDIUMINT NOT NULL AUTO_INCREMENT, f FLOAT, d DATETIME, PRIMARY KEY(n)); +END| +CREATE PROCEDURE test.p2() +BEGIN + DROP TABLE IF EXISTS test.t1; + DROP TABLE IF EXISTS test.t2; + INSERT INTO test.t3 VALUES(NULL,11111111.233333,NOW()); +END| +delimiter ;| + +CALL test.p1(); +SELECT * FROM test.t1 ORDER BY a; +SELECT * FROM test.t2 ORDER BY a; +sync_slave_with_master; +SELECT * FROM test.t1 ORDER BY a; +SELECT * FROM test.t2 ORDER BY a; + +connection master; +CALL test.p2(); +USE test; +SHOW TABLES; +#SELECT * FROM test.t3; +sync_slave_with_master; +USE test; +SHOW TABLES; +#SELECT * FROM test.t3; + +connection master; +CALL test.p1(); +SELECT * FROM test.t1 ORDER BY a; +SELECT * FROM test.t2 ORDER BY a; +#SELECT * FROM test.t3; +sync_slave_with_master; +SELECT * FROM test.t1 ORDER BY a; +SELECT * FROM test.t2 ORDER BY a; +#SELECT * FROM test.t3; + +--exec $MYSQL_DUMP --compact --order-by-primary --skip-extended-insert --no-create-info test > $MYSQLTEST_VARDIR/tmp/sp004_master.sql +--exec $MYSQL_DUMP_SLAVE --compact --order-by-primary --skip-extended-insert --no-create-info test > $MYSQLTEST_VARDIR/tmp/sp004_slave.sql + +# Cleanup +connection master; +#show binlog events; +DROP PROCEDURE IF EXISTS test.p1; +DROP PROCEDURE IF EXISTS test.p2; +DROP TABLE IF EXISTS test.t1; +DROP TABLE IF EXISTS test.t2; +DROP TABLE IF EXISTS test.t3; +sync_slave_with_master; + +# If the test fails, you will need to diff the dumps to see why. + +diff_files $MYSQLTEST_VARDIR/tmp/sp004_master.sql $MYSQLTEST_VARDIR/tmp/sp004_slave.sql; + + +# End of 5.0 test case +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_sp_effects-master.opt b/mysql-test/suite/rpl/t/rpl_sp_effects-master.opt new file mode 100644 index 00000000..27fad140 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_sp_effects-master.opt @@ -0,0 +1 @@ +--log_bin_trust_function_creators=1 diff --git a/mysql-test/suite/rpl/t/rpl_sp_effects-slave.opt b/mysql-test/suite/rpl/t/rpl_sp_effects-slave.opt new file mode 100644 index 00000000..27fad140 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_sp_effects-slave.opt @@ -0,0 +1 @@ +--log_bin_trust_function_creators=1 diff --git a/mysql-test/suite/rpl/t/rpl_sp_effects.test b/mysql-test/suite/rpl/t/rpl_sp_effects.test new file mode 100644 index 00000000..08d806b1 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_sp_effects.test @@ -0,0 +1,294 @@ +########################################## +# Change Author: JBM +# Change Date: 2006-05-02 +########################################## + +# Test of replication of stored procedures (WL#2146 for MySQL 5.0) +-- source include/master-slave.inc + +# **************************************************************** +connection master; + +SET @old_log_bin_trust_function_creators= @@global.log_bin_trust_function_creators; + +# cleanup +--disable_warnings +drop procedure if exists p1; +drop procedure if exists p2; +drop function if exists f1; +drop table if exists t1,t2; +drop view if exists v1; +--enable_warnings +create table t1 (a int); + +SET GLOBAL log_bin_trust_function_creators = 1; + +# 1. Test simple variables use. +delimiter //; +create procedure p1() +begin + declare spv int default 0; + while spv < 5 do + insert into t1 values(spv+1); + set spv=spv+1; + end while; +end// +delimiter ;// + +call p1(); + +sync_slave_with_master; +connection slave; +SELECT * FROM t1 ORDER BY a; +connection master; +SELECT * FROM t1 ORDER BY a; + +# 2. Test SP variable name +delimiter //; +create procedure p2() +begin + declare a int default 4; + create table t2 as select a; +end// +delimiter ;// + +call p2(); +SELECT * FROM t2 ORDER BY a; +sync_slave_with_master; +connection slave; +SELECT * FROM t2 ORDER BY a; + +connection master; +drop procedure p1; +drop procedure p2; +drop table t2; + +# 3. Test FUNCTIONs in various places + +delimiter //; +create function f1(x int) returns int +begin + insert into t1 values(x); + return x+1; +end// + +create procedure p1(a int, b int) +begin + declare v int default f1(5); + if (f1(6)) then + select 'yes'; + end if; + set v = f1(7); + while f1(8) < 1 do + select 'this cant be'; + end while; + +end// +delimiter ;// + +call p1(f1(1), f1(2)); +SELECT * FROM t1 ORDER BY a; + +create table t2(a int); +insert into t2 values (10),(11); +--disable_ps2_protocol +SELECT a,f1(a) FROM t2 ORDER BY a; +--enable_ps2_protocol + +# This shouldn't put separate 'call f1(3)' into binlog: +insert into t2 select f1(3); +SELECT 'master:',a FROM t1 ORDER BY a; + +sync_slave_with_master; +connection slave; +SELECT 'slave:',a FROM t1 ORDER BY a; + +connection master; +drop procedure p1; +delete from t1; +delete from t2; + +# 4. VIEWs +delete from t1; +insert into t2 values(1),(2); +create view v1 as select f1(a) as f from t2; +--disable_ps2_protocol +select * from v1 order by f; +--enable_ps2_protocol +SELECT 'master:',a FROM t1 ORDER BY a; + +sync_slave_with_master; +connection slave; +SELECT 'slave:',a FROM t1 ORDER BY a; + +connection master; +drop view v1; +delete from t1; + +# 5. Prepared statements. +prepare s1 from 'select f1(?)'; +set @xx=123; +execute s1 using @xx; +SELECT 'master:',a FROM t1 ORDER BY a; + +sync_slave_with_master; +connection slave; +SELECT 'slave:',a FROM t1 ORDER BY a; + +connection master; +delete from t1; + +# 5. Cursors. +# t2 has (1),(2); +delimiter //; +create procedure p1(spv int) +begin + declare c cursor for select f1(spv) from t2; + while (spv > 2) do + open c; + fetch c into spv; + close c; + set spv= spv - 10; + end while; +end// +delimiter ;// +call p1(15); +SELECT 'master:',a FROM t1 ORDER BY a; +sync_slave_with_master; +connection slave; +SELECT 'slave:',a FROM t1 ORDER BY a; + +connection master; +drop procedure p1; +drop function f1; +drop table t1,t2; + +# BUG#12637: User variables + SPs replication +create table t1 (a int); +delimiter //; +create procedure p1() +begin + insert into t1 values(@x); + set @x=@x+1; + insert into t1 values(@x); + if (f2()) then + insert into t1 values(1243); + end if; +end// + +create function f2() returns int +begin + insert into t1 values(@z); + set @z=@z+1; + insert into t1 values(@z); + return 0; +end// + +create function f1() returns int +begin + insert into t1 values(@y); + call p1(); + return 0; +end// + +delimiter ;// + +set @x=10; +set @y=20; +set @z=100; +--disable_ps2_protocol +select f1(); +--enable_ps2_protocol + +set @x=30; +call p1(); + +SELECT 'master', a FROM t1 ORDER BY a; +sync_slave_with_master; +connection slave; +SELECT 'slave', a FROM t1 ORDER BY a; + +# +# cleanup +# + +connection master; +drop table t1; +drop function f1; +drop function f2; +drop procedure p1; +sync_slave_with_master; + +# +# bug#26199 Replication Failure on Slave when using stored procs +# with bit-type parameters + +connection master; + +create table t2 (b BIT(7)); +delimiter //; +create procedure sp_bug26199(bitvalue BIT(7)) +begin + insert into t2 set b = bitvalue; +end // + +create function sf_bug26199(b BIT(7)) returns int +begin + insert into t2 values(b); + return 0; +end// + +DELIMITER ;// + + + +call sp_bug26199(b'1110'); +call sp_bug26199('\0'); +--disable_ps2_protocol +select sf_bug26199(b'1111111'); +SET STATEMENT sql_mode = '' FOR +select sf_bug26199(b'101111111'); +select sf_bug26199('\''); +--enable_ps2_protocol +select hex(b) from t2; + +sync_slave_with_master; +#connection slave; +select hex(b) from t2; + +# +# cleanup bug#26199 +# +connection master; +drop table t2; +drop procedure sp_bug26199; +drop function sf_bug26199; + +SET @@global.log_bin_trust_function_creators= @old_log_bin_trust_function_creators; + +sync_slave_with_master; + +# +# Bug#16056537: MYSQLD CRASHES IN ITEM_FUNC_GET_USER_VAR::FIX_LENGTH_AND_DEC() +# +set names utf8; +--delimiter | +CREATE FUNCTION f() RETURNS timestamp DETERMINISTIC +BEGIN RETURN '2012-12-21 12:12:12'; END | +CREATE PROCEDURE p(t timestamp) +BEGIN + SET @t = t; + PREPARE stmt FROM " + UPDATE t1 SET a = @t WHERE '2012-12-31 08:00:00' < f() "; + EXECUTE stmt; + DEALLOCATE PREPARE stmt; +END | +--delimiter ; +create table t1 (a timestamp); +call p('2012-12-31 08:00:00'); +drop table t1; +drop procedure p; +drop function f; + +--echo end of the tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_sp_variables.test b/mysql-test/suite/rpl/t/rpl_sp_variables.test new file mode 100644 index 00000000..87e9fe19 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_sp_variables.test @@ -0,0 +1,28 @@ +source include/master-slave.inc; + +--echo # +--echo # MDEV-13685 Can not replay binary log due to Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8mb4_general_ci,COERCIBLE) for operation 'concat' +--echo # + +connection master; +SET NAMES utf8; +CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET utf8); +DELIMITER $$; +CREATE PROCEDURE p1() +BEGIN + DECLARE v_id INT DEFAULT 2017; + INSERT INTO test.t1 SELECT CONCAT(v_id, '오'); +END; +$$ +DELIMITER ;$$ +CALL p1; +SELECT * FROM t1; +sync_slave_with_master; +SET NAMES utf8; +SELECT * FROM t1; +connection master; +DROP PROCEDURE p1; +DROP TABLE t1; +sync_slave_with_master; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_spec_variables.test b/mysql-test/suite/rpl/t/rpl_spec_variables.test new file mode 100644 index 00000000..fdd000d0 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_spec_variables.test @@ -0,0 +1,312 @@ +############################################################# +# Author: Serge Kozlov <skozlov@mysql.com> +# Date: 07/01/2008 +# Purpose: Testing possible affects of some system dynamic +# variables to the replication. +# Scenario for each variable: +# 1) Set different values for master and slave +# 2) Create and replicate a data from master to slave +# 3) Check results on master and slave: changes on slave +# shouldn't be affected to replicated data. +############################################################# +--source include/have_innodb.inc +--source include/master-slave.inc +--echo + +# +# AUTO_INCREMENT +# +--echo * auto_increment_increment, auto_increment_offset * + +--connection master +SET @@global.auto_increment_increment=2; +SET @@session.auto_increment_increment=2; +SET @@global.auto_increment_offset=10; +SET @@session.auto_increment_offset=10; + +--connection slave +SET @@global.auto_increment_increment=3; +SET @@session.auto_increment_increment=3; +SET @@global.auto_increment_offset=20; +SET @@session.auto_increment_offset=20; + +--connection master +CREATE TABLE t1 (a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, b VARCHAR(10)) ENGINE=MyISAM; +INSERT INTO t1 (b) VALUES ('master'); +INSERT INTO t1 (b) VALUES ('master'); +SELECT * FROM t1 ORDER BY a; + +--sync_slave_with_master +CREATE TABLE t2 (a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, b VARCHAR(10)) ENGINE=MyISAM; +INSERT INTO t1 (b) VALUES ('slave'); +INSERT INTO t1 (b) VALUES ('slave'); +INSERT INTO t2 (b) VALUES ('slave'); +INSERT INTO t2 (b) VALUES ('slave'); +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +--connection master +--disable_warnings +DROP TABLE IF EXISTS t1,t2; +--enable_warnings +SET @@global.auto_increment_increment=1; +SET @@session.auto_increment_increment=1; +SET @@global.auto_increment_offset=1; +SET @@session.auto_increment_offset=1; + +--connection slave +SET @@global.auto_increment_increment=1; +SET @@session.auto_increment_increment=1; +SET @@global.auto_increment_offset=1; +SET @@session.auto_increment_offset=1; + +--connection slave +SET auto_increment_increment=1; +SET auto_increment_offset=1; +--echo + +# +# CHARACTER_SET_DATABASE, COLLATION_SERVER +# +--echo * character_set_database, collation_server * + +--connection master +SET @restore_master_character_set_database=@@global.character_set_database; +SET @restore_master_collation_server=@@global.collation_server; +SET @@global.character_set_database=latin1; +SET @@session.character_set_database=latin1; +SET @@global.collation_server=latin1_german1_ci; +SET @@session.collation_server=latin1_german1_ci; + +--connection slave +SET @restore_slave_character_set_database=@@global.character_set_database; +SET @restore_slave_collation_server=@@global.collation_server; +SET @@global.character_set_database=utf8; +SET @@session.character_set_database=utf8; +SET @@global.collation_server=utf8_bin; +SET @@session.collation_server=utf8_bin; + +--connection master +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b VARCHAR(10)) ENGINE=MyISAM; +SHOW CREATE TABLE t1; + +--sync_slave_with_master +CREATE TABLE t2 (a INT NOT NULL PRIMARY KEY, b VARCHAR(10)) ENGINE=MyISAM; +SHOW CREATE TABLE t1; +SHOW CREATE TABLE t2; + +SET @@global.collation_server=latin1_swedish_ci; +SET @@session.collation_server=latin1_swedish_ci; + +--connection master +SET @@global.collation_server=latin1_swedish_ci; +SET @@session.collation_server=latin1_swedish_ci; + +--disable_warnings +DROP TABLE IF EXISTS t1,t2; +--enable_warnings +--echo + +# +# DEFAULT_WEEK_FORMAT +# +--echo * default_week_format * + +--connection master +SET @@global.default_week_format=0; +SET @@session.default_week_format=0; + +--connection slave +SET @@global.default_week_format=1; +SET @@session.default_week_format=1; + +--connection master +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b VARCHAR(10), c INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1, 'master ', WEEK('2008-01-07')); +SELECT * FROM t1 ORDER BY a; + +--sync_slave_with_master +INSERT INTO t1 VALUES (2, 'slave ', WEEK('2008-01-07')); +SELECT * FROM t1 ORDER BY a; + +--connection master +DROP TABLE t1; + +--connection slave +SET @@global.default_week_format=0; +SET @@session.default_week_format=0; +--echo + +# +# LOCAL_INFILE +# +--echo * local_infile * + +--connection slave +SET @@global.local_infile=0; + +--connection master +CREATE TABLE t1 (a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, b VARCHAR(20), c CHAR(254)) ENGINE=MyISAM; +--copy_file ./std_data/words.dat $MYSQLTEST_VARDIR/tmp/words.dat +--copy_file ./std_data/words2.dat $MYSQLTEST_VARDIR/tmp/words2.dat +--replace_regex /\'.+\'/'FILE'/ +--eval LOAD DATA LOCAL INFILE '$MYSQLTEST_VARDIR/tmp/words.dat' INTO TABLE t1 (b) +SELECT COUNT(*) FROM t1; +--sync_slave_with_master +--replace_regex /\'.+\'/'FILE2'/ +--error ER_LOAD_INFILE_CAPABILITY_DISABLED +--eval LOAD DATA LOCAL INFILE '$MYSQLTEST_VARDIR/tmp/words2.dat' INTO TABLE t1 (b) +SELECT COUNT(*) FROM t1; + +SET @@global.local_infile=1; + +--connection master +DROP TABLE t1; +--echo + +# +# MAX_HEAP_TABLE_SIZE +# +--echo * max_heap_table_size * + +--connection slave +SET @restore_slave_max_heap_table_size=@@global.max_heap_table_size; +SET @@global.max_heap_table_size=16384; +SET @@session.max_heap_table_size=16384; + +--connection master +CREATE TABLE t1 (a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, b VARCHAR(10), c CHAR(254)) ENGINE=MEMORY; +let $counter=2000; +--disable_query_log +while ($counter) { + INSERT INTO t1 (b,c) VALUES ('master', REPEAT('A', 254)); + dec $counter; +} +--enable_query_log +SELECT COUNT(*)=2000 FROM t1; + +--sync_slave_with_master +let $counter=2000; +--disable_query_log +while ($counter) { + --error 0,1114 + INSERT INTO t1 (b,c) VALUES ('slave', REPEAT('A', 254)); + dec $counter; +} +CREATE TABLE t2 (a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, b VARCHAR(10), c CHAR(254)) ENGINE=MEMORY; +let $counter=2000; +--disable_query_log +while ($counter) { + --error 0,1114 + INSERT INTO t2 (b,c) VALUES ('slave', REPEAT('A', 254)); + dec $counter; +} +--enable_query_log +# We don't know how many memory used and can't check exact values so need to check following +# conditions +SELECT COUNT(*)=2000 FROM t1 WHERE b='master' GROUP BY b ORDER BY b; +SELECT COUNT(*)<2000 AND COUNT(*)>0 FROM t1 WHERE b='slave' GROUP BY b ORDER BY b; +SELECT COUNT(*)<2000 AND COUNT(*)>0 FROM t2 WHERE b='slave' GROUP BY b ORDER BY b; + +--connection master +--disable_warnings +DROP TABLE IF EXISTS t1,t2; +--enable_warnings +--echo + +# +# STORAGE_ENGINE +# +--echo * storage_engine * + +--connection master +SET @restore_master_storage_engine=@@global.default_storage_engine; +SET @@global.default_storage_engine=InnoDB; +SET @@session.default_storage_engine=InnoDB; + +--connection slave +SET @restore_slave_storage_engine=@@global.default_storage_engine; +SET @@global.default_storage_engine=Memory; +SET @@session.default_storage_engine=Memory; + +--connection master +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b VARCHAR(10)); +CREATE TABLE t2 (a INT NOT NULL PRIMARY KEY, b VARCHAR(10)) ENGINE=InnoDB; + +--sync_slave_with_master +CREATE TABLE t3 (a INT NOT NULL PRIMARY KEY, b VARCHAR(10)); + +--connection master +SHOW CREATE TABLE t1; +SHOW CREATE TABLE t2; + +--connection slave +SHOW CREATE TABLE t1; +SHOW CREATE TABLE t2; +SHOW CREATE TABLE t3; + +SET @@global.default_storage_engine=InnoDB; +SET @@session.default_storage_engine=InnoDB; + +--connection master +--disable_warnings +DROP TABLE IF EXISTS t1,t2,t3; +--enable_warnings +--echo + +# +# SQL_MODE +# +--echo * sql_mode * + +--connection master +SET @old_sql_mode_master= @@global.sql_mode; +SET @@global.sql_mode=ANSI; +SET @@session.sql_mode=ANSI; + +--connection slave +SET @old_sql_mode_slave= @@global.sql_mode; +SET @@global.sql_mode=TRADITIONAL; +SET @@session.sql_mode=TRADITIONAL; + +--connection master +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b VARCHAR(10), c DATE); +INSERT INTO t1 VALUES (1, 'master', '0000-00-00'); +SELECT * FROM t1 ORDER BY a; + +--sync_slave_with_master +--error 1292 +INSERT INTO t1 VALUES (1, 'slave', '0000-00-00'); +SELECT * FROM t1 ORDER BY a; +SET @@global.sql_mode=''; +SET @@session.sql_mode=''; + +--connection master +SET @@global.sql_mode=''; +SET @@session.sql_mode=''; +DROP TABLE t1; +--echo + + +# Clean up +--echo *** clean up *** +--connection master +SET @@global.character_set_database=@restore_master_character_set_database; +SET @@global.collation_server=@restore_master_collation_server; +SET @@global.default_storage_engine=@restore_master_storage_engine; +SET @@global.sql_mode=@old_sql_mode_master; +--sync_slave_with_master +SET @@global.character_set_database=@restore_slave_character_set_database; +SET @@global.collation_server=@restore_slave_collation_server; +SET @@global.max_heap_table_size=@restore_slave_max_heap_table_size; +SET @@global.default_storage_engine=@restore_slave_storage_engine; +SET @@global.sql_mode=@old_sql_mode_slave; + +# Put at the end since the test otherwise emptied the table. +remove_file $MYSQLTEST_VARDIR/tmp/words.dat; +remove_file $MYSQLTEST_VARDIR/tmp/words2.dat; +--echo +call mtr.add_suppression("The table 't[12]' is full"); + +# End of 5.1 test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_special_charset.opt b/mysql-test/suite/rpl/t/rpl_special_charset.opt new file mode 100644 index 00000000..b071fb20 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_special_charset.opt @@ -0,0 +1 @@ +--character-set-server=utf16 diff --git a/mysql-test/suite/rpl/t/rpl_special_charset.test b/mysql-test/suite/rpl/t/rpl_special_charset.test new file mode 100644 index 00000000..641aa483 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_special_charset.test @@ -0,0 +1,32 @@ +# +# This include file is used by more than one test suite +# (currently rpl and binlog_encryption). +# Please check all dependent tests after modifying it +# + +################################################################################ +# Bug#19855907 IO THREAD AUTHENTICATION ISSUE WITH SOME CHARACTER SETS +# Problem: IO thread fails to connect to master if servers are configured with +# special character sets like utf16, utf32, ucs2. +# +# Analysis: MySQL server does not support few special character sets like +# utf16,utf32 and ucs2 as "client's character set"(eg: utf16,utf32, ucs2). +# When IO thread is trying to connect to Master, it sets server's character +# set as client's character set. When Slave server is started with these +# special character sets, IO thread (a connection to Master) fails because +# of the above said reason. +# +# Fix: If server's character set is not supported as client's character set, +# then set default's client character set(latin1) as client's character set. +############################################################################### +--source include/master-slave.inc +call mtr.add_suppression("'utf16' can not be used as client character set"); +CREATE TABLE t1(i VARCHAR(20)); +INSERT INTO t1 VALUES (0xFFFF); +--sync_slave_with_master +--let diff_tables=master:t1, slave:t1 +--source include/diff_tables.inc +# Cleanup +--connection master +DROP TABLE t1; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_sporadic_master-master.opt b/mysql-test/suite/rpl/t/rpl_sporadic_master-master.opt new file mode 100644 index 00000000..5f038b69 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_sporadic_master-master.opt @@ -0,0 +1 @@ +--debug-sporadic-binlog-dump-fail --debug-max-binlog-dump-events=2 diff --git a/mysql-test/suite/rpl/t/rpl_sporadic_master.test b/mysql-test/suite/rpl/t/rpl_sporadic_master.test new file mode 100644 index 00000000..ad4c44cb --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_sporadic_master.test @@ -0,0 +1,32 @@ +# +# This include file is used by more than one test suite +# (currently rpl and binlog_encryption). +# Please check all dependent tests after modifying it +# + +# test to see if replication can continue when master sporadically fails on +# COM_BINLOG_DUMP and additionally limits the number of events per dump + +source include/master-slave.inc; + +create table t2(n int); +create table t1(n int not null auto_increment primary key); +insert into t1 values (NULL),(NULL); +truncate table t1; +# We have to use 4 in the following to make this test work with all table types +insert into t1 values (4),(NULL); +sync_slave_with_master; +--source include/stop_slave.inc +--source include/start_slave.inc +connection master; +insert into t1 values (NULL),(NULL); +flush logs; +truncate table t1; +insert into t1 values (10),(NULL),(NULL),(NULL),(NULL),(NULL); +sync_slave_with_master; +select * from t1 ORDER BY n; +connection master; +drop table t1,t2; +sync_slave_with_master; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_sql_thd_start_errno_cleared.test b/mysql-test/suite/rpl/t/rpl_sql_thd_start_errno_cleared.test new file mode 100644 index 00000000..f6dcfd91 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_sql_thd_start_errno_cleared.test @@ -0,0 +1,93 @@ +# +# Ensure that when the slave restarts, the last error code displayed by +# SHOW SLAVE STATUS is cleared before Slave_SQL_Running is set. +# +# To ensure that, this test uses the debug_sync mechanism to pause an errored +# and restarting slave's SQL thread after it has set its running state to YES, +# and then ensures that Last_SQL_Errno is 0. The slave error is a forced innodb +# row lock timeout. +# +# +# References +# MDEV-31177: SHOW SLAVE STATUS Last_SQL_Errno Race Condition on Errored +# Slave Restart +# +source include/have_binlog_format_row.inc; +source include/have_innodb.inc; +source include/have_debug.inc; +source include/have_debug_sync.inc; +source include/master-slave.inc; + +--connection master +create table t1 (a int primary key, b int) engine=innodb; +insert t1 values (1,1); +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc +set @save_innodb_lock_wait_timeout= @@global.innodb_lock_wait_timeout; +set @save_slave_trans_retries= @@global.slave_transaction_retries; +set @@global.innodb_lock_wait_timeout= 1; +set @@global.slave_transaction_retries= 0; + +--connection master +update t1 set b=b+10 where a=1; +--source include/save_master_gtid.inc + +--connection slave1 +BEGIN; +--eval SELECT * FROM t1 WHERE a=1 FOR UPDATE + +--connection slave +--source include/start_slave.inc + +--let $slave_sql_errno= 1205 +--source include/wait_for_slave_sql_error.inc + +--connection slave1 +ROLLBACK; + +--connection slave +set @save_dbug = @@global.debug_dbug; +set @@global.debug_dbug= "+d,delay_sql_thread_after_release_run_lock"; +--source include/start_slave.inc +set debug_sync= "now wait_for sql_thread_run_lock_released"; + +--let $sql_running = query_get_value("SHOW SLAVE STATUS", Slave_SQL_Running, 1) +--echo # Validating that the SQL thread is running.. +if (`SELECT strcmp("$sql_running", "YES") != 0`) +{ + --echo # ..failed + --echo # Slave_SQL_Running: $sql_running + --die Slave SQL thread is not running +} +--echo # ..success + +--let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1) +--echo # Validating that Last_SQL_Errno is cleared.. +if ($last_error) +{ + --echo # ..failed + --echo # Last_SQL_Errno: $last_error + --die SHOW SLAVE STATUS shows the error from the last session on startup +} +--echo # ..success + +set debug_sync= "now signal sql_thread_continue"; + +set @@global.debug_dbug= @saved_dbug; +set debug_sync= "RESET"; + +--echo # Cleanup +--connection master +drop table t1; + +--connection slave +--source include/stop_slave.inc +set @@global.innodb_lock_wait_timeout= @save_innodb_lock_wait_timeout; +set @@global.slave_transaction_retries= @save_slave_trans_retries; +--source include/start_slave.inc + +--source include/rpl_end.inc +--echo # End of rpl_sql_thd_start_errno_cleared.test diff --git a/mysql-test/suite/rpl/t/rpl_ssl.test b/mysql-test/suite/rpl/t/rpl_ssl.test new file mode 100644 index 00000000..0420a6c8 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_ssl.test @@ -0,0 +1,116 @@ +# +# This include file is used by more than one test suite +# (currently rpl and binlog_encryption). +# Please check all dependent tests after modifying it +# + +source include/no_valgrind_without_big.inc; +source include/have_ssl_communication.inc; +source include/master-slave.inc; + +# create a user for replication that requires ssl encryption +connection master; +create user replssl@localhost; +grant replication slave on *.* to replssl@localhost require ssl; +create table t1 (t int auto_increment, KEY(t)); + +sync_slave_with_master; + +# Set slave to use SSL for connection to master +stop slave; +--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +eval change master to + master_user='replssl', + master_password='', + master_ssl=1, + master_ssl_ca ='$MYSQL_TEST_DIR/std_data/cacert.pem', + master_ssl_cert='$MYSQL_TEST_DIR/std_data/client-cert.pem', + master_ssl_key='$MYSQL_TEST_DIR/std_data/client-key.pem'; +start slave; + +# Switch to master and insert one record, then sync it to slave +connection master; +insert into t1 values(1); +sync_slave_with_master; + +# The record should now be on slave +select * from t1; + +# The slave is synced and waiting/reading from master +# SHOW SLAVE STATUS will show "Waiting for master to send event" +let $status_items= Master_SSL_Allowed, Master_SSL_CA_Path, Master_SSL_CA_File, Master_SSL_Crl, Master_SSL_Crlpath, Master_SSL_Cert, Master_SSL_Key; +source include/show_slave_status.inc; +source include/check_slave_is_running.inc; + +# Stop the slave, as reported in bug#21871 it would hang +STOP SLAVE; + +select * from t1; + +# Do the same thing a number of times +disable_query_log; +disable_result_log; +# 2007-11-27 mats Bug #32756 Starting and stopping the slave in a loop can lose rows +# After discussions with Engineering, I'm disabling this part of the test to avoid it causing +# red trees. +disable_parsing; +let $i= 100; +while ($i) +{ + start slave; + connection master; + insert into t1 values (NULL); + select * from t1; # Some variance + connection slave; + select * from t1; # Some variance + stop slave; + dec $i; +} +enable_parsing; +START SLAVE; +enable_query_log; +enable_result_log; +connection master; +# INSERT one more record to make sure +# the sync has something to do +insert into t1 values (NULL); +let $master_count= `select count(*) from t1`; + +sync_slave_with_master; +--source include/wait_for_slave_to_start.inc +source include/show_slave_status.inc; +source include/check_slave_is_running.inc; + +let $slave_count= `select count(*) from t1`; + +if ($slave_count != $master_count) +{ + echo master and slave differed in number of rows; + echo master: $master_count; + echo slave: $slave_count; + + connection master; + select count(*) t1; + select * from t1; + connection slave; + select count(*) t1; + select * from t1; + query_vertical show slave status; +} + +connection master; +drop user replssl@localhost; +drop table t1; +sync_slave_with_master; + +--source include/stop_slave.inc +CHANGE MASTER TO + master_user = 'root', + master_ssl = 0, + master_ssl_ca = '', + master_ssl_cert = '', + master_ssl_key = ''; + +--echo End of 5.0 tests +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_ssl1.test b/mysql-test/suite/rpl/t/rpl_ssl1.test new file mode 100644 index 00000000..d994dd21 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_ssl1.test @@ -0,0 +1,110 @@ +source include/have_ssl_communication.inc; +source include/master-slave.inc; + +# We don't test all types of ssl auth params here since it's a bit hard +# until problems with OpenSSL 0.9.7 are unresolved + +# creating replication user for whom ssl auth is required +# preparing playground +connection master; +create user replssl@localhost; +grant replication slave on *.* to replssl@localhost require ssl; +create table t1 (t int); + +sync_slave_with_master; + +#trying to use this user without ssl +stop slave; +--source include/wait_for_slave_to_stop.inc +change master to master_user='replssl',master_password=''; +start slave; + +#showing that replication don't work +connection master; +insert into t1 values (1); +#reasonable timeout for changes to propagate to slave +let $wait_condition= SELECT COUNT(*) = 1 FROM t1; +source include/wait_condition.inc; +connection slave; +select * from t1; + +#showing that replication could work with ssl params +stop slave; +--source include/wait_for_slave_to_stop.inc +--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +eval change master to master_ssl=1 , master_ssl_ca ='$MYSQL_TEST_DIR/std_data/cacert.pem', master_ssl_cert='$MYSQL_TEST_DIR/std_data/client-cert.pem', master_ssl_key='$MYSQL_TEST_DIR/std_data/client-key.pem'; +start slave; +--source include/wait_for_slave_to_start.inc + +#avoiding unneeded sleeps +connection master; +sync_slave_with_master; + +#checking that replication is ok +select * from t1; + +#checking show slave status +let $status_items= Master_SSL_Allowed, Master_SSL_CA_Path, Master_SSL_CA_File, Master_SSL_Cert, Master_SSL_Key; +source include/show_slave_status.inc; +source include/check_slave_is_running.inc; + +#checking if replication works without ssl also performing clean up +stop slave; +--source include/wait_for_slave_to_stop.inc +change master to master_user='root',master_password='', master_ssl=0; +start slave; +--source include/wait_for_slave_to_start.inc +connection master; +drop user replssl@localhost; +drop table t1; + +sync_slave_with_master; +source include/show_slave_status.inc; +source include/check_slave_is_running.inc; +# End of 4.1 tests + +# Start replication with ssl_verify_server_cert turned on +connection slave; +stop slave; +--source include/wait_for_slave_to_stop.inc +--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +eval change master to + master_host="localhost", + master_ssl=1 , + master_ssl_ca ='$MYSQL_TEST_DIR/std_data/cacert.pem', + master_ssl_cert='$MYSQL_TEST_DIR/std_data/client-cert.pem', + master_ssl_key='$MYSQL_TEST_DIR/std_data/client-key.pem', + master_ssl_verify_server_cert=1; +start slave; +--source include/wait_for_slave_to_start.inc + +connection master; +create table t1 (t int); +insert into t1 values (1); + +sync_slave_with_master; + +echo on slave; +#checking that replication is ok +select * from t1; + +#checking show slave status +source include/show_slave_status.inc; +--source include/check_slave_is_running.inc + +# ==== Clean up ==== + +connection master; +drop table t1; +sync_slave_with_master; +--source include/stop_slave.inc +CHANGE MASTER TO + master_host="127.0.0.1", + master_ssl_ca ='', + master_ssl_cert='', + master_ssl_key='', + master_ssl_verify_server_cert=0, + master_ssl=0; + +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_start_alter_1.test b/mysql-test/suite/rpl/t/rpl_start_alter_1.test new file mode 100644 index 00000000..9ce061f1 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_alter_1.test @@ -0,0 +1,33 @@ +# +# Start Alter with Legacy Replication +# +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/master-slave.inc + +--connection master +--let $binlog_alter_two_phase= `select @@binlog_alter_two_phase` +set global binlog_alter_two_phase = ON; +set binlog_alter_two_phase = ON; +--connection slave +--let $gtid_strict_mode= `select @@gtid_strict_mode` +set global gtid_strict_mode=1; + +--echo # Legacy Master Slave +--let $domain_1=0 +--let $domain_2=0 +--let $M_port= $MASTER_MYPORT +--let $S_port= $SLAVE_MYPORT +--let $sync_slave=1 + +--source include/start_alter_include.inc +--connection master +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc +--eval set global gtid_strict_mode = $gtid_strict_mode; + +--connection master +--eval set global binlog_alter_two_phase=$binlog_alter_two_phase; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_start_alter_2.test b/mysql-test/suite/rpl/t/rpl_start_alter_2.test new file mode 100644 index 00000000..457409c5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_alter_2.test @@ -0,0 +1,53 @@ +# +# Start Alter with Parallel Replication +# 1 domain id +# |Concurrent alters| < |Parallel workers on slave| +# |x| denotes number of entities it encloses +# +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/master-slave.inc +--connection master +--let $binlog_alter_two_phase= `select @@binlog_alter_two_phase` +set global binlog_alter_two_phase = ON; +set binlog_alter_two_phase = ON; +--connection slave +--let $gtid_strict_mode= `select @@gtid_strict_mode` +--let $slave_parallel_threads= `select @@slave_parallel_threads` +--let $slave_parallel_mode= `select @@slave_parallel_mode` +set global gtid_strict_mode=1; + + +--connection slave +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=10; +set global slave_parallel_mode=optimistic; +change master to master_use_gtid=slave_pos; +--source include/start_slave.inc + +--echo # Parallel Slave +--connection master +--let $master_server= "master" +--let $domain_1=0 +--let $domain_2=0 +--let $M_port= $MASTER_MYPORT +--let $S_port= $SLAVE_MYPORT +--let $sync_slave=1 +--source include/start_alter_include.inc +--connection master +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc + +--echo # cleanup +--source include/stop_slave.inc +--eval set global slave_parallel_threads = $slave_parallel_threads; +--eval set global slave_parallel_mode = $slave_parallel_mode; +--eval set global gtid_strict_mode = $gtid_strict_mode; +set global gtid_domain_id= 0; +--source include/start_slave.inc + +--connection master +--eval set global binlog_alter_two_phase=$binlog_alter_two_phase; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_start_alter_3.test b/mysql-test/suite/rpl/t/rpl_start_alter_3.test new file mode 100644 index 00000000..b280aeb9 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_alter_3.test @@ -0,0 +1,54 @@ +# +# Start Alter with Parallel Replication +# 1 domain id +# |Concurrent alters| >= |Parallel workers on slave| +# |x| denotes number of entities it encloses +# +--source include/have_log_bin.inc +--source include/have_innodb.inc +--source include/master-slave.inc +--source include/have_debug.inc +--connection master +--let $binlog_alter_two_phase= `select @@binlog_alter_two_phase` +set global binlog_alter_two_phase = ON; +set binlog_alter_two_phase = ON; +--connection slave +--let $gtid_strict_mode= `select @@gtid_strict_mode` +--let $slave_parallel_threads= `select @@slave_parallel_threads` +--let $slave_parallel_mode= `select @@slave_parallel_mode` +set global gtid_strict_mode=1; + + +--connection slave +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=4; +set global slave_parallel_mode=optimistic; +change master to master_use_gtid=slave_pos; +--source include/start_slave.inc + +--echo # Parallel Slave +--connection master +--let $master_server= "master" +--let $domain_1=0 +--let $domain_2=0 +--let $M_port= $MASTER_MYPORT +--let $S_port= $SLAVE_MYPORT +--let $sync_slave=1 +--source include/start_alter_include.inc +--connection master +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc + +--echo # cleanup +--source include/stop_slave.inc +--eval set global slave_parallel_threads = $slave_parallel_threads; +--eval set global slave_parallel_mode = $slave_parallel_mode; +--eval set global gtid_strict_mode = $gtid_strict_mode; +set global gtid_domain_id= 0; +--source include/start_slave.inc + +--connection master +--eval set global binlog_alter_two_phase=$binlog_alter_two_phase; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_start_alter_4.test b/mysql-test/suite/rpl/t/rpl_start_alter_4.test new file mode 100644 index 00000000..8c67b50a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_alter_4.test @@ -0,0 +1,54 @@ +# +# Start Alter with Parallel Replication +# 2 domain id +# |Concurrent alters| < |Parallel workers on slave| +# |x| denotes number of entities it encloses +# +--source include/have_log_bin.inc +--source include/have_innodb.inc +--source include/master-slave.inc +--source include/have_debug.inc +--connection master +--let $binlog_alter_two_phase= `select @@binlog_alter_two_phase` +set global binlog_alter_two_phase = ON; +set binlog_alter_two_phase = ON; +--connection slave +--let $gtid_strict_mode= `select @@gtid_strict_mode` +--let $slave_parallel_threads= `select @@slave_parallel_threads` +--let $slave_parallel_mode= `select @@slave_parallel_mode` +set global gtid_strict_mode=1; + +--connection slave +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=10; +set global slave_parallel_mode=optimistic; +change master to master_use_gtid=slave_pos; +--source include/start_slave.inc + +--echo # Parallel Slave +--connection master +--let $master_server= "master" +--let $domain_1=11 +--let $domain_2=12 +--let $M_port= $MASTER_MYPORT +--let $S_port= $SLAVE_MYPORT +--let $sync_slave=1 +--source include/start_alter_include.inc +--connection master +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc + +--echo # cleanup +--source include/stop_slave.inc +--eval set global slave_parallel_threads = $slave_parallel_threads; +--eval set global slave_parallel_mode = $slave_parallel_mode; +--eval set global gtid_strict_mode = $gtid_strict_mode; +set global gtid_domain_id= 0; +--source include/start_slave.inc + +--connection master +--eval set global binlog_alter_two_phase=$binlog_alter_two_phase; +set global gtid_domain_id= 0; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_start_alter_5.test b/mysql-test/suite/rpl/t/rpl_start_alter_5.test new file mode 100644 index 00000000..10d0d523 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_alter_5.test @@ -0,0 +1,54 @@ +# +# Start Alter with Parallel Replication +# 2 domain id +# |Concurrent alters| >= |Parallel workers on slave| +# |x| denotes number of entities it encloses +# +--source include/have_log_bin.inc +--source include/have_innodb.inc +--source include/master-slave.inc +--source include/have_debug.inc +--connection master +--let $binlog_alter_two_phase= `select @@binlog_alter_two_phase` +set global binlog_alter_two_phase = ON; +set binlog_alter_two_phase = ON; +--connection slave +--let $gtid_strict_mode= `select @@gtid_strict_mode` +--let $slave_parallel_threads= `select @@slave_parallel_threads` +--let $slave_parallel_mode= `select @@slave_parallel_mode` +set global gtid_strict_mode=1; + +--connection slave +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=4; +set global slave_parallel_mode=optimistic; +change master to master_use_gtid=slave_pos; +--source include/start_slave.inc + +--echo # Parallel Slave +--connection master +--let $master_server= "master" +--let $domain_1=11 +--let $domain_2=12 +--let $M_port= $MASTER_MYPORT +--let $S_port= $SLAVE_MYPORT +--let $sync_slave=1 +--source include/start_alter_include.inc +--connection master +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc + +--echo # cleanup +--source include/stop_slave.inc +--eval set global slave_parallel_threads = $slave_parallel_threads; +--eval set global slave_parallel_mode = $slave_parallel_mode; +--eval set global gtid_strict_mode = $gtid_strict_mode; +set global gtid_domain_id= 0; +--source include/start_slave.inc + +--connection master +--eval set global binlog_alter_two_phase=$binlog_alter_two_phase; +set global gtid_domain_id= 0; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_start_alter_6.test b/mysql-test/suite/rpl/t/rpl_start_alter_6.test new file mode 100644 index 00000000..fc49ea4a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_alter_6.test @@ -0,0 +1,58 @@ +# +# Start Alter with Parallel Replication +# 2 domain id +# |Concurrent alters| < |Parallel workers on slave| +# |x| denotes number of entities it encloses +# slave_domain_parallel_threads < |Concurrent Alters| +# +--source include/have_log_bin.inc +--source include/have_innodb.inc +--source include/master-slave.inc +--source include/have_debug.inc +--connection master +--let $binlog_alter_two_phase= `select @@binlog_alter_two_phase` +set global binlog_alter_two_phase = ON; +set binlog_alter_two_phase = ON; +--connection slave +--let $gtid_strict_mode= `select @@gtid_strict_mode` +--let $slave_parallel_threads= `select @@slave_parallel_threads` +--let $slave_parallel_mode= `select @@slave_parallel_mode` +--let $slave_domain_parallel_threads= `select @@slave_domain_parallel_threads` +set global gtid_strict_mode=1; + +--connection slave +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=10; +set global slave_parallel_mode=optimistic; +set global slave_domain_parallel_threads=3; +change master to master_use_gtid=slave_pos; +--source include/start_slave.inc + +--echo # Parallel Slave +--connection master +--let $master_server= "master" +--let $domain_1=11 +--let $domain_2=12 +--let $M_port= $MASTER_MYPORT +--let $S_port= $SLAVE_MYPORT +--let $sync_slave=1 +--source include/start_alter_include.inc +--connection master +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc + +--echo # cleanup +--source include/stop_slave.inc +--eval set global slave_parallel_threads = $slave_parallel_threads; +--eval set global slave_parallel_mode = $slave_parallel_mode; +--eval set global gtid_strict_mode = $gtid_strict_mode; +--eval set global slave_domain_parallel_threads = $slave_domain_parallel_threads; +set global gtid_domain_id= 0; +--source include/start_slave.inc + +--connection master +--eval set global binlog_alter_two_phase=$binlog_alter_two_phase; +set global gtid_domain_id= 0; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_start_alter_7.cnf b/mysql-test/suite/rpl/t/rpl_start_alter_7.cnf new file mode 100644 index 00000000..a0f6dc57 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_alter_7.cnf @@ -0,0 +1,19 @@ +!include ../my.cnf + +[mysqld.1] +log-bin +log-slave-updates + +[mysqld.2] +log-bin +log-slave-updates + +[mysqld.3] +log-bin +log-slave-updates + + +[ENV] +SERVER_MYPORT_1= @mysqld.1.port +SERVER_MYPORT_2= @mysqld.2.port +SERVER_MYPORT_3= @mysqld.3.port diff --git a/mysql-test/suite/rpl/t/rpl_start_alter_7.test b/mysql-test/suite/rpl/t/rpl_start_alter_7.test new file mode 100644 index 00000000..7225c075 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_alter_7.test @@ -0,0 +1,112 @@ +# +# Start Alter with Parallel Replication, With 2 sources +# 2 domain id (From 2 sources) +# |Concurrent alters| >= |Parallel workers on slave| +# |x| denotes number of entities it encloses +# +--source include/have_log_bin.inc +--source include/have_innodb.inc +--source include/have_debug.inc +--connect (server_1,127.0.0.1,root,,,$SERVER_MYPORT_1) +--connect (server_2,127.0.0.1,root,,,$SERVER_MYPORT_2) +--connect (server_3,127.0.0.1,root,,,$SERVER_MYPORT_3) + +--connection server_1 +--let $binlog_alter_two_phase= `select @@binlog_alter_two_phase` +set global binlog_alter_two_phase = ON; +set binlog_alter_two_phase = ON; + +--connection server_2 +stop slave; +set global binlog_alter_two_phase=true; + +--connection server_3 +--let $gtid_strict_mode= `select @@gtid_strict_mode` +--let $slave_parallel_threads= `select @@slave_parallel_threads` +--let $slave_parallel_mode= `select @@slave_parallel_mode` +SET GLOBAL slave_parallel_threads=8; +set global slave_parallel_mode=optimistic; +set global gtid_strict_mode=1; + + +--disable_warnings +--disable_query_log +--replace_result $SERVER_MYPORT_1 MYPORT_1 +eval change master 'm1' to master_port=$SERVER_MYPORT_1 , master_host='127.0.0.1', master_user='root', master_use_gtid=slave_pos; +--replace_result $SERVER_MYPORT_2 MYPORT_2 +eval change master 'm2' to master_port=$SERVER_MYPORT_2 , master_host='127.0.0.1', master_user='root', master_use_gtid=slave_pos; +--enable_query_log +--enable_warnings + +--connection server_1 +set gtid_domain_id= 11; +create database s1; +use s1; +--let $domain_1=11 +--let $domain_2=11 +--let $M_port= $SERVER_MYPORT_1 +--let $S_port= $SERVER_MYPORT_3 +--let $sync_slave=0 +--let $db_name=s1 +--source include/start_alter_include.inc +--connection server_1 +drop database s1; +select @@gtid_binlog_pos; +--let $master_pos_1= `SELECT @@gtid_binlog_pos` + +--connection server_2 +set gtid_domain_id= 12; +create database s2; +use s2; +--let $domain_1=12 +--let $domain_2=12 +--let $M_port= $SERVER_MYPORT_2 +--let $S_port= $SERVER_MYPORT_3 +--let $sync_slave=0 +--let $db_name=s2 +--source include/start_alter_include.inc +--connection server_2 +drop database s2; +select @@gtid_binlog_pos; +--let $master_pos_2= `SELECT @@gtid_binlog_pos` + +--connection server_3 +start all slaves; +set default_master_connection = 'm1'; +--source include/wait_for_slave_to_start.inc +set default_master_connection = 'm2'; +--source include/wait_for_slave_to_start.inc + +set default_master_connection = 'm1'; +--let $master_pos= $master_pos_1 +--source include/sync_with_master_gtid.inc +set default_master_connection = 'm2'; +--let $master_pos= $master_pos_2 +--source include/sync_with_master_gtid.inc + +--echo # cleanup +--connection server_3 +set default_master_connection = 'm1'; +--source include/stop_slave.inc +set default_master_connection = 'm2'; +--source include/stop_slave.inc +--eval set global slave_parallel_threads = $slave_parallel_threads; +--eval set global slave_parallel_mode = $slave_parallel_mode; +--eval set global gtid_strict_mode = $gtid_strict_mode; +set global gtid_domain_id= 0; +reset master; +RESET SLAVE ALL; +SET GLOBAL gtid_slave_pos= ''; + +--connection server_1 +--eval set global binlog_alter_two_phase=$binlog_alter_two_phase; +set global gtid_domain_id= 0; +reset master; +--connection server_2 +set global gtid_domain_id= 0; +--eval set global binlog_alter_two_phase=$binlog_alter_two_phase +reset master; + +--disconnect server_1 +--disconnect server_2 +--disconnect server_3 diff --git a/mysql-test/suite/rpl/t/rpl_start_alter_8.cnf b/mysql-test/suite/rpl/t/rpl_start_alter_8.cnf new file mode 100644 index 00000000..a0f6dc57 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_alter_8.cnf @@ -0,0 +1,19 @@ +!include ../my.cnf + +[mysqld.1] +log-bin +log-slave-updates + +[mysqld.2] +log-bin +log-slave-updates + +[mysqld.3] +log-bin +log-slave-updates + + +[ENV] +SERVER_MYPORT_1= @mysqld.1.port +SERVER_MYPORT_2= @mysqld.2.port +SERVER_MYPORT_3= @mysqld.3.port diff --git a/mysql-test/suite/rpl/t/rpl_start_alter_8.test b/mysql-test/suite/rpl/t/rpl_start_alter_8.test new file mode 100644 index 00000000..4ab8e2b0 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_alter_8.test @@ -0,0 +1,109 @@ +# +# Start Alter with Parallel Replication, With 2 sources +# 2 domain id (From 2 sources) +# |Concurrent alters| < |Parallel workers on slave| +# |x| denotes number of entities it encloses +# +--source include/have_log_bin.inc +--source include/have_innodb.inc +--source include/have_debug.inc +--connect (server_1,127.0.0.1,root,,,$SERVER_MYPORT_1) +--connect (server_2,127.0.0.1,root,,,$SERVER_MYPORT_2) +--connect (server_3,127.0.0.1,root,,,$SERVER_MYPORT_3) + +--connection server_1 +--let $binlog_alter_two_phase= `select @@binlog_alter_two_phase` +set global binlog_alter_two_phase = ON; +set binlog_alter_two_phase = ON; + +--connection server_2 +stop slave; +set global binlog_alter_two_phase=true; + +--connection server_3 +--let $gtid_strict_mode= `select @@gtid_strict_mode` +--let $slave_parallel_threads= `select @@slave_parallel_threads` +--let $slave_parallel_mode= `select @@slave_parallel_mode` +SET GLOBAL slave_parallel_threads=20; +set global slave_parallel_mode=optimistic; +set global gtid_strict_mode=1; + +--disable_warnings +--disable_query_log +--replace_result $SERVER_MYPORT_1 MYPORT_1 +eval change master 'm1' to master_port=$SERVER_MYPORT_1 , master_host='127.0.0.1', master_user='root', master_use_gtid=slave_pos; +--replace_result $SERVER_MYPORT_2 MYPORT_2 +eval change master 'm2' to master_port=$SERVER_MYPORT_2 , master_host='127.0.0.1', master_user='root', master_use_gtid=slave_pos; +--enable_query_log +--enable_warnings + +--connection server_1 +set gtid_domain_id= 11; +create database s1; +use s1; +--let $domain_1=11 +--let $domain_2=11 +--let $M_port= $SERVER_MYPORT_1 +--let $S_port= $SERVER_MYPORT_3 +--let $sync_slave=0 +--let $db_name=s1 +--source include/start_alter_include.inc +--connection server_1 +drop database s1; +--let $master_pos_1= `SELECT @@gtid_binlog_pos` + +--connection server_2 +set gtid_domain_id= 12; +create database s2; +use s2; +--let $domain_1=12 +--let $domain_2=12 +--let $M_port= $SERVER_MYPORT_2 +--let $S_port= $SERVER_MYPORT_3 +--let $sync_slave=0 +--let $db_name=s2 +--source include/start_alter_include.inc +--connection server_2 +drop database s2; +--let $master_pos_2= `SELECT @@gtid_binlog_pos` + +--connection server_3 +start all slaves; +set default_master_connection = 'm1'; +--source include/wait_for_slave_to_start.inc +set default_master_connection = 'm2'; +--source include/wait_for_slave_to_start.inc + +set default_master_connection = 'm1'; +--let $master_pos= $master_pos_1 +--source include/sync_with_master_gtid.inc +set default_master_connection = 'm2'; +--let $master_pos= $master_pos_2 +--source include/sync_with_master_gtid.inc + +--echo # cleanup +--connection server_3 +set default_master_connection = 'm1'; +--source include/stop_slave.inc +set default_master_connection = 'm2'; +--source include/stop_slave.inc +--eval set global slave_parallel_threads = $slave_parallel_threads; +--eval set global slave_parallel_mode = $slave_parallel_mode; +--eval set global gtid_strict_mode = $gtid_strict_mode; +set global gtid_domain_id= 0; +reset master; +RESET SLAVE ALL; +SET GLOBAL gtid_slave_pos= ''; + +--connection server_1 +--eval set global binlog_alter_two_phase=$binlog_alter_two_phase; +set global gtid_domain_id= 0; +reset master; +--connection server_2 +set global gtid_domain_id= 0; +--eval set global binlog_alter_two_phase=$binlog_alter_two_phase; +reset master; + +--disconnect server_1 +--disconnect server_2 +--disconnect server_3 diff --git a/mysql-test/suite/rpl/t/rpl_start_alter_bugs.test b/mysql-test/suite/rpl/t/rpl_start_alter_bugs.test new file mode 100644 index 00000000..52eef9fb --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_alter_bugs.test @@ -0,0 +1,47 @@ +# +# MDEV-22985 Assertion `!(thd->rgi_slave && thd->rgi_slave->did_mark_start_commit)' failed in ha_rollback_trans# +# +# + +--source include/have_log_bin.inc +--source include/have_innodb.inc +--source include/master-slave.inc + +--connection master +set global binlog_alter_two_phase=true; + +--connection slave +stop slave; +SET global slave_parallel_threads=2; +set global slave_parallel_mode=optimistic; +start slave; +--connection master + +CREATE TABLE t1 (i int primary key) ENGINE = InnoDB; +--connection master1 +ALTER TABLE t1 DROP PRIMARY KEY; +ALTER TABLE t1 ADD UNIQUE KEY ui (i); +ALTER TABLE t1 ADD PRIMARY KEY (i); + +--sync_slave_with_master + + #MENT 1274 +--connection master +drop table t1; +CREATE TABLE t1 (a int)engine=innodb; +ALTER TABLE t1 add column b int, LOCK=EXCLUSIVE; +drop table t1; +CREATE TABLE t1 (pk int)engine=innodb; +--error ER_CANT_DROP_FIELD_OR_KEY +ALTER TABLE t1 DROP FOREIGN KEY y, LOCK=EXCLUSIVE; +drop table t1; +--sync_slave_with_master +--connection master +set global binlog_alter_two_phase=false; + +--connection slave +--source include/stop_slave.inc +SET global slave_parallel_threads=0; +--source include/start_slave.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_start_alter_chain_basic.cnf b/mysql-test/suite/rpl/t/rpl_start_alter_chain_basic.cnf new file mode 100644 index 00000000..498d8ed1 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_alter_chain_basic.cnf @@ -0,0 +1,24 @@ +!include ../my.cnf + +[mysqld.1] +log-slave-updates +loose-innodb + +[mysqld.2] +log-slave-updates +loose-innodb + +[mysqld.3] +log-slave-updates +binlog_alter_two_phase=1 +loose-innodb + +[mysqld.4] +loose-innodb + +[ENV] +SERVER_MYPORT_3= @mysqld.3.port +SERVER_MYSOCK_3= @mysqld.3.socket + +SERVER_MYPORT_4= @mysqld.4.port +SERVER_MYSOCK_4= @mysqld.4.socket diff --git a/mysql-test/suite/rpl/t/rpl_start_alter_chain_basic.test b/mysql-test/suite/rpl/t/rpl_start_alter_chain_basic.test new file mode 100644 index 00000000..2c6f9c0f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_alter_chain_basic.test @@ -0,0 +1,54 @@ +# +# MENT-662 Lag Free alter for slave +# In this we will see if chain replication works as +# M->S(Legacy)->S(Parallel)->S(Legacy, without log-slave-upadates) +# +--source include/have_innodb.inc +--let $rpl_topology=1->2->3->4 +--source include/rpl_init.inc + +--connection server_3 +--let $gtid_strict_mode= `select @@gtid_strict_mode` +--let $slave_parallel_threads= `select @@slave_parallel_threads` +--let $slave_parallel_mode= `select @@slave_parallel_mode` +set global gtid_strict_mode=1; + +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads=10; +set global slave_parallel_mode=optimistic; +change master to master_use_gtid=slave_pos; +--source include/start_slave.inc + + +--connection server_1 +--let $binlog_alter_two_phase= `select @@binlog_alter_two_phase` +set global binlog_alter_two_phase=ON; +set binlog_alter_two_phase=ON; +--let $engine=innodb +--let $sync_slave= 1 +connect(master_node,127.0.0.1,root,,$db_name, $SERVER_MYPORT_1); +connect(slave_node,127.0.0.1,root,,test, $SERVER_MYPORT_2); +--source include/start_alter_basic.inc +--disconnect master_node +--disconnect slave_node +--connection server_1 +--eval set global binlog_alter_two_phase=$binlog_alter_two_phase +--source include/rpl_sync.inc + + +--connection server_2 +select domain_id, seq_no from mysql.gtid_slave_pos order by seq_no desc limit 1; + +--connection server_3 +select domain_id, seq_no from mysql.gtid_slave_pos order by seq_no desc limit 1; +--source include/stop_slave.inc +--eval set global slave_parallel_threads = $slave_parallel_threads; +--eval set global slave_parallel_mode = $slave_parallel_mode; +--eval set global gtid_strict_mode = $gtid_strict_mode; +--source include/start_slave.inc +select @@slave_parallel_threads; + +--connection server_4 +select domain_id, seq_no from mysql.gtid_slave_pos order by seq_no desc limit 1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_start_alter_ftwrl.test b/mysql-test/suite/rpl/t/rpl_start_alter_ftwrl.test new file mode 100644 index 00000000..a8528cc6 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_alter_ftwrl.test @@ -0,0 +1,91 @@ +# +# MDEV-11675 Two phase ALTER binlogging +# +# Prove that FTWRL in the middle of START and "COMPLETE" parts of ALTER +# is safe. + +--source include/have_debug.inc +--source include/have_innodb.inc +--source include/master-slave.inc + +--connection slave +--let $slave_parallel_threads= `select @@slave_parallel_threads` +--let $slave_parallel_mode= `select @@slave_parallel_mode` +--let $debug = `SELECT @@global.debug_dbug` + +--source include/stop_slave.inc + +SET @@global.slave_parallel_threads=4; +SET @@global.slave_parallel_mode=optimistic; +CHANGE MASTER TO master_use_gtid=slave_pos; + +SET @@global.debug_dbug="+d,at_write_start_alter"; +--source include/start_slave.inc + +--connection master +SET @@session.binlog_alter_two_phase=true; + +CREATE TABLE t1 (a INT) ENGINE=innodb; +--source include/save_master_gtid.inc + +# Make sure the table exists on slave now. +--connection slave +--source include/sync_with_master_gtid.inc + +--connection master +SET @@session.alter_algorithm='INSTANT'; +SET @@session.gtid_domain_id=11; +ALTER TABLE t1 ADD COLUMN b int; + + +--echo # START Alter having exclusive lock is waiting for the signal +--connection slave +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'debug sync point: now' +--source include/wait_condition.inc + +--echo # FTWRL is sent first to wait for SA +--connection slave1 +--send FLUSH TABLES WITH READ LOCK + +--echo # SA completes +# First wait for the FTWRL arrival. +--connection slave +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO = 'FLUSH TABLES WITH READ LOCK' and STATE = 'Waiting for worker threads to pause for global read lock' +--source include/wait_condition.inc + +set DEBUG_SYNC= "now signal alter_cont"; + +--connection slave1 +--reap + +# Commit ALTER is hanging now +--connection slave +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND = 'Slave_worker' AND STATE = 'Waiting for backup lock' +--source include/wait_condition.inc + +--echo # Release CA +--connection slave1 +UNLOCK TABLES; + +--connection master +--sync_slave_with_master + +SHOW CREATE TABLE t1; +--source include/show_binlog_events.inc + +--connection master +DROP TABLE t1; + +--sync_slave_with_master + +--echo # cleanup +--connection slave +set DEBUG_SYNC = RESET; +--source include/stop_slave.inc +--eval set global slave_parallel_threads = $slave_parallel_threads +--eval set global slave_parallel_mode = $slave_parallel_mode +--eval set @@global.debug_dbug = "$debug" +--source include/start_slave.inc + + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_start_alter_instant.test b/mysql-test/suite/rpl/t/rpl_start_alter_instant.test new file mode 100644 index 00000000..ecb62e04 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_alter_instant.test @@ -0,0 +1,30 @@ +# MDEV-11675 +# Prove that "fast" ALTER options also combine with @@binlog_alter_two_phase. +--source include/have_innodb.inc +--source include/master-slave.inc + +--connection master +set binlog_alter_two_phase=true; +CREATE OR REPLACE TABLE tab ( + a int PRIMARY KEY, + b varchar(50), + c varchar(50) +) CHARACTER SET=latin1 engine=innodb; + +SET SESSION alter_algorithm='INSTANT'; +ALTER TABLE tab MODIFY COLUMN b varchar(100); +SET SESSION alter_algorithm='NOCOPY'; +ALTER TABLE tab MODIFY COLUMN c varchar(100); +SHOW CREATE TABLE tab; +--source include/show_binlog_events.inc + +--sync_slave_with_master +SHOW CREATE TABLE tab; +--source include/show_binlog_events.inc + +--connection master +DROP TABLE tab; + +--sync_slave_with_master + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_start_alter_mysqlbinlog_1.test b/mysql-test/suite/rpl/t/rpl_start_alter_mysqlbinlog_1.test new file mode 100644 index 00000000..f655d3c1 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_alter_mysqlbinlog_1.test @@ -0,0 +1,38 @@ +# +# Start Alter with binlog applied using mysqlbinlog +# single master with only one domain id +# +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/master-slave.inc + +--connection master +set global binlog_alter_two_phase=true; +--connection slave +--source include/stop_slave.inc +set global gtid_strict_mode=1; + +--echo # Legacy Master Slave +--let $domain_1=0 +--let $domain_2=0 +--let $M_port= $MASTER_MYPORT +--let $S_port= $SLAVE_MYPORT +--let $sync_slave=0 + +--source include/start_alter_include.inc +--connection master +--let $MYSQLD_DATADIR= `select @@datadir;` +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/master.sql +select @@gtid_binlog_state; +RESET master; + +--connection slave +--exec $MYSQL --host=127.0.0.1 --port=$SLAVE_MYPORT -e "source $MYSQLTEST_VARDIR/tmp/master.sql" +select @@gtid_binlog_state; +set global gtid_strict_mode=0; +--source include/start_slave.inc + +--connection master +set global binlog_alter_two_phase=false; +remove_file $MYSQLTEST_VARDIR/tmp/master.sql; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_start_alter_mysqlbinlog_2.cnf b/mysql-test/suite/rpl/t/rpl_start_alter_mysqlbinlog_2.cnf new file mode 100644 index 00000000..a0f6dc57 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_alter_mysqlbinlog_2.cnf @@ -0,0 +1,19 @@ +!include ../my.cnf + +[mysqld.1] +log-bin +log-slave-updates + +[mysqld.2] +log-bin +log-slave-updates + +[mysqld.3] +log-bin +log-slave-updates + + +[ENV] +SERVER_MYPORT_1= @mysqld.1.port +SERVER_MYPORT_2= @mysqld.2.port +SERVER_MYPORT_3= @mysqld.3.port diff --git a/mysql-test/suite/rpl/t/rpl_start_alter_mysqlbinlog_2.test b/mysql-test/suite/rpl/t/rpl_start_alter_mysqlbinlog_2.test new file mode 100644 index 00000000..c7d5bd66 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_alter_mysqlbinlog_2.test @@ -0,0 +1,164 @@ +# +# MENT-662 Lag Free Alter On Slave +# + +# Start Alter with Parallel Replication, With 2 sources +# 2 domain id (From 2 sources) +# |Concurrent alters| < |Parallel workers on slave| +# |x| denotes number of entities it encloses +# And then binary log from slave is replayed to slave again to check if +# binlog output is okay. +# + +--source include/have_log_bin.inc +--source include/have_innodb.inc +--source include/have_debug.inc +--connect (server_1,127.0.0.1,root,,,$SERVER_MYPORT_1) +--connect (server_2,127.0.0.1,root,,,$SERVER_MYPORT_2) +--connect (server_3,127.0.0.1,root,,,$SERVER_MYPORT_3) + +--connection server_1 +SET @save_binlog_alter_two_phase= @@GLOBAL.binlog_alter_two_phase; +SET GLOBAL binlog_alter_two_phase = ON; +SET binlog_alter_two_phase = ON; +--echo # Create table and perform CA and RA +CREATE TABLE t1( a INT, b INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES(1,1); +INSERT INTO t1 VALUES(2,2); +--echo # Normal Alter +ALTER TABLE t1 ADD COLUMN c INT; +--echo # Failed Alter +INSERT INTO t1 VALUES(1,1, NULL); +--error ER_DUP_ENTRY +ALTER TABLE t1 CHANGE a a INT UNIQUE; +SHOW CREATE TABLE t1; +SELECT @@gtid_binlog_state; + +--echo # apply the binlog +let MYSQLD_DATADIR= `select @@datadir;`; +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/master_1.sql +DROP TABLE t1; +--echo # reset the binlog +RESET MASTER; + +--echo # execute the binlog +--exec $MYSQL --port=$SERVER_MYPORT_1 --host=127.0.0.1 -e "source $MYSQLTEST_VARDIR/tmp/master_1.sql" +SELECT @@gtid_binlog_state; +--echo # Same as before +SHOW CREATE TABLE t1; +DROP TABLE t1; +--echo # reset the binlog +RESET MASTER; +RESET SLAVE; +remove_file $MYSQLTEST_VARDIR/tmp/master_1.sql; + +--connection server_2 +SET @save_binlog_alter_two_phase= @@GLOBAL.binlog_alter_two_phase; +SET GLOBAL binlog_alter_two_phase = ON; + +--connection server_3 +SET @save_gtid_strict_mode= @@GLOBAL.gtid_strict_mode; +SET @slave_parallel_threads= @@GLOBAL.slave_parallel_threads; +SET @slave_parallel_mode= @@GLOBAL.slave_parallel_mode; +SET GLOBAL slave_parallel_threads=20; +SET GLOBAL slave_parallel_mode=optimistic; +SET GLOBAL gtid_strict_mode=1; + +--disable_warnings +--disable_query_log +--replace_result $SERVER_MYPORT_1 MYPORT_1 +eval CHANGE MASTER 'm1' TO MASTER_PORT=$SERVER_MYPORT_1, MASTER_HOST='127.0.0.1', MASTER_USER='root', MASTER_USE_GTID=slave_pos; +--replace_result $SERVER_MYPORT_2 MYPORT_2 +eval CHANGE MASTER 'm2' TO MASTER_PORT=$SERVER_MYPORT_2, MASTER_HOST='127.0.0.1', MASTER_USER='root', MASTER_USE_GTID=slave_pos; +--enable_query_log +--enable_warnings + +--connection server_1 +SET gtid_domain_id= 11; +CREATE DATABASE s1; +USE s1; +--let $domain_1=11 +--let $domain_2=11 +--let $M_port= $SERVER_MYPORT_1 +--let $S_port= $SERVER_MYPORT_3 +--let $sync_slave=0 +--let $db_name=s1 +--source include/start_alter_include.inc + +--connection server_1 +DROP DATABASE s1; +--let $master_pos_1= `SELECT @@gtid_binlog_pos` + +--connection server_2 +SET gtid_domain_id= 12; +CREATE DATABASE s2; +USE s2; +--let $domain_1=12 +--let $domain_2=12 +--let $M_port= $SERVER_MYPORT_2 +--let $S_port= $SERVER_MYPORT_3 +--let $sync_slave=0 +--let $db_name=s2 +--source include/start_alter_include.inc +--connection server_2 +DROP DATABASE s2; +--let $master_pos_2= `SELECT @@gtid_binlog_pos` + +--connection server_3 +START ALL SLAVES; +SET default_master_connection = 'm1'; +--source include/wait_for_slave_to_start.inc +SET default_master_connection = 'm2'; +--source include/wait_for_slave_to_start.inc + +SET default_master_connection = 'm1'; +--let $master_pos= $master_pos_1 +--source include/sync_with_master_gtid.inc +SET default_master_connection = 'm2'; +--let $master_pos= $master_pos_2 +--source include/sync_with_master_gtid.inc + +--echo # Stop slaves and apply binlog +--connection server_3 +SET default_master_connection = 'm1'; +--source include/stop_slave.inc +SET default_master_connection = 'm2'; +--source include/stop_slave.inc +SET GLOBAL slave_parallel_threads = @slave_parallel_threads; +SET GLOBAL slave_parallel_mode = @slave_parallel_mode; +SET GLOBAL gtid_strict_mode = @save_gtid_strict_mode; +SET GLOBAL gtid_domain_id= 0; +SELECT @@gtid_binlog_state; + +let MYSQLD_DATADIR= `select @@datadir;`; +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/slave_1.sql +--echo # reset the binlog +RESET MASTER; +--echo # execute the binlog +--exec $MYSQL --port=$SERVER_MYPORT_3 --host=127.0.0.1 -e "source $MYSQLTEST_VARDIR/tmp/slave_1.sql" +SELECT @@gtid_binlog_state; + +--echo # One more time to simulate S->S case +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/slave_2.sql +RESET MASTER; +--echo # execute the binlog +--exec $MYSQL --port=$SERVER_MYPORT_3 --host=127.0.0.1 -e "source $MYSQLTEST_VARDIR/tmp/slave_2.sql" +SELECT @@gtid_binlog_state; +remove_file $MYSQLTEST_VARDIR/tmp/slave_1.sql; +remove_file $MYSQLTEST_VARDIR/tmp/slave_2.sql; +RESET MASTER; +RESET SLAVE ALL; +SET GLOBAL gtid_slave_pos= ''; + +--connection server_1 +SET GLOBAL binlog_alter_two_phase=@save_binlog_alter_two_phase; +SET GLOBAL gtid_domain_id= 0; +RESET MASTER; +--connection server_2 +SET GLOBAL gtid_domain_id= 0; +SET GLOBAL binlog_alter_two_phase=@save_binlog_alter_two_phase; +RESET MASTER; + +--disconnect server_1 +--disconnect server_2 +--disconnect server_3 diff --git a/mysql-test/suite/rpl/t/rpl_start_alter_optimize.test b/mysql-test/suite/rpl/t/rpl_start_alter_optimize.test new file mode 100644 index 00000000..528f2b52 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_alter_optimize.test @@ -0,0 +1,25 @@ +# MDEV-11675 two phase logged ALTER +# +# The tests verifies execution of non-ALTER queries that are handled +# through mysql_alter_table function. + +--source include/have_log_bin.inc +--source include/have_innodb.inc +--source include/master-slave.inc + +--connection master +set binlog_alter_two_phase = ON; + +--connection master +CREATE TABLE t1 (i int) engine=innodb; +CREATE TABLE t2 (i int) engine=innodb; + +ALTER TABLE t1 DROP CONSTRAINT IF EXISTS y; +OPTIMIZE TABLE t2; + +--sync_slave_with_master + +--connection master +drop table t1,t2; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_start_alter_options.test b/mysql-test/suite/rpl/t/rpl_start_alter_options.test new file mode 100644 index 00000000..12125b49 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_alter_options.test @@ -0,0 +1,31 @@ +# This test will test all the option related to the Alter Table command +# NOTE not all alter statements will follow alter_algorithm since for some statements +# copy is only option +# parameters +# $alter_algorithm {DEFAULT|INPLACE|COPY|NOCOPY|INSTANT} +# $show_binlog +# + +--source include/have_partition.inc +--source include/have_innodb.inc +--source include/master-slave.inc + +--let $alter_algorithm= default +#--let $show_binlog= false +--source include/start_alter_options.inc + +--let $alter_algorithm= inplace +--source include/start_alter_options.inc + +--let $alter_algorithm= copy +--source include/start_alter_options.inc + +--echo # Prove formal support for nocopy and instant +--let $alter_algorithm= instant +--source include/start_alter_options.inc + +--let $alter_algorithm= nocopy +--source include/start_alter_options.inc + + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_start_alter_para_to_seq.test b/mysql-test/suite/rpl/t/rpl_start_alter_para_to_seq.test new file mode 100644 index 00000000..37e25313 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_alter_para_to_seq.test @@ -0,0 +1,24 @@ +# MDEV-11675 binlog_alter_two_phase +# MDEV-27511 Assertion `rgi->gtid_ev_flags_extra & Gtid_log_event::FL_COMMIT_ALTER_E1' failed +# in write_bin_log_start_alter +# +--source include/have_log_bin.inc +--source include/master-slave.inc + +# The test proves the assert is not hit anymore. +--connection master +CREATE TABLE t1 (a1 int, d1 int DEFAULT 0); +INSERT INTO t1 VALUES (1,1) ; +SET binlog_alter_two_phase = ON; +ALTER TABLE t1 WAIT 9 RENAME COLUMN a1 TO a2; +SET binlog_alter_two_phase = OFF; +ALTER TABLE t1 ALTER COLUMN d1 DROP DEFAULT; + +--sync_slave_with_master + +# Cleanup +--connection master +drop table t1; +--sync_slave_with_master + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_start_alter_restart_master.test b/mysql-test/suite/rpl/t/rpl_start_alter_restart_master.test new file mode 100644 index 00000000..aac3af6f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_alter_restart_master.test @@ -0,0 +1,81 @@ +# Test crashing of master after writing start alter into binary log. +# And the doing the same alter again, to test on slave if that is successful +# ====> SA Crash SA CA Case +# +--source include/have_log_bin.inc +--source include/have_binlog_format_mixed.inc +--source include/have_innodb.inc +--source include/master-slave.inc +--source include/have_debug.inc +--source include/no_valgrind_without_big.inc + +--connection slave +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=NO; +--source include/start_slave.inc + +--connection slave +SET @old_debug_slave= @@global.debug; +stop slave; +--let $gtid_strict_mode= `select @@gtid_strict_mode` +--let $slave_parallel_threads= `select @@slave_parallel_threads` +--let $slave_parallel_mode= `select @@slave_parallel_mode` +SET GLOBAL slave_parallel_threads=4; +set global slave_parallel_mode=optimistic; +set global gtid_strict_mode=1; +start slave; + +--connection master +call mtr.add_suppression("ALTER query started at .+ could not be completed"); + +SET @old_debug_master= @@global.debug; +--let $binlog_alter_two_phase= `select @@binlog_alter_two_phase` +set binlog_alter_two_phase=true; +create table t3( a int primary key, b int) engine=innodb; + +--connection master +--sync_slave_with_master +--source include/stop_slave.inc + + +--connection master +--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +SET SESSION debug_dbug="d,start_alter_kill_after_binlog"; +--error 2013 +alter table t3 add column d int; + +--let $rpl_server_number= 1 +--source include/rpl_reconnect.inc +set binlog_alter_two_phase= true; +alter table t3 add column d int; +show create table t3; +--source include/show_binlog_events.inc +--let $binlog_file=master-bin.000002 +--source include/show_binlog_events.inc +--let $binlog_file= + +--connection slave +--source include/start_slave.inc + +--connection master +--sync_slave_with_master +--source include/show_binlog_events.inc +show create table t3; + + +--connection master +SET GLOBAL debug_dbug= @old_debug_master; +drop table t3; +--eval set global binlog_alter_two_phase = $binlog_alter_two_phase + +--sync_slave_with_master +SET GLOBAL debug_dbug= @old_debug_slave; +stop slave; +--eval set global slave_parallel_threads = $slave_parallel_threads; +--eval set global slave_parallel_mode = $slave_parallel_mode; +--eval set global gtid_strict_mode = $gtid_strict_mode; +start slave; +--connection master +let MYSQLD_DATADIR= `select @@datadir;`; +--remove_files_wildcard $MYSQLD_DATADIR/test #sql*.frm +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_start_alter_restart_slave.test b/mysql-test/suite/rpl/t/rpl_start_alter_restart_slave.test new file mode 100644 index 00000000..df028ff1 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_alter_restart_slave.test @@ -0,0 +1,121 @@ +# This test will restart the slave in middle of start alter commit alter processing +# slave will be restarted after start alter and before binlogging of commit alter, +# Then we will recieved commit alter from the master. +# Commit alter will act like standalone alter +# =====> SA SA CA(Stop Slave before binlogging) CA +# +--source include/have_log_bin.inc +--source include/have_innodb.inc +--source include/master-slave.inc +--source include/have_debug.inc + +--connection slave +SET @old_debug_slave= @@global.debug; +--source include/stop_slave.inc +--let $gtid_strict_mode= `select @@gtid_strict_mode` +--let $slave_parallel_threads= `select @@slave_parallel_threads` +--let $slave_parallel_mode= `select @@slave_parallel_mode` +SET GLOBAL slave_parallel_threads=4; +set global slave_parallel_mode=optimistic; +set global gtid_strict_mode=1; + +set global debug_dbug="+d,rpl_slave_stop_CA_before_binlog"; + +--source include/start_slave.inc +# +# SLAVE Shutdown +--connection master +SET @old_debug_master= @@global.debug; +set global debug_dbug="+d,start_alter_delay_master"; +--let $binlog_alter_two_phase= `select @@binlog_alter_two_phase` +set global binlog_alter_two_phase=true; +create table t1( a int primary key, b int) engine=myisam; +create table t2( a int primary key, b int) engine=myisam; + +--connect (con1,localhost,root,,) +--send alter table t1 add column c int; + +--connection master +--echo # Get into binlog first and wait +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'debug sync point: now'; +--source include/wait_condition.inc +--let $master_gtid_state = `select @@gtid_binlog_state` +--echo # master gtid state is $master_gtid_state + +--connect (con2,localhost,root,,) +--send alter table t2 add column c int; + +--connection master +--echo # Get into binlog next and wait as well +--let $wait_condition = SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'debug sync point: now'; +--source include/wait_condition.inc +--let $master_gtid_state = `select @@gtid_binlog_state` +--echo # master gtid state is $master_gtid_state + +# Memorize for slave's next sync with master +--let $master_pos=$master_gtid_state + +set DEBUG_SYNC= "now signal alter_cont"; + +--connection con1 +--reap +--connection con2 +--reap +create table t3( a int primary key, b int) engine=innodb; +--let $master_gtid_state = `select @@gtid_binlog_state` +--echo # master gtid state is $master_gtid_state +--let $replace_regexp=/alter table t[12]/alter table <t>/ /id=[0-9]+/id=<seq_no>/ +--source include/show_binlog_events2.inc + +--echo # Stop Slave +--echo # As master binlog is SA SA CA CA +--echo # let's stop at first CA processing (in process_commit_alter) + +--connection slave +--source include/sync_with_master_gtid.inc +# set debug_sync="now wait_for CA_1_processing"; +connect(extra_slave,127.0.0.1,root,,test,$SLAVE_MYPORT); +--send stop slave; +--connection slave +# set debug_sync="now signal proceed_CA_1"; +--connection extra_slave +--reap +SET GLOBAL debug_dbug= @old_debug_slave; + +--connection slave +--source include/wait_for_slave_sql_to_stop.inc +--echo # The list of events after the slave has stopped must have just one CA: +--let $replace_regexp=/alter table t[12]/alter table <t>/ /id=[0-9]+/id=<seq_no>/ +--source include/show_binlog_events2.inc + +select domain_id, seq_no from mysql.gtid_slave_pos order by seq_no desc limit 1; +--source include/start_slave.inc +--connection master +--sync_slave_with_master +--echo # Everything from the master binlog must have been applied now: +select domain_id, seq_no from mysql.gtid_slave_pos order by seq_no desc limit 1; +--let $slave_gtid_state = `select @@gtid_binlog_state` +--echo # slave gtid state is $slave_gtid_state +if (`select $master_gtid_state <> $slave_gtid_state`) +{ + --echo Gtid state mismatch: $master_gtid_state <> $slave_gtid_state + --die +} +--echo # The list of events after the slave has synchronized must have both CA: +--let $replace_regexp=/alter table t[12]/alter table <t>/ /id=[0-9]+/id=<seq_no>/ +--source include/show_binlog_events2.inc + +--connection master +drop table t1,t2,t3; +--eval set global binlog_alter_two_phase = $binlog_alter_two_phase +SET GLOBAL debug_dbug= @old_debug_master; +set DEBUG_SYNC= 'RESET'; + +--sync_slave_with_master +stop slave; +--eval set global slave_parallel_threads = $slave_parallel_threads; +--eval set global slave_parallel_mode = $slave_parallel_mode; +--eval set global gtid_strict_mode = $gtid_strict_mode; +set DEBUG_SYNC= 'RESET'; +start slave; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_start_stop_slave-slave.opt b/mysql-test/suite/rpl/t/rpl_start_stop_slave-slave.opt new file mode 100644 index 00000000..c7cdc20f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_stop_slave-slave.opt @@ -0,0 +1 @@ +--loose-innodb-lock-wait-timeout=60 diff --git a/mysql-test/suite/rpl/t/rpl_start_stop_slave.test b/mysql-test/suite/rpl/t/rpl_start_stop_slave.test new file mode 100644 index 00000000..23b25b1b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_stop_slave.test @@ -0,0 +1,65 @@ +# +#BUG#11752315 : STOP SLAVE UNABLE TO COMPLETE WHEN SLAVE THREAD IS TRYING +# TO RECONNECT TO +# +# ==== Purpose ==== +# +#Tests that the slave does not go to a sleep for a long duration after the +#master is killed and we do a START_SLAVE and STOP_SLAVE. +# +# ==== Method ==== +# +#This is a new functionality of having an interruptable sleep of the slave. +#We find the thread id for the slave thread. On finding the thread ID of the +#slave thread we kill the slave thread. A successful kill in less than 60 sec +#should serve the purpose of checking the functionality. +# + +--source include/have_log_bin.inc +--source include/master-slave.inc + +connection slave; +--let $connection_id=`SELECT id FROM information_schema.processlist where state LIKE 'Waiting for master to send event'` + +if(!$connection_id) +{ + # Something went wrong (timing) + # Show process list so that we can debug. In this case we will abort with + # wrong result + -- echo "Could not find connect id. Dumping process list for debugging" + SELECT * FROM information_schema.processlist; + exit; +} + +set @time_before_kill := (select CURRENT_TIMESTAMP); + +--echo [Time before the query] +--echo [Connection ID of the slave I/O thread found] + +--replace_regex /kill [0-9]*/kill <connection_id>/ +--eval kill $connection_id +--source include/wait_for_slave_io_to_stop.inc + +set @time_after_kill := (select CURRENT_TIMESTAMP); + +--echo [Time after the query] + +if(`select TIMESTAMPDIFF(SECOND,@time_after_kill, @time_before_kill) > 60`) +{ +--echo # assert : The difference between the timestamps 'time_after_kill' and 'time_before_kill' should be less than 60sec. +--die +} +--echo [Killing of the slave IO thread was successful] + +START SLAVE IO_THREAD; +--source include/wait_for_slave_io_to_start.inc + +# Ensure that the slave io thread started properly +connection master; +create table t1 (a int primary key); +sync_slave_with_master; +connection master; +drop table t1; + +# End of test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_stm_000001.test b/mysql-test/suite/rpl/t/rpl_stm_000001.test new file mode 100644 index 00000000..3851e618 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_000001.test @@ -0,0 +1,118 @@ +# Requires binlog_format=statement format since query involving +# get_lock() is logged in row format if binlog_format=mixed or row. +-- source include/have_binlog_format_statement.inc +-- source include/master-slave.inc + +CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); + +# Load some data into t1 +create table t1 (word char(20) not null); +load data infile '../../std_data/words.dat' into table t1; +--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +eval load data local infile '$MYSQL_TEST_DIR/std_data/words.dat' into table t1; +select * from t1 limit 10; + +# +# Test slave with wrong password +# +sync_slave_with_master; +stop slave; +connection master; +create temporary table tmp select * from mysql.global_priv where host="localhost" and user="root"; +set password for root@"localhost" = password('foo'); +connection slave; +start slave; +connection master; +# +# Give slave time to do at last one failed connect retry +# This one must be short so that the slave will not stop retrying +real_sleep 2; +replace into mysql.global_priv select * from tmp; +drop temporary table tmp; +flush privileges; +# Give slave time to connect (will retry every second) +sleep 2; + +create table t3(n int); +insert into t3 values(1),(2); +sync_slave_with_master; +select * from t3; +select sum(length(word)) from t1; +connection master; +drop table t1,t3; +sync_slave_with_master; + +# Test if the slave SQL thread can be more than 16K behind the slave +# I/O thread (> IO_SIZE) + +connection master; +# we'll use table-level locking to delay slave SQL thread +eval create table t1 (n int); +sync_slave_with_master; +connection master; +reset master; +connection slave; +stop slave; +--source include/reset_slave.inc + +connection master; +let $1=5000; +# Generate 16K of relay log +disable_query_log; +while ($1) +{ + eval insert into t1 values($1); + dec $1; +} +enable_query_log; + +# Try to cause a large relay log lag on the slave by locking t1 +connection slave; +lock tables t1 read; +start slave; +connection master; +--source include/sync_slave_io_with_master.inc +unlock tables; + +#test handling of aborted connection in the middle of update + +connection master; +create table t2(id int); +insert into t2 values(connection_id()); + +connection master1; +# Avoid generating result +create temporary table t3(n int); +--disable_warnings +insert into t3 select get_lock('crash_lock%20C', 1) from t2; +--enable_warnings + +connection master; +send update t1 set n = n + get_lock('crash_lock%20C', 2); +connection master1; +let $wait_condition= SELECT count(*) > 0 FROM information_schema.processlist WHERE info LIKE 'update%' AND state='User lock'; +source include/wait_condition.inc; +select (@id := id) - id from t2; +kill @id; +drop table t2; +drop temporary table t3; +connection master; +# The get_lock function causes warning for unsafe statement. +--disable_warnings +# 2013 = CR_SERVER_LOST +--error ER_QUERY_INTERRUPTED,ER_CONNECTION_KILLED,2013 +reap; +--enable_warnings +connection slave; +# The SQL slave thread should now have stopped because the query was killed on +# the master (so it has a non-zero error code in the binlog). +# 1927 = ER_CONNECTION_KILLED +--let $slave_sql_errno= 1927 +--source include/wait_for_slave_sql_error_and_skip.inc + +select count(*) from t1; +connection master1; +drop table t1; + +# End of 4.1 tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_stm_EE_err2.test b/mysql-test/suite/rpl/t/rpl_stm_EE_err2.test new file mode 100644 index 00000000..07b1000c --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_EE_err2.test @@ -0,0 +1,8 @@ +############################# +# Author: JBM +# Date: 2006-01-11 +# Purpose: Engine Wrapper for rpl_stm_EE_err2.test +############################## +-- source include/have_binlog_format_mixed_or_statement.inc +let $engine_type=myisam; +-- source include/rpl_stm_EE_err2.test diff --git a/mysql-test/suite/rpl/t/rpl_stm_auto_increment_bug33029.test b/mysql-test/suite/rpl/t/rpl_stm_auto_increment_bug33029.test new file mode 100644 index 00000000..280cfcc5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_auto_increment_bug33029.test @@ -0,0 +1,106 @@ +# BUG#33029 5.0 to 5.1 replication fails on dup key when inserting +# using a trig in SP + +# For all 5.0 up to 5.0.58 exclusive, and 5.1 up to 5.1.12 exclusive, +# if one statement in a SP generated AUTO_INCREMENT value by the top +# statement, all statements after it would be considered generated +# AUTO_INCREMENT value by the top statement, and a erroneous INSERT_ID +# value might be associated with these statement, which could cause +# duplicate entry error and stop the slave. + +source include/have_binlog_format_statement.inc; +source include/master-slave.inc; + +CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); +--connection slave +CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); +--connection master + +CREATE TABLE t1 (id INT AUTO_INCREMENT PRIMARY KEY); +CREATE TABLE t2 (id INT AUTO_INCREMENT PRIMARY KEY); + +delimiter //; + +CREATE PROCEDURE p1() +BEGIN + DECLARE ins_count INT DEFAULT 10; + + WHILE ins_count > 0 DO + INSERT INTO t1 VALUES (NULL); + SET ins_count = ins_count - 1; + END WHILE; + + DELETE FROM t1 WHERE id = 1; + DELETE FROM t1 WHERE id = 2; + DELETE FROM t2 WHERE id = 1; + DELETE FROM t2 WHERE id = 2; +END// + +CREATE PROCEDURE p2() +BEGIN + INSERT INTO t1 VALUES (NULL); + DELETE FROM t1 WHERE id = f1(3); + DELETE FROM t1 WHERE id = f1(4); + DELETE FROM t2 WHERE id = 3; + DELETE FROM t2 WHERE id = 4; +END// + +CREATE TRIGGER tr1 BEFORE DELETE + ON t1 FOR EACH ROW + BEGIN + INSERT INTO t2 VALUES (NULL); + END// + +CREATE FUNCTION f1 (i int) RETURNS int + BEGIN + INSERT INTO t2 VALUES (NULL); + RETURN i; + END// + +delimiter ;// + +# the $binlog_start will be used by the show_binlog_events.inc, so +# that we can skip binlog events we don't care +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +CALL p1(); +source include/show_binlog_events.inc; + +echo # Result on master; +SELECT * FROM t1; +SELECT * FROM t2; + +sync_slave_with_master; + +SELECT * FROM t1; +SELECT * FROM t2; + +connection master; + +DROP TRIGGER tr1; + +# the $binlog_start will be used by the show_binlog_events.inc, so +# that we can skip binlog events we don't care +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +CALL p2(); +source include/show_binlog_events.inc; + +echo # Result on master; +SELECT * FROM t1; +SELECT * FROM t2; + +sync_slave_with_master; + +SELECT * FROM t1; +SELECT * FROM t2; + +# clean up +connection master; +disable_warnings; +DROP TABLE IF EXISTS t1, t2; +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +DROP FUNCTION IF EXISTS f1; +DROP TRIGGER IF EXISTS tr1; +enable_warnings; +sync_slave_with_master; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_stm_binlog_direct-master.opt b/mysql-test/suite/rpl/t/rpl_stm_binlog_direct-master.opt new file mode 100644 index 00000000..561902d0 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_binlog_direct-master.opt @@ -0,0 +1 @@ +--binlog-direct-non-transactional-updates diff --git a/mysql-test/suite/rpl/t/rpl_stm_binlog_max_cache_size.test b/mysql-test/suite/rpl/t/rpl_stm_binlog_max_cache_size.test new file mode 100644 index 00000000..f893f909 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_binlog_max_cache_size.test @@ -0,0 +1,8 @@ +--source include/have_innodb.inc +--source include/not_embedded.inc +--source include/not_windows.inc +--source include/have_binlog_format_statement.inc +--source include/master-slave.inc + +--source include/rpl_binlog_max_cache_size.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_stm_conflicts.test b/mysql-test/suite/rpl/t/rpl_stm_conflicts.test new file mode 100644 index 00000000..a4f59253 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_conflicts.test @@ -0,0 +1,6 @@ +source include/have_binlog_format_mixed_or_statement.inc; +source include/master-slave.inc; + +source include/rpl_conflicts.test; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_stm_drop_create_temp_table.test b/mysql-test/suite/rpl/t/rpl_stm_drop_create_temp_table.test new file mode 100644 index 00000000..b971af71 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_drop_create_temp_table.test @@ -0,0 +1,12 @@ +################################################################################### +# This test cases evaluates the mixture of non-transactional and transcational +# tables. Specifically when drop temporary tables and create temporary tables +# are used. +################################################################################### +--source include/big_test.inc +--source include/have_binlog_format_statement.inc +--source include/have_innodb.inc +--source include/master-slave.inc + +--source include/rpl_drop_create_temp_table.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_stm_flsh_tbls.test b/mysql-test/suite/rpl/t/rpl_stm_flsh_tbls.test new file mode 100644 index 00000000..70178c2e --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_flsh_tbls.test @@ -0,0 +1,6 @@ +# depends on the binlog output +--source include/have_binlog_format_mixed_or_statement.inc +--source include/binlog_start_pos.inc + +let $rename_event_pos= `select @binlog_start_pos + 578`; +-- source include/rpl_flsh_tbls.test diff --git a/mysql-test/suite/rpl/t/rpl_stm_found_rows.test b/mysql-test/suite/rpl/t/rpl_stm_found_rows.test new file mode 100644 index 00000000..c1b7e023 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_found_rows.test @@ -0,0 +1,124 @@ +source include/have_binlog_format_statement.inc; +source include/master-slave.inc; + +disable_query_log; +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); +enable_query_log; + +# It is not possible to replicate FOUND_ROWS() using statement-based +# replication, but there is a workaround that stores the result of +# FOUND_ROWS() into a user variable and then replicates this instead. +# +# The purpose of this test case is to test that the workaround works +# properly even when inside stored programs (i.e., stored routines and +# triggers). + +--echo ==== Initialize ==== + +connection master; +CREATE TABLE t1 (a INT); +CREATE TABLE logtbl (sect INT, test INT, count INT); + +INSERT INTO t1 VALUES (1),(2),(3); +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; +INSERT INTO t1 SELECT 2*a+3 FROM t1; + + +--echo ==== Simple test ==== + +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; + +# Instead of +# INSERT INTO logtbl VALUES(1, 1, FOUND_ROWS()); +# we write +--disable_ps2_protocol +SELECT FOUND_ROWS() INTO @a; +--enable_ps2_protocol +INSERT INTO logtbl VALUES(1,1,@a); + +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; +# Instead of +# INSERT INTO logtbl VALUES(1, 2, FOUND_ROWS()); +# we write +--disable_ps2_protocol +SELECT FOUND_ROWS() INTO @a; +--enable_ps2_protocol +INSERT INTO logtbl VALUES(1,2,@a); + +SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test; +sync_slave_with_master; +SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test; + + +--echo ==== Stored procedure ==== + +# Here we do both the calculation and the logging. We also do it twice +# to make sure that there are no limitations on how many times it can +# be used. + +connection master; +--delimiter $$ +CREATE PROCEDURE calc_and_log(sect INT, test INT) BEGIN + DECLARE cnt INT; + SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1; + SELECT FOUND_ROWS() INTO cnt; + INSERT INTO logtbl VALUES(sect,test,cnt); + SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; + SELECT FOUND_ROWS() INTO cnt; + INSERT INTO logtbl VALUES(sect,test+1,cnt); +END $$ +--delimiter ; + +CALL calc_and_log(2,1); + +--delimiter $$ +CREATE PROCEDURE just_log(sect INT, test INT, found_rows INT) BEGIN + INSERT INTO logtbl VALUES (sect,test,found_rows); +END $$ +--delimiter ; + +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +--disable_ps2_protocol +SELECT FOUND_ROWS() INTO @found_rows; +--enable_ps2_protocol +CALL just_log(2,3,@found_rows); + +SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test; +sync_slave_with_master; +SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test; + + +--echo ==== Stored functions ==== +connection master; +--delimiter $$ +CREATE FUNCTION log_rows(sect INT, test INT, found_rows INT) + RETURNS INT +BEGIN + INSERT INTO logtbl VALUES(sect,test,found_rows); + RETURN found_rows; +END $$ +--delimiter ; + +SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1; +--disable_ps2_protocol +SELECT FOUND_ROWS() INTO @found_rows; +SELECT log_rows(3,1,@found_rows), log_rows(3,2,@found_rows); +--enable_ps2_protocol + +SELECT * FROM logtbl WHERE sect = 3 ORDER BY sect,test; +sync_slave_with_master; +SELECT * FROM logtbl WHERE sect = 3 ORDER BY sect,test; + + +--echo ==== Cleanup ==== +connection master; +DROP TABLE t1, logtbl; +DROP PROCEDURE just_log; +DROP PROCEDURE calc_and_log; +DROP FUNCTION log_rows; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_stm_implicit_commit_binlog.test b/mysql-test/suite/rpl/t/rpl_stm_implicit_commit_binlog.test new file mode 100644 index 00000000..6b127182 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_implicit_commit_binlog.test @@ -0,0 +1,12 @@ +################################################################################ +# Check file include/rpl_implicit_commit_binlog.test +################################################################################ +--source include/have_udf.inc +--source include/have_binlog_format_statement.inc +--source include/have_innodb.inc +--source include/master-slave.inc + +--let $engine=Innodb +set session default_storage_engine=innodb; +--source include/rpl_implicit_commit_binlog.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_stm_innodb.test b/mysql-test/suite/rpl/t/rpl_stm_innodb.test new file mode 100644 index 00000000..dbfbc7f6 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_innodb.test @@ -0,0 +1,9 @@ +# File for specialities regarding replication from or to InnoDB +# tables. + +source include/have_innodb.inc; +source include/have_binlog_format_mixed_or_statement.inc; +source include/master-slave.inc; + +source include/rpl_innodb.test; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_stm_lcase_tblnames-slave.opt b/mysql-test/suite/rpl/t/rpl_stm_lcase_tblnames-slave.opt new file mode 100644 index 00000000..8be29bbe --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_lcase_tblnames-slave.opt @@ -0,0 +1 @@ +--replicate-do-db=bug_37656 --replicate-ignore-table=bug_37656.t1 --replicate-do-table=bug_37656.t2 --replicate-do-table=bug_37656.t3 --lower-case-table-names=1 diff --git a/mysql-test/suite/rpl/t/rpl_stm_lcase_tblnames.test b/mysql-test/suite/rpl/t/rpl_stm_lcase_tblnames.test new file mode 100644 index 00000000..3809cd89 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_lcase_tblnames.test @@ -0,0 +1,12 @@ +# BUG#37656 +# +# For details look into extra/rpl_tests/rpl_lower_case_table_names.test +# + +-- source include/not_windows.inc +-- source include/have_innodb.inc +-- source include/have_binlog_format_mixed_or_statement.inc +-- source include/master-slave.inc + +-- let $engine=InnoDB +-- source include/rpl_lower_case_table_names.test diff --git a/mysql-test/suite/rpl/t/rpl_stm_loaddata_concurrent.test b/mysql-test/suite/rpl/t/rpl_stm_loaddata_concurrent.test new file mode 100644 index 00000000..4409a1a8 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_loaddata_concurrent.test @@ -0,0 +1,14 @@ +-- source include/have_log_bin.inc +-- source include/have_binlog_format_statement.inc +RESET MASTER; + +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +CREATE TABLE t1 (c1 char(50)) ENGINE=MyISAM; +LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE t1; +LOAD DATA CONCURRENT INFILE '../../std_data/words.dat' INTO TABLE t1; +-- source include/show_binlog_events.inc +DROP TABLE t1; + +let $lock_option= CONCURRENT; +let $engine_type=MyISAM; +-- source include/rpl_loaddata.test diff --git a/mysql-test/suite/rpl/t/rpl_stm_loadfile.test b/mysql-test/suite/rpl/t/rpl_stm_loadfile.test new file mode 100644 index 00000000..5ff3846d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_loadfile.test @@ -0,0 +1,24 @@ +############################################################################# +# Original Author: JBM # +# Original Date: Aug/18/2005 # +############################################################################# +# TEST: To test the LOAD_FILE() in rbr # +############################################################################# +# Change Author: JBM +# Change Date: 2006-01-16 +# Change: Split the original test file. This one forces STATEMENT only because +# when in STATEMENT mode, the load_file will issue a warning, whereas +# in RBR or MIXED mode it does not (by lsoares). +########## + +# Includes +-- source include/have_binlog_format_statement.inc +-- source include/master-slave.inc + +disable_query_log; +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); +enable_query_log; + +-- source include/rpl_loadfile.test + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_stm_log-slave.opt b/mysql-test/suite/rpl/t/rpl_stm_log-slave.opt new file mode 100644 index 00000000..203fc228 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_log-slave.opt @@ -0,0 +1 @@ +--log-slave-updates diff --git a/mysql-test/suite/rpl/t/rpl_stm_log.test b/mysql-test/suite/rpl/t/rpl_stm_log.test new file mode 100644 index 00000000..4a0df442 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_log.test @@ -0,0 +1,8 @@ +# Requires statement logging +-- source include/have_binlog_format_statement.inc +-- source include/master-slave.inc +let $engine_type=MyISAM; +-- source include/rpl_log.test + +# End of 4.1 tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_stm_maria.test b/mysql-test/suite/rpl/t/rpl_stm_maria.test new file mode 100644 index 00000000..d5a4c5c3 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_maria.test @@ -0,0 +1,59 @@ +# Test of Maria-specific replication bugs + +--source include/have_maria.inc +--source include/have_binlog_format_mixed_or_statement.inc +--source include/master-slave.inc + +# Suppress warnings that rand() is unsafe in statement binlog mode +CALL mtr.add_suppression('Unsafe statement written to the binary log using statement format'); + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +DROP TABLE IF EXISTS t3; +--enable_warnings + +# This one taken from rpl_trigger.test (from BUG#12482) +# used to segfault slave in execution of row-based events + +# Need an explicit ENGINE= clause as @@STORAGE_ENGINE is not replicated +create table t1 (a int auto_increment, primary key (a), b int, +rand_value double not null) engine=maria; +create table t2 (a int auto_increment, primary key (a), b int) engine=maria; +create table t3 (a int auto_increment, primary key (a), name +varchar(64) not null, old_a int, old_b int, rand_value double not +null) engine=maria; + +delimiter |; +create trigger t1 before insert on t1 for each row +begin + insert into t3 values (NULL, "t1", new.a, new.b, rand()); +end| + +create trigger t2 after insert on t2 for each row +begin + insert into t3 values (NULL, "t2", new.a, new.b, rand()); +end| +delimiter ;| + +insert into t3 values(100,"log",0,0,0); + +SET @@RAND_SEED1=658490765, @@RAND_SEED2=635893186; + +--disable_warnings +insert into t1 values(1,1,rand()),(NULL,2,rand()); +insert into t2 (b) values(last_insert_id()); +insert into t2 values(3,0),(NULL,0); +insert into t2 values(NULL,0),(500,0); +--enable_warnings + +select a,b, truncate(rand_value,4) from t1; +select * from t2; +select a,name, old_a, old_b, truncate(rand_value,4) from t3; +sync_slave_with_master; +connection master; +drop table t1,t2,t3; +sync_slave_with_master; + +# End of tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_stm_max_relay_size.test b/mysql-test/suite/rpl/t/rpl_stm_max_relay_size.test new file mode 100644 index 00000000..bea51ed2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_max_relay_size.test @@ -0,0 +1,8 @@ +# Test of options max_binlog_size and max_relay_log_size and +# how they act (if max_relay_log_size == 0, use max_binlog_size +# for relay logs too). +# Test of manual relay log rotation with FLUSH LOGS. + +# Requires statement logging +-- source include/have_binlog_format_mixed_or_statement.inc +-- source include/rpl_max_relay_size.test diff --git a/mysql-test/suite/rpl/t/rpl_stm_mix_show_relaylog_events.test b/mysql-test/suite/rpl/t/rpl_stm_mix_show_relaylog_events.test new file mode 100644 index 00000000..ab823799 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_mix_show_relaylog_events.test @@ -0,0 +1,19 @@ +# BUG#28777 SHOW BINLOG EVENTS does not work on relay log files +# +# GOAL +# ==== +# +# Test that SHOW BINLOG EVENTS and the new SHOW RELAYLOG EVENTS works after +# the patch, both on master and slave. +# +# HOW +# === +# +# This test issues SHOW [BINLOG|RELAYLOG] EVENTS both on master and slave after +# some statements have been issued. + +-- source include/have_binlog_format_mixed_or_statement.inc +-- source include/master-slave.inc + +-- source include/rpl_show_relaylog_events.inc +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_stm_mixing_engines.test b/mysql-test/suite/rpl/t/rpl_stm_mixing_engines.test new file mode 100644 index 00000000..e8b52885 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_mixing_engines.test @@ -0,0 +1,50 @@ +################################################################################### +# This test cases evaluates the mixture of non-transactional and transcational +# tables. For further details, please, read WL#2687 and WL#5072. +################################################################################### +--source include/have_binlog_format_statement.inc +--source include/have_innodb.inc +# MDEV-31790 FIXME: This test is extremely slow +--source include/not_msan.inc +--source include/master-slave.inc + +let $engine_type=Innodb; +let $database_name=test; +--source include/rpl_mixing_engines.test + +# +# BUG#49522: Replication problem with mixed MyISAM/InnoDB +# + +--source include/rpl_reset.inc +-- connection master + +CREATE TABLE `t1` ( + `c1` int(10) unsigned NOT NULL AUTO_INCREMENT, + `c2` tinyint(1) unsigned DEFAULT NULL, + `c3` varchar(300) DEFAULT NULL, + `c4` int(10) unsigned NOT NULL, + `c5` int(10) unsigned DEFAULT NULL, + PRIMARY KEY (`c1`)) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- sync_slave_with_master +ALTER TABLE `t1` Engine=InnoDB; + +-- connection master +SET AUTOCOMMIT=0; + +INSERT INTO t1 (c1,c2,c3,c4,c5) VALUES (1, 1, 'X', 1, NULL); +COMMIT; +ROLLBACK; +SET AUTOCOMMIT=1; + +-- sync_slave_with_master + +-- let $diff_tables= master:t1, slave:t1 +-- source include/diff_tables.inc + +-- connection master +DROP TABLE `t1`; +-- sync_slave_with_master + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_stm_multi_query.test b/mysql-test/suite/rpl/t/rpl_stm_multi_query.test new file mode 100644 index 00000000..2a593efd --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_multi_query.test @@ -0,0 +1,7 @@ +# Test for BUG#8436: verify that a multi-query (i.e. one query +# containing several queries (assuming client has +# CLIENT_MULTI_STATEMENTS) will be binlogged ONE-query-per-event (not +# one binlog event containing all queries) + +-- source include/have_binlog_format_mixed_or_statement.inc +-- source include/rpl_multi_query.test diff --git a/mysql-test/suite/rpl/t/rpl_stm_no_op.test b/mysql-test/suite/rpl/t/rpl_stm_no_op.test new file mode 100644 index 00000000..1605b177 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_no_op.test @@ -0,0 +1,94 @@ +# It's true only in statement-based replication that a statement which +# updates no rows (UPDATE/DELETE) is binlogged; in row-based +# replication, as we log modified rows, nothing is binlogged in this +# case. So this test is meaningul only in statement-based (and if it was +# enabled in row-based, it would fail as expected). + +-- source include/have_binlog_format_mixed_or_statement.inc + +source include/master-slave.inc; + +# see if DROP DATABASE is binlogged even if no effect +connection slave; +create database mysqltest; +connection master; +drop database if exists mysqltest; +sync_slave_with_master; +# can't read dir +--replace_result "Errcode: 1" "Errcode: X" "Errcode: 2" "Errcode: X" \\ / +--error 1049 +show tables from mysqltest; + +# see if DROP TABLE is binlogged even if no effect +connection slave; +create table t1 (a int); +connection master; +drop table if exists t1; +sync_slave_with_master; +# table does not exist +--error 1146 +select * from t1; + +# see if single-table DELETE is binlogged even if no effect +connection master; +create table t1 (a int, b int); +sync_slave_with_master; +insert into t1 values(1,1); +connection master; +delete from t1; +sync_slave_with_master; +select * from t1; + +# see if single-table UPDATE is binlogged even if no effect +insert into t1 values(1,1); +connection master; +insert into t1 values(2,1); +update t1 set a=2; +sync_slave_with_master; +select * from t1; + +# End of 4.1 tests + +# see if multi-table UPDATE is binlogged even if no effect (BUG#13348) + +connection master; +create table t2 (a int, b int); +delete from t1; +insert into t1 values(1,1); +insert into t2 values(1,1); + +sync_slave_with_master; +# force a difference to see if master's multi-UPDATE will correct it +update t1 set a=2; + +connection master; +UPDATE t1, t2 SET t1.a = t2.a; + +sync_slave_with_master; +select * from t1; +select * from t2; + +# See if multi-table DELETE is binlogged even if no effect + +connection master; +delete from t1; +delete from t2; + +sync_slave_with_master; +# force a difference to see if master's multi-DELETE will correct it +insert into t1 values(1,1); +insert into t2 values(1,1); + +connection master; +DELETE t1.*, t2.* from t1, t2; + +sync_slave_with_master; +select * from t1; +select * from t2; + + +# cleanup +connection master; +drop table t1, t2; +sync_slave_with_master; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_stm_relay_ign_space-slave.opt b/mysql-test/suite/rpl/t/rpl_stm_relay_ign_space-slave.opt new file mode 100644 index 00000000..f780540a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_relay_ign_space-slave.opt @@ -0,0 +1 @@ +--relay-log-space-limit=8192 --relay-log-purge --max-relay-log-size=4096 diff --git a/mysql-test/suite/rpl/t/rpl_stm_relay_ign_space.test b/mysql-test/suite/rpl/t/rpl_stm_relay_ign_space.test new file mode 100644 index 00000000..654a5d47 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_relay_ign_space.test @@ -0,0 +1,107 @@ +# +# This include file is used by more than one test suite +# (currently rpl and binlog_encryption). +# Please check all dependent tests after modifying it +# + +# +# BUG#12400313 / BUG#64503 test case +# +# +# Description +# ----------- +# +# This test case starts the slave server with: +# --relay-log-space-limit=8192 --relay-log-purge --max-relay-log-size=4096 +# +# Then it issues some queries that will cause the slave to reach +# relay-log-space-limit. We lock the table so that the SQL thread is +# not able to purge the log and then we issue some more statements. +# +# The purpose is to show that the IO thread will honor the limits +# while the SQL thread is not able to purge the relay logs, which did +# not happen before this patch. In addition we assert that while +# ignoring the limit (SQL thread needs to rotate before purging), the +# IO thread does not do it in an uncontrolled manner. + +--source include/have_binlog_format_statement.inc +--source include/have_innodb.inc +--source include/master-slave.inc + +--disable_query_log +CREATE TABLE t1 (c1 TEXT) engine=InnoDB; + +INSERT INTO t1 VALUES ('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'); +INSERT INTO t1 VALUES ('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'); +INSERT INTO t1 VALUES ('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'); +INSERT INTO t1 VALUES ('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'); + +--sync_slave_with_master + +# wait for the SQL thread to sleep +--let $show_statement= SHOW PROCESSLIST +--let $field= State +--let $condition= = 'Slave has read all relay log; waiting for more updates' +--source include/wait_show_condition.inc + +# now the io thread has set rli->ignore_space_limit +# lets lock the table so that once the SQL thread awakes +# it blocks there and does not set rli->ignore_space_limit +# back to zero +LOCK TABLE t1 WRITE; + +# now issue more statements that will overflow the +# rli->log_space_limit (in this case ~10K) +--connection master + +INSERT INTO t1 VALUES ('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'); +INSERT INTO t1 VALUES ('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'); +INSERT INTO t1 VALUES ('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'); +INSERT INTO t1 VALUES ('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'); +INSERT INTO t1 VALUES ('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'); +INSERT INTO t1 VALUES ('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'); +INSERT INTO t1 VALUES ('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'); +INSERT INTO t1 VALUES ('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'); +INSERT INTO t1 VALUES ('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'); +INSERT INTO t1 VALUES ('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'); + +--connection slave + +# ASSERT that the IO thread waits for the SQL thread to release some +# space before continuing +--let $show_statement= SHOW PROCESSLIST +--let $field= State +--let $condition= LIKE 'Waiting for %' +# before the patch (IO would have transfered everything) +#--let $condition= = 'Waiting for master to send event' +# after the patch (now it waits for space to be freed) +#--let $condition= = 'Waiting for the slave SQL thread to free enough relay log space' +--source include/wait_show_condition.inc + +# without the patch we can uncomment the following two lines and +# watch the IO thread synchronize with the master, thus writing +# relay logs way over the space limit +#--connection master +#--source include/sync_slave_io_with_master.inc + +## ASSERT that the IO thread has honored the limit+few bytes required to be able to purge +--let $relay_log_space_while_sql_is_executing = query_get_value(SHOW SLAVE STATUS, Relay_Log_Space, 1) +--let $relay_log_space_limit = query_get_value(SHOW VARIABLES LIKE "relay_log_space_limit", Value, 1) +--let $assert_text= Assert that relay log space is close to the limit +--let $assert_cond= $relay_log_space_while_sql_is_executing <= $relay_log_space_limit * 1.15 +--source include/assert.inc + +# unlock the table and let SQL thread continue applying events +UNLOCK TABLES; + +--connection master +--sync_slave_with_master +--let $diff_tables=master:test.t1,slave:test.t1 +--source include/diff_tables.inc + +--connection master +DROP TABLE t1; +--enable_query_log +--sync_slave_with_master + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_stm_reset_slave.test b/mysql-test/suite/rpl/t/rpl_stm_reset_slave.test new file mode 100644 index 00000000..e32b0a78 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_reset_slave.test @@ -0,0 +1,6 @@ +# TBF - difference in row level logging +-- source include/have_binlog_format_mixed_or_statement.inc +-- source include/rpl_reset_slave.test + +# End of 4.1 tests +# diff --git a/mysql-test/suite/rpl/t/rpl_stm_sp.test b/mysql-test/suite/rpl/t/rpl_stm_sp.test new file mode 100644 index 00000000..b99906b8 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_sp.test @@ -0,0 +1,30 @@ +--source include/have_binlog_format_statement.inc +--source include/master-slave.inc + +--echo # +--echo # MDEV-11815 SP variables of temporal data types do not replicate correctly +--echo # + +connection master; +CREATE TABLE t1(a INT); +DELIMITER $$; +CREATE PROCEDURE p1() +BEGIN + DECLARE a TIME DEFAULT '01:01:01'; + INSERT INTO t1 VALUES (a=10101); +END; +$$ +DELIMITER ;$$ +CALL p1; +SELECT * FROM t1; + +sync_slave_with_master; +SELECT * FROM t1; + +connection master; +DROP TABLE t1; +DROP PROCEDURE p1; +sync_slave_with_master; + + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_stm_sql_mode.test b/mysql-test/suite/rpl/t/rpl_stm_sql_mode.test new file mode 100644 index 00000000..56821621 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_sql_mode.test @@ -0,0 +1,25 @@ +-- source include/have_binlog_format_statement.inc +-- source include/master-slave.inc + +# +# Bug #51055 Replication failure on duplicate key + traditional SQL mode +# + +CREATE TABLE t1 (pk integer auto_increment , primary key (pk)); + +SET SESSION SQL_MODE='traditional'; + +-- echo # **** [MASTER] ***** +-- echo # action: raise DUP KEY error (error code should be set in the +-- echo # query log event) +-- error ER_DUP_ENTRY +INSERT INTO t1 (`pk`) VALUES (1), (1); + +DROP TABLE t1; + +-- echo # **** [ sync slave with master ] **** +-- echo # assertion: sync slave with master makes slave not to stop with +-- echo # duplicate key error (because it has received event +-- echo # with expected error code). +-- sync_slave_with_master +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_stm_start_stop_slave.test b/mysql-test/suite/rpl/t/rpl_stm_start_stop_slave.test new file mode 100644 index 00000000..f401db33 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_start_stop_slave.test @@ -0,0 +1,26 @@ +################################################################################ +# Please, check ./include/rpl_start_stop_slave.test +################################################################################ +--source include/have_binlog_format_statement.inc +--source include/have_innodb.inc +--source include/master-slave.inc + +# make innodb updates run fast +--connection slave +SET @old_innodb_flush_log_at_trx_commit= @@global.innodb_flush_log_at_trx_commit; +SET @@global.innodb_flush_log_at_trx_commit= 0; +--connection master +SET @old_innodb_flush_log_at_trx_commit= @@global.innodb_flush_log_at_trx_commit; +SET @@global.innodb_flush_log_at_trx_commit= 0; + +SET @@session.binlog_direct_non_transactional_updates= FALSE; +--source ./include/rpl_start_stop_slave.test + +# clean up +--connection slave +SET @@global.innodb_flush_log_at_trx_commit= @old_innodb_flush_log_at_trx_commit; +call mtr.add_suppression("Slave SQL.*Request to stop slave SQL Thread received while applying a group that has non-transactional changes; waiting for completion of the group"); +--connection master +SET @@global.innodb_flush_log_at_trx_commit= @old_innodb_flush_log_at_trx_commit; +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_stm_stop_middle_group.test b/mysql-test/suite/rpl/t/rpl_stm_stop_middle_group.test new file mode 100644 index 00000000..f2315f5e --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_stop_middle_group.test @@ -0,0 +1,11 @@ +################################################################################### +# Please, check include/rpl_stop_middle_group.test. +################################################################################### +-- source include/have_debug.inc +-- source include/have_innodb.inc +-- source include/have_binlog_format_statement.inc +-- source include/master-slave.inc + +SET @@session.binlog_direct_non_transactional_updates= FALSE; +-- source include/rpl_stop_middle_group.test +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_stm_until.test b/mysql-test/suite/rpl/t/rpl_stm_until.test new file mode 100644 index 00000000..ebfd355b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_until.test @@ -0,0 +1,184 @@ +# ==== Purpose ==== +# +# Verify that START SLAVE UNTIL replicates until the given binlog +# position but not longer. Verify that START SLAVE UNTIL with various +# incorrect arguments gives an error. +# +# ==== Method ==== +# +# On master, create a table and insert some rows. On slave, START +# SLAVE UNTIL so that it reads one event at a time, and check the +# table and the slave status each time. +# +# Then, on slave, run START SLAVE UNTIL with incorrect arguments and +# verify that it gives an error. +# +# ==== Related bugs ==== +# +# Bug in this test: BUG#37717: rpl.rpl_stm_until 'stmt' fails sporadically on pushbuild + +-- source include/have_binlog_format_mixed_or_statement.inc +-- source include/master-slave.inc +--let $master_use_gtid_option= No +-- source include/rpl_reset.inc + +# Test is dependent on binlog positions +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); + +# prepare version for substitutions +let $VERSION=`select version()`; + +# Stop slave before it starts replication. Also sync with master +# to avoid nondeterministic behaviour. +sync_slave_with_master; +--source include/stop_slave.inc + +--echo ==== Create some events on master ==== + +connection master; +create table t1(n int not null auto_increment primary key); +insert into t1 values (1),(2),(3),(4); +let $master_log_pos_1= query_get_value(SHOW MASTER STATUS, Position, 1); +let $master_log_file= query_get_value(SHOW MASTER STATUS, File, 1); +drop table t1; +create table t2(n int not null auto_increment primary key); +insert into t2 values (1),(2); +let $master_log_pos_2= query_get_value(SHOW MASTER STATUS, Position, 1); +insert into t2 values (3),(4); +drop table t2; + +--echo ==== Replicate one event at a time on slave ==== + +# try to replicate all queries until drop of t1 +connection slave; +--replace_result $master_log_file MASTER_LOG_FILE $master_log_pos_1 MASTER_LOG_POS +eval start slave until master_log_file='$master_log_file', master_log_pos=$master_log_pos_1; +--source include/wait_for_slave_io_to_start.inc +--source include/wait_for_slave_sql_to_stop.inc +# here table should be still not deleted +select * from t1; +--let $slave_param= Exec_Master_Log_Pos +--let $slave_param_value= $master_log_pos_1 +--source include/check_slave_param.inc + +# this should fail right after start +start slave until master_log_file='master-no-such-bin.000001', master_log_pos=291; +--source include/wait_for_slave_io_to_start.inc +--source include/wait_for_slave_sql_to_stop.inc +# again this table should be still not deleted +select * from t1; +--let $slave_param= Exec_Master_Log_Pos +--let $slave_param_value= $master_log_pos_1 +--source include/check_slave_param.inc + +let $relay_log_file= slave-relay-bin.000003; +let $master_log_pos= $master_log_pos_2; +source include/get_relay_log_pos.inc; +# try replicate all up to and not including the second insert to t2; +--replace_result $relay_log_pos RELAY_LOG_POS +eval start slave until relay_log_file='$relay_log_file', relay_log_pos=$relay_log_pos; +--source include/wait_for_slave_io_to_start.inc +--source include/wait_for_slave_sql_to_stop.inc +select * from t2; +--let $slave_param= Exec_Master_Log_Pos +--let $slave_param_value= $master_log_pos +--source include/check_slave_param.inc + +# clean up +start slave; +connection master; +sync_slave_with_master; +--source include/stop_slave.inc + +--let $exec_log_pos_1= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1) +# this should stop immediately as we are already there +--replace_result $master_log_file MASTER_LOG_FILE $master_log_pos_2 MASTER_LOG_POS +eval start slave until master_log_file='$master_log_file', master_log_pos=$master_log_pos_2; +--source include/wait_for_slave_io_to_start.inc +--source include/wait_for_slave_sql_to_stop.inc +--let $slave_param= Exec_Master_Log_Pos +--let $slave_param_value= $exec_log_pos_1 +--source include/check_slave_param.inc + +--echo ==== Test various error conditions ==== + +--error 1277 +start slave until master_log_file='master-bin', master_log_pos=561; +--error 1277 +start slave until master_log_file='master-bin.000001', master_log_pos=561, relay_log_pos=12; +--error 1277 +start slave until master_log_file='master-bin.000001'; +--error 1277 +start slave until relay_log_file='slave-relay-bin.000002'; +--error 1277 +start slave until relay_log_file='slave-relay-bin.000002', master_log_pos=561; +# Warning should be given for second command +start slave sql_thread; +start slave until master_log_file='master-bin.000001', master_log_pos=776; + +# +# bug#47210 first execution of "start slave until" stops too early +# +# testing that a slave rotate event that is caused by stopping the slave +# does not intervene anymore in UNTIL condition. +# + +connection slave; +source include/stop_slave.inc; +--disable_warnings +drop table if exists t1; +--enable_warnings +--source include/reset_slave.inc +--replace_result $MASTER_MYPORT MASTER_PORT +eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root'; + +connection master; +--disable_warnings +drop table if exists t1; +--enable_warnings +reset master; +create table t1 (a int primary key auto_increment); +save_master_pos; +let $master_pos= query_get_value(SHOW MASTER STATUS, Position, 1); + +connection slave; +start slave; +sync_with_master; + +# at this point slave will close the relay log stamping it with its own +# Rotate log event. This event won't be examined on matter of the master +# UNTIL pos anymore. +source include/stop_slave.inc; +let $slave_exec_pos= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1); + +--echo master and slave are in sync now +let $diff_pos= `select $master_pos - $slave_exec_pos`; +eval select $diff_pos as zero; + +connection master; +insert into t1 set a=null; +let $until_pos= query_get_value(SHOW MASTER STATUS, Position, 1); +insert into t1 set a=null; +select count(*) as two from t1; + +connection slave; +--replace_result $master_log_file MASTER_LOG_FILE $until_pos UNTIL_POS; +eval start slave until master_log_file='$master_log_file', master_log_pos= $until_pos; +source include/wait_for_slave_sql_to_stop.inc; +let $slave_exec_pos= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1); +--echo slave stopped at the prescribed position +let $diff_pos= `select $until_pos - $slave_exec_pos`; +eval select $diff_pos as zero; +select count(*) as one from t1; + + +connection master; +drop table t1; + +connection slave; +start slave; +sync_with_master; + +# End of tests +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_stm_user_variables.test b/mysql-test/suite/rpl/t/rpl_stm_user_variables.test new file mode 100644 index 00000000..18b90658 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stm_user_variables.test @@ -0,0 +1,202 @@ +# +# BUG#49562: SBR out of sync when using numeric data types + user variable +# + +-- source include/have_binlog_format_statement.inc +-- source include/master-slave.inc + +## Setup user variables for several numeric types, so that we get +## coverage on the User_var_log_event different val types + +-- let $max_unsigned_long= 18446744073709551615 +-- let $min_signed_long= -9223372036854775808 +-- eval SET @positive= $max_unsigned_long +-- eval SET @negative= $min_signed_long + +CREATE TABLE t1 (`tinyint` TINYINT, + `smallint` SMALLINT, + `mediumint` MEDIUMINT, + `integer` INTEGER, + `bigint` BIGINT, + `utinyint` TINYINT UNSIGNED, + `usmallint` SMALLINT UNSIGNED, + `umediumint` MEDIUMINT UNSIGNED, + `uinteger` INTEGER UNSIGNED, + `ubigint` BIGINT UNSIGNED, + `double` DOUBLE, + `float` FLOAT, + `real` REAL(30,2), + `decimal` DECIMAL(30,2)) ENGINE = MyISAM; + +-- disable_warnings + +-- echo ### insert max unsigned +-- echo ### a) declarative +-- eval INSERT IGNORE INTO t1 VALUES ($max_unsigned_long, $max_unsigned_long, $max_unsigned_long, $max_unsigned_long, $max_unsigned_long, $max_unsigned_long, $max_unsigned_long,$max_unsigned_long, $max_unsigned_long, $max_unsigned_long, $max_unsigned_long, $max_unsigned_long, $max_unsigned_long, $max_unsigned_long); + +-- echo ######################################### +-- query_vertical SELECT * FROM t1 +-- sync_slave_with_master +-- query_vertical SELECT * FROM t1 +-- echo ######################################### +-- connection master +-- echo ## assertion: master and slave tables are in sync +-- let $diff_tables=master:t1,slave:t1 +-- source include/diff_tables.inc +-- connection master +TRUNCATE t1; + +-- echo ### b) user var +INSERT IGNORE INTO t1 VALUES (@positive, + @positive, + @positive, + @positive, + @positive, + @positive, + @positive, + @positive, + @positive, + @positive, + @positive, + @positive, + @positive, + @positive); + +-- echo ######################################### +-- query_vertical SELECT * FROM t1 +-- sync_slave_with_master +-- query_vertical SELECT * FROM t1 +-- echo ######################################### +-- connection master +-- echo ## assertion: master and slave tables are in sync +-- let $diff_tables=master:t1,slave:t1 +-- source include/diff_tables.inc +-- connection master +TRUNCATE t1; + + +-- echo ### insert min signed +-- echo ### a) declarative +-- eval INSERT IGNORE INTO t1 VALUES ($min_signed_long, $min_signed_long, $min_signed_long, $min_signed_long, $min_signed_long, $min_signed_long, $min_signed_long,$min_signed_long, $min_signed_long, $min_signed_long, $min_signed_long, $min_signed_long, $min_signed_long, $min_signed_long); + +-- echo ######################################### +-- query_vertical SELECT * FROM t1 +-- sync_slave_with_master +-- query_vertical SELECT * FROM t1 +-- echo ######################################### +-- connection master +-- echo ## assertion: master and slave tables are in sync +-- let $diff_tables=master:t1,slave:t1 +-- source include/diff_tables.inc +-- connection master +TRUNCATE t1; + +-- echo ### b) user var +INSERT IGNORE INTO t1 VALUES (@negative, + @negative, + @negative, + @negative, + @negative, + @negative, + @negative, + @negative, + @negative, + @negative, + @negative, + @negative, + @negative, + @negative); + +-- echo ######################################### +-- query_vertical SELECT * FROM t1 +-- sync_slave_with_master +-- query_vertical SELECT * FROM t1 +-- echo ######################################### +-- connection master + +-- echo ## assertion: master and slave tables are in sync +-- let $diff_tables=master:t1,slave:t1 +-- source include/diff_tables.inc +-- connection master +TRUNCATE t1; + +-- echo ## check: contents of both tables master's and slave's +-- enable_warnings + +## cleanup +-- connection master +DROP TABLE t1; +-- sync_slave_with_master + +##################################################################### +# +# BUG#51426 +# +##################################################################### +--source include/rpl_reset.inc +-- connection master +SET sql_mode = 'NO_ENGINE_SUBSTITUTION'; +CREATE TABLE t1 ( c INT, PRIMARY KEY (c)) Engine=MyISAM; + +# offending trigger that would reset the unsigned flag for aux before +# binlogging of User_var_log_event would take place. +CREATE TRIGGER tr1 AFTER INSERT ON t1 FOR EACH ROW SET @aux = -1 ; + +SET @aux = 10294947273192243200; +SET @aux1= @aux; +-- error ER_DUP_ENTRY +INSERT INTO t1 VALUES (@aux) , (@aux1); +SET sql_mode = DEFAULT; + +-- sync_slave_with_master + +-- echo ## assertion: master and slave tables are in sync +-- let $diff_tables=master:t1,slave:t1 +-- source include/diff_tables.inc + +--connection master +DROP TRIGGER tr1; +DROP TABLE t1; + +-- sync_slave_with_master + +--echo +--echo # The GET DIAGNOSTICS itself is not replicated, but it can set +--echo # variables which can be used in statements that are replicated. +--echo + +--source include/rpl_reset.inc +connection master; + +CREATE TABLE t1 (a INT, b INT); +GET DIAGNOSTICS @var1 = NUMBER; +INSERT INTO t1 VALUES (@var1, 0), (@var1, 0); + +DELIMITER |; +CREATE PROCEDURE p1() +LANGUAGE SQL +BEGIN + DECLARE count INT; + UPDATE t1 SET b = 2 WHERE a = 0; + GET DIAGNOSTICS count = ROW_COUNT; + INSERT INTO t1 VALUES (1, count); +END| +DELIMITER ;| + +CALL p1(); + +-- sync_slave_with_master + +connection slave; +--echo # check if the statement was replicated. +SELECT * FROM t1 ORDER BY a; + +connection master; +--echo # Show events and cleanup +--source include/show_binlog_events.inc +DROP TABLE t1; +DROP PROCEDURE p1; + +-- sync_slave_with_master + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_stop_slave.test b/mysql-test/suite/rpl/t/rpl_stop_slave.test new file mode 100644 index 00000000..14c6641f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stop_slave.test @@ -0,0 +1,146 @@ +source include/have_innodb.inc; +source include/have_debug.inc; +source include/have_debug_sync.inc; +source include/have_binlog_format_mixed_or_statement.inc; +source include/master-slave.inc; + +--connection slave +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=NO; +--source include/start_slave.inc +--connection master + +--echo +--echo # BUG#56118 STOP SLAVE does not wait till trx with CREATE TMP TABLE ends +--echo # +--echo # If a temporary table is created or dropped, the transaction should be +--echo # regarded similarly that a non-transactional table is modified. So +--echo # STOP SLAVE should wait until the transaction has finished. + +CREATE TABLE t1(c1 INT) ENGINE=InnoDB; +CREATE TABLE t2(c1 INT) ENGINE=InnoDB; + +sync_slave_with_master; +SET DEBUG_SYNC= 'RESET'; +source include/stop_slave.inc; + +--echo +--echo # Suspend the INSERT statement in current transaction on SQL thread. +--echo # It guarantees that SQL thread is applying the transaction when +--echo # STOP SLAVE command launchs. +SET @saved_dbug = @@GLOBAL.debug_dbug; +set global debug_dbug= '+d,after_mysql_insert'; +source include/start_slave.inc; + +--echo +--echo # CREATE TEMPORARY TABLE with InnoDB engine +--echo # ----------------------------------------- +let $tmp_table_stm= CREATE TEMPORARY TABLE tt1(c1 INT) ENGINE = InnoDB; +source include/rpl_stop_slave.test; + +--echo +--echo # CREATE TEMPORARY TABLE ... SELECT with InnoDB engine +--echo # ---------------------------------------------------- +let $tmp_table_stm= CREATE TEMPORARY TABLE tt1(c1 INT) ENGINE = InnoDB + SELECT c1 FROM t2; +source include/rpl_stop_slave.test; + +# Don't need to verify 'CREATE TEMPORARY TABLE' with MyIASM engine, as it +# never is binlogged into a transaction since 5.5. + +--echo +--echo # Test end +SET @@GLOBAL.debug_dbug = @saved_dbug; +source include/restart_slave_sql.inc; + +connection slave; +call mtr.add_suppression("Slave SQL.*Request to stop slave SQL Thread received while applying a group that has non-transactional changes; waiting for completion of the group"); +connection master; + +DROP TABLE t1, t2; + +--echo +--echo # Bug#58546 test rpl_packet timeout failure sporadically on PB +--echo # ---------------------------------------------------------------------- +--echo # STOP SLAVE stopped IO thread first and then stopped SQL thread. It was +--echo # possible that IO thread stopped after replicating part of a transaction +--echo # which SQL thread was executing. SQL thread would be hung if the +--echo # transaction could not be rolled back safely. +--echo # It caused some sporadic failures on PB2. +--echo # +--echo # This test verifies that when 'STOP SLAVE' is issued by a user, IO +--echo # thread will continue to fetch the rest events of the transaction which +--echo # is being executed by SQL thread and is not able to be rolled back safely. + +CREATE TABLE t1 (c1 INT KEY, c2 INT) ENGINE=InnoDB; +CREATE TABLE t2 (c1 INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES(1, 1); + +sync_slave_with_master; +--source include/stop_slave.inc + +connection master; +# make sure that there are no zombie threads +--source include/stop_dump_threads.inc + +SET @saved_dbug = @@GLOBAL.debug_dbug; +set global debug_dbug= '+d,dump_thread_wait_before_send_xid'; + +connection slave; +--source include/start_slave.inc + +BEGIN; +UPDATE t1 SET c2 = 2 WHERE c1 = 1; + +connection master; +BEGIN; +INSERT INTO t1 VALUES(2, 2); +INSERT INTO t2 VALUES(1); +UPDATE t1 SET c2 = 3 WHERE c1 = 1; +COMMIT; + +# wait for the dump thread reach the sync point +--let $wait_condition= select count(*)=1 from information_schema.processlist where state LIKE '%debug sync point%' and command='Binlog Dump' +--source include/wait_condition.inc + +connection slave1; +let $show_statement= SHOW PROCESSLIST; +let $field= Info; +let $condition= = 'UPDATE t1 SET c2 = 3 WHERE c1 = 1'; +source include/wait_show_condition.inc; + +send STOP SLAVE; + +connection slave; +ROLLBACK; + +connection master; + +SET DEBUG_SYNC= 'now SIGNAL signal.continue'; +SET DEBUG_SYNC= 'now WAIT_FOR signal.continued'; + +connection slave; +source include/wait_for_slave_to_stop.inc; + +connection slave1; +reap; + +# Slave has stopped, thence lets make sure that +# we kill the zombie dump threads. Also, make +# sure that we disable the DBUG_EXECUTE_IF +# that would set the dump thread to wait +connection master; +SET @@GLOBAL.debug_dbug = @saved_dbug; +# make sure that there are no zombie threads +--source include/stop_dump_threads.inc + +connection slave1; +# now the dump thread on the master will start +# from a clean slate, i.e. without the +# DBUG_EXECUTE_IF set +source include/start_slave.inc; + +connection master; +DROP TABLE t1, t2; +--source include/rpl_end.inc +SET DEBUG_SYNC= 'RESET'; diff --git a/mysql-test/suite/rpl/t/rpl_stop_slave_error-slave.opt b/mysql-test/suite/rpl/t/rpl_stop_slave_error-slave.opt new file mode 100644 index 00000000..32c4527a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stop_slave_error-slave.opt @@ -0,0 +1 @@ +--log-error=$MYSQLTEST_VARDIR/tmp/slave_log.err diff --git a/mysql-test/suite/rpl/t/rpl_stop_slave_error.test b/mysql-test/suite/rpl/t/rpl_stop_slave_error.test new file mode 100644 index 00000000..10d7c773 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_stop_slave_error.test @@ -0,0 +1,16 @@ +# +# MDEV-8345 STOP SLAVE should not cause an ERROR to be logged to the error log +# +source include/have_binlog_format_mixed.inc; # don't repeat the test three times +source include/master-slave.inc; + +connection master; +sync_slave_with_master; +source include/stop_slave.inc; +let SEARCH_FILE=$MYSQLTEST_VARDIR/tmp/slave_log.err; +let SEARCH_PATTERN=Error reading packet from server: Lost connection; +source include/search_pattern_in_file.inc; + +source include/start_slave.inc; +source include/rpl_end.inc; + diff --git a/mysql-test/suite/rpl/t/rpl_strict_password_validation.test b/mysql-test/suite/rpl/t/rpl_strict_password_validation.test new file mode 100644 index 00000000..c4dda1e1 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_strict_password_validation.test @@ -0,0 +1,24 @@ +if (!$SIMPLE_PASSWORD_CHECK_SO) { + skip No SIMPLE_PASSWORD_CHECK plugin; +} + +--source include/master-slave.inc + + +--connection slave +install soname "simple_password_check"; +select @@strict_password_validation; + +--connection master +create user foo1 identified by password '11111111111111111111111111111111111111111'; +set password for foo1 = PASSWORD('PLAINtext-password!!99'); +drop user foo1; +--sync_slave_with_master + +--connection slave +--error ER_OPTION_PREVENTS_STATEMENT +create user foo1 identified by password '11111111111111111111111111111111111111111'; + +uninstall plugin simple_password_check; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test b/mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test new file mode 100644 index 00000000..6b28e344 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test @@ -0,0 +1,651 @@ +# +# This include file is used by more than one test suite +# (currently rpl and binlog_encryption). +# Please check all dependent tests after modifying it +# + +# +# rpl_switch_stm_row_mixed tests covers +# +# - Master is switching explicitly between STATEMENT, ROW, and MIXED +# binlog format showing when it is possible and when not. +# - Master switching from MIXED to RBR implicitly listing all use +# cases, e.g a query invokes SYS_GUID(), thereafter to serve as the +# definition of MIXED binlog format +# - correctness of execution + + +-- source include/have_binlog_format_mixed_or_row.inc +-- source include/master-slave.inc + +# Since this test generates row-based events in the binary log, the +# slave SQL thread cannot be in STATEMENT mode to execute this test, +# so we only execute it for MIXED and ROW as default value of +# BINLOG_FORMAT. + +connection slave; + +connection master; +--disable_warnings +drop database if exists mysqltest1; +create database mysqltest1; +--enable_warnings +use mysqltest1; + +# Save binlog format +set @my_binlog_format= @@global.binlog_format; + +# play with switching +set session binlog_format=mixed; +show session variables like "binlog_format%"; +set session binlog_format=statement; +show session variables like "binlog_format%"; +set session binlog_format=row; +show session variables like "binlog_format%"; + +set global binlog_format=DEFAULT; +show global variables like "binlog_format%"; +set global binlog_format=MIXED; +show global variables like "binlog_format%"; +set global binlog_format=STATEMENT; +show global variables like "binlog_format%"; +set global binlog_format=ROW; +show global variables like "binlog_format%"; +show session variables like "binlog_format%"; +select @@global.binlog_format, @@session.binlog_format; + +CREATE TABLE t1 (a varchar(100)); + +prepare stmt1 from 'insert into t1 select concat(SYS_GUID(),?)'; +set @string="emergency_1_"; +insert into t1 values("work_2_"); +execute stmt1 using @string; +deallocate prepare stmt1; + +prepare stmt1 from 'insert into t1 select ?'; +insert into t1 values(concat(SYS_GUID(),"work_3_")); +execute stmt1 using @string; +deallocate prepare stmt1; + +insert into t1 values(concat("for_4_",SYS_GUID())); +insert into t1 select "yesterday_5_"; + +# verify that temp tables prevent a switch to SBR +create temporary table tmp(a char(100)); +insert into tmp values("see_6_"); +--error ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR +set binlog_format=statement; +insert into t1 select * from tmp; +drop temporary table tmp; + +# Now we go to SBR +set binlog_format=statement; +show global variables like "binlog_format%"; +show session variables like "binlog_format%"; +select @@global.binlog_format, @@session.binlog_format; +set global binlog_format=statement; +show global variables like "binlog_format%"; +show session variables like "binlog_format%"; +select @@global.binlog_format, @@session.binlog_format; + +prepare stmt1 from 'insert into t1 select ?'; +set @string="emergency_7_"; +insert into t1 values("work_8_"); +execute stmt1 using @string; +deallocate prepare stmt1; + +prepare stmt1 from 'insert into t1 select ?'; +insert into t1 values("work_9_"); +execute stmt1 using @string; +deallocate prepare stmt1; + +insert into t1 values("for_10_"); +insert into t1 select "yesterday_11_"; + +# test statement (is not default after wl#3368) +set binlog_format=statement; +select @@global.binlog_format, @@session.binlog_format; +set global binlog_format=statement; +select @@global.binlog_format, @@session.binlog_format; + +prepare stmt1 from 'insert into t1 select ?'; +set @string="emergency_12_"; +insert into t1 values("work_13_"); +execute stmt1 using @string; +deallocate prepare stmt1; + +prepare stmt1 from 'insert into t1 select ?'; +insert into t1 values("work_14_"); +execute stmt1 using @string; +deallocate prepare stmt1; + +insert into t1 values("for_15_"); +insert into t1 select "yesterday_16_"; + +# and now the mixed mode + +set global binlog_format=mixed; +select @@global.binlog_format, @@session.binlog_format; +set binlog_format=default; +select @@global.binlog_format, @@session.binlog_format; + +prepare stmt1 from 'insert into t1 select concat(SYS_GUID(),?)'; +set @string="emergency_17_"; +insert into t1 values("work_18_"); +execute stmt1 using @string; +deallocate prepare stmt1; + +prepare stmt1 from 'insert into t1 select ?'; +insert into t1 values(concat(SYS_GUID(),"work_19_")); +execute stmt1 using @string; +deallocate prepare stmt1; + +insert into t1 values(concat("for_20_",SYS_GUID())); +insert into t1 select "yesterday_21_"; + +prepare stmt1 from 'insert into t1 select ?'; +insert into t1 values(concat(SYS_GUID(),"work_22_")); +execute stmt1 using @string; +deallocate prepare stmt1; + +insert into t1 values(concat("for_23_",SYS_GUID())); +insert into t1 select "yesterday_24_"; + +# Test of CREATE TABLE SELECT + +create table t2 ENGINE=MyISAM select rpad(SYS_GUID(),100,' '); +create table t3 select 1 union select SYS_GUID(); +--disable_warnings +SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR +create table t4 select * from t1 where 3 in (select 1 union select 2 union select SYS_GUID() union select 3); +--enable_warnings +SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR +create table t5 select * from t1 where 3 in (select 1 union select 2 union select curdate() union select 3); +# what if SYS_GUID() is first: +--disable_warnings +insert ignore into t5 select SYS_GUID() from t1 where 3 in (select 1 union select 2 union select 3 union select * from t4); +--enable_warnings + +# inside a stored procedure + +delimiter |; +create procedure foo() +begin +insert into t1 values("work_25_"); +insert into t1 values(concat("for_26_",SYS_GUID())); +insert into t1 select "yesterday_27_"; +end| +create procedure foo2() +begin +insert into t1 values(concat("emergency_28_",SYS_GUID())); +insert into t1 values("work_29_"); +insert into t1 values(concat("for_30_",SYS_GUID())); +set session binlog_format=row; # accepted for stored procs +insert into t1 values("more work_31_"); +set session binlog_format=mixed; +end| +create function foo3() returns bigint unsigned +begin + set session binlog_format=row; # rejected for stored funcs + insert into t1 values("alarm"); + return 100; +end| +create procedure foo4(x varchar(100)) +begin +insert into t1 values(concat("work_250_",x)); +insert into t1 select "yesterday_270_"; +end| +delimiter ;| +call foo(); +call foo2(); +call foo4("hello"); +call foo4(SYS_GUID()); +call foo4("world"); + +# test that can't SET in a stored function +--error ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT +select foo3(); +select * from t1 where a="alarm"; + +# Tests of stored functions/triggers/views for BUG#20930 "Mixed +# binlogging mode does not work with stored functions, triggers, +# views" + +# Function which calls procedure +drop function foo3; +delimiter |; +create function foo3() returns bigint unsigned +begin + insert into t1 values("foo3_32_"); + call foo(); + return 100; +end| +delimiter ;| +insert into t2 select foo3(); + +prepare stmt1 from 'insert into t2 select foo3()'; +execute stmt1; +execute stmt1; +deallocate prepare stmt1; + +# Test if stored function calls stored function which calls procedure +# which requires row-based. + +delimiter |; +create function foo4() returns bigint unsigned +begin + insert into t2 select foo3(); + return 100; +end| +delimiter ;| +--disable_ps2_protocol +select foo4(); +--enable_ps2_protocol + +prepare stmt1 from 'select foo4()'; +execute stmt1; +execute stmt1; +deallocate prepare stmt1; + +# A simple stored function +delimiter |; +create function foo5() returns bigint unsigned +begin + insert into t2 select SYS_GUID(); + return 100; +end| +delimiter ;| +--disable_ps2_protocol +select foo5(); +--enable_ps2_protocol + +prepare stmt1 from 'select foo5()'; +execute stmt1; +execute stmt1; +deallocate prepare stmt1; + +# A simple stored function where SYS_GUID() is in the argument +delimiter |; +create function foo6(x varchar(100)) returns bigint unsigned +begin + insert into t2 select x; + return 100; +end| +delimiter ;| +--disable_ps2_protocol +select foo6("foo6_1_"); +select foo6(concat("foo6_2_",SYS_GUID())); +--enable_ps2_protocol + +prepare stmt1 from 'select foo6(concat("foo6_3_",SYS_GUID()))'; +execute stmt1; +execute stmt1; +deallocate prepare stmt1; + + +# Test of views using SYS_GUID() + +create view v1 as select SYS_GUID(); +create table t11 (data varchar(255)); +insert into t11 select * from v1; +# Test of querying INFORMATION_SCHEMA which parses the view's body, +# to verify that it binlogs statement-based (is not polluted by +# the parsing of the view's body). +insert into t11 select TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='mysqltest1' and TABLE_NAME IN ('v1','t11'); +prepare stmt1 from "insert into t11 select TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='mysqltest1' and TABLE_NAME IN ('v1','t11')"; +execute stmt1; +execute stmt1; +deallocate prepare stmt1; + +# Test of triggers with SYS_GUID() +delimiter |; +create trigger t11_bi before insert on t11 for each row +begin + set NEW.data = concat(NEW.data,SYS_GUID()); +end| +delimiter ;| +insert into t11 values("try_560_"); + +# Test that INSERT DELAYED works in mixed mode (BUG#20649) +insert delayed into t2 values("delay_1_"); +insert delayed into t2 values(concat("delay_2_",SYS_GUID())); +insert delayed into t2 values("delay_6_"); + +# Test for BUG#20633 (INSERT DELAYED RAND()/user_variable does not +# replicate fine in statement-based ; we test that in mixed mode it +# works). +insert delayed into t2 values(rand()); +set @a=2.345; +insert delayed into t2 values(@a); + +# With INSERT DELAYED, rows are written to the binlog after they are +# written to the table. Therefore, it is not enough to wait until the +# rows make it to t2 on the master (the rows may not be in the binlog +# at that time, and may still not be in the binlog when +# sync_slave_with_master is later called). Instead, we wait until the +# rows make it to t2 on the slave. We first call +# sync_slave_with_master, so that we are sure that t2 has been created +# on the slave. +sync_slave_with_master; +let $wait_condition= SELECT COUNT(*) = 19 FROM mysqltest1.t2; +--source include/wait_condition.inc +connection master; + +# If you want to do manual testing of the mixed mode regarding UDFs (not +# testable automatically as quite platform- and compiler-dependent), +# you just need to set the variable below to 1, and to +# "make udf_example.so" in sql/, and to copy sql/udf_example.so to +# MYSQL_TEST_DIR/lib/mysql. +let $you_want_to_test_UDF=0; +if ($you_want_to_test_UDF) +{ + CREATE FUNCTION metaphon RETURNS STRING SONAME 'udf_example.so'; + prepare stmt1 from 'insert into t1 select metaphon(?)'; + set @string="emergency_133_"; + insert into t1 values("work_134_"); + execute stmt1 using @string; + deallocate prepare stmt1; + prepare stmt1 from 'insert into t1 select ?'; + insert into t1 values(metaphon("work_135_")); + execute stmt1 using @string; + deallocate prepare stmt1; + insert into t1 values(metaphon("for_136_")); + insert into t1 select "yesterday_137_"; + create table t6 select metaphon("for_138_"); + create table t7 select 1 union select metaphon("for_139_"); + create table t8 select * from t1 where 3 in (select 1 union select 2 union select metaphon("for_140_") union select 3); + create table t9 select * from t1 where 3 in (select 1 union select 2 union select curdate() union select 3); +} + +create table t20 select * from t1; # save for comparing later +create table t21 select * from t2; +create table t22 select * from t3; +drop table t1,t2,t3; + +# This tests the fix to +# BUG#19630 stored function inserting into two auto_increment breaks statement-based binlog +# We verify that under the mixed binlog mode, a stored function +# modifying at least two tables having an auto_increment column, +# is binlogged row-based. Indeed in statement-based binlogging, +# only the auto_increment value generated for the first table +# is recorded in the binlog, the value generated for the 2nd table +# lacking. + +create table t1 (a int primary key auto_increment, b varchar(100)); +create table t2 (a int primary key auto_increment, b varchar(100)); +create table t3 (b varchar(100)); +delimiter |; +create function f (x varchar(100)) returns int deterministic +begin + insert into t1 values(null,x); + insert into t2 values(null,x); + return 1; +end| +delimiter ;| +--disable_ps2_protocol +select f("try_41_"); +--enable_ps2_protocol +# Two operations which compensate each other except that their net +# effect is that they advance the auto_increment counter of t2 on slave: +sync_slave_with_master; +use mysqltest1; +insert into t2 values(2,null),(3,null),(4,null); +delete from t2 where a>=2; + +connection master; +# this is the call which didn't replicate well +--disable_ps2_protocol +select f("try_42_"); +--enable_ps2_protocol +sync_slave_with_master; + +# now use prepared statement and test again, just to see that the RBB +# mode isn't set at PREPARE but at EXECUTE. + +insert into t2 values(3,null),(4,null); +delete from t2 where a>=3; + +connection master; +prepare stmt1 from 'select f(?)'; +set @string="try_43_"; +insert into t1 values(null,"try_44_"); # should be SBB +execute stmt1 using @string; # should be RBB +deallocate prepare stmt1; +sync_slave_with_master; + +# verify that if only one table has auto_inc, it does not trigger RBB +# (we'll check in binlog further below) + +connection master; +create table t12 select * from t1; # save for comparing later +drop table t1; +create table t1 (a int, b varchar(100), key(a)); +--disable_ps2_protocol +select f("try_45_"); +--enable_ps2_protocol + +# restore table's key +create table t13 select * from t1; +drop table t1; +create table t1 (a int primary key auto_increment, b varchar(100)); + +# now test if it's two functions, each of them inserts in one table + +drop function f; +# we need a unique key to have sorting of rows by mysqldump +create table t14 (unique (a)) select * from t2; +truncate table t2; +delimiter |; +create function f1 (x varchar(100)) returns int deterministic +begin + insert into t1 values(null,x); + return 1; +end| +create function f2 (x varchar(100)) returns int deterministic +begin + insert into t2 values(null,x); + return 1; +end| +delimiter ;| +--disable_ps2_protocol +select f1("try_46_"),f2("try_47_"); +--enable_ps2_protocol + +sync_slave_with_master; +insert into t2 values(2,null),(3,null),(4,null); +delete from t2 where a>=2; + +connection master; +# Test with SELECT and INSERT +--disable_ps2_protocol +select f1("try_48_"),f2("try_49_"); +--enable_ps2_protocol +insert into t3 values(concat("try_50_",f1("try_51_"),f2("try_52_"))); +sync_slave_with_master; + +# verify that if f2 does only read on an auto_inc table, this does not +# switch to RBB +connection master; +drop function f2; +delimiter |; +create function f2 (x varchar(100)) returns int deterministic +begin + declare y int; + insert into t1 values(null,x); + set y = (select count(*) from t2); + return y; +end| +delimiter ;| +--disable_ps2_protocol +select f1("try_53_"),f2("try_54_"); +--enable_ps2_protocol +sync_slave_with_master; + +# And now, a normal statement with a trigger (no stored functions) + +connection master; +drop function f2; +delimiter |; +create trigger t1_bi before insert on t1 for each row +begin + insert into t2 values(null,"try_55_"); +end| +delimiter ;| +insert into t1 values(null,"try_56_"); +# and now remove one auto_increment and verify SBB +alter table t1 modify a int, drop primary key; +insert into t1 values(null,"try_57_"); +sync_slave_with_master; + +# Test for BUG#20499 "mixed mode with temporary table breaks binlog" +# Slave used to have only 2 rows instead of 3. +connection master; +CREATE TEMPORARY TABLE t15 SELECT SYS_GUID(); +create table t16 like t15; +INSERT INTO t16 SELECT * FROM t15; +# we'll verify that this one is done RBB +insert into t16 values("try_65_"); +drop table t15; +# we'll verify that this one is done SBB +insert into t16 values("try_66_"); +sync_slave_with_master; + +# and now compare: + +connection master; + +# first check that data on master is sensible +select count(*) from t1; +select count(*) from t2; +select count(*) from t3; +select count(*) from t4; +select count(*) from t5; +select count(*) from t11; +select count(*) from t20; +select count(*) from t21; +select count(*) from t22; +select count(*) from t12; +select count(*) from t13; +select count(*) from t14; +select count(*) from t16; +if ($you_want_to_test_UDF) +{ + select count(*) from t6; + select count(*) from t7; + select count(*) from t8; + select count(*) from t9; +} + +sync_slave_with_master; + +# +# Bug#20863 If binlog format is changed between update and unlock of +# tables, wrong binlog +# + +connection master; +DROP TABLE IF EXISTS t11; +SET SESSION BINLOG_FORMAT=STATEMENT; +CREATE TABLE t11 (song VARCHAR(255)); +LOCK TABLES t11 WRITE; +SET SESSION BINLOG_FORMAT=ROW; +INSERT INTO t11 VALUES('Several Species of Small Furry Animals Gathered Together in a Cave and Grooving With a Pict'); +SET SESSION BINLOG_FORMAT=STATEMENT; +INSERT INTO t11 VALUES('Careful With That Axe, Eugene'); +UNLOCK TABLES; + +--query_vertical SELECT * FROM t11 +sync_slave_with_master; +USE mysqltest1; +--query_vertical SELECT * FROM t11 + +connection master; +DROP TABLE IF EXISTS t12; +SET SESSION BINLOG_FORMAT=MIXED; +CREATE TABLE t12 (data LONG); +LOCK TABLES t12 WRITE; +INSERT INTO t12 VALUES(SYS_GUID()); +UNLOCK TABLES; +sync_slave_with_master; + +# +# BUG#28086: SBR of USER() becomes corrupted on slave +# + +connection master; + +# Just to get something that is non-trivial, albeit still simple, we +# stuff the result of USER() and CURRENT_USER() into a variable. +--delimiter $$ +CREATE FUNCTION my_user() + RETURNS CHAR(64) +BEGIN + DECLARE user CHAR(64); + SELECT USER() INTO user; + RETURN user; +END $$ +--delimiter ; + +--delimiter $$ +CREATE FUNCTION my_current_user() + RETURNS CHAR(64) +BEGIN + DECLARE user CHAR(64); + SELECT CURRENT_USER() INTO user; + RETURN user; +END $$ +--delimiter ; + +DROP TABLE IF EXISTS t13; +CREATE TABLE t13 (data CHAR(64)); +INSERT INTO t13 VALUES (USER()); +INSERT INTO t13 VALUES (my_user()); +INSERT INTO t13 VALUES (CURRENT_USER()); +INSERT INTO t13 VALUES (my_current_user()); + +sync_slave_with_master; + +# as we're using SYS_GUID we don't SELECT but use "diff" like in rpl_row_UUID +--exec $MYSQL_DUMP --compact --order-by-primary --skip-extended-insert --no-create-info mysqltest1 > $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_master.sql +--exec $MYSQL_DUMP_SLAVE --compact --order-by-primary --skip-extended-insert --no-create-info mysqltest1 > $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_slave.sql + +# Let's compare. Note: If they match test will pass, if they do not match +# the test will show that the diff statement failed and not reject file +# will be created. You will need to go to the mysql-test dir and diff +# the files your self to see what is not matching + +diff_files $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_master.sql $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_slave.sql; + +connection master; + +# Now test that mysqlbinlog works fine on a binlog generated by the +# mixed mode + +# BUG#11312 "DELIMITER is not written to the binary log that causes +# syntax error" makes that mysqlbinlog will fail if we pass it the +# text of queries; this forces us to use --base64-output here. + +# BUG#20929 "BINLOG command causes invalid free plus assertion +# failure" makes mysqld segfault when receiving --base64-output + +# So I can't enable this piece of test +# SIGH + +if ($enable_when_11312_or_20929_fixed) +{ +--exec $MYSQL_BINLOG --base64-output $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_mixed.sql +drop database mysqltest1; +--exec $MYSQL < $MYSQLTEST_VARDIR/tmp/mysqlbinlog_mixed.sql +--exec $MYSQL_DUMP --compact --order-by-primary --skip-extended-insert --no-create-info mysqltest1 > $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_master.sql +# the old mysqldump output on slave is the same as what it was on +# master before restoring on master. +diff_files $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_master.sql $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_slave.sql; +} + +drop database mysqltest1; +sync_slave_with_master; + +connection master; +# Restore binlog format setting +set global binlog_format =@my_binlog_format; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_sync-master.opt b/mysql-test/suite/rpl/t/rpl_sync-master.opt new file mode 100644 index 00000000..04b06bfa --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_sync-master.opt @@ -0,0 +1,2 @@ +--default-storage-engine=MyISAM +--loose-innodb-file-per-table=0 diff --git a/mysql-test/suite/rpl/t/rpl_sync-slave.opt b/mysql-test/suite/rpl/t/rpl_sync-slave.opt new file mode 100644 index 00000000..fc560657 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_sync-slave.opt @@ -0,0 +1,2 @@ +--sync-relay-log-info=1 --relay-log-recovery=1 --default-storage-engine=MyISAM --loose-innodb-file-per-table=0 +--skip-core-file diff --git a/mysql-test/suite/rpl/t/rpl_sync.test b/mysql-test/suite/rpl/t/rpl_sync.test new file mode 100644 index 00000000..1e2ec2ca --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_sync.test @@ -0,0 +1,159 @@ +# +# This include file is used by more than one test suite +# (currently rpl and binlog_encryption). +# Please check all dependent tests after modifying it +# + +######################################################################################## +# This test verifies the options --sync-relay-log-info and --relay-log-recovery by +# crashing the slave in two different situations: +# (case-1) - Corrupt the relay log with changes which were not processed by +# the SQL Thread and crashes it. +# (case-2) - Corrupt the master.info with wrong coordinates and crashes it. +# +# Case 1: +# 1 - Stops the SQL Thread +# 2 - Inserts new records into the master. +# 3 - Corrupts the relay-log.bin* which most likely has such changes. +# 4 - Crashes the slave +# 5 - Verifies if the slave is sync with the master which means that the information +# loss was circumvented by the recovery process. +# +# Case 2: +# 1 - Stops the SQL/IO Threads +# 2 - Inserts new records into the master. +# 3 - Corrupts the master.info with wrong coordinates. +# 4 - Crashes the slave +# 5 - Verifies if the slave is sync with the master which means that the information +# loss was circumvented by the recovery process. +######################################################################################## + +######################################################################################## +# Configuring the environment +######################################################################################## +--echo =====Configuring the enviroment=======; +--source include/not_embedded.inc +--source include/not_valgrind.inc +--source include/have_debug.inc +--source include/have_innodb.inc +--source include/not_crashrep.inc +--source include/master-slave.inc + +call mtr.add_suppression('Attempting backtrace'); +call mtr.add_suppression("Recovery from master pos .* and file master-bin.000001"); +# Use innodb so we do not get "table should be repaired" issues. +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +flush tables; +CREATE TABLE t1(a INT, PRIMARY KEY(a)) engine=innodb; + +insert into t1(a) values(1); +insert into t1(a) values(2); +insert into t1(a) values(3); + +######################################################################################## +# Case 1: Corrupt a relay-log.bin* +######################################################################################## +--echo =====Inserting data on the master but without the SQL Thread being running=======; +sync_slave_with_master; + +connection slave; +let $MYSQLD_SLAVE_DATADIR= `select @@datadir`; +--replace_result $MYSQLD_SLAVE_DATADIR MYSQLD_SLAVE_DATADIR +--copy_file $MYSQLD_SLAVE_DATADIR/master.info $MYSQLD_SLAVE_DATADIR/master.backup +--source include/stop_slave_sql.inc + +connection master; +insert into t1(a) values(4); +insert into t1(a) values(5); +insert into t1(a) values(6); + +--echo =====Removing relay log files and crashing/recoverying the slave=======; +connection slave; +--source include/stop_slave_io.inc + +let $file= query_get_value("SHOW SLAVE STATUS", Relay_Log_File, 1); + +--let FILE_TO_CORRUPT= $MYSQLD_SLAVE_DATADIR/$file +perl; +$file= $ENV{'FILE_TO_CORRUPT'}; +open(FILE, ">$file") || die "Unable to open $file."; +truncate(FILE,0); +print FILE "failure"; +close ($file); +EOF + +--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +SET SESSION debug_dbug="d,crash_before_rotate_relaylog"; +--error 2013 +FLUSH LOGS; + +--let $rpl_server_number= 2 +--source include/rpl_reconnect.inc + +--echo =====Dumping and comparing tables=======; +--source include/start_slave.inc + +connection master; +sync_slave_with_master; + +let $diff_tables=master:t1,slave:t1; +source include/diff_tables.inc; + +######################################################################################## +# Case 2: Corrupt a master.info +######################################################################################## +--echo =====Corrupting the master.info=======; +connection slave; +--source include/stop_slave.inc + +connection master; +FLUSH LOGS; + +insert into t1(a) values(7); +insert into t1(a) values(8); +insert into t1(a) values(9); + +connection slave; +let MYSQLD_SLAVE_DATADIR=`select @@datadir`; + +--perl +use strict; +use warnings; +my $src= "$ENV{'MYSQLD_SLAVE_DATADIR'}/master.backup"; +my $dst= "$ENV{'MYSQLD_SLAVE_DATADIR'}/master.info"; +open(FILE, "<", $src) or die; +my @content= <FILE>; +close FILE; +open(FILE, ">", $dst) or die; +binmode FILE; +print FILE @content; +close FILE; +EOF + +--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +SET SESSION debug_dbug="d,crash_before_rotate_relaylog"; +--error 2013 +FLUSH LOGS; + +--let $rpl_server_number= 2 +--source include/rpl_reconnect.inc + +--echo =====Dumping and comparing tables=======; +--source include/start_slave.inc + +connection master; +sync_slave_with_master; + +let $diff_tables=master:t1,slave:t1; +source include/diff_tables.inc; + +######################################################################################## +# Clean up +######################################################################################## +--echo =====Clean up=======; +connection master; +drop table t1; + +--remove_file $MYSQLD_SLAVE_DATADIR/master.backup +--source include/rpl_end.inc + diff --git a/mysql-test/suite/rpl/t/rpl_table_options.test b/mysql-test/suite/rpl/t/rpl_table_options.test new file mode 100644 index 00000000..335bf8d8 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_table_options.test @@ -0,0 +1,38 @@ +--source include/not_windows_embedded.inc +--source include/have_example_plugin.inc +--source include/master-slave.inc + +--replace_regex /\.dll/.so/ +eval install plugin example soname '$HA_EXAMPLE_SO'; +set default_storage_engine=example; + +sync_slave_with_master; +connection master; + +# +# only master has example engine installed, +# the slave will have the table created in myisam, +# that does not have ULL table option. +# but because the table was created by the replication +# slave thread, the table will be created anyway, even if +# the option is unknown. +# +create table t1 (a int not null) ull=12340; +alter table t1 ull=12350; +show create table t1; + +sync_slave_with_master; +connection slave; +show create table t1; +set sql_mode=ignore_bad_table_options; +show create table t1; + +connection master; +drop table t1; +set default_storage_engine=default; +select 1; + +# Cleanup +uninstall plugin example; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_temp_table.test b/mysql-test/suite/rpl/t/rpl_temp_table.test new file mode 100644 index 00000000..8b3af5d5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_temp_table.test @@ -0,0 +1,85 @@ +# drop table t1 t2 t3 are included int master-slave.inc +# meaningful only in statement-based: + +-- source include/have_binlog_format_mixed_or_statement.inc +-- source include/master-slave.inc + +--disable_query_log +CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); +--enable_query_log + +create table t2 (n int, PRIMARY KEY(n)); +create temporary table t1 (n int); +create temporary table t3 (n int not null); + +insert into t1 values(1),(2),(3),(100),(25),(26),(200),(300); +--disable_warnings +insert into t2 select * from t1; +--enable_warnings +alter table t3 add primary key(n); + +flush logs; +insert into t3 values (1010); +--disable_warnings +insert into t2 select * from t3; +--enable_warnings + +drop table if exists t3; +insert into t2 values (1012); + +connection master1; +create temporary table t1 (n int); +insert into t1 values (4),(5); +--disable_warnings +insert into t2 select * from t1; +--enable_warnings + +save_master_pos; +disconnect master; + +connection slave; +#add 1 to the saved position, so we will catch drop table on disconnect +#for sure +sync_with_master 1; + +connection master1; +insert into t2 values(61); + +save_master_pos; +disconnect master1; + +connection slave; +#same trick - make sure we catch drop of temporary table on disconnect +sync_with_master 1; + +select * from t2; +select count(*) from t2; +select sum(n) from t2; +show status like 'Slave_open_temp_tables'; + +--echo *** MDEV-8016: Replication aborts on DROP /*!40005 TEMPORARY */ TABLE IF EXISTS *** +connect (master2,localhost,root,,); +INSERT INTO t2 VALUES (2000), (2001); +CREATE FUNCTION f() RETURNS INTEGER RETURN 1; +CREATE TEMPORARY TABLE t3 AS SELECT f() AS col FROM t2; +--let $gtid=`SELECT @@gtid_binlog_pos` +--disconnect master2 +--connection default +# Wait for implicit DROP TEMPORARY TABLE tmp to be binlogged. +--let $wait_condition= SELECT @@gtid_binlog_pos != '$gtid' +--source include/wait_condition.inc + +--sync_slave_with_master + + +# +# Clean up +# +connect (master2,localhost,root,,); +connection master2; +drop table if exists t1,t2; +drop function f; +sync_slave_with_master; + + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_temp_table_mix_row.test b/mysql-test/suite/rpl/t/rpl_temp_table_mix_row.test new file mode 100644 index 00000000..766acb14 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_temp_table_mix_row.test @@ -0,0 +1,206 @@ +# ==== Purpose ==== +# +# Test that temporary tables are correctly replicated after switching to ROW format in MIX mode. +# This test case will test the condition of the bug#40013. +# The test step is: +# 1: create temp table on connection 'master'; +# 2: switch to ROW format using 'INSERT INTO t1 VALUES (SYS_GUID());' +# 3: disconnect 'master' and connect to a new connection 'master1'; +# 4: sync to slave and check the number of temp tables on slave. +# + +source include/have_binlog_format_mixed.inc; +source include/have_innodb.inc; +source include/master-slave.inc; + +--echo ==== Initialize ==== + +--connection master + +CREATE TABLE t1 (a CHAR(48)); +CREATE TEMPORARY TABLE t1_tmp1(a INT); +INSERT INTO t1 VALUES (SYS_GUID()); + +sync_slave_with_master; + +--echo ==== Verify results on slave ==== +SHOW STATUS LIKE "Slave_open_temp_tables"; + +--connection master + +disconnect master; +--connection master1 + +# waiting DROP TEMPORARY TABLE event to be written into binlog +let $wait_binlog_event= DROP; +source include/wait_for_binlog_event.inc; + +sync_slave_with_master; + +--echo ==== Verify results on slave ==== +SHOW STATUS LIKE "Slave_open_temp_tables"; + +--echo ==== Clean up ==== + +--let $rpl_connection_name= master +--let $rpl_server_number= 1 +--source include/rpl_connect.inc +--connection master +DROP TABLE t1; + +sync_slave_with_master; + +# +# BUG#43046: mixed mode switch to row format with temp table lead to wrong +# result +# +# NOTES +# ===== +# +# 1. Temporary tables cannot be logged using the row-based +# format. Thus, once row-based logging is used, all subsequent +# statements using that table are unsafe, and we approximate this +# condition by treating all statements made by that client as +# unsafe until the client no longer holds any temporary tables. +# +# 2. Two different connections can use the same temporary table +# name without conflicting with each other or with an +# existing non-TEMPORARY table of the same name. +# +# DESCRIPTION +# =========== +# +# The test is implemented as follows: +# 1. create regular tables +# 2. create a temporary table t1_tmp: should be logged as statement +# 3. issue an alter table: should be logged as statement +# 4. issue statement that forces switch to RBR +# 5. create another temporary table t2_tmp: should not be logged +# 6. issue alter table on t1_tmp: should not be logged +# 7. drop t1_tmp and regular table on same statement: should log both in +# statement format (but different statements) +# 8. issue deterministic insert: logged as row (because t2_tmp still +# exists). +# 9. drop t2_tmp and issue deterministic statement: should log drop and +# query in statement format (show switch back to STATEMENT format) +# 10. in the end the slave should not have open temp tables. +# + +--source include/rpl_reset.inc +-- connection master + +# action: setup environment +CREATE TABLE t1 (a int) engine=innodb; +CREATE TABLE t2 ( i1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (i1) ) + engine=innodb; +CREATE TABLE t3 ( i1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (i1) ); +CREATE TRIGGER tr1 AFTER DELETE ON t2 FOR EACH ROW INSERT INTO t3 () VALUES (); + +# assertion: assert that CREATE is logged as STATEMENT +CREATE TEMPORARY TABLE t1_tmp (i1 int); + +# assertion: assert that ALTER TABLE is logged as STATEMENT +ALTER TABLE t1_tmp ADD COLUMN b INT; + +# action: force switch to RBR +INSERT INTO t1 values(1); +INSERT INTO t2 (i1) select * from t1; + +# assertion: assert that t2_tmp will not make into the binlog (RBR logging atm) +CREATE TEMPORARY TABLE t2_tmp (a int); + +# assertion: assert that ALTER TABLE on t1_tmp will not make into the binlog +ALTER TABLE t1_tmp ADD COLUMN c INT; + +-- echo ### assertion: assert that there is one open temp table on slave +-- sync_slave_with_master +SHOW STATUS LIKE 'Slave_open_temp_tables'; + +-- connection master + +# assertion: assert that both drops are logged +DROP TABLE t1_tmp, t2; + +# assertion: assert that statement is logged as row (master still has one +# opened temporary table - t2_tmp. +INSERT INTO t1 VALUES (1); + +# assertion: assert that DROP TABLE *is* logged despite CREATE is not. +DROP TEMPORARY TABLE t2_tmp; + +# assertion: assert that statement is now logged as STMT (mixed mode switches +# back to STATEMENT). +INSERT INTO t1 VALUES (2); + +-- sync_slave_with_master + +-- echo ### assertion: assert that slave has no temporary tables opened +SHOW STATUS LIKE 'Slave_open_temp_tables'; + +-- connection master + +# action: drop remaining tables +DROP TABLE t3, t1; + +-- sync_slave_with_master + +-- source include/show_binlog_events.inc + +--echo +--echo # Bug#55478 Row events wrongly apply on the temporary table of the same name +--echo # ========================================================================== +connection master; + +let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1); +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); + +--echo # The statement should be binlogged +CREATE TEMPORARY TABLE t1(c1 INT) ENGINE=InnoDB; + +--echo +--echo # Case 1: CREATE TABLE t1 ... SELECT +--echo # ---------------------------------- +let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1); +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); + +--echo +--echo # The statement generates row events on t1. And the rows events should +--echo # be inserted into the base table on slave. +CREATE TABLE t1 ENGINE=MyISAM SELECT rand(); + +source include/show_binlog_events.inc; +let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1); +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); + +--echo +--echo # Case 2: DROP TEMPORARY TABLE in a transacation +--echo # ---------------------------------------------- +--echo + +BEGIN; +DROP TEMPORARY TABLE t1; + +# The patch for BUG#55478 fixed the problem only on RBR. The problem on SBR +# will be fixed by the patch for bug#55709. So This statement cannot be +# executed until Bug#55709 is fixed +# +# INSERT INTO t1 VALUES(1); + +--echo # The rows event will binlogged after 'INSERT INTO t1 VALUES(1)' +--disable_warnings +INSERT IGNORE INTO t1 VALUES(SYS_GUID()+0); +--enable_warnings +COMMIT; + +source include/show_binlog_events.inc; + +--sync_slave_with_master + +--echo # Compare the base table. +--let $diff_tables= master:t1, slave:t1 +--source include/diff_tables.inc + +--echo +connection master; +DROP TABLE t1; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_temporal_format_default_to_default.test b/mysql-test/suite/rpl/t/rpl_temporal_format_default_to_default.test new file mode 100644 index 00000000..6728ff55 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_temporal_format_default_to_default.test @@ -0,0 +1,82 @@ +# +# This include file is used by more than one test suite +# (currently rpl and binlog_encryption). +# Please check all dependent tests after modifying it +# + +--source include/master-slave.inc + +if ($force_master_mysql56_temporal_format) +{ + connection master; + eval SET @@global.mysql56_temporal_format=$force_master_mysql56_temporal_format; +} + +if ($force_slave_mysql56_temporal_format) +{ + connection slave; + eval SET @@global.mysql56_temporal_format=$force_slave_mysql56_temporal_format; +} + +connection master; +SELECT @@global.mysql56_temporal_format AS on_master; +connection slave; +SELECT @@global.mysql56_temporal_format AS on_slave; +connection master; + +CREATE TABLE t1 +( + c0 TIME(0), + c1 TIME(1), + c2 TIME(2), + c3 TIME(3), + c4 TIME(4), + c5 TIME(5), + c6 TIME(6) +); +CREATE TABLE t2 +( + c0 TIMESTAMP(0), + c1 TIMESTAMP(1), + c2 TIMESTAMP(2), + c3 TIMESTAMP(3), + c4 TIMESTAMP(4), + c5 TIMESTAMP(5), + c6 TIMESTAMP(6) +); + +CREATE TABLE t3 +( + c0 DATETIME(0), + c1 DATETIME(1), + c2 DATETIME(2), + c3 DATETIME(3), + c4 DATETIME(4), + c5 DATETIME(5), + c6 DATETIME(6) +); +INSERT INTO t1 VALUES ('01:01:01','01:01:01.1','01:01:01.11','01:01:01.111','01:01:01.1111','01:01:01.11111','01:01:01.111111'); +INSERT INTO t2 VALUES ('2001-01-01 01:01:01','2001-01-01 01:01:01.1','2001-01-01 01:01:01.11','2001-01-01 01:01:01.111','2001-01-01 01:01:01.1111','2001-01-01 01:01:01.11111','2001-01-01 01:01:01.111111'); +INSERT INTO t3 VALUES ('2001-01-01 01:01:01','2001-01-01 01:01:01.1','2001-01-01 01:01:01.11','2001-01-01 01:01:01.111','2001-01-01 01:01:01.1111','2001-01-01 01:01:01.11111','2001-01-01 01:01:01.111111'); +SELECT TABLE_NAME, TABLE_ROWS, AVG_ROW_LENGTH,DATA_LENGTH FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_NAME RLIKE 't[1-3]' ORDER BY TABLE_NAME; +sync_slave_with_master; + +connection slave; +--query_vertical SELECT * FROM t1; +--query_vertical SELECT * FROM t2; +--query_vertical SELECT * FROM t3; +SELECT TABLE_NAME, TABLE_ROWS, AVG_ROW_LENGTH,DATA_LENGTH FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_NAME RLIKE 't[1-3]' ORDER BY TABLE_NAME; + +connection master; +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; + +connection slave; +SET @@global.mysql56_temporal_format=DEFAULT; +connection master; +SET @@global.mysql56_temporal_format=DEFAULT; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_temporal_format_mariadb53_to_mariadb53.test b/mysql-test/suite/rpl/t/rpl_temporal_format_mariadb53_to_mariadb53.test new file mode 100644 index 00000000..058ad017 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_temporal_format_mariadb53_to_mariadb53.test @@ -0,0 +1,4 @@ +--let $force_master_mysql56_temporal_format=false; +--let $force_slave_mysql56_temporal_format=false; + +--source rpl_temporal_format_default_to_default.test diff --git a/mysql-test/suite/rpl/t/rpl_temporal_format_mariadb53_to_mysql56.test b/mysql-test/suite/rpl/t/rpl_temporal_format_mariadb53_to_mysql56.test new file mode 100644 index 00000000..547b0831 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_temporal_format_mariadb53_to_mysql56.test @@ -0,0 +1,14 @@ +# +# MariaDB-5.3 fractional temporal types do not store metadata +# when running with --binlog-format=row, thus can replicate +# only into a field with exactly the same data type and format. +# +# Skip when running with --binlog-format=row. +# But mixed and statement formats should work without problems. +# +-- source include/have_binlog_format_mixed_or_statement.inc + +--let $force_master_mysql56_temporal_format=false; +--let $force_slave_mysql56_temporal_format=true; + +--source rpl_temporal_format_default_to_default.test diff --git a/mysql-test/suite/rpl/t/rpl_temporal_format_mariadb53_to_mysql56_dst.test b/mysql-test/suite/rpl/t/rpl_temporal_format_mariadb53_to_mysql56_dst.test new file mode 100644 index 00000000..511bdc15 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_temporal_format_mariadb53_to_mysql56_dst.test @@ -0,0 +1,37 @@ +# +# MDEV-12672 Replicated TIMESTAMP fields given wrong value near DST change +# +source include/have_binlog_format_row.inc; +source include/master-slave.inc; + +connection slave; +set global time_zone='Europe/Moscow'; +set time_zone='UTC'; +stop slave; +start slave; + +connection master; +set global mysql56_temporal_format=false; +set global time_zone='Europe/Moscow'; +set time_zone='UTC'; + +create table t1 (pk int primary key, t timestamp not null); +set timestamp = 1288477526; +insert into t1 values (1,null); +set timestamp = 1288481126; +insert into t1 values (2,null); + +sync_slave_with_master; + +select pk, t, unix_timestamp(t) from t1; +set time_zone=default; +select pk, t, unix_timestamp(t) from t1; + +set global time_zone=default; + +connection master; +drop table t1; +set global time_zone=default; +set global mysql56_temporal_format=default; + +source include/rpl_end.inc; diff --git a/mysql-test/suite/rpl/t/rpl_temporal_format_mysql56_to_mariadb53.test b/mysql-test/suite/rpl/t/rpl_temporal_format_mysql56_to_mariadb53.test new file mode 100644 index 00000000..dbee9f05 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_temporal_format_mysql56_to_mariadb53.test @@ -0,0 +1,4 @@ +--let $force_master_mysql56_temporal_format=true; +--let $force_slave_mysql56_temporal_format=false; + +--source rpl_temporal_format_default_to_default.test diff --git a/mysql-test/suite/rpl/t/rpl_temporal_format_mysql56_to_mysql56.test b/mysql-test/suite/rpl/t/rpl_temporal_format_mysql56_to_mysql56.test new file mode 100644 index 00000000..9c7994b6 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_temporal_format_mysql56_to_mysql56.test @@ -0,0 +1,4 @@ +--let $force_master_mysql56_temporal_format=true; +--let $force_slave_mysql56_temporal_format=true; + +--source rpl_temporal_format_default_to_default.test diff --git a/mysql-test/suite/rpl/t/rpl_temporal_mysql56.test b/mysql-test/suite/rpl/t/rpl_temporal_mysql56.test new file mode 100644 index 00000000..f21f125b --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_temporal_mysql56.test @@ -0,0 +1,48 @@ +--source include/master-slave.inc + +connection master; +SET TIME_ZONE='+00:00'; +let $MYSQLD_MASTER_DATADIR= `select @@datadir`; + +connection slave; +SET TIME_ZONE='+00:00'; +let $MYSQLD_SLAVE_DATADIR= `select @@datadir`; + +--copy_file std_data/mysql56time.frm $MYSQLD_MASTER_DATADIR/test/mysql56time.frm +--copy_file std_data/mysql56time.MYD $MYSQLD_MASTER_DATADIR/test/mysql56time.MYD +--copy_file std_data/mysql56time.MYI $MYSQLD_MASTER_DATADIR/test/mysql56time.MYI +--copy_file std_data/mysql56time.frm $MYSQLD_SLAVE_DATADIR/test/mysql56time.frm +--copy_file std_data/mysql56time.MYD $MYSQLD_SLAVE_DATADIR/test/mysql56time.MYD +--copy_file std_data/mysql56time.MYI $MYSQLD_SLAVE_DATADIR/test/mysql56time.MYI + +--copy_file std_data/mysql56datetime.frm $MYSQLD_MASTER_DATADIR/test/mysql56datetime.frm +--copy_file std_data/mysql56datetime.MYD $MYSQLD_MASTER_DATADIR/test/mysql56datetime.MYD +--copy_file std_data/mysql56datetime.MYI $MYSQLD_MASTER_DATADIR/test/mysql56datetime.MYI +--copy_file std_data/mysql56datetime.frm $MYSQLD_SLAVE_DATADIR/test/mysql56datetime.frm +--copy_file std_data/mysql56datetime.MYD $MYSQLD_SLAVE_DATADIR/test/mysql56datetime.MYD +--copy_file std_data/mysql56datetime.MYI $MYSQLD_SLAVE_DATADIR/test/mysql56datetime.MYI + +--copy_file std_data/mysql56timestamp.frm $MYSQLD_MASTER_DATADIR/test/mysql56timestamp.frm +--copy_file std_data/mysql56timestamp.MYD $MYSQLD_MASTER_DATADIR/test/mysql56timestamp.MYD +--copy_file std_data/mysql56timestamp.MYI $MYSQLD_MASTER_DATADIR/test/mysql56timestamp.MYI +--copy_file std_data/mysql56timestamp.frm $MYSQLD_SLAVE_DATADIR/test/mysql56timestamp.frm +--copy_file std_data/mysql56timestamp.MYD $MYSQLD_SLAVE_DATADIR/test/mysql56timestamp.MYD +--copy_file std_data/mysql56timestamp.MYI $MYSQLD_SLAVE_DATADIR/test/mysql56timestamp.MYI + +connection master; +INSERT INTO mysql56time VALUES ('01:01:01','01:01:01.1','01:01:01.11','01:01:01.111','01:01:01.1111','01:01:01.11111','01:01:01.111111'); +INSERT INTO mysql56datetime VALUES ('2001-01-01 01:01:01','2001-01-01 01:01:01.1','2001-01-01 01:01:01.11','2001-01-01 01:01:01.111','2001-01-01 01:01:01.1111','2001-01-01 01:01:01.11111','2001-01-01 01:01:01.111111'); +INSERT INTO mysql56timestamp VALUES ('2001-01-01 01:01:01','2001-01-01 01:01:01.1','2001-01-01 01:01:01.11','2001-01-01 01:01:01.111','2001-01-01 01:01:01.1111','2001-01-01 01:01:01.11111','2001-01-01 01:01:01.111111'); +sync_slave_with_master; + +connection slave; +--query_vertical SELECT * FROM mysql56time +--query_vertical SELECT * FROM mysql56datetime +--query_vertical SELECT * FROM mysql56timestamp + +connection master; +DROP TABLE mysql56time; +DROP TABLE mysql56datetime; +DROP TABLE mysql56timestamp; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_temporal_mysql56_to_mariadb.test b/mysql-test/suite/rpl/t/rpl_temporal_mysql56_to_mariadb.test new file mode 100644 index 00000000..efbff934 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_temporal_mysql56_to_mariadb.test @@ -0,0 +1,55 @@ +--source include/master-slave.inc + +if ($force_slave_mysql56_temporal_format) +{ + connection slave; + eval SET @@global.mysql56_temporal_format=$force_slave_mysql56_temporal_format; + connection master; +} + + +--echo # +--echo # Testing replication from MariaDB-10.0 master +--echo # started over MySQL-5.6 data directory +--echo # to MariaDB-10.0 slave running with natively created tables +--echo # + +connection master; +SET TIME_ZONE='+00:00'; +let $MYSQLD_MASTER_DATADIR= `select @@datadir`; + +--copy_file std_data/temporal_upgrade/mysql050614_temporal0.frm $MYSQLD_MASTER_DATADIR/test/mysql050614_temporal0.frm +--copy_file std_data/temporal_upgrade/mysql050614_temporal0.MYD $MYSQLD_MASTER_DATADIR/test/mysql050614_temporal0.MYD +--copy_file std_data/temporal_upgrade/mysql050614_temporal0.MYI $MYSQLD_MASTER_DATADIR/test/mysql050614_temporal0.MYI + +--copy_file std_data/temporal_upgrade/mysql050614_temporal1.frm $MYSQLD_MASTER_DATADIR/test/mysql050614_temporal1.frm +--copy_file std_data/temporal_upgrade/mysql050614_temporal1.MYD $MYSQLD_MASTER_DATADIR/test/mysql050614_temporal1.MYD +--copy_file std_data/temporal_upgrade/mysql050614_temporal1.MYI $MYSQLD_MASTER_DATADIR/test/mysql050614_temporal1.MYI +SHOW CREATE TABLE mysql050614_temporal0; +SHOW CREATE TABLE mysql050614_temporal1; + +connection slave; +SELECT @@mysql56_temporal_format; +SET TIME_ZONE='+00:00'; +CREATE TABLE mysql050614_temporal0 (a time(0), b datetime(0), c timestamp(0)) engine=myisam; +CREATE TABLE mysql050614_temporal1 (a time(1), b datetime(1), c timestamp(1)) engine=myisam; + +connection master; +INSERT INTO mysql050614_temporal0 VALUES ('00:00:02','2001-01-01 00:00:02','2001-01-01 00:00:02'); +INSERT INTO mysql050614_temporal1 VALUES ('00:00:02.1','2001-01-01 00:00:02.2','2001-01-01 00:00:02.3'); +SELECT TABLE_NAME, TABLE_ROWS, AVG_ROW_LENGTH, DATA_LENGTH FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_NAME LIKE 'mysql050614_temporal%' ORDER BY TABLE_NAME; +sync_slave_with_master; + +connection slave; +SELECT * FROM mysql050614_temporal0; +SELECT * FROM mysql050614_temporal1; +SELECT TABLE_NAME, TABLE_ROWS, AVG_ROW_LENGTH,DATA_LENGTH FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_NAME LIKE 'mysql050614_temporal%' ORDER BY TABLE_NAME; +SET @@global.mysql56_temporal_format=DEFAULT; + +connection master; +DROP TABLE mysql050614_temporal0; +DROP TABLE mysql050614_temporal1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_temporal_mysql56_to_mariadb53.test b/mysql-test/suite/rpl/t/rpl_temporal_mysql56_to_mariadb53.test new file mode 100644 index 00000000..435dad57 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_temporal_mysql56_to_mariadb53.test @@ -0,0 +1,2 @@ +--let $force_slave_mysql56_temporal_format=false; +--source rpl_temporal_mysql56_to_mariadb.test diff --git a/mysql-test/suite/rpl/t/rpl_temporal_round.test b/mysql-test/suite/rpl/t/rpl_temporal_round.test new file mode 100644 index 00000000..c13c18bd --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_temporal_round.test @@ -0,0 +1,35 @@ +--source include/master-slave.inc + +SET sql_mode=TIME_ROUND_FRACTIONAL; +SET time_zone='+00:00'; +SET timestamp=UNIX_TIMESTAMP('2010-12-31 23:59:59.999999'); + +CREATE TABLE t1 (id SERIAL, a TIMESTAMP(4)); +INSERT INTO t1 (a) VALUES (now(6)); +INSERT INTO t1 (a) VALUES ('2011-01-01 23:59:59.999999'); + +CREATE TABLE t2 (id SERIAL, a DATETIME(4)); +INSERT INTO t2 (a) VALUES (now(6)); +INSERT INTO t2 (a) VALUES ('2011-01-01 23:59:59.999999'); + +CREATE TABLE t3 (id SERIAL, a TIME(4)); +INSERT INTO t3 (a) VALUES (now(6)); +INSERT INTO t3 (a) VALUES ('2011-01-01 23:59:59.999999'); + +SELECT * FROM t1; +SELECT * FROM t2; +SELECT * FROM t3; + +sync_slave_with_master; +connection slave; +SET time_zone='+00:00'; +SELECT * FROM t1; +SELECT * FROM t2; +SELECT * FROM t3; + +connection master; +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_temporary.test b/mysql-test/suite/rpl/t/rpl_temporary.test new file mode 100644 index 00000000..0ec57715 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_temporary.test @@ -0,0 +1,420 @@ +# Test need anonymous user when connection are made as "zedjzlcsjhd" +# But we only need it on the master, not the slave. +SET sql_log_bin = 0; +source include/add_anonymous_users.inc; +SET sql_log_bin = 1; + +-- source include/master-slave.inc + +# Clean up old slave's binlogs. +# The slave is started with --log-slave-updates +# and this test does SHOW BINLOG EVENTS on the slave's +# binlog. But previous tests can influence the current test's +# binlog (e.g. a temporary table in the previous test has not +# been explicitly deleted, or it has but the slave hasn't had +# enough time to catch it before STOP SLAVE, +# and at the beginning of the current +# test the slave immediately writes DROP TEMPORARY TABLE this_old_table). +# We wait for the slave to have written all he wants to the binlog +# (otherwise RESET MASTER may come too early). +save_master_pos; +connection slave; + +sync_with_master; +reset master; + +# ################################################################## +# BUG#41725: slave crashes when inserting into temporary table after +# stop/start slave +# +# This test checks that both reported issues (assertion failure and +# crash) go away. It is implemented as follows: +# +# case 1: assertion failure +# i) create and insert into temporary table on master +# ii) sync slave with master +# iii) stop and restart slave +# iv) insert into master another value +# v) sync slave with master +# +# +# case 2: crash (SIGSEV) +# i) create and insert into temporary table on master (insert +# produces warnings) +# ii) sync slave with master +# iii) stop and restart slave +# iv) insert into master more values +# v) sync slave with master + +# case 1: Assertion in Field_string::store() failed because current +# thread reference differed from table->in_use after slave +# restart + +connection master; + +--disable_query_log +CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); +--enable_query_log + +disable_warnings; +DROP TABLE IF EXISTS t1; +enable_warnings; + +CREATE TEMPORARY TABLE t1 (a char(1)); +INSERT INTO t1 VALUES ('a'); +sync_slave_with_master; + +source include/stop_slave.inc; +source include/start_slave.inc; + +connection master; +INSERT INTO t1 VALUES ('b'); +sync_slave_with_master; + +# case 2: crash on sp_rcontext::find_handler because it used +# reference to invalid THD object after slave restart + +connection master; + +disable_warnings; +DROP TABLE IF EXISTS t1; +enable_warnings; +CREATE TEMPORARY TABLE `t1`(`a` tinyint,`b` char(1))engine=myisam; +INSERT IGNORE INTO `t1` set `a`=128,`b`='128'; + +sync_slave_with_master; + +source include/stop_slave.inc; +source include/start_slave.inc; + +connection master; +INSERT IGNORE INTO `t1` set `a`=128,`b`='128'; +sync_slave_with_master; + +# cleanup + +connection master; +DROP TABLE t1; +sync_slave_with_master; + +connection master; + +create user zedjzlcsjhd@localhost; +GRANT ALL on test.* to zedjzlcsjhd@localhost; + +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); +# We want to connect as an unprivileged user. But if we use user="" then this +# will pick the Unix login, which will cause problems if you're running the test +# as root. +connect (con3,localhost,zedjzlcsjhd,,); + +# We are going to use SET PSEUDO_THREAD_ID in this test; +# check that it requires the SUPER privilege. + +connection con3; +SET @save_select_limit=@@session.sql_select_limit; +--error 1227 +SET @@session.sql_select_limit=10, @@session.pseudo_thread_id=100; +SELECT @@session.sql_select_limit = @save_select_limit; #shouldn't have changed +# While we are here we also test that SQL_LOG_BIN can't be set +--error 1227 +SET @@session.sql_select_limit=10, @@session.sql_log_bin=0; +SELECT @@session.sql_select_limit = @save_select_limit; #shouldn't have changed +# Now as root, to be sure it works +connection con2; +SET @save_conn_id= connection_id(); +SET @@session.pseudo_thread_id=100; +SET @@session.pseudo_thread_id=connection_id(); +SET @@session.pseudo_thread_id=@save_conn_id; +SET @@session.sql_log_bin=0; +SET @@session.sql_log_bin=1; + +connection con3; +let $VERSION=`select version()`; + +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +create table t1(f int); +create table t2(f int); +insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); +# Auxiliary select (We want that all rows are in the table) +SELECT COUNT(*) FROM t1; + +connection con1; +create temporary table t3(f int); +--disable_warnings +insert into t3 select * from t1 where f<6; +--enable_warnings +let $wait_condition= SELECT COUNT(*) = 5 FROM t3; +--source include/wait_condition.inc + +connection con2; +create temporary table t3(f int); + +connection con1; +--disable_warnings +insert into t2 select count(*) from t3; +--enable_warnings +let $wait_condition= SELECT COUNT(*) = 1 FROM t2; +--source include/wait_condition.inc + +connection con2; +--disable_warnings +insert into t3 select * from t1 where f>=4; +--enable_warnings +let $wait_condition= SELECT COUNT(*) = 7 FROM t3; +--source include/wait_condition.inc + +connection con1; +drop temporary table t3; + +connection con2; +--disable_warnings +insert into t2 select count(*) from t3; +--enable_warnings +drop temporary table t3; + +select * from t2 ORDER BY f; + +# Commented out 8/30/2005 to make compatable with both sbr and rbr +#--replace_result $VERSION VERSION +#--replace_column 2 # 5 # +#show binlog events; + +drop table t1, t2; +drop user zedjzlcsjhd@localhost; + +use test; +SET TIMESTAMP=1040323920; +create table t1(f int); +SET TIMESTAMP=1040323931; +create table t2(f int); +SET TIMESTAMP=1040323938; +insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); + +SET TIMESTAMP=1040323945; +SET @@session.pseudo_thread_id=1; +create temporary table t3(f int); +SET TIMESTAMP=1040323952; +SET @@session.pseudo_thread_id=1; +--disable_warnings +insert into t3 select * from t1 where f<6; +--enable_warnings +SET TIMESTAMP=1040324145; +SET @@session.pseudo_thread_id=2; +create temporary table t3(f int); +SET TIMESTAMP=1040324186; +SET @@session.pseudo_thread_id=1; +--disable_warnings +insert into t2 select count(*) from t3; +--enable_warnings +SET TIMESTAMP=1040324200; +SET @@session.pseudo_thread_id=2; +--disable_warnings +insert into t3 select * from t1 where f>=4; +--enable_warnings +SET TIMESTAMP=1040324211; +SET @@session.pseudo_thread_id=1; +drop temporary table t3; +SET TIMESTAMP=1040324219; +SET @@session.pseudo_thread_id=2; +--disable_warnings +insert into t2 select count(*) from t3; +--enable_warnings +SET TIMESTAMP=1040324224; +SET @@session.pseudo_thread_id=2; +drop temporary table t3; + +select * from t2 ORDER BY f; +drop table t1,t2; + +# Create last a temporary table that is not dropped at end to ensure that we +# don't get any memory leaks for this + +create temporary table t3 (f int); +sync_slave_with_master; + +# The server will now close done + +# +# Bug#17284 erroneous temp table cleanup on slave +# The test targets at verifying that reconnected slave +# retained the former session's temporary tables +# +connection master; +create temporary table t4 (f int); +create table t5 (f int); +sync_slave_with_master; +# connection slave +stop slave; # to prepare for reconnecting w/o waiting for timeout +connection master; +--disable_warnings +insert into t5 select * from t4; +--enable_warnings +save_master_pos; + +connection slave; +start slave; +sync_with_master; +select * from t5 /* must be 1 after reconnection */; + +connection master; +drop temporary table t4; +drop table t5; + +# +# BUG#17263 incorrect generation DROP temp tables +# Temporary tables of connection are dropped in batches +# where a batch correspond to pseudo_thread_id +# value was set up at the moment of temp table creation +# +connection con1; +set @@session.pseudo_thread_id=100; +create temporary table t101 (id int); +create temporary table t102 (id int); +set @@session.pseudo_thread_id=200; +create temporary table t201 (id int); +create temporary table `t``201` (id int); +# emulate internal temp table not to come to binlog +create temporary table `#sql_not_user_table202` (id int); +set @@session.pseudo_thread_id=300; +create temporary table t301 (id int); +create temporary table t302 (id int); +create temporary table `#sql_not_user_table303` (id int); +disconnect con1; + +#now do something to show that slave is ok after DROP temp tables +connection master; +create table t1(f int); +insert into t1 values (1); + +sync_slave_with_master; +#connection slave; +select * from t1 /* must be 1 */; + +connection master; +drop table t1; + +# +#14157: utf8 encoding in binlog without set character_set_client +# +--write_file $MYSQLTEST_VARDIR/tmp/bug14157.sql +create table t1 (a int); +set names latin1; +create temporary table `äöüÄÖÜ` (a int); +insert into `äöüÄÖÜ` values (1); +insert into t1 select * from `äöüÄÖÜ` +EOF +--exec $MYSQL --character-sets-dir=../sql/share/charsets/ --default-character-set=latin1 test < $MYSQLTEST_VARDIR/tmp/bug14157.sql + +sync_slave_with_master; +#connection slave; +select * from t1; + +connection master; +drop table t1; +--remove_file $MYSQLTEST_VARDIR/tmp/bug14157.sql + +--sync_slave_with_master + +# Delete the anonymous users. +--source include/stop_slave.inc +source include/delete_anonymous_users.inc; +--connection master +source include/delete_anonymous_users.inc; +--let $rpl_only_running_threads= 1 +--source include/rpl_reset.inc + + +# +# Bug#43748: crash when non-super user tries to kill the replication threads +# + +--echo -- Bug#43748 + +--echo -- make a user on the slave that can list but not kill system threads. +connection slave; + +FLUSH PRIVILEGES; +GRANT USAGE ON *.* TO user43748@127.0.0.1 IDENTIFIED BY 'meow'; +GRANT PROCESS ON *.* TO user43748@127.0.0.1; + +--echo -- try to KILL system-thread as that non-privileged user (on slave). +connect (cont43748,127.0.0.1,user43748,meow,"*NO-ONE*",$SLAVE_MYPORT,); +connection cont43748; + +SELECT id INTO @id FROM information_schema.processlist WHERE user='system user' LIMIT 1; + +--error ER_KILL_DENIED_ERROR,ER_NO_SUCH_THREAD +KILL @id; + +disconnect cont43748; + +--echo -- throw out test-user on slave. +connection slave; + +DROP USER user43748@127.0.0.1; + +--echo # +--echo # MDEV-10216: Assertion `strcmp(share->unique_file_name,filename) || +--echo # share->last_version' failed in myisam/mi_open.c:67: test_if_reopen +--echo # + +connection master; +CREATE TEMPORARY TABLE t1(i INT PRIMARY KEY) ENGINE=MYISAM; +INSERT INTO t1 VALUES(1); +SELECT COUNT(*)=1 FROM t1; + +ALTER TABLE t1 RENAME t2; +SELECT COUNT(*)=1 FROM t2; +ALTER TABLE t2 RENAME t1; + +ALTER TABLE t1 DISABLE KEYS; +ALTER TABLE t1 ENABLE KEYS; + +# LOCK TABLES is ignored for temporary tables. +LOCK TABLES t1 WRITE; +ALTER TABLE t1 RENAME t2; +SELECT COUNT(*)=1 FROM t2; +ALTER TABLE t2 RENAME t1; +ALTER TABLE t1 DISABLE KEYS; +ALTER TABLE t1 ENABLE KEYS; +UNLOCK TABLES; + +LOCK TABLES t1 READ; +ALTER TABLE t1 RENAME t2; +SELECT COUNT(*)=1 FROM t2; +ALTER TABLE t2 RENAME t1; +ALTER TABLE t1 DISABLE KEYS; +ALTER TABLE t1 ENABLE KEYS; +UNLOCK TABLES; + +FLUSH TABLES WITH READ LOCK; +ALTER TABLE t1 RENAME t2; +SELECT COUNT(*)=1 FROM t2; +ALTER TABLE t2 RENAME t1; +ALTER TABLE t1 DISABLE KEYS; +ALTER TABLE t1 ENABLE KEYS; +UNLOCK TABLES; + +ALTER TABLE t1 RENAME t2, LOCK SHARED; +ALTER TABLE t2 RENAME t1, LOCK EXCLUSIVE; + +DROP TABLE t1; + +--echo # +--echo # MDEV-10320: NO-OP ALTER TABLE on temporary tables getting logged +--echo # under row binlog format +--echo # +connection master; +CREATE TEMPORARY TABLE t1(i INT PRIMARY KEY) ENGINE=MYISAM; +ALTER TABLE t1; +ALTER TABLE t1 ADD COLUMN IF NOT EXISTS I INT; +DROP TABLE t1; + +--echo End of 5.1 tests +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_temporary_error2.test b/mysql-test/suite/rpl/t/rpl_temporary_error2.test new file mode 100644 index 00000000..49194c5d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_temporary_error2.test @@ -0,0 +1,79 @@ +--source include/have_innodb.inc +--source include/master-slave.inc + +call mtr.add_suppression("Deadlock found when trying to get lock; try restarting transaction"); + +--echo *** Provoke a deadlock on the slave, check that transaction retry succeeds. *** +--connection master +CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; +CREATE TABLE t2 (a INT) ENGINE=InnoDB; +INSERT INTO t1(a) VALUES (1), (2), (3), (4), (5); + +--sync_slave_with_master +SELECT * FROM t1 ORDER BY a; +# Use MyISAM for t2 on the slave, so we have a way to see how far the +# slave replication thread has proceeded in the transaction. +SET sql_log_bin=0; +ALTER TABLE t2 ENGINE=MyISAM; +SET sql_log_bin=1; +let $old_retry= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); + +# Setup a separate connection that can deadlock with the replication thread. +# Docs say that InnoDB will try to roll back the smaller transaction. So +# let us make this transaction a big one, so the one in the replication +# thread will be selected for rollback and retry. +--connect (con_temp1,127.0.0.1,root,,test,$SERVER_MYPORT_2,) +--connection con_temp1 +BEGIN; +UPDATE t1 SET b=2 WHERE a=4; +--disable_query_log +--let $count=200 +while ($count) +{ + eval INSERT INTO t1(a) VALUES ($count + 10); + dec $count; +} +--enable_query_log +# Note that InnoDB also (undocumented?) tries to avoid rolling back a +# "transaction" that modified non-transactional tables. So be sure to also +# touch the MyISAM table in this transaction. +INSERT INTO t2 VALUES (2); +DELETE FROM t2 WHERE a=2; + +# Create the transaction that should participate in the deadlock on the slave. +--connection master +BEGIN; +UPDATE t1 SET b=1 WHERE a=2; +INSERT INTO t2 VALUES (1); +UPDATE t1 SET b=1 WHERE a=4; +COMMIT; +--save_master_pos + +--connection slave +# Wait until replication thread has gone to wait on the a=4 row lock. +--let $wait_condition= SELECT COUNT(*) = 1 FROM t2 WHERE a=1 +--source include/wait_condition.inc + +# Now provoke the deadlock by waiting on the a=2 row lock while the +# other thread is waiting for our a=4 row lock. +--connection con_temp1 +UPDATE t1 SET b=2 WHERE a=2; +SELECT * FROM t1 WHERE a<10 ORDER BY a; +ROLLBACK; + +--connection slave +--sync_with_master +SELECT * FROM t1 ORDER BY a; +--echo * There will be two rows in t2 due to the retry. +SELECT * FROM t2 ORDER BY a; +let $new_retry= query_get_value(SHOW STATUS LIKE 'Slave_retried_transactions', Value, 1); +--disable_query_log +eval SELECT $new_retry - $old_retry AS retries; +--enable_query_log +--let $status_items= Last_SQL_Errno, Last_SQL_Error +--source include/show_slave_status.inc + +--connection master +DROP TABLE t1; +DROP TABLE t2; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_temporary_errors-slave.opt b/mysql-test/suite/rpl/t/rpl_temporary_errors-slave.opt new file mode 100644 index 00000000..5c5164c6 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_temporary_errors-slave.opt @@ -0,0 +1 @@ +--loose-debug-dbug="+d,all_errors_are_temporary_errors" --slave-transaction-retries=2 diff --git a/mysql-test/suite/rpl/t/rpl_temporary_errors.test b/mysql-test/suite/rpl/t/rpl_temporary_errors.test new file mode 100644 index 00000000..85e16afa --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_temporary_errors.test @@ -0,0 +1,116 @@ +source include/have_binlog_format_row.inc; +source include/have_innodb.inc; +source include/master-slave.inc; + +call mtr.add_suppression("Deadlock found"); +call mtr.add_suppression("Can't find record in 't.'"); + +connection master; +CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=innodb; +INSERT INTO t1 VALUES (1,1), (2,2), (3,3), (4,4); +sync_slave_with_master; +SHOW STATUS LIKE 'Slave_retried_transactions'; +# since bug#31552/31609 idempotency is not default any longer. In order +# the following UPDATE t1 to pass the mode is switched temprorarily +set @@global.slave_exec_mode= 'IDEMPOTENT'; +UPDATE t1 SET a = 5, b = 47 WHERE a = 1; +SELECT * FROM t1 ORDER BY a; +connection master; +UPDATE t1 SET a = 5, b = 5 WHERE a = 1; +SELECT * FROM t1 ORDER BY a; +#SHOW BINLOG EVENTS; +sync_slave_with_master; +set @@global.slave_exec_mode= default; +SHOW STATUS LIKE 'Slave_retried_transactions'; +SELECT * FROM t1 ORDER BY a; +source include/check_slave_is_running.inc; + +connection slave; +call mtr.add_suppression("Slave SQL.*Could not execute Update_rows event on table test.t1"); +call mtr.add_suppression("Slave SQL for channel '': worker thread retried transaction"); +call mtr.add_suppression("The slave coordinator and worker threads are stopped"); +# +# Bug#24764800 REPLICATION FAILING ON SLAVE WITH XAER_RMFAIL ERROR +# +# Verify that a temporary failing replicated xa transaction completes +# upon slave applier restart after previous +# @@global.slave_transaction_retries number of retries in vain. +# +connection slave; + +set @save_innodb_lock_wait_timeout=@@global.innodb_lock_wait_timeout; +set @save_slave_transaction_retries=@@global.slave_transaction_retries; + +# Slave applier parameters for the failed retry +set @@global.innodb_lock_wait_timeout=1; +set @@global.slave_transaction_retries=2; +--source include/restart_slave_sql.inc + +# Temporary error implement: a record is blocked by slave local trx +connection slave1; +BEGIN; +INSERT INTO t1 SET a = 6, b = 7; + +connection master; +INSERT INTO t1 SET a = 99, b = 99; # slave applier warm up trx +XA START 'xa1'; +INSERT INTO t1 SET a = 6, b = 6; # this record eventually must be found on slave +XA END 'xa1'; +XA PREPARE 'xa1'; + +connection slave; +# convert_error(ER_LOCK_WAIT_TIMEOUT) +--let $err_timeout= 1205 +# convert_error(ER_LOCK_DEADLOCK) +--let $err_deadlock= 1213 +--let $slave_sql_errno=$err_deadlock,$err_timeout +--let $show_slave_sql_error= +--source include/wait_for_slave_sql_error.inc + +# b. Slave applier parameters for successful retry after restart +set @@global.innodb_lock_wait_timeout=1; +set @@global.slave_transaction_retries=100; + +--source include/restart_slave_sql.inc + +--let $last_retries= query_get_value(SHOW GLOBAL STATUS LIKE 'Slave_retried_transactions', Value, 1) +--let $status_type=GLOBAL +--let $status_var=Slave_retried_transactions +--let $status_var_value=`SELECT 1 + $last_retries` +--let $$status_var_comparsion= > +--source include/wait_for_status_var.inc + +# Release the record after just one retry +connection slave1; +ROLLBACK; + +connection master; +XA COMMIT 'xa1'; + +--source include/sync_slave_sql_with_master.inc + +# Proof of correctness: the committed XA is on the slave +connection slave; +--let $assert_text=XA transaction record must be in the table +--let $assert_cond=count(*)=1 FROM t1 WHERE a=6 AND b=6 +--source include/assert.inc + +# Bug#24764800 cleanup: +set @@global.innodb_lock_wait_timeout=@save_innodb_lock_wait_timeout; +set @@global.slave_transaction_retries= @save_slave_transaction_retries; + +# +# Total cleanup: +# +connection master; +DROP TABLE t1; +--sync_slave_with_master +--connection master + +# We must wait for the slave to stop. +# Otherwise the warnings in the error log about deadlock may be written to +# the error log only during shutdown, and currently the suppression of +# "Deadlock found" set in this test case is not effective during server +# shutdown. + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_test_framework.cnf b/mysql-test/suite/rpl/t/rpl_test_framework.cnf new file mode 100644 index 00000000..755e3622 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_test_framework.cnf @@ -0,0 +1,28 @@ +!include ../my.cnf +[mysqld.1] +log-slave-updates +[mysqld.2] +log-slave-updates +[mysqld.3] +log-slave-updates +[mysqld.4] +log-slave-updates +[mysqld.5] +log-slave-updates +[mysqld.6] +log-slave-updates +[mysqld.7] +log-slave-updates +[mysqld.8] +log-slave-updates +[mysqld.9] +log-slave-updates + +[ENV] +SERVER_MYPORT_3= @mysqld.3.port +SERVER_MYPORT_4= @mysqld.4.port +SERVER_MYPORT_5= @mysqld.5.port +SERVER_MYPORT_6= @mysqld.6.port +SERVER_MYPORT_7= @mysqld.7.port +SERVER_MYPORT_8= @mysqld.8.port +SERVER_MYPORT_9= @mysqld.9.port diff --git a/mysql-test/suite/rpl/t/rpl_test_framework.test b/mysql-test/suite/rpl/t/rpl_test_framework.test new file mode 100644 index 00000000..cf559072 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_test_framework.test @@ -0,0 +1,143 @@ +# ==== Purpose ==== +# +# Test that the sync chain generated by +# include/rpl_change_topology.inc (sourced from include/rpl_init.inc) +# is correct. +# +# We test a number of different topologies. Each topology is tested +# in include/rpl_test_framework.inc. See +# include/rpl_test_framework.inc for details on how the sync +# chain is tested. +# +# ==== Related bugs ==== +# +# BUG#49978: Replication tests don't clean up replication state at the end + + +# We only need to execute this test once. Also, we rely on 'DELETE +# FROM t1' to remove rows in slave tables that don't exist in master +# tables (see include/rpl_test_framework.inc for details). +--source include/have_binlog_format_statement.inc + + +--echo ==== Create t1 on all servers. ==== +if ($mtr_supports_more_than_10_servers) +{ + --let $rpl_server_count= 15 + --let $rpl_topology= 1->2->3->4->5->6->7->8->9->10->11->12->13->14->15 +} +if (!$mtr_supports_more_than_10_servers) +{ + --let $rpl_server_count= 9 + --let $rpl_topology= 1->2->3->4->5->6->7->8->9 +} +--source include/rpl_init.inc +CREATE TABLE t1 (a INT); +--source include/rpl_end.inc + +# Initialize $next_number before first call to +# include/rpl_test_framework.text +--let $next_number= 0 + + +--echo ==== Test 3-server topologies ==== + +--let $rpl_server_count= 3 + +--let $rpl_topology= 1 -> 2 +--let $masters= 1,3 +--source include/rpl_test_framework.inc + +--let $rpl_topology= 2 -> 3 +--let $masters= 1,2 +--source include/rpl_test_framework.inc + +--let $rpl_topology= none +--let $masters= 1,2,3 +--source include/rpl_test_framework.inc + +--let $rpl_topology= 1->2, 2->1 +--let $masters= 1,3 +--source include/rpl_test_framework.inc + +--let $rpl_topology= 1->2->1 +--let $masters= 2,3 +--source include/rpl_test_framework.inc + +--let $rpl_topology= 2->1->2 +--let $masters= 1,3 +--source include/rpl_test_framework.inc + +--let $rpl_topology= 1->2->3 +--let $masters= 1 +--source include/rpl_test_framework.inc + +--let $rpl_topology= 2->3->2->1 +--let $masters= 3 +--source include/rpl_test_framework.inc + +--let $rpl_topology= 1->2,2->3,3->1 +--let $masters= 3 +--source include/rpl_test_framework.inc + +--let $rpl_topology= 1->3->2->1 +--let $masters= 3 +--source include/rpl_test_framework.inc + + +--echo ==== Test 6-server topologies ==== + +--let $rpl_server_count= 6 + +--let $rpl_topology= 1->2->3->4->1->5->6 +--let $masters= 1 +--source include/rpl_test_framework.inc + +--let $rpl_topology= 3->4->5->6->3->1->2 +--let $masters= 4 +--source include/rpl_test_framework.inc + +--let $rpl_topology= 6->5->4->3->2->1 +--let $masters= 6 +--source include/rpl_test_framework.inc + +--let $rpl_topology= 1->2->3->1,4->5->6 +--let $masters= 3,4 +--source include/rpl_test_framework.inc + + +--echo ==== Test 9-server topology ==== + +--let $rpl_server_count= 9 + +--let $rpl_topology= 1->2, 2->3, 3->4, 4->5, 5->1, 1->6, 6->7, 6->8, 8->9 +--let $masters= 2 +--source include/rpl_test_framework.inc + +if ($mtr_supports_more_than_10_servers) { +--echo ==== Test 15-server topologies ==== + +--let $rpl_server_count= 15 + +--let $rpl_topology= 1->2->3->4->5->6->7->8->9->10->11->12->13->14->15->1 +--let $masters= 2 +--source include/rpl_test_framework.inc + +# This is a binary tree +--let $rpl_topology= 1->2->4->8,1->3->6->12,2->5->10,3->7->14,4->9,5->11,6->13,7->15 +--let $masters= 1 +--source include/rpl_test_framework.inc +} + +--echo ==== Clean up ==== + +if ($mtr_supports_more_than_10_servers) { + --let $rpl_topology= 1->2->3->4->5->6->7->8->9->10->11->12->13->14->15 +} +if (!$mtr_supports_more_than_10_servers) { + --let $rpl_topology= 1->2->3->4->5->6->7->8->9 +} +--source include/rpl_init.inc +--connection server_1 +DROP TABLE t1; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_timestamp.test b/mysql-test/suite/rpl/t/rpl_timestamp.test new file mode 100644 index 00000000..a3f4010f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_timestamp.test @@ -0,0 +1,18 @@ +source include/master-slave.inc; + +set timestamp=1656940000; +set explicit_defaults_for_timestamp=!@@explicit_defaults_for_timestamp; +connection master; + +create table t1 (f1 timestamp, f2 timestamp); +show create table t1; +sync_slave_with_master; +show create table t1; +connection master; +drop table t1; +flush binary logs; + +let $datadir=`select @@datadir`; +exec $MYSQL_BINLOG -s $datadir/master-bin.000001; + +source include/rpl_end.inc; diff --git a/mysql-test/suite/rpl/t/rpl_timezone-master.opt b/mysql-test/suite/rpl/t/rpl_timezone-master.opt new file mode 100644 index 00000000..8e43bfbb --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_timezone-master.opt @@ -0,0 +1 @@ +--default-time-zone=Europe/Moscow diff --git a/mysql-test/suite/rpl/t/rpl_timezone-slave.opt b/mysql-test/suite/rpl/t/rpl_timezone-slave.opt new file mode 100644 index 00000000..191182c3 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_timezone-slave.opt @@ -0,0 +1 @@ +--default-time-zone=Japan diff --git a/mysql-test/suite/rpl/t/rpl_timezone.test b/mysql-test/suite/rpl/t/rpl_timezone.test new file mode 100644 index 00000000..4b5778ca --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_timezone.test @@ -0,0 +1,211 @@ +####################################### +# Change Author: JBM +# Change Date: 2006-01-17 +# Change: Added order by +####################################### +# Test of replication of time zones. +###################################### +# There is currently some bug possibly in prepared statements (this +# test fails with --ps-protocol): sys_var_thd_time_zone::value_ptr() +# is called only at prepare time, not at execution time. So, +# thd->time_zone_used is not equal to 1 (it is back to 0, because of +# reset_thd_for_next_command called at execution time), so the +# timezone used in CONVERT_TZ is not binlogged. To debug (by Guilhem +# and possibly Konstantin). + +source include/master-slave.inc; + +--disable_query_log +CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); +--enable_query_log + +--disable_ps_protocol + +# Save original timezone +set @my_time_zone= @@global.time_zone; + +# Some preparations +let $VERSION=`select version()`; +set timestamp=100000000; # for fixed output of mysqlbinlog +create table t1 (t timestamp, n int not null auto_increment, PRIMARY KEY(n)); +create table t2 (t char(32), n int not null auto_increment, PRIMARY KEY(n)); + +connection slave; +select @@time_zone; +#set time_zone='UTC'; +#select @@time_zone; +# +# Let us check how well replication works when we are saving datetime +# value in TIMESTAMP field. +# +connection master; +select @@time_zone; +#set time_zone='UTC'; +#select @@time_zone; +insert into t1 values ('20050101000000', NULL), ('20050611093902',NULL); +insert into t1 values ('20040101000000',NULL), ('20040611093902',NULL); +SELECT * FROM t1 ORDER BY n; +sync_slave_with_master; +#set time_zone='UTC'; +SELECT * FROM t1 ORDER BY n; + +# Let us check also that setting of time_zone back to default also works +# well +connection master; +delete from t1; +set time_zone='Europe/Moscow'; +insert into t1 values ('20040101000000',NULL), ('20040611093902',NULL); +SELECT * FROM t1 ORDER BY n; +sync_slave_with_master; +set time_zone='Europe/Moscow'; +SELECT * FROM t1 ORDER BY n; +connection master; +# Change Author: JBM +# Change Date: 2005-12-22 +# Change: Comment out the exec of the binlog so test works for both SBR and RBR +#--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +#--exec $MYSQL_BINLOG --short-form $MYSQLTEST_VARDIR/log/master-bin.000001 + +# Let us check with LOAD DATA INFILE +# (we do it after mysqlbinlog because the temp files names are not constant) +connection master; +delete from t1; +set time_zone='UTC'; +load data infile '../../std_data/rpl_timezone2.dat' ignore into table t1; +SELECT * FROM t1 ORDER BY n; +sync_slave_with_master; +set time_zone='UTC'; +SELECT * FROM t1 ORDER BY n; +set time_zone='Europe/Moscow'; + +# Put back values of before the LOAD +connection master; +set time_zone='Europe/Moscow'; +delete from t1; +insert into t1 values ('20040101000000',NULL), ('20040611093902',NULL); + +# +# Now let us check how well we replicate statments reading TIMESTAMP fields +# (We should see the same data on master and on slave but it should differ +# from originally inserted) +# +set time_zone='MET'; +--disable_warnings ONCE +insert into t2 (select * from t1); +SELECT * FROM t1 ORDER BY n; +sync_slave_with_master; +SELECT * FROM t2 ORDER BY n; + +# +# Now let us check how well we replicate various CURRENT_* functions +# +connection master; +delete from t2; +set timestamp=1000072000; +insert into t2 values (current_timestamp,NULL), (current_date,NULL), (current_time,NULL); +sync_slave_with_master; +SELECT * FROM t2 ORDER BY n; + +# +# At last let us check replication of FROM_UNIXTIME/UNIX_TIMESTAMP functions. +# +connection master; +delete from t2; +insert into t2 values (from_unixtime(1000000000),NULL), + (unix_timestamp('2001-09-09 03:46:40'),NULL); +SELECT * FROM t2 ORDER BY n; +sync_slave_with_master; +# We should get same result on slave as on master +SELECT * FROM t2 ORDER BY n; + +# +# Let us check that we are allowing to set global time_zone with +# replication +# +connection master; +set global time_zone='MET'; + +# +# Let us see if CONVERT_TZ(@@time_zone) replicates +# +delete from t2; +set time_zone='UTC'; +insert into t2 values(convert_tz('2004-01-01 00:00:00','MET',@@time_zone),NULL); +insert into t2 values(convert_tz('2005-01-01 00:00:00','MET','Japan'),NULL); +SELECT * FROM t2 ORDER BY n; +sync_slave_with_master; +SELECT * FROM t2 ORDER BY n; + +# Clean up +connection master; +drop table t1, t2; +sync_slave_with_master; + + +# Restore original timezone +connection master; +set global time_zone= @my_time_zone; + +--echo End of 4.1 tests + +# +# Bug #29536: timestamp inconsistent in replication around 1970 +# +connection master; + +CREATE TABLE t1 (a INT, b TIMESTAMP); +INSERT INTO t1 VALUES (1, NOW()); + +SET @@session.time_zone='Japan'; +--disable_warnings +UPDATE IGNORE t1 SET b= '1970-01-01 08:59:59' WHERE a= 1; +--enable_warnings +SELECT * FROM t1 ORDER BY a; + +sync_slave_with_master; +SET @@session.time_zone='Japan'; +# must procdure the same result as the SELECT on the master +SELECT * FROM t1 ORDER BY a; + +SET @@session.time_zone = default; +connection master; +DROP TABLE t1; +SET @@session.time_zone = default; +--sync_slave_with_master +--source include/stop_slave.inc + +# Bug#41719 delayed INSERT into timestamp col needs set time_zone for concurrent binlogging +# To test that time_zone is correctly binloging for 'insert delayed' statement +# Insert 2 values into timestamp col with different time_zone. Check result. + +--connection master +reset master; +CREATE TABLE t1 (date timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, a int(11) default NULL); + +SET @@session.time_zone='+01:00'; +insert into t1 values('2008-12-23 19:39:39',1); + +--connection master1 +SET @@session.time_zone='+02:00'; +insert delayed into t1 values ('2008-12-23 19:39:39',2); + +# wait for the delayed insert to be executed +let $wait_condition= SELECT date FROM t1 WHERE a=2; +--source include/wait_condition.inc + +flush table t1; +flush logs; +select * from t1; +DROP TABLE t1; + +let $MYSQLD_DATADIR= `select @@datadir;`; +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 | $MYSQL +--connection master1 +select * from t1 order by a; +DROP TABLE t1; +SET @@session.time_zone = default; + +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc + +--echo End of 5.0 tests diff --git a/mysql-test/suite/rpl/t/rpl_tmp_table_and_DDL.test b/mysql-test/suite/rpl/t/rpl_tmp_table_and_DDL.test new file mode 100644 index 00000000..7029729d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_tmp_table_and_DDL.test @@ -0,0 +1,169 @@ +# +# Bug#49132 +# This test verifies if executing DDL statement before trying to manipulate +# a temporary table causes row-based replication to break with error 'table +# does not exist' base on myisam engine. +# + +source include/have_binlog_format_row.inc; +source include/master-slave.inc; + +LET $ENGINE_TYPE= MyISAM; +source include/rpl_tmp_table_and_DDL.test; +sync_slave_with_master; + +# +# BUG #51839 +# The test makes sure the binlog format is not changed +# after a execution of DDL with a table locked, so that +# the following DML statements will not cause the slave +# to stop. +# + +--connection master +--disable_abort_on_error + +CREATE TABLE t1 (a CHAR(30)); +CREATE TEMPORARY TABLE t2 (b CHAR(60)); + +# CREATE FUNCTION when a table is locked. +LOCK TABLE t1 WRITE; +CREATE FUNCTION f1 () RETURNS TINYINT RETURN 13; +INSERT INTO t2 VALUES ("CREATE FUNCTION f1 with table locked"); + +UNLOCK TABLE; +CREATE FUNCTION f2 () RETURNS TINYINT RETURN 13; + +# ALTER FUNCTION when a table is locked. +LOCK TABLE t1 WRITE; +ALTER FUNCTION f2 SQL SECURITY INVOKER; +INSERT INTO t2 VALUES ("ALTER FUNCTION f2 with table locked"); + +# DROP FUNCTION when a table is locked. +LOCK TABLE t1 WRITE; +DROP FUNCTION f2; +INSERT INTO t2 VALUES ("DROP FUNCTION f2 with table locked"); + + +# CREATE PROCEDURE when a table is locked. +CREATE PROCEDURE p1() SELECT 1; +INSERT INTO t2 VALUES ("CREATE PROCEDURE p1 with table locked"); + +UNLOCK TABLE; +CREATE PROCEDURE p2() SELECT 1; + +# ALTER PROCEDURE when a table is locked. +LOCK TABLE t1 WRITE; +ALTER PROCEDURE p2 SQL SECURITY INVOKER; +INSERT INTO t2 VALUES ("ALTER PROCEDURE P2 with table locked"); + +# DROP PROCEDURE when a table is locked. +DROP PROCEDURE p2; +INSERT INTO t2 VALUES ("DROP PROCEDURE p2 with table locked"); + + +# CREATE EVENT when a table is locked. +CREATE EVENT e1 ON SCHEDULE EVERY 10 HOUR DO SELECT 1; +INSERT INTO t2 VALUES ("CREATE EVENT e1 with table locked"); + +UNLOCK TABLE; +CREATE EVENT e2 ON SCHEDULE EVERY 10 HOUR DO SELECT 1; + +# ALTER EVENT when a table is locked. +LOCK TABLE t1 WRITE; +ALTER EVENT e2 ON SCHEDULE EVERY 20 HOUR DO SELECT 1; +INSERT INTO t2 VALUES ("ALTER EVENT e2 with table locked"); + +# DROP EVENT when a table is locked. +DROP EVENT e2; +INSERT INTO t2 VALUES ("DROP EVENT e2 with table locked"); + + +# CREATE DATABASE when a table is locked. +CREATE DATABASE mysqltest1; +INSERT INTO t2 VALUES ("CREATE DATABASE mysqltest1 with table locked"); + +UNLOCK TABLE; +CREATE DATABASE mysqltest2; + +# DROP DATABASE when a table is locked. +LOCK TABLE t1 WRITE; +DROP DATABASE mysqltest2; +INSERT INTO t2 VALUES ("DROP DATABASE mysqltest2 with table locked"); + +UNLOCK TABLE; +DROP DATABASE mysqltest2; + +# CREATE USER when a table is locked. +LOCK TABLE t1 WRITE; +CREATE USER test_1@localhost; +INSERT INTO t2 VALUES ("CREATE USER test_1@localhost with table locked"); + +UNLOCK TABLE; +CREATE USER test_2@localhost; + +# GRANT select on table to user when a table is locked. +LOCK TABLE t1 WRITE; +GRANT SELECT ON t1 TO test_2@localhost; +INSERT INTO t2 VALUES ("GRANT select on table to user with table locked"); + +# GRANT all on function to user when a table is locked. +GRANT ALL ON f2 TO test_2@localhost; +INSERT INTO t2 VALUES ("GRANT ALL ON f2 TO test_2 with table locked"); + +# GRANT all on procdure to user when a table is locked. +GRANT ALL ON p2 TO test_2@localhost; +INSERT INTO t2 VALUES ("GRANT ALL ON p2 TO test_2 with table locked"); + +# GRANT USAGE ON *.* to user when a table is locked. +GRANT USAGE ON *.* TO test_2@localhost; +INSERT INTO t2 VALUES ("GRANT USAGE ON *.* TO test_2 with table locked"); + + +# REVOKE ALL PRIVILEGES on function to user when a table is locked. +REVOKE ALL PRIVILEGES ON f2 FROM test_2@localhost; +INSERT INTO t2 VALUES ("REVOKE ALL PRIVILEGES on function to user with table locked"); + +# REVOKE ALL PRIVILEGES on procedure to user when a table is locked. +REVOKE ALL PRIVILEGES ON p2 FROM test_2@localhost; +INSERT INTO t2 VALUES ("REVOKE ALL PRIVILEGES on procedure to user with table locked"); + +# REVOKE ALL PRIVILEGES on table to user when a table is locked. +REVOKE ALL PRIVILEGES ON t1 FROM test_2@localhost; +INSERT INTO t2 VALUES ("REVOKE ALL PRIVILEGES on table to user with table locked"); + +# REVOKE USAGE ON *.* to user when a table is locked. +REVOKE USAGE ON *.* FROM test_2@localhost; +INSERT INTO t2 VALUES ("REVOKE USAGE ON *.* TO test_2 with table locked"); + + +# RENAME USER when a table is locked. +RENAME USER test_2@localhost TO test_3@localhost; +INSERT INTO t2 VALUES ("RENAME USER test_2 TO test_3 with table locked"); + +UNLOCK TABLE; +RENAME USER test_2@localhost TO test_3@localhost; + +# DROP USER when a table is locked. +LOCK TABLE t1 WRITE; +DROP USER test_3@localhost; +INSERT INTO t2 VALUES ("DROP USER test_3@localhost with table locked"); + +UNLOCK TABLE; + +# Bug #20439913 CREATE TABLE DB.TABLE LIKE TMPTABLE IS +# BINLOGGED INCORRECTLY - BREAKS A SLAVE +CREATE DATABASE db; +CREATE TABLE db.t1 LIKE t2; +CREATE TABLE t3 LIKE t2; +DROP TABLE t3; +DROP DATABASE db; +# end of Bug #20439913 test + +DROP USER test_3@localhost; +DROP FUNCTION f2; +DROP PROCEDURE p2; +DROP EVENT e2; +DROP TABLE t1, t2; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_tmp_table_and_DDL_innodb.test b/mysql-test/suite/rpl/t/rpl_tmp_table_and_DDL_innodb.test new file mode 100644 index 00000000..1a09b685 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_tmp_table_and_DDL_innodb.test @@ -0,0 +1,55 @@ +source include/have_innodb.inc; +source include/have_binlog_format_row.inc; +source include/master-slave.inc; +# +# BUG#20574550 +# CREATE TABLE LIKE <TEMP_TABLE> does not preserve original table storage +# engine when using row based replication +# +--connection master + +# Define temp_t1 and temp_t2 storage engines +--let $engine_temp_t1= InnoDB +--let $engine_temp_t2= MyISAM + +# Create the two temporary tables +--eval CREATE TEMPORARY TABLE temp_t1 (c1 INT) ENGINE=$engine_temp_t1 +--eval CREATE TEMPORARY TABLE temp_t2 (c1 INT) ENGINE=$engine_temp_t2 + +# Create t1 and t2 based on temporary tables +CREATE TABLE t1 LIKE temp_t1; +CREATE TABLE t2 LIKE temp_t2; +--sync_slave_with_master + +# On master +--connection master +# Assert that t1 and t2 have the same storage engines as temp_t1 and temp_t2 +--let $engine_t1= query_get_value(SHOW TABLE STATUS WHERE Name='t1', Engine, 1) +--let $assert_cond= "$engine_t1" = "$engine_temp_t1" +--let $assert_text= "t1 on master and temp_t1 have the same storage engine" +--source include/assert.inc + +--let $engine_t2= query_get_value(SHOW TABLE STATUS WHERE Name='t2', Engine, 1) +--let $assert_cond= "$engine_t2" = "$engine_temp_t2" +--let $assert_text= "t2 on master and temp_t2 have the same storage engine" +--source include/assert.inc + +# On slave +--connection slave +# Assert that t1 and t2 have the same storage engines as temp_t1 and temp_t2 +--let $engine_t1= query_get_value(SHOW TABLE STATUS WHERE Name='t1', Engine, 1) +--let $assert_cond= "$engine_t1" = "$engine_temp_t1" +--let $assert_text= "t1 on slave and temp_t1 have the same storage engine" +--source include/assert.inc + +--let $engine_t2= query_get_value(SHOW TABLE STATUS WHERE Name='t2', Engine, 1) +--let $assert_cond= "$engine_t2" = "$engine_temp_t2" +--let $assert_text= "t2 on slave and temp_t2 have the same storage engine" +--source include/assert.inc + +# Cleanup +--connection master +DROP TEMPORARY TABLE temp_t1, temp_t2; +DROP TABLE t1, t2; +--source include/rpl_end.inc + diff --git a/mysql-test/suite/rpl/t/rpl_trans_no_trans.test b/mysql-test/suite/rpl/t/rpl_trans_no_trans.test new file mode 100644 index 00000000..f6e3731d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_trans_no_trans.test @@ -0,0 +1,72 @@ +# +# Test mixing transactional and non transactional tables +# + +--source include/master-slave.inc +--source include/have_innodb.inc +--source include/have_binlog_format_row.inc + +# +# Test updating conditionally a non transactinal table in a function +# This verifies that we don't write only a table map for a non transactional, +# without any row events +# The original bug caused a crash on the slave when doing a sync_slave +# + +create or replace table t1(id int)engine=innodb; +create or replace table t3(id int)engine=myisam; + +delimiter //; +create or replace function t99 (a int) +returns int(10) +MODIFIES SQL DATA +begin + if (a > 100) + then + insert into t3 values (a); + end if; + return a; +end// +delimiter ;// +begin; +insert into t1 values(t99(1)); +insert into t1 values(t99(101)); +commit; +select * from t1; +select * from t3; +insert into t1 values(t99(1)); + +drop function t99; +drop table t1,t3; + +sync_slave_with_master; +connection master; + +# +# MDEV-8203 +# Assertion `!current_stmt_is_commit || !rgi->tables_to_lock' failed in +# Query_log_event::do_apply_event(rpl_group_info*, const char*, uint32) +# + +CREATE TABLE t1 (i INT) ENGINE=InnoDB; +CREATE TABLE t2 (j INT) ENGINE=MyISAM; + +--delimiter || +CREATE TRIGGER tr AFTER INSERT ON t1 FOR EACH ROW +BEGIN + SET @a = unknown_column_just_to_raise_an_error; + INSERT INTO t2 VALUES (NULL) ; +END|| +--delimiter ; + +--error ER_BAD_FIELD_ERROR +INSERT INTO t1 VALUES (1); +--sync_slave_with_master + +connection master; + +drop trigger tr; +drop table t1,t2; + +# End of 4.1 tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_trigger.test b/mysql-test/suite/rpl/t/rpl_trigger.test new file mode 100644 index 00000000..e442ed94 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_trigger.test @@ -0,0 +1,596 @@ +# +# Test of triggers with replication +# Adding statement include due to Bug 12574 +# TODO: Remove statement include once 12574 is patched +--source include/have_binlog_format_mixed_or_statement.inc +--source include/have_innodb.inc +--source include/master-slave.inc + +connection slave; +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=NO; +--source include/start_slave.inc + +connection master; + +disable_query_log; +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); +enable_query_log; + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +DROP TABLE IF EXISTS t3; + +--enable_warnings + +# +# #12482: Triggers has side effects with auto_increment values +# + +create table t1 (a int auto_increment, primary key (a), b int, rand_value double not null); +create table t2 (a int auto_increment, primary key (a), b int) engine=innodb; +create table t3 (a int auto_increment, primary key (a), name varchar(64) not null, old_a int, old_b int, rand_value double not null); + +delimiter |; +create trigger t1 before insert on t1 for each row +begin + insert into t3 values (NULL, "t1", new.a, new.b, rand()); +end| + +create trigger t2 after insert on t2 for each row +begin + insert into t3 values (NULL, "t2", new.a, new.b, rand()); +end| +delimiter ;| + +insert into t3 values(100,"log",0,0,0); + +# Ensure we always have same random numbers +SET @@RAND_SEED1=658490765, @@RAND_SEED2=635893186; + +# Emulate that we have rows 2-9 deleted on the slave +--disable_warnings +insert into t1 values(1,1,rand()),(NULL,2,rand()); +insert into t2 (b) values(last_insert_id()); +insert into t2 values(3,0),(NULL,0); +insert into t2 values(NULL,0),(500,0); +--enable_warnings + +select a,b, truncate(rand_value,4) from t1; +select * from t2; +select a,name, old_a, old_b, truncate(rand_value,4) from t3; +sync_slave_with_master; +select a,b, truncate(rand_value,4) from t1; +select * from t2; +select a,name, old_a, old_b, truncate(rand_value,4) from t3; +connection master; +drop table t1,t2,t3; + +# +# #12480: NOW() is not constant in a trigger +# #12481: Using NOW() in a stored function breaks statement based replication +# + +# Start by getting a lock on 'bug12480' to be able to use get_lock() as sleep() +connect (con2,localhost,root,,); +connection con2; +select get_lock("bug12480",2); +connection default; + +create table t1 (a datetime,b datetime, c datetime); +--disable_warnings +drop function if exists bug12480; +--enable_warnings + +delimiter |; + +create function bug12480() returns datetime +begin + set @a=get_lock("bug12480",2); + return now(); +end| + +create trigger t1_first before insert on t1 +for each row begin + set @a=get_lock("bug12480",2); + set new.b= now(); + set new.c= bug12480(); +end +| + +delimiter ;| +# The trigger causes a warning for unsafe statement when +# binlog_format=statement since it uses get_lock. +--disable_warnings +insert into t1 set a = now(); +--enable_warnings +select a=b && a=c from t1; +let $time=`select a from t1`; + +# Check that definer attribute is replicated properly: +# - dump definers on the master; +# - wait for the slave to synchronize with the master; +# - dump definers on the slave; + +SELECT routine_name, definer +FROM information_schema.routines +WHERE routine_name = 'bug12480'; + +SELECT trigger_name, definer +FROM information_schema.triggers +WHERE trigger_name = 't1_first'; + +sync_slave_with_master; + +# XXX: Definers of stored procedures and functions are not replicated. WL#2897 +# (Complete definer support in the stored routines) addresses this issue. So, +# the result file is expected to be changed after implementation of this WL +# item. + +SELECT routine_name, definer +FROM information_schema.routines +WHERE routine_name = 'bug12480'; + +SELECT trigger_name, definer +FROM information_schema.triggers +WHERE trigger_name = 't1_first'; + +select a=b && a=c from t1; +--disable_query_log +eval select a='$time' as 'test' from t1; +--enable_query_log + +connection master; +disconnect con2; + +truncate table t1; +drop trigger t1_first; + +# The trigger causes a warning for unsafe statement when +# binlog_format=statement since it uses get_lock. +--disable_warnings +insert into t1 values ("2003-03-03","2003-03-03","2003-03-03"),(bug12480(),bug12480(),bug12480()),(now(),now(),now()); +--enable_warnings +select a=b && a=c from t1; + +drop function bug12480; +drop table t1; + +# +# #14614: Replication of tables with trigger generates error message if databases is changed +# Note. The error message is emitted by _myfree() using fprintf() to the stderr +# and because of that does not fall into the .result file. +# + +create table t1 (i int); +create table t2 (i int); + +delimiter |; +create trigger tr1 before insert on t1 for each row +begin + insert into t2 values (1); +end| +delimiter ;| + +create database other; +use other; +insert into test.t1 values (1); + +sync_slave_with_master; + +connection master; +use test; +drop table t1,t2; +drop database other; + + +# +# Test specific triggers including SELECT into var with replication +# BUG#13227: +# slave performs an update to the replicatable table, t1, +# and modifies its local data, t3, by mean of its local trigger that uses +# another local table t2. +# Expected values are commented into queries. +# +# Body of the test executes in a loop since the problem occurred randomly. +# + +let $max_rows=5; +let $rnd=10; + +--echo test case for BUG#13227 +while ($rnd) +{ + --echo ------------------- + echo $rnd; + --echo ------------------- + +### SETUP + +--disable_warnings + connection master; + eval drop table if exists t1$rnd; + connection slave; + eval drop table if exists t2$rnd,t3$rnd; +--enable_warnings + + connection master; + eval create table t1$rnd (f1 int) /* 2 replicate */; + let $i=$max_rows; + while ($i) + { + eval insert into t1$rnd values (-$i); + dec $i; + } + + sync_slave_with_master; +#connection slave; + eval select * from t1$rnd; + delimiter |; + eval create trigger trg1$rnd before update on t1$rnd /* slave local */ + for each row + begin + DECLARE r integer; + SELECT f2 INTO r FROM t2$rnd where f1=NEW.f1; + INSERT INTO t3$rnd values (r); + end| + delimiter ;| + eval create table t2$rnd (f1 int, f2 int) /* slave local */; + eval create table t3$rnd (f3 int) /* slave local */; + let $i=$max_rows; + while ($i) + { + eval insert into t2$rnd values ($i, $i*100); + dec $i; + } + +### Test + +#connection slave; + +# trigger works as specified when updates from slave + eval select * from t2$rnd; + eval UPDATE t1$rnd SET f1=$max_rows where f1=-$max_rows; + eval SELECT * from t1$rnd /* must be f1 $max_rows, 1 - $max_rows 2 - $max_rows ... -1 */; + eval SELECT * from t3$rnd /* must be f3 $max_rows*100 */; + + connection master; + let $i=$max_rows; + while ($i) + { + eval UPDATE t1$rnd SET f1=$i where f1=-$i; + dec $i; + } + + sync_slave_with_master; +#connection slave; + eval SELECT * from t1$rnd /* must be f1 $max_rows ... 1 */; + eval SELECT * from t3$rnd /* must be f3 $max_rows * 100 ... 100 */; + +### CLEANUP +#connection slave; + eval drop trigger trg1$rnd; + eval drop table t2$rnd,t3$rnd; + + connection master; + eval drop table t1$rnd; + sync_slave_with_master; + connection master; + + dec $rnd; +} + + +# +# BUG#16266: Definer is not fully qualified error during replication. +# +# The idea of this test is to emulate replication of a trigger from the old +# master (master w/o "DEFINER in triggers" support) to the new slave and check +# that: +# 1. the trigger on the slave will be replicated w/o errors; +# 2. the trigger on the slave will be non-SUID (will have no DEFINER); +# 3. the trigger can be activated later on the slave w/o errors. +# +# In order to emulate this kind of replication, we make the slave playing the binlog, +# recorded by 5.0.16 master. This binlog contains the following statements: +# CREATE TABLE t1(c INT); +# CREATE TABLE t2(s CHAR(200)); +# CREATE TRIGGER trg1 AFTER INSERT ON t1 +# FOR EACH ROW +# INSERT INTO t2 VALUES(CURRENT_USER()); +# INSERT INTO t1 VALUES(1); +# + +# 1. Check that the trigger's replication is succeeded. + +# Stop the slave. + +connection slave; +STOP SLAVE; + +# Replace master's binlog. + +connection master; +let $MYSQLD_DATADIR= `select @@datadir`; +FLUSH LOGS; + +# Stop master server +--let $rpl_server_number= 1 +--source include/rpl_stop_server.inc + +# Replace binlog +remove_file $MYSQLD_DATADIR/master-bin.000001; +copy_file $MYSQL_TEST_DIR/std_data/bug16266.000001 $MYSQLD_DATADIR/master-bin.000001; + +--let $rpl_server_number= 1 +--source include/rpl_start_server.inc + +let $binlog_version= query_get_value(SHOW BINLOG EVENTS, Info, 1); + + +# Make the slave to replay the new binlog. +--echo --> Master binlog: $binlog_version + +# Make the slave to replay the new binlog. + +connection slave; +--let $master_use_gtid_option= No +--source include/reset_slave.inc +START SLAVE; + +SELECT MASTER_POS_WAIT('master-bin.000001', 513) >= 0; + +# Check that the replication succeeded. + +SHOW TABLES LIKE 't_'; +--replace_column 6 # +SHOW TRIGGERS; +SELECT * FROM t1; +SELECT * FROM t2; + +# 2. Check that the trigger is non-SUID on the slave; +# 3. Check that the trigger can be activated on the slave. +# +# We disable warnings here since it affects the result file in +# different ways depending on the mode being used. + +disable_warnings; +INSERT INTO t1 VALUES(2); +enable_warnings; + +SELECT * FROM t1; +SELECT * FROM t2; + +# That's all, cleanup. + +DROP TRIGGER trg1; +DROP TABLE t1; +DROP TABLE t2; + +STOP SLAVE; +--source include/reset_slave.inc + +# The master should be clean. + +connection master; +SHOW TABLES LIKE 't_'; +--replace_column 6 # +SHOW TRIGGERS; + +RESET MASTER; + +# Restart slave. + +connection slave; +START SLAVE; + + +# +# BUG#20438: CREATE statements for views, stored routines and triggers can be +# not replicable. +# + +--echo +--echo ---> Test for BUG#20438 + +# Prepare environment. + +--echo +--echo ---> Preparing environment... +--connection master + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +--enable_warnings + +--echo +--echo ---> Synchronizing slave with master... + +--sync_slave_with_master + +--echo +--connection master + +# Test. + +--echo +--echo ---> Creating objects... + +CREATE TABLE t1(c INT); +CREATE TABLE t2(c INT); + +/*!50003 CREATE TRIGGER t1_bi BEFORE INSERT ON t1 + FOR EACH ROW + INSERT INTO t2 VALUES(NEW.c * 10) */; + +--echo +--echo ---> Inserting value... + +INSERT INTO t1 VALUES(1); + +--echo +--echo ---> Checking on master... + +SELECT * FROM t1; +SELECT * FROM t2; + +--echo +--echo ---> Synchronizing slave with master... + +--sync_slave_with_master + +--echo +--echo ---> Checking on slave... + +SELECT * FROM t1; +SELECT * FROM t2; + +# Cleanup. + +--echo +--connection master + +--echo +--echo ---> Cleaning up... + +DROP TABLE t1; +DROP TABLE t2; + +--sync_slave_with_master +--connection master + +# +# BUG#23703: DROP TRIGGER needs an IF EXISTS +# + +connection master; + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1(a int, b varchar(50)); + +-- error ER_TRG_DOES_NOT_EXIST +drop trigger not_a_trigger; + +drop trigger if exists not_a_trigger; + +create trigger t1_bi before insert on t1 +for each row set NEW.b := "In trigger t1_bi"; + +insert into t1 values (1, "a"); +drop trigger if exists t1_bi; +insert into t1 values (2, "b"); +drop trigger if exists t1_bi; +insert into t1 values (3, "c"); + +select * from t1; +sync_slave_with_master; +select * from t1; + +connection master; + +drop table t1; +sync_slave_with_master; + +# +# Bug#40116: Uncommited changes are replicated and stay on slave after +# rollback on master +# + +connection master; +--source include/rpl_reset.inc + +connection slave; +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=NO; +--source include/start_slave.inc + +connection master; + +create table t1 ( f int ) engine = innodb; +create table log ( r int ) engine = myisam; +create trigger tr + after insert on t1 + for each row insert into log values ( new.f ); + +set autocommit = 0; +--disable_warnings +insert into t1 values ( 1 ); +--enable_warnings +rollback; +sync_slave_with_master; + +let $diff_tables= master:t1, slave:t1; +--source include/diff_tables.inc + +let $diff_tables= master:log, slave:log; +--source include/diff_tables.inc + +connection master; +drop table t1, log; +sync_slave_with_master; + +# +# MDEV-6769 DROP TRIGGER IF NOT EXIST binlogged on master but not on slave +# +let $slave_pos= query_get_value(SHOW MASTER STATUS, Position, 1); +connection master; +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +drop trigger if exists notexistent; +source include/show_binlog_events.inc; +sync_slave_with_master; +let $binlog_start= $slave_pos; +source include/show_binlog_events.inc; +connection master; + +# +# MDEV-6112 multiple triggers per table +# + +create table t1 (a int primary key, b int); +create trigger tr3 + before insert on t1 + for each row set NEW.b := (NEW.b+1)*4; +create trigger tr1 + before insert on t1 + for each row precedes tr3 set NEW.b := (NEW.b+1)*2; +create trigger tr2 + before insert on t1 + for each row follows tr1 set NEW.b := (NEW.b+1)*3; + +--replace_column 6 # +show triggers; +insert into t1 values (1,1); +select * from t1; +sync_slave_with_master; +--replace_column 6 # +show triggers; +select * from t1; +connection master; +drop table t1; + +# +# MDEV-10924 CREATE OR REPLACE TRIGGER which fails on PRECEDES/FOLLOWS drops +# the trigger, but isn't written to binlog; replication fails +# + +CREATE TABLE t1 (i INT); +CREATE OR REPLACE TRIGGER tr BEFORE INSERT ON t1 FOR EACH ROW SET @a=1; +--error ER_REFERENCED_TRG_DOES_NOT_EXIST +CREATE OR REPLACE TRIGGER tr BEFORE DELETE ON t1 FOR EACH ROW PRECEDES non_existing_trigger SET @a=2; +--replace_column 6 # +SHOW TRIGGERS; +--sync_slave_with_master +--replace_column 6 # +SHOW TRIGGERS; +connection master; +drop table t1; + +# +# End of tests +# +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_trunc_temp.test b/mysql-test/suite/rpl/t/rpl_trunc_temp.test new file mode 100644 index 00000000..1ef0fced --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_trunc_temp.test @@ -0,0 +1,57 @@ +# ==== Purpose ==== +# +# Verify that Slave_open_temp_tables is increased when a temporary +# table is opened on the slave, and decreased when a temporary table +# is closed on the slave, and that it is preserved during 'DELETE FROM +# table' and 'TRUNCATE table'. +# +# ==== Method ==== +# +# Create a temporary table on master, insert rows, and try: +# - delete rows from the table +# - truncate the table +# - drop the table +# +# ==== Related bugs ==== +# +# BUG#17137 Running "truncate table" on temporary table leaves the table open on a slave +# +# Bug in this test: BUG#37493: rpl_trunc_temp.test nondeterministic + + +# Requires statement-based logging since temporary tables are not +# logged in row-based logging +-- source include/have_binlog_format_mixed_or_statement.inc + +source include/master-slave.inc; + +create temporary table t1 (n int); +insert into t1 values(1); +sync_slave_with_master; +show status like 'Slave_open_temp_tables'; + +# Perform a delete from temp table +connection master; +delete from t1; +sync_slave_with_master; +show status like 'Slave_open_temp_tables'; + +# Perform truncate on temp table +connection master; +truncate t1; +sync_slave_with_master; +show status like 'Slave_open_temp_tables'; + +# Disconnect the master, temp table on slave should disappear +disconnect master; + +connection slave; + +# Wait until drop of temp tables appers in slave's binlog +let $wait_binlog_event= DROP; +source include/wait_for_binlog_event.inc; + +show status like 'Slave_open_temp_tables'; + + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_truncate_2myisam.test b/mysql-test/suite/rpl/t/rpl_truncate_2myisam.test new file mode 100644 index 00000000..e8b55b86 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_truncate_2myisam.test @@ -0,0 +1,2 @@ +let $engine=MyISAM; +--source include/rpl_truncate.test diff --git a/mysql-test/suite/rpl/t/rpl_truncate_3innodb.test b/mysql-test/suite/rpl/t/rpl_truncate_3innodb.test new file mode 100644 index 00000000..bac911b9 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_truncate_3innodb.test @@ -0,0 +1,3 @@ +--source include/have_innodb.inc +let $engine=InnoDB; +--source include/rpl_truncate.test diff --git a/mysql-test/suite/rpl/t/rpl_typeconv-slave.opt b/mysql-test/suite/rpl/t/rpl_typeconv-slave.opt new file mode 100644 index 00000000..48457b17 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_typeconv-slave.opt @@ -0,0 +1 @@ +--loose-innodb diff --git a/mysql-test/suite/rpl/t/rpl_typeconv.test b/mysql-test/suite/rpl/t/rpl_typeconv.test new file mode 100644 index 00000000..9e566258 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_typeconv.test @@ -0,0 +1,78 @@ +# +# This include file is used by more than one test suite +# (currently rpl and binlog_encryption suite). +# Please check all dependent tests after modifying it +# + +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +connection slave; +set @saved_slave_type_conversions = @@global.slave_type_conversions; +CREATE TABLE type_conversions ( + TestNo INT AUTO_INCREMENT PRIMARY KEY, + Source TEXT, + Target TEXT, + Flags TEXT, + On_Master LONGTEXT, + On_Slave LONGTEXT, + Expected LONGTEXT, + Compare INT, + Error TEXT); + +SELECT @@global.slave_type_conversions; +SET GLOBAL SLAVE_TYPE_CONVERSIONS=''; +SELECT @@global.slave_type_conversions; +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_NON_LOSSY'; +SELECT @@global.slave_type_conversions; +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_LOSSY'; +SELECT @@global.slave_type_conversions; +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_LOSSY,ALL_NON_LOSSY'; +SELECT @@global.slave_type_conversions; +--error ER_WRONG_VALUE_FOR_VAR +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_LOSSY,ALL_NON_LOSSY,NONEXISTING_BIT'; +SELECT @@global.slave_type_conversions; + +# Checking strict interpretation of type conversions +connection slave; +SET GLOBAL SLAVE_TYPE_CONVERSIONS=''; +source suite/rpl/include/type_conversions.test; + +# Checking lossy integer type conversions +connection slave; +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_NON_LOSSY'; +source suite/rpl/include/type_conversions.test; + +# Checking non-lossy integer type conversions +connection slave; +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_LOSSY'; +source suite/rpl/include/type_conversions.test; + +# Checking all type conversions +connection slave; +SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_LOSSY,ALL_NON_LOSSY'; +source suite/rpl/include/type_conversions.test; + +connection slave; +--echo **** Result of conversions **** +disable_query_log; +SELECT RPAD(Source, 15, ' ') AS Source_Type, + RPAD(Target, 15, ' ') AS Target_Type, + RPAD(Flags, 25, ' ') AS All_Type_Conversion_Flags, + IF(Compare IS NULL AND Error IS NOT NULL, '<Correct error>', + IF(Compare, '<Correct value>', + CONCAT("'", On_Slave, "' != '", Expected, "'"))) + AS Value_On_Slave + FROM type_conversions; +enable_query_log; +DROP TABLE type_conversions; + +call mtr.add_suppression("Slave SQL.*Column 1 of table .test.t1. cannot be converted from type.* error.* 1677"); + +connection master; +DROP TABLE t1; +sync_slave_with_master; + +set global slave_type_conversions = @saved_slave_type_conversions; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_typeconv_innodb.test b/mysql-test/suite/rpl/t/rpl_typeconv_innodb.test new file mode 100644 index 00000000..ba217210 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_typeconv_innodb.test @@ -0,0 +1,26 @@ +--source include/have_binlog_format_row.inc +--source include/have_innodb.inc +--source include/master-slave.inc + +# +# BUG#49618: Field length stored incorrectly in binary log for InnoDB +# + +connection slave; +SET @saved_slave_type_conversions = @@GLOBAL.SLAVE_TYPE_CONVERSIONS; +SET GLOBAL SLAVE_TYPE_CONVERSIONS = ''; + +connection master; +CREATE TABLE t1(b1 BIT(1), b2 BIT(2), b3 BIT(3)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (b'0', b'01', b'101'); +sync_slave_with_master; + +let $diff_tables= master:t1, slave:t1; +source include/diff_tables.inc; + +connection master; +DROP TABLE t1; +sync_slave_with_master; + +SET GLOBAL SLAVE_TYPE_CONVERSIONS = @saved_slave_type_conversions; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_udf.test b/mysql-test/suite/rpl/t/rpl_udf.test new file mode 100644 index 00000000..cda99ace --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_udf.test @@ -0,0 +1,11 @@ +################################################################### +# Author: Chuck Bell # +# Date: 2006-12-21 # +# Purpose: To test that UDFs are replicated in both row based and # +# statement based format. This tests work completed in WL#3629. # +################################################################### + +let $engine_type= MyISAM; +--source include/rpl_udf.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_unsafe_statements.test b/mysql-test/suite/rpl/t/rpl_unsafe_statements.test new file mode 100644 index 00000000..40c9b9bb --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_unsafe_statements.test @@ -0,0 +1,215 @@ +################################################################################ +# Bug#17047208 REPLICATION DIFFERENCE FOR MULTIPLE TRIGGERS +# Problem: If DML invokes a trigger or a stored function that inserts into an +# AUTO_INCREMENT column, that DML has to be marked as 'unsafe' statement. If the +# tables are locked in the transaction prior to DML statement (using LOCK +# TABLES), then the DML statement is not marked as 'unsafe' statement. + +# Steps to reproduce the reported test case (BINLOG_STMT_UNSAFE_AUTOINC_COLUMNS) +# Case-1: +# > Create a trigger on a table and do a insert in the trigger that updates +# auto increment column +# > A DML that executes the trigger in step.1 and check that DML is marked +# as unsafe and DML is written into binlog using row format (in MBR) +# > Execute the step 2 by locking the required tables prior to DML and check +# that DML is marked as unsafe and DML is written into binlog using row +# format (in MBR) +# +# This test script also adds test cases to cover few other unsafe statements. +# Case-2: BINLOG_STMT_UNSAFE_WRITE_AUTOINC_SELECT +# Case-3: BINLOG_STMT_UNSAFE_AUTOINC_NOT_FIRST +# Case-4: BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS +# Case-5: BINLOG_STMT_UNSAFE_SKIP_LOCKED +################################################################################ + +--source include/have_innodb.inc +--source include/have_binlog_format_mixed.inc +--source include/master-slave.inc + +# Case-1: BINLOG_STMT_UNSAFE_AUTOINC_COLUMNS +# Statement is unsafe because it invokes a trigger or a +# stored function that inserts into an AUTO_INCREMENT column. + +# Step-1.1: Create two tables, one with AUTO_INCREMENT column. +CREATE TABLE t1(id INT AUTO_INCREMENT, i INT, PRIMARY KEY (id)) ENGINE=INNODB; +CREATE TABLE t2(id INT AUTO_INCREMENT, i INT, PRIMARY KEY (id)) ENGINE=INNODB; + +# Step-1.2: Create a trigger that inserts into an AUTO_INCREMENT column. +CREATE TRIGGER trig1 AFTER INSERT ON t1 +FOR EACH ROW + INSERT INTO t2(i) VALUES(new.i); + +# Step-1.3: Create some gap in auto increment value on master's t2 table +# but not on slave (by doing rollback). Just in case if the unsafe statements +# are written in statement format, diff tables will fail. +START TRANSACTION; +INSERT INTO t2(i) VALUES (1); +ROLLBACK; + +# Step-1.4: Insert a tuple into table t1 that triggers trig1 which inserts +# into an AUTO_INCREMENT column. +INSERT INTO t1(i) VALUES(2); + +# Step-1.5: Repeat step 1.4 but using 'LOCK TABLES' logic. +START TRANSACTION; +LOCK TABLES t1 WRITE, t2 WRITE; +INSERT INTO t1(i) VALUES(3); +UNLOCK TABLES; +COMMIT; + +# Step-1.6: Sync slave with master +--sync_slave_with_master + +# Step-1.7: Diff master-slave tables to make sure everything is in sync. +--let $diff_tables=master:t1, slave:t1 +--source include/diff_tables.inc + +--let $diff_tables=master:t2, slave:t2 +--source include/diff_tables.inc + +# Step-1.8: Cleanup +--connection master +DROP TABLE t1,t2; + +# Case-2: BINLOG_STMT_UNSAFE_WRITE_AUTOINC_SELECT +# Statements writing to a table with an auto-increment column after selecting +# from another table are unsafe because the order in which rows are retrieved +# determines what (if any) rows will be written. This order cannot be +# predicted and may differ on master and the slave. + +# Step-2.1: Create two tables, one with AUTO_INCREMENT column. +CREATE TABLE t1(i INT) ENGINE=INNODB; +CREATE TABLE t2(id INT AUTO_INCREMENT, i INT, PRIMARY KEY (id)) ENGINE=INNODB; + +# Step-2.2: Create some tuples in table t1. +INSERT INTO t1 values (1), (2), (3); + +# Step-2.3: Create some gap in auto increment value on master's t2 table +# but not on slave (by doing rollback). Just in case if the unsafe statements +# are written in statement format, diff tables will fail. +START TRANSACTION; +INSERT INTO t2(i) VALUES (1); +ROLLBACK; + +# Step-2.4: Insert into t2 (table with an auto-increment) by selecting tuples +# from table t1. +INSERT INTO t2(i) SELECT i FROM t1; + +# Step-2.5: Repeat step 2.4 but now with 'LOCK TABLES' logic. +START TRANSACTION; +LOCK TABLES t2 WRITE, t1 READ; +INSERT INTO t2(i) SELECT i FROM t1; +UNLOCK TABLES; +COMMIT; + +# Step-2.6: Sync slave with master +--sync_slave_with_master + +# Step-2.7: Diff master-slave tables to make sure everything is in sync. +--let $diff_tables=master:t1, slave:t1 +--source include/diff_tables.inc + +--let $diff_tables=master:t2, slave:t2 +--source include/diff_tables.inc + +# Step-2.8: Cleanup +--connection master +DROP TABLE t1,t2; + +# Case-3: BINLOG_STMT_UNSAFE_AUTOINC_NOT_FIRST +# INSERT into autoincrement field which is not the first part in the +# composed primary key is unsafe +# +# Step-3.1: Create a table with auto increment column and a composed primary key +# (second column is auto increment column). Such a definition is allowed only +# with 'myisam' engine. +CREATE TABLE t1(i int, id INT AUTO_INCREMENT, PRIMARY KEY (i, id)) ENGINE=MYISAM; + +# Step-3.2: Inserting into such a table is unsafe. +INSERT INTO t1 (i) values (1); + +# Step-3.3: Repeat step 3.2, now with 'LOCK TABLES' logic. +START TRANSACTION; +LOCK TABLES t1 WRITE; +INSERT INTO t1 (i) values (2); +UNLOCK TABLES; +COMMIT; + +# Step-3.4: Sync slave with master +--sync_slave_with_master + +# Step-3.5: Diff master-slave tables to make sure everything is in sync. +--let $diff_tables=master:t1, slave:t1 +--source include/diff_tables.inc + +# Step-3.6: Cleanup +--connection master +DROP TABLE t1; + +# Case-4: BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS +# INSERT... ON DUPLICATE KEY UPDATE on a table with more than one UNIQUE KEY +# is unsafe Statement + +# Step-4.1: Create a table with two unique keys +CREATE TABLE t1(i INT, j INT, UNIQUE KEY(i), UNIQUE KEY(j)) ENGINE=INNODB; + +# Step-4.2: Inserting into such a table is unsafe. +INSERT INTO t1 (i,j) VALUES (1,2) ON DUPLICATE KEY UPDATE j=j+1; + +# Step-4.3: Repeat step 3.2, now with 'LOCK TABLES' logic. +START TRANSACTION; +LOCK TABLES t1 WRITE; +INSERT INTO t1 (i,j) VALUES (1,2) ON DUPLICATE KEY UPDATE j=j+1; +UNLOCK TABLES; +COMMIT; + +# Step-4.4: Sync slave with master +--sync_slave_with_master + +# Step-4.5: Diff master-slave tables to make sure everything is in sync. +--let $diff_tables=master:t1, slave:t1 +--source include/diff_tables.inc + +# Step-4.6: Cleanup +--connection master +DROP TABLE t1; + +# Case-5: BINLOG_STMT_UNSAFE_SKIP_LOCKED +# INSERT... ON KEY UPDATE SKIP LOCKED is unsafe Statement + +# Step-5.1: Create a table some index +CREATE TABLE t1(i INT,PRIMARY KEY(i)) ENGINE=INNODB; +CREATE TABLE t2(i INT,PRIMARY KEY(i)) ENGINE=INNODB; + +# Step-5.2: Inserting some values +INSERT INTO t1 (i) VALUES (1),(2),(3),(4),(5); + +# Step-5.3: Lock one of the values +connect (con1, localhost, root,); +START TRANSACTION; +SELECT i FROM t1 WHERE i=3 FOR UPDATE; + +# Step-5.4: Create non-deterministic inserts/tables +--connection master +INSERT INTO t2 SELECT i FROM t1 LOCK IN SHARE MODE SKIP LOCKED; +CREATE TABLE t3 AS SELECT i FROM t1 LOCK IN SHARE MODE SKIP LOCKED; +SELECT * FROM t2 ORDER BY i; +SELECT * FROM t3 ORDER BY i; + +# Step-5.5: Sync slave with master +--sync_slave_with_master + +# Step-5.6: Diff master-replica tables insert statements are in sync +--let $diff_tables=master:t2, slave:t2 +--source include/diff_tables.inc + +# Step-5.7: Diff master-replica tables create select table is in sync +--let $diff_tables=master:t3, slave:t3 +--source include/diff_tables.inc + +# Step-5.8: Cleanup +--disconnect con1 +--connection master +DROP TABLE t1, t2, t3; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_update.test b/mysql-test/suite/rpl/t/rpl_update.test new file mode 100644 index 00000000..b3807877 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_update.test @@ -0,0 +1,15 @@ +source include/master-slave.inc; + +# +# MDEV-13417 UPDATE produces wrong values if an updated column is later used as an update source +# +set sql_mode=simultaneous_assignment; +create table t1 (a int, b int); +insert into t1 values(1, 2); +update t1 set a=b, b=a; +select * from t1; +sync_slave_with_master; +select * from t1; +connection master; +drop table t1; +source include/rpl_end.inc; diff --git a/mysql-test/suite/rpl/t/rpl_upgrade_master_info.test b/mysql-test/suite/rpl/t/rpl_upgrade_master_info.test new file mode 100644 index 00000000..fb0e3cf4 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_upgrade_master_info.test @@ -0,0 +1,167 @@ +--source include/master-slave.inc + +--echo *** MDEV-9383: Server fails to read master.info after upgrade 10.0 -> 10.1 *** + +--connection slave +--source include/stop_slave.inc +--let $datadir= `SELECT @@datadir` + +--let $rpl_server_number= 2 +--source include/rpl_stop_server.inc + +--remove_file $datadir/master.info +--copy_file $MYSQL_TEST_DIR/std_data/bad_master.info $datadir/master.info + +--let $rpl_server_number= 2 +--source include/rpl_start_server.inc + +--source include/wait_until_connected_again.inc + +--connection master +CREATE TABLE t1 (a INT PRIMARY KEY); +INSERT INTO t1 VALUES (1); +--source include/save_master_gtid.inc + +--connection slave +# Fix the port after we replaced master.info. +--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1 +eval CHANGE MASTER TO master_host='127.0.0.1', master_port=$SERVER_MYPORT_1; +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +FLUSH NO_WRITE_TO_BINLOG TABLES; +SELECT * FROM t1; + +--source include/stop_slave.inc + +--let $rpl_server_number= 2 +--source include/rpl_stop_server.inc + +--remove_file $datadir/master.info +--copy_file $MYSQL_TEST_DIR/std_data/bad2_master.info $datadir/master.info + +--let $rpl_server_number= 2 +--source include/rpl_start_server.inc + +--source include/wait_until_connected_again.inc + +--connection master +INSERT INTO t1 VALUES (2); +--source include/save_master_gtid.inc + +--connection slave +# Fix the port after we replaced master.info. +--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1 +eval CHANGE MASTER TO master_host='127.0.0.1', master_port=$SERVER_MYPORT_1; +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +FLUSH NO_WRITE_TO_BINLOG TABLES; +SELECT * FROM t1 ORDER BY a; + +--source include/stop_slave.inc + +--let $rpl_server_number= 2 +--source include/rpl_stop_server.inc + +--remove_file $datadir/master.info +--copy_file $MYSQL_TEST_DIR/std_data/bad3_master.info $datadir/master.info + +--let $rpl_server_number= 2 +--source include/rpl_start_server.inc + +--source include/wait_until_connected_again.inc + +--connection master +INSERT INTO t1 VALUES (3); +--source include/save_master_gtid.inc + +--connection slave +# Fix the port after we replaced master.info. +--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1 +eval CHANGE MASTER TO master_host='127.0.0.1', master_port=$SERVER_MYPORT_1; +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +FLUSH NO_WRITE_TO_BINLOG TABLES; +SELECT * FROM t1 ORDER BY a; + +--source include/stop_slave.inc + +--let $rpl_server_number= 2 +--source include/rpl_stop_server.inc + +--remove_file $datadir/master.info +--copy_file $MYSQL_TEST_DIR/std_data/bad4_master.info $datadir/master.info + +--let $rpl_server_number= 2 +--source include/rpl_start_server.inc + +--source include/wait_until_connected_again.inc + +--connection master +INSERT INTO t1 VALUES (4); +--source include/save_master_gtid.inc + +--connection slave +# Fix the port after we replaced master.info. +--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1 +eval CHANGE MASTER TO master_host='127.0.0.1', master_port=$SERVER_MYPORT_1; +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +FLUSH NO_WRITE_TO_BINLOG TABLES; +SELECT * FROM t1 ORDER BY a; + +--source include/stop_slave.inc + +--let $rpl_server_number= 2 +--source include/rpl_stop_server.inc + +--remove_file $datadir/master.info +--copy_file $MYSQL_TEST_DIR/std_data/bad5_master.info $datadir/master.info + +--let $rpl_server_number= 2 +--source include/rpl_start_server.inc + +--source include/wait_until_connected_again.inc + +--connection master +INSERT INTO t1 VALUES (5); +--source include/save_master_gtid.inc + +--connection slave +# Fix the port after we replaced master.info. +--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1 +eval CHANGE MASTER TO master_host='127.0.0.1', master_port=$SERVER_MYPORT_1; +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +FLUSH NO_WRITE_TO_BINLOG TABLES; +SELECT * FROM t1 ORDER BY a; + +--source include/stop_slave.inc + +--let $rpl_server_number= 2 +--source include/rpl_stop_server.inc + +--remove_file $datadir/master.info +--copy_file $MYSQL_TEST_DIR/std_data/bad6_master.info $datadir/master.info + +--let $rpl_server_number= 2 +--source include/rpl_start_server.inc + +--source include/wait_until_connected_again.inc + +--connection master +INSERT INTO t1 VALUES (6); +--source include/save_master_gtid.inc + +--connection slave +# Fix the port after we replaced master.info. +--replace_result $SERVER_MYPORT_1 SERVER_MYPORT_1 +eval CHANGE MASTER TO master_host='127.0.0.1', master_port=$SERVER_MYPORT_1; +--source include/start_slave.inc +--source include/sync_with_master_gtid.inc +SELECT * FROM t1 ORDER BY a; + + +# Cleanup +--connection master +DROP TABLE t1; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_user.test b/mysql-test/suite/rpl/t/rpl_user.test new file mode 100644 index 00000000..079c2bf2 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_user.test @@ -0,0 +1,73 @@ +# BUG#33862 completely failed DROP USER statement gets replicated + +--source include/master-slave.inc + +# +# remove all users will be used in the test +# +connection master; +set session sql_log_bin=0; +delete from mysql.user where Host='fakehost'; +set session sql_log_bin=1; + +connection slave; +set session sql_log_bin=0; +delete from mysql.user where Host='fakehost'; +set session sql_log_bin=1; + +# +# Test create user +# +connection master; +create user 'foo'@'fakehost'; +--error ER_CANNOT_USER +create user 'foo'@'fakehost', 'bar'@'fakehost'; +--error ER_CANNOT_USER +create user 'foo'@'fakehost', 'bar'@'fakehost'; + +sync_slave_with_master; +select Host,User from mysql.user where Host='fakehost'; + +# +# Test rename user +# +connection master; +rename user 'foo'@'fakehost' to 'foofoo'@'fakehost'; +--error ER_CANNOT_USER +rename user 'not_exist_user1'@'fakehost' to 'foobar'@'fakehost', 'bar'@'fakehost' to 'barbar'@'fakehost'; +--error ER_CANNOT_USER +rename user 'not_exist_user1'@'fakehost' to 'foobar'@'fakehost', 'not_exist_user2'@'fakehost' to 'barfoo'@'fakehost'; + +sync_slave_with_master; +select Host,User from mysql.user where Host='fakehost'; + +# +# Test alter user +# +connection master; +alter user 'foofoo'@'fakehost' identified by 'foo'; +--error ER_CANNOT_USER +alter user 'non_exist_user1'@'fakehost' identified by 'foo', 'barbar'@'fakehost' identified by 'bar'; +--error ER_CANNOT_USER +alter user 'non_exist_user1'@'fakehost' identified by 'foo', 'non_exist_user2'@'fakehost' identified by 'bar'; +sync_slave_with_master; + +# +# Test drop user +# +connection master; +drop user 'foofoo'@'fakehost'; +--error ER_CANNOT_USER +drop user 'not_exist_user1'@'fakehost', 'barbar'@'fakehost'; +--error ER_CANNOT_USER +drop user 'not_exist_user1'@'fakehost', 'not_exist_user2'@'fakehost'; + +sync_slave_with_master; +select Host,User from mysql.user where Host='fakehost'; + +# +# show the binlog events on the master +# +connection master; +source include/show_binlog_events.inc; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_user_variables.test b/mysql-test/suite/rpl/t/rpl_user_variables.test new file mode 100644 index 00000000..08d9b4ae --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_user_variables.test @@ -0,0 +1,385 @@ +################################### +# +# Test of replicating user variables +# +################################### + +-- source include/master-slave.inc + +disable_query_log; +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); +enable_query_log; + +# Disable PS as the log positions differs +--disable_ps_protocol + + +# Clean up old slave's binlogs. +# The slave is started with --log-slave-updates +# and this test does SHOW BINLOG EVENTS on the slave's +# binlog. But previous tests can influence the current test's +# binlog (e.g. a temporary table in the previous test has not +# been explicitly deleted, or it has but the slave hasn't had +# enough time to catch it before STOP SLAVE, +# and at the beginning of the current +# test the slave immediately writes DROP TEMPORARY TABLE this_old_table). +# We wait for the slave to have written all he wants to the binlog +# (otherwise RESET MASTER may come too early). +sync_slave_with_master; +reset master; +connection master; + +create table t1(n char(30)); +set @i1:=12345678901234, @i2:=-12345678901234, @i3:=0, @i4:=-1; +set @s1:='This is a test', @r1:=12.5, @r2:=-12.5; +set @n1:=null; +set @s2:='', @s3:='abc\'def', @s4:= 'abc\\def', @s5:= 'abc''def'; +insert into t1 values (@i1), (@i2), (@i3), (@i4); +insert into t1 values (@r1), (@r2); +insert into t1 values (@s1), (@s2), (@s3), (@s4), (@s5); +insert into t1 values (@n1); +insert into t1 values (@n2); # not explicitly set before +insert into t1 values (@a:=0), (@a:=@a+1), (@a:=@a+1); +insert into t1 values (@a+(@b:=@a+1)); +set @q:='abc'; +insert t1 values (@q), (@q:=concat(@q, 'n1')), (@q:=concat(@q, 'n2')); +set @a:=5; +insert into t1 values (@a),(@a); +# To flush the pending event, we add the following statement. RBR can +# concatenate the result of several statements, which SBR cannot. +select * from t1 where n = '<nonexistant>'; +connection master1; # see if variable is reset in binlog when thread changes +insert into t1 values (@a),(@a),(@a*5); +SELECT * FROM t1 ORDER BY n; +sync_slave_with_master; +SELECT * FROM t1 ORDER BY n; +connection master; +insert into t1 select * FROM (select @var1 union select @var2) AS t2; +drop table t1; +--echo End of 4.1 tests. + +# BUG#20141 +# The following tests ensure that if user-defined variables are used in SF/Triggers +# that they are replicated correctly. These tests should be run in both SBR and RBR +# modes. + +# This test uses a procedure that inserts data values based on the value of a +# user-defined variable. It also has a trigger that inserts data based on the +# same variable. Successful test runs show that the @var is replicated +# properly and that the procedure and trigger insert the correct data on the +# slave. +# +# The test of stored procedure was included for completeness. Replication of stored +# procedures was not directly affected by BUG#20141. +# +# This test was constructed for BUG#20141 + +--disable_warnings +DROP TABLE IF EXISTS t20; +DROP TABLE IF EXISTS t21; +DROP PROCEDURE IF EXISTS test.insert; +--enable_warnings + +CREATE TABLE t20 (a VARCHAR(20)); +CREATE TABLE t21 (a VARCHAR(20)); +DELIMITER |; + +# Create a procedure that uses the @var for flow control + +CREATE PROCEDURE test.insert() +BEGIN + IF (@VAR) + THEN + INSERT INTO test.t20 VALUES ('SP_TRUE'); + ELSE + INSERT INTO test.t20 VALUES ('SP_FALSE'); + END IF; +END| + +# Create a trigger that uses the @var for flow control + +CREATE TRIGGER test.insert_bi BEFORE INSERT + ON test.t20 FOR EACH ROW + BEGIN + IF (@VAR) + THEN + INSERT INTO test.t21 VALUES ('TRIG_TRUE'); + ELSE + INSERT INTO test.t21 VALUES ('TRIG_FALSE'); + END IF; + END| +DELIMITER ;| + +sync_slave_with_master; +connection master; + +# Set @var and call the procedure, repeat with different values + +SET @VAR=0; +CALL test.insert(); +SET @VAR=1; +CALL test.insert(); + +--echo Check the tables for correct data + +SELECT * FROM t20; +SELECT * FROM t21; + +sync_slave_with_master; + +--echo Check the tables for correct data and it matches master + +SELECT * FROM t20; +SELECT * FROM t21; +connection master; + +# Cleanup + +DROP TABLE t20; +DROP TABLE t21; +DROP PROCEDURE test.insert; + +# This test uses a stored function that uses user-defined variables to return data +# This test was constructed for BUG#20141 + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP FUNCTION IF EXISTS test.square; +--enable_warnings + +CREATE TABLE t1 (i INT); + +# Create function that returns a value from @var. In this case, the square function + +CREATE FUNCTION test.square() RETURNS INTEGER DETERMINISTIC RETURN +(@var * @var); + +# Set the @var to different values and insert them into a table + +SET @var = 1; +INSERT INTO t1 VALUES (square()); +SET @var = 2; +INSERT INTO t1 VALUES (square()); +SET @var = 3; +INSERT INTO t1 VALUES (square()); +SET @var = 4; +INSERT INTO t1 VALUES (square()); +SET @var = 5; +INSERT INTO t1 VALUES (square()); + +--echo Retrieve the values from the table + +SELECT * FROM t1; + +sync_slave_with_master; + +--echo Retrieve the values from the table and verify they are the same as on master + +SELECT * FROM t1; + +connection master; + +# Cleanup + +DROP TABLE t1; +DROP FUNCTION test.square; + +# This test uses stored functions that uses user-defined variables to return data +# based on the use of @vars inside a function body. +# This test was constructed for BUG#14914 + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP FUNCTION IF EXISTS f1; +DROP FUNCTION IF EXISTS f2; +--enable_warnings + +CREATE TABLE t1(a int); +DELIMITER |; + +# Create a function that simply returns the value of an @var. +# Create a function that uses an @var for flow control, creates and uses another +# @var and sets its value to a value based on another @var. + +CREATE FUNCTION f1() returns int deterministic BEGIN + return @a; +END | + +CREATE FUNCTION f2() returns int deterministic BEGIN + IF (@b > 0) then + SET @c = (@a + @b); + else + SET @c = (@a - 1); + END if; + return @c; +END | +DELIMITER ;| + +sync_slave_with_master; +connection master; + +# Set an @var to a value and insert data into a table using the first function. +# Set two more @vars to some values and insert data into a table using the second function. + +SET @a=500; +INSERT INTO t1 values(f1()); +SET @b = 125; +SET @c = 1; +INSERT INTO t1 values(f2()); + +--echo Retrieve the values from the table + +sync_slave_with_master; +connection master; + +SELECT * from t1; + +connection slave; + +--echo Check the tables for correct data and it matches master + +SELECT * from t1; + +connection master; + +# Cleanup + +DROP TABLE t1; +DROP FUNCTION f1; +DROP FUNCTION f2; + +# This test uses a function that changes a user-defined variable in its body. This test +# will ensure the @vars are replicated when needed and not interrupt the normal execution +# of the function on the slave. This also applies to procedures and triggers. + +# This test was constructed for BUG#25167 + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +--enable_warnings +CREATE TABLE t1 (i int); +CREATE TABLE t2 (k int); +DELIMITER |; + +# Create a trigger that inserts data into another table, changes the @var then inserts +# another row with the modified value. + +CREATE trigger t1_bi before INSERT on t1 for each row BEGIN + INSERT INTO t2 values (@a); + SET @a:=42; + INSERT INTO t2 values (@a); +END | +DELIMITER ;| + +sync_slave_with_master; +connection master; + +# Set the @var to a value then insert data into first table. + +SET @a:=100; +INSERT INTO t1 values (5); + +--echo Check to see that data was inserted correctly in both tables + +SELECT * from t1; +SELECT * from t2; + +sync_slave_with_master; + +--echo Check the tables for correct data and it matches master + +SELECT * from t1; +SELECT * from t2; + +connection master; +drop table t1, t2; + +# +# Bug #12826: Possible to get inconsistent slave using SQL syntax Prepared Statements +# +connection master; +create table t1(a int, b int); +prepare s1 from 'insert into t1 values (@x:=@x+1, ?)'; +set @x=1; execute s1 using @x; +select * from t1; +sync_slave_with_master; +connection slave; +select * from t1; +connection master; +drop table t1; + +# +# Bug#33851: Passing UNSIGNED param to EXECUTE returns ERROR 1210 +# + +connection master; +create table t1(a int); +insert into t1 values (1),(2); +prepare s1 from 'insert into t1 select a from t1 limit ?'; +set @x='1.1'; +--disable_warnings +execute s1 using @x; +--enable_warnings +select * from t1; +sync_slave_with_master; +connection slave; +select * from t1; +connection master; +drop table t1; + +--echo End of 5.0 tests. + +# This test uses a stored function that uses user-defined variables to return data +# The test ensures the value of the user-defined variable is replicated correctly +# and in the correct order of assignment. + +# This test was constructed for BUG#20141 + +--disable_warnings +DROP FUNCTION IF EXISTS f1; +DROP FUNCTION IF EXISTS f2; +--enable_warnings + +CREATE TABLE t1 (i INT); + +# Create two functions. One simply returns the user-defined variable. The other +# returns a value based on the user-defined variable. + +CREATE FUNCTION f1() RETURNS INT RETURN @a; DELIMITER |; CREATE +FUNCTION f2() RETURNS INT BEGIN + INSERT INTO t1 VALUES (10 + @a); + RETURN 0; +END| +DELIMITER ;| + +sync_slave_with_master; +connection master; + +# Set the variable and execute the functions. + +SET @a:=123; +SELECT f1(), f2(); + +--echo Check to see that data was inserted correctly + +INSERT INTO t1 VALUES(f1()); +SELECT * FROM t1; + +sync_slave_with_master; + +--echo Check the table for correct data and it matches master + +SELECT * FROM t1; + +connection master; + +# Cleanup + +DROP FUNCTION f1; +DROP FUNCTION f2; +DROP TABLE t1; + +sync_slave_with_master; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_using_gtid_default.test b/mysql-test/suite/rpl/t/rpl_using_gtid_default.test new file mode 100644 index 00000000..eab5b4dd --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_using_gtid_default.test @@ -0,0 +1,303 @@ +# +# Purpose: +# This test ensures that a replica's default value for Using_Gtid is set +# correctly. Specifically, it should default to 'Slave_Pos' unless the primary +# server does not support GTIDs (if its version is less than 10), in which case +# the replica should fall back to 'No'. +# +# Methodology: +# Validate the value of Using_Gtid on replica initialization and after +# RESET SLAVE commands. Specifically, we validate the following use cases: +# +# Case 1) A replica will initialize with Slave_Pos if the primary supports +# GTIDs +# Case 2) A replica configured with the Using_Gtid=Slave_Pos issued +# RESET SLAVE will preserve Using_Gtid without any informational +# messages. +# Case 3) A replica configured with Using_Gtid=No against a master which +# supports GTIDs will revert to Using_Gtid=Slave_Pos after issued +# RESET SLAVE and provide an informational note +# Case 4) A fresh replica targeting a primary which does not support GTIDs +# will fall back to Using_Gtid=No when starting. An informational +# message should be logged. +# Case 5) A replica connected to a primary which does not support GTIDs +# should preserve Using_Gtid=No when issued RESET SLAVE. No message +# should be provided to the user. +# Case 6) A replica configured with Using_Gtid=Current_Pos should revert +# to Slave_Pos when issued RESET SLAVE. An informational message +# should be provided to the user. +# Case 7) The MTR include file rpl_change_topology.inc should implicitly +# set MASTER_USE_GTID=NO when provided with $rpl_master_log_file +# Case 8) The MTR include file reset_slave.inc should keep/delete GTID state +# when reset_slave_keep_gtid_state is set, respectively. +# Case 9) A replica issued CHANGE MASTER TO specified with log coordinates +# but not master_use_gtid=No should warn the user that Using_Gtid is +# being changed to No. +# Case 10) A replica issued CHANGE MASTER TO specified with log coordinates +# and master_use_gtid=Slave_Pos should warn the user that the log +# coordinates will be ignored. +# +# References: +# MDEV-19801: Change defaults for CHANGE MASTER TO so that GTID-based +# replication is used by default if master supports it +# +--source include/have_debug.inc +--source include/master-slave.inc + +# Format independent test so just use one +--source include/have_binlog_format_mixed.inc + +--echo # +--echo # Slave default configuration should be Slave_Pos +--let $expected_default_using_gtid= Slave_Pos +--connection slave +--let $using_gtid= query_get_value(SHOW SLAVE STATUS, Using_Gtid, 1) +if ($using_gtid != $expected_default_using_gtid) +{ + --die Using_Gtid had wrong default value of '$using_gtid' when it should have been '$expected_default_using_gtid' +} + +--echo # +--echo # Ensure that a slave configured with Using_Gtid=Slave_Pos will remain +--echo # as Slave_Pos after RESET SLAVE +--source include/stop_slave.inc +RESET SLAVE; +--echo # No warning should be given because Slave_Pos never changed +SHOW WARNINGS; +--source include/start_slave.inc +--let $using_gtid= query_get_value(SHOW SLAVE STATUS, Using_Gtid, 1) +if ($using_gtid != $expected_default_using_gtid) +{ + --die Using_Gtid has wrong value of '$using_gtid' when it should be '$expected_default_using_gtid' +} + + +--echo # +--echo # Ensure that a slave configured with Using_Gtid=No will revert to its +--echo # default of Slave_Pos after RESET SLAVE for a master which supports +--echo # GTIDs + +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=NO; +--source include/start_slave.inc +--source include/stop_slave.inc +RESET SLAVE; +--echo # A notification that Using_Gtid was reverted should exist +SHOW WARNINGS; +--source include/start_slave.inc +--let $using_gtid= query_get_value(SHOW SLAVE STATUS, Using_Gtid, 1) +if ($using_gtid != $expected_default_using_gtid) +{ + --die Using_Gtid has wrong value of '$using_gtid' when it should be '$expected_default_using_gtid' +} + +--echo # Clear SHOW WARNINGS +--disable_query_log +set SQL_LOG_BIN=0; +CREATE TABLE t1 (a int); +DROP TABLE t1; +set SQL_LOG_BIN=1; +--enable_query_log + + +--echo # +--echo # If the primary does not support GTIDs (version < 10), the replica +--echo # should fall back to Using_Gtid=No on slave start, and should not +--echo # revert Using_Gtid to Slave_Pos after RESET SLAVE + +--source include/stop_slave.inc +RESET SLAVE ALL; + +--replace_result $MASTER_MYPORT MASTER_MYPORT +--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=1 +SET @saved_dbug= @@GLOBAL.debug_dbug; +set @@global.debug_dbug= "d,mock_mariadb_primary_v5_in_get_master_version"; +--source include/start_slave.inc + +--echo # Replica should detect at start that the primary does not support GTIDs +--echo # and fall-back to Using_Gtid=No +--let $using_gtid= query_get_value(SHOW SLAVE STATUS, Using_Gtid, 1) +if ($using_gtid != 'No') +{ + --die Using_Gtid has wrong value of '$using_gtid' when it should be 'No' +} + +--echo # Replica should have an informational message stating it is falling +--echo # back to Using_Gtid=No +let $log_error_= `SELECT @@GLOBAL.log_error`; +if(!$log_error_) +{ + # MySQL Server on windows is started with --console and thus + # does not know the location of its .err log, use default location + let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.2.err; +} +--let SEARCH_FILE=$log_error_ +--let SEARCH_PATTERN=Falling back to Using_Gtid=No because master does not support GTIDs +--source include/search_pattern_in_file.inc + +--source include/stop_slave.inc +RESET SLAVE; + +--echo # Replica should know that the primary does not support GTIDs and +--echo # preserve Using_Gtid=No +--let $using_gtid= query_get_value(SHOW SLAVE STATUS, Using_Gtid, 1) +if ($using_gtid != 'No') +{ + --die Using_Gtid has wrong value of '$using_gtid' when it should be 'No' +} +--echo # 'No' was not reverted and therefore no note should be added +SHOW WARNINGS; +set @@global.debug_dbug= @saved_dbug; +--source include/start_slave.inc + + +--echo # +--echo # Ensure that a slave configured with Using_Gtid=Current_Pos will revert +--echo # to its default of Slave_Pos after RESET SLAVE. + +--source include/stop_slave.inc +CHANGE MASTER TO MASTER_USE_GTID=Current_Pos; +--source include/start_slave.inc +--source include/stop_slave.inc +RESET SLAVE; +--echo # A notification that Using_Gtid was reverted should exist +SHOW WARNINGS; +--source include/start_slave.inc +--let $using_gtid= query_get_value(SHOW SLAVE STATUS, Using_Gtid, 1) +if ($using_gtid != $expected_default_using_gtid) +{ + --die Using_Gtid has wrong value of '$using_gtid' when it should be '$expected_default_using_gtid' +} + +--echo # Clear SHOW WARNINGS +--disable_query_log +set SQL_LOG_BIN=0; +CREATE TABLE t1 (a int); +DROP TABLE t1; +set SQL_LOG_BIN=1; +--enable_query_log + +--echo # The MTR include file rpl_change_topology.inc should implicitly set +--echo # MASTER_USE_GTID=NO when provided with \$rpl_master_log_file. Note that +--echo # this will switch master and slave roles. +--connection slave +--source include/stop_slave.inc +--let $pos_c= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1) +--let $file_c= query_get_value(SHOW SLAVE STATUS, Master_Log_File, 1) +--let $rpl_master_log_file= 2:$file_c +--let $rpl_master_log_pos= 2:$pos_c +--let $rpl_topology= 2->1 +--source include/rpl_change_topology.inc + +--echo # connection 'master' is the slave in this comparison +--connection master +--let $using_gtid= query_get_value(SHOW SLAVE STATUS, Using_Gtid, 1) +--echo # Validating Using_Gtid=No.. +if (`SELECT strcmp("$using_gtid","No") != 0`) +{ + --die Using_Gtid should be No when calling rpl_change_topology with \$rpl_master_log_file set +} +--echo # ..success + +--let $rpl_master_log_file= +--let $rpl_topology= 1->2 +--source include/rpl_change_topology.inc + +--echo # connection 'slave' is back to slave role +--connection slave +--let $using_gtid= query_get_value(SHOW SLAVE STATUS, Using_Gtid, 1) +--echo # Validating Using_Gtid=$expected_default_using_gtid.. +if (`SELECT strcmp("$using_gtid","$expected_default_using_gtid")!= 0`) +{ + --die Using_Gtid should be back to $expected_default_using_gtid with empty \$rpl_master_log_file +} +--echo # ..success +--source include/start_slave.inc + +--echo # +--echo # The MTR include file reset_slave.inc should keep/delete GTID state +--echo # when reset_slave_keep_gtid_state is set, respectively. +--echo # +--connection master +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1); +DROP TABLE t1; +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc + +--echo # Tagging gtid_slave_pos before reset_slave.inc as old_slave_pos +--let $old_slave_pos= `SELECT @@gtid_slave_pos` +if (`SELECT strcmp("$old_slave_pos","") = 0`) +{ + die gtid_slave_pos is empty but should not be; +} + +--echo # Using reset_slave_keep_gtid_state=1 should preserve GTID state +--let $master_use_gtid_option=Slave_Pos +--let $reset_slave_keep_gtid_state=1 +--source include/reset_slave.inc + +--echo # Tagging gtid_slave_pos after reset_slave.inc as new_slave_pos +--let $new_slave_pos= `SELECT @@gtid_slave_pos` +--echo # Validating old_slave_pos == new_slave_pos.. +if ($old_slave_pos != $new_slave_pos) +{ + die gtid_slave_pos unexpectedly changed after running reset_slave.inc; +} +--echo # ..success + +--echo # Using reset_slave_keep_gtid_state=0 should empty GTID state +--let $master_use_gtid_option=Slave_Pos +--let $reset_slave_keep_gtid_state=0 +--source include/reset_slave.inc + +--echo # Tagging gtid_slave_pos as new_slave_pos +--let $new_slave_pos= `SELECT @@gtid_slave_pos` +--echo # Validating new_slave_pos is empty.. +if (`SELECT strcmp("$new_slave_pos","") != 0`) +{ + die gtid_slave_pos should be empty after reset_slave.inc without keeping gtid state; +} +--echo # ..success +--replace_result $old_slave_pos old_slave_pos +eval set global gtid_slave_pos="$old_slave_pos"; +--source include/start_slave.inc + +--echo # +--echo # A replica issued CHANGE MASTER TO specified with log coordinates but +--echo # not master_use_gtid=no should warn the user that Using_Gtid is being +--echo # changed to No. +--echo # +--connection slave +--let $io_log_pos= query_get_value('SHOW SLAVE STATUS', Read_Master_Log_Pos, 1) +--let $io_log_file= query_get_value('SHOW SLAVE STATUS', Master_Log_File, 1) +--source include/stop_slave.inc +--replace_result $io_log_file io_log_file $io_log_pos io_log_pos +--eval CHANGE MASTER TO master_log_pos=$io_log_pos, master_log_file='$io_log_file' +--source include/start_slave.inc + + +--echo # +--echo # A replica issued CHANGE MASTER TO specified with log coordinates and +--echo # master_use_gtid=Slave_Pos should warn the user that the log +--echo # coordinates will be ignored. +--echo # +--connection slave +--let $io_log_pos= query_get_value('SHOW SLAVE STATUS', Read_Master_Log_Pos, 1) +--let $io_log_file= query_get_value('SHOW SLAVE STATUS', Master_Log_File, 1) +--let $relay_log_pos= 4 +--let $relay_log_file= slave-relay-bin.000001 +--source include/stop_slave.inc +--replace_result $io_log_file io_log_file $io_log_pos io_log_pos +--eval CHANGE MASTER TO master_log_pos=$io_log_pos, master_log_file='$io_log_file', master_use_gtid=Slave_Pos +--replace_result $relay_log_file relay_log_file $relay_log_pos relay_log_pos +--eval CHANGE MASTER TO relay_log_pos=$relay_log_pos, relay_log_file='$relay_log_file', master_use_gtid=Slave_Pos +--source include/start_slave.inc + +--source include/rpl_end.inc + +--echo # +--echo # End of rpl_using_gtid_default.test diff --git a/mysql-test/suite/rpl/t/rpl_variables.test b/mysql-test/suite/rpl/t/rpl_variables.test new file mode 100644 index 00000000..f6e88c5a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_variables.test @@ -0,0 +1,739 @@ +# ==== Purpose ==== +# +# Test that queries referencing variables are replicated correctly in +# mixed and row-based logging mode. +# +# +# ==== Method ==== +# +# The test simply does a lot of "INSERT INTO t1 VALUES (@@variable)" +# and checks the result on the slave. +# +# Statements referencing a variable only replicate correctly in mixed +# and row mode: in row mode, the values inserted are replicated. In +# mixed mode, statements referencing a variable are marked as unsafe, +# meaning they will be replicated by row. In statement mode, the +# slave's value will be used and replication will break. (Except in a +# small number of special cases: random seeds, insert_id, and +# auto_increment are replicated). +# +# We test the following variable scopes: +# - server system variables +# - server session variables +# - server "both" variables +# - user variables +# +# For each scope, we use variables of the following types if they +# exist: +# - boolean +# - numeric +# - string +# - enumeration variables +# +# We use these types of variables in the following contexts: +# - directly +# - from a stored procedure +# - from a stored function +# - from a trigger +# - from a prepared statement +# +# For all variables where it is possible, we set the variable to one +# value on slave, and insert it on the master with two distinct +# values. +# +# The same insertions are made in four different tables using direct +# insert, stored procedure, stored function, or trigger. Then all +# eight resulting tables on master and slave are compared. +# +# +# ==== Related bugs ==== +# +# BUG#31168: @@hostname does not replicate +# +# +# ==== Related test cases ==== +# +# binlog.binlog_unsafe tests that a warning is issued if system +# variables are replicated in statement mode. +# +# rpl.rpl_variables_stm tests the small subset of variables that +# actually can be replicated safely in statement mode. + + +source include/have_binlog_format_mixed_or_row.inc; +source include/master-slave.inc; + + +--echo ==== Initialization ==== + +# Backup the values of global variables so that they can be restored +# later. +connection master; +SET @m_default_week_format= @@global.default_week_format; +SET @m_init_slave= @@global.init_slave; +SET @m_lc_time_names= @@global.lc_time_names; +SET @m_low_priority_updates= @@global.low_priority_updates; +SET @m_relay_log_purge= @@global.relay_log_purge; +SET @m_slave_exec_mode= @@global.slave_exec_mode; +SET @m_sql_mode= @@global.sql_mode; +SET @m_sync_binlog= @@global.sync_binlog; + +connection slave; +SET @s_default_week_format= @@global.default_week_format; +SET @s_init_slave= @@global.init_slave; +SET @s_lc_time_names= @@global.lc_time_names; +SET @s_low_priority_updates= @@global.low_priority_updates; +SET @s_relay_log_purge= @@global.relay_log_purge; +SET @s_slave_exec_mode= @@global.slave_exec_mode; +SET @s_sql_mode= @@global.sql_mode; +SET @s_sync_binlog= @@global.sync_binlog; + +# Set global variables on slave to something different than on master. +SET @@global.relay_log_purge = OFF; +SET @@global.sync_binlog = 1000000; +SET @@global.slave_exec_mode = 'STRICT'; +SET @@sql_big_selects = OFF; +SET @@last_insert_id = 10; +SET @@global.low_priority_updates = OFF; +SET @@local.low_priority_updates = OFF; +SET @@global.default_week_format = 1; +SET @@local.default_week_format = 2; +SET @@global.lc_time_names = 'zh_HK'; +SET @@local.lc_time_names = 'zh_TW'; +SET @@global.sql_mode = 'ALLOW_INVALID_DATES'; +SET @@local.sql_mode = 'ANSI_QUOTES,ERROR_FOR_DIVISION_BY_ZERO,HIGH_NOT_PRECEDENCE'; +SET @user_num = 10; +SET @user_text = 'Alunda'; + +# Stop slave so that we get a fresh sql thread, reading the slave's +# global values of variables into its local copies. +--source include/stop_slave.inc +--source include/start_slave.inc + +# We would have wanted to set this together with the other variables +# above, but can't because it affects how the slave works. +SET @@global.init_slave = 'SELECT 1'; + + +connection master; +# checking values of read-only variables +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +query_vertical SELECT @@pid_file, @@datadir; +--echo **** Relay log variables +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +query_vertical SELECT @@relay_log, @@relay_log_index, @@relay_log_basename; +--echo **** Binary log variables +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +query_vertical SELECT @@log_bin, @@log_bin_index, @@log_bin_basename; + +connection slave; +# checking values of read-only variables +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +query_vertical SELECT @@pid_file, @@datadir; +--echo **** Relay log variables +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +query_vertical SELECT @@relay_log, @@relay_log_index, @@relay_log_basename; +--echo **** Binary log variables +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +query_vertical SELECT @@log_bin, @@log_bin_index, @@log_bin_basename; + +connection master; + +# Tables where everything happens. +CREATE TABLE tstmt (id INT AUTO_INCREMENT PRIMARY KEY, + truth BOOLEAN, + num INT, + text VARCHAR(100)); +CREATE TABLE tproc LIKE tstmt; +CREATE TABLE tfunc LIKE tstmt; +CREATE TABLE ttrig LIKE tstmt; +CREATE TABLE tprep LIKE tstmt; + +# Table on which we put a trigger. +CREATE TABLE trigger_table (text CHAR(4)); + + +--echo ==== Insert variables directly ==== + +--echo ---- global variables ---- + +# boolean +SET @@global.relay_log_purge = ON; +INSERT INTO tstmt(truth) VALUES (@@global.relay_log_purge); +SET @@global.relay_log_purge = OFF; +INSERT INTO tstmt(truth) VALUES (@@global.relay_log_purge); + +# numeric +SET @@global.sync_binlog = 2000000; +INSERT INTO tstmt(num) VALUES (@@global.sync_binlog); +SET @@global.sync_binlog = 3000000; +INSERT INTO tstmt(num) VALUES (@@global.sync_binlog); + +# string +SET @@global.init_slave = 'SELECT 2'; +INSERT INTO tstmt(text) VALUES (@@global.init_slave); +SET @@global.init_slave = 'SELECT 3'; +INSERT INTO tstmt(text) VALUES (@@global.init_slave); + +# enumeration +SET @@global.slave_exec_mode = 'IDEMPOTENT'; +INSERT INTO tstmt(text) VALUES (@@global.slave_exec_mode); +SET @@global.slave_exec_mode = 'STRICT'; +INSERT INTO tstmt(text) VALUES (@@global.slave_exec_mode); + + +--echo ---- session variables ---- + +# boolean +SET @@sql_big_selects = ON; +INSERT INTO tstmt(truth) VALUES (@@sql_big_selects); +SET @@sql_big_selects = OFF; +INSERT INTO tstmt(truth) VALUES (@@sql_big_selects); + +# numeric +SET @@last_insert_id = 20; +INSERT INTO tstmt(num) VALUES (@@last_insert_id); +SET @@last_insert_id = 30; +INSERT INTO tstmt(num) VALUES (@@last_insert_id); + +--echo ---- global and session variables ---- + +# boolean +SET @@global.low_priority_updates = ON; +SET @@local.low_priority_updates = OFF; +INSERT INTO tstmt(truth) VALUES (@@global.low_priority_updates); +INSERT INTO tstmt(truth) VALUES (@@local.low_priority_updates); +SET @@global.low_priority_updates = OFF; +SET @@local.low_priority_updates = ON; +INSERT INTO tstmt(truth) VALUES (@@global.low_priority_updates); +INSERT INTO tstmt(truth) VALUES (@@local.low_priority_updates); + +# numeric +SET @@global.default_week_format = 3; +SET @@local.default_week_format = 4; +INSERT INTO tstmt(num) VALUES (@@global.default_week_format); +INSERT INTO tstmt(num) VALUES (@@local.default_week_format); +SET @@global.default_week_format = 5; +SET @@local.default_week_format = 6; +INSERT INTO tstmt(num) VALUES (@@global.default_week_format); +INSERT INTO tstmt(num) VALUES (@@local.default_week_format); + +# string +SET @@global.lc_time_names = 'sv_SE'; +SET @@local.lc_time_names = 'sv_FI'; +INSERT INTO tstmt(text) VALUES (@@global.lc_time_names); +INSERT INTO tstmt(text) VALUES (@@local.lc_time_names); +SET @@global.lc_time_names = 'ar_TN'; +SET @@local.lc_time_names = 'ar_IQ'; +INSERT INTO tstmt(text) VALUES (@@global.lc_time_names); +INSERT INTO tstmt(text) VALUES (@@local.lc_time_names); + +# enum +SET @@global.sql_mode = ''; +SET @@local.sql_mode = 'IGNORE_SPACE,NO_AUTO_CREATE_USER'; +INSERT INTO tstmt(text) VALUES (@@global.sql_mode); +INSERT INTO tstmt(text) VALUES (@@local.sql_mode); +SET @@global.sql_mode = 'NO_AUTO_VALUE_ON_ZERO,NO_BACKSLASH_ESCAPES,NO_DIR_IN_CREATE,NO_ENGINE_SUBSTITUTION'; +SET @@local.sql_mode = 'NO_FIELD_OPTIONS,NO_KEY_OPTIONS,NO_TABLE_OPTIONS'; +INSERT INTO tstmt(text) VALUES (@@global.sql_mode); +INSERT INTO tstmt(text) VALUES (@@local.sql_mode); + +--echo ---- user variables ---- + +# numeric +SET @user_num = 20; +INSERT INTO tstmt(num) VALUES (@user_num); +SET @user_num = 30; +INSERT INTO tstmt(num) VALUES (@user_num); + +# string +SET @user_text = 'Bergsbrunna'; +INSERT INTO tstmt(text) VALUES (@user_text); +SET @user_text = 'Centrum'; +INSERT INTO tstmt(text) VALUES (@user_text); + + +--echo ==== Insert variables from a stored procedure ==== + +DELIMITER |; +CREATE PROCEDURE proc() +BEGIN + + # GLOBAL + + # boolean + SET @@global.relay_log_purge = ON; + INSERT INTO tproc(truth) VALUES (@@global.relay_log_purge); + SET @@global.relay_log_purge = OFF; + INSERT INTO tproc(truth) VALUES (@@global.relay_log_purge); + + # numeric + SET @@global.sync_binlog = 2000000; + INSERT INTO tproc(num) VALUES (@@global.sync_binlog); + SET @@global.sync_binlog = 3000000; + INSERT INTO tproc(num) VALUES (@@global.sync_binlog); + + # string + SET @@global.init_slave = 'SELECT 2'; + INSERT INTO tproc(text) VALUES (@@global.init_slave); + SET @@global.init_slave = 'SELECT 3'; + INSERT INTO tproc(text) VALUES (@@global.init_slave); + + # enumeration + SET @@global.slave_exec_mode = 'IDEMPOTENT'; + INSERT INTO tproc(text) VALUES (@@global.slave_exec_mode); + SET @@global.slave_exec_mode = 'STRICT'; + INSERT INTO tproc(text) VALUES (@@global.slave_exec_mode); + + # SESSION + + # boolean + SET @@sql_big_selects = ON; + INSERT INTO tproc(truth) VALUES (@@sql_big_selects); + SET @@sql_big_selects = OFF; + INSERT INTO tproc(truth) VALUES (@@sql_big_selects); + + # numeric + SET @@last_insert_id = 20; + INSERT INTO tproc(num) VALUES (@@last_insert_id); + SET @@last_insert_id = 30; + INSERT INTO tproc(num) VALUES (@@last_insert_id); + + # BOTH + + # boolean + SET @@global.low_priority_updates = ON; + SET @@local.low_priority_updates = OFF; + INSERT INTO tproc(truth) VALUES (@@global.low_priority_updates); + INSERT INTO tproc(truth) VALUES (@@local.low_priority_updates); + SET @@global.low_priority_updates = OFF; + SET @@local.low_priority_updates = ON; + INSERT INTO tproc(truth) VALUES (@@global.low_priority_updates); + INSERT INTO tproc(truth) VALUES (@@local.low_priority_updates); + + # numeric + SET @@global.default_week_format = 3; + SET @@local.default_week_format = 4; + INSERT INTO tproc(num) VALUES (@@global.default_week_format); + INSERT INTO tproc(num) VALUES (@@local.default_week_format); + SET @@global.default_week_format = 5; + SET @@local.default_week_format = 6; + INSERT INTO tproc(num) VALUES (@@global.default_week_format); + INSERT INTO tproc(num) VALUES (@@local.default_week_format); + + # text + SET @@global.lc_time_names = 'sv_SE'; + SET @@local.lc_time_names = 'sv_FI'; + INSERT INTO tproc(text) VALUES (@@global.lc_time_names); + INSERT INTO tproc(text) VALUES (@@local.lc_time_names); + SET @@global.lc_time_names = 'ar_TN'; + SET @@local.lc_time_names = 'ar_IQ'; + INSERT INTO tproc(text) VALUES (@@global.lc_time_names); + INSERT INTO tproc(text) VALUES (@@local.lc_time_names); + + # enum + SET @@global.sql_mode = ''; + SET @@local.sql_mode = 'IGNORE_SPACE,NO_AUTO_CREATE_USER'; + INSERT INTO tproc(text) VALUES (@@global.sql_mode); + INSERT INTO tproc(text) VALUES (@@local.sql_mode); + SET @@global.sql_mode = 'NO_AUTO_VALUE_ON_ZERO,NO_BACKSLASH_ESCAPES,NO_DIR_IN_CREATE,NO_ENGINE_SUBSTITUTION'; + SET @@local.sql_mode = 'NO_FIELD_OPTIONS,NO_KEY_OPTIONS,NO_TABLE_OPTIONS'; + INSERT INTO tproc(text) VALUES (@@global.sql_mode); + INSERT INTO tproc(text) VALUES (@@local.sql_mode); + + # USER + + # numeric + SET @user_num = 20; + INSERT INTO tproc(num) VALUES (@user_num); + SET @user_num = 30; + INSERT INTO tproc(num) VALUES (@user_num); + + # string + SET @user_text = 'Bergsbrunna'; + INSERT INTO tproc(text) VALUES (@user_text); + SET @user_text = 'Centrum'; + INSERT INTO tproc(text) VALUES (@user_text); + +END| +DELIMITER ;| + +CALL proc(); + + +--echo ==== Insert variables from a stored function ==== + +DELIMITER |; +CREATE FUNCTION func() +RETURNS INT +BEGIN + + # GLOBAL + + # boolean + SET @@global.relay_log_purge = ON; + INSERT INTO tfunc(truth) VALUES (@@global.relay_log_purge); + SET @@global.relay_log_purge = OFF; + INSERT INTO tfunc(truth) VALUES (@@global.relay_log_purge); + + # numeric + SET @@global.sync_binlog = 2000000; + INSERT INTO tfunc(num) VALUES (@@global.sync_binlog); + SET @@global.sync_binlog = 3000000; + INSERT INTO tfunc(num) VALUES (@@global.sync_binlog); + + # string + SET @@global.init_slave = 'SELECT 2'; + INSERT INTO tfunc(text) VALUES (@@global.init_slave); + SET @@global.init_slave = 'SELECT 3'; + INSERT INTO tfunc(text) VALUES (@@global.init_slave); + + # enumeration + SET @@global.slave_exec_mode = 'IDEMPOTENT'; + INSERT INTO tfunc(text) VALUES (@@global.slave_exec_mode); + SET @@global.slave_exec_mode = 'STRICT'; + INSERT INTO tfunc(text) VALUES (@@global.slave_exec_mode); + + # SESSION + + # boolean + SET @@sql_big_selects = ON; + INSERT INTO tfunc(truth) VALUES (@@sql_big_selects); + SET @@sql_big_selects = OFF; + INSERT INTO tfunc(truth) VALUES (@@sql_big_selects); + + # numeric + SET @@last_insert_id = 20; + INSERT INTO tfunc(num) VALUES (@@last_insert_id); + SET @@last_insert_id = 30; + INSERT INTO tfunc(num) VALUES (@@last_insert_id); + + # BOTH + + # boolean + SET @@global.low_priority_updates = ON; + SET @@local.low_priority_updates = OFF; + INSERT INTO tfunc(truth) VALUES (@@global.low_priority_updates); + INSERT INTO tfunc(truth) VALUES (@@local.low_priority_updates); + SET @@global.low_priority_updates = OFF; + SET @@local.low_priority_updates = ON; + INSERT INTO tfunc(truth) VALUES (@@global.low_priority_updates); + INSERT INTO tfunc(truth) VALUES (@@local.low_priority_updates); + + # numeric + SET @@global.default_week_format = 3; + SET @@local.default_week_format = 4; + INSERT INTO tfunc(num) VALUES (@@global.default_week_format); + INSERT INTO tfunc(num) VALUES (@@local.default_week_format); + SET @@global.default_week_format = 5; + SET @@local.default_week_format = 6; + INSERT INTO tfunc(num) VALUES (@@global.default_week_format); + INSERT INTO tfunc(num) VALUES (@@local.default_week_format); + + # text + SET @@global.lc_time_names = 'sv_SE'; + SET @@local.lc_time_names = 'sv_FI'; + INSERT INTO tfunc(text) VALUES (@@global.lc_time_names); + INSERT INTO tfunc(text) VALUES (@@local.lc_time_names); + SET @@global.lc_time_names = 'ar_TN'; + SET @@local.lc_time_names = 'ar_IQ'; + INSERT INTO tfunc(text) VALUES (@@global.lc_time_names); + INSERT INTO tfunc(text) VALUES (@@local.lc_time_names); + + # enum + SET @@global.sql_mode = ''; + SET @@local.sql_mode = 'IGNORE_SPACE,NO_AUTO_CREATE_USER'; + INSERT INTO tfunc(text) VALUES (@@global.sql_mode); + INSERT INTO tfunc(text) VALUES (@@local.sql_mode); + SET @@global.sql_mode = 'NO_AUTO_VALUE_ON_ZERO,NO_BACKSLASH_ESCAPES,NO_DIR_IN_CREATE,NO_ENGINE_SUBSTITUTION'; + SET @@local.sql_mode = 'NO_FIELD_OPTIONS,NO_KEY_OPTIONS,NO_TABLE_OPTIONS'; + INSERT INTO tfunc(text) VALUES (@@global.sql_mode); + INSERT INTO tfunc(text) VALUES (@@local.sql_mode); + + # USER + + # numeric + SET @user_num = 20; + INSERT INTO tfunc(num) VALUES (@user_num); + SET @user_num = 30; + INSERT INTO tfunc(num) VALUES (@user_num); + + # string + SET @user_text = 'Bergsbrunna'; + INSERT INTO tfunc(text) VALUES (@user_text); + SET @user_text = 'Centrum'; + INSERT INTO tfunc(text) VALUES (@user_text); + + RETURN 0; +END| +DELIMITER ;| + +--disable_ps2_protocol +SELECT func(); +--enable_ps2_protocol + +--echo ==== Insert variables from a trigger ==== + +DELIMITER |; +CREATE TRIGGER trig +BEFORE INSERT ON trigger_table +FOR EACH ROW +BEGIN + + # GLOBAL + + # boolean + SET @@global.relay_log_purge = ON; + INSERT INTO ttrig(truth) VALUES (@@global.relay_log_purge); + SET @@global.relay_log_purge = OFF; + INSERT INTO ttrig(truth) VALUES (@@global.relay_log_purge); + + # numeric + SET @@global.sync_binlog = 2000000; + INSERT INTO ttrig(num) VALUES (@@global.sync_binlog); + SET @@global.sync_binlog = 3000000; + INSERT INTO ttrig(num) VALUES (@@global.sync_binlog); + + # string + SET @@global.init_slave = 'SELECT 2'; + INSERT INTO ttrig(text) VALUES (@@global.init_slave); + SET @@global.init_slave = 'SELECT 3'; + INSERT INTO ttrig(text) VALUES (@@global.init_slave); + + # enumeration + SET @@global.slave_exec_mode = 'IDEMPOTENT'; + INSERT INTO ttrig(text) VALUES (@@global.slave_exec_mode); + SET @@global.slave_exec_mode = 'STRICT'; + INSERT INTO ttrig(text) VALUES (@@global.slave_exec_mode); + + # SESSION + + # boolean + SET @@sql_big_selects = ON; + INSERT INTO ttrig(truth) VALUES (@@sql_big_selects); + SET @@sql_big_selects = OFF; + INSERT INTO ttrig(truth) VALUES (@@sql_big_selects); + + # numeric + SET @@last_insert_id = 20; + INSERT INTO ttrig(num) VALUES (@@last_insert_id); + SET @@last_insert_id = 30; + INSERT INTO ttrig(num) VALUES (@@last_insert_id); + + # BOTH + + # boolean + SET @@global.low_priority_updates = ON; + SET @@local.low_priority_updates = OFF; + INSERT INTO ttrig(truth) VALUES (@@global.low_priority_updates); + INSERT INTO ttrig(truth) VALUES (@@local.low_priority_updates); + SET @@global.low_priority_updates = OFF; + SET @@local.low_priority_updates = ON; + INSERT INTO ttrig(truth) VALUES (@@global.low_priority_updates); + INSERT INTO ttrig(truth) VALUES (@@local.low_priority_updates); + + # numeric + SET @@global.default_week_format = 3; + SET @@local.default_week_format = 4; + INSERT INTO ttrig(num) VALUES (@@global.default_week_format); + INSERT INTO ttrig(num) VALUES (@@local.default_week_format); + SET @@global.default_week_format = 5; + SET @@local.default_week_format = 6; + INSERT INTO ttrig(num) VALUES (@@global.default_week_format); + INSERT INTO ttrig(num) VALUES (@@local.default_week_format); + + # text + SET @@global.lc_time_names = 'sv_SE'; + SET @@local.lc_time_names = 'sv_FI'; + INSERT INTO ttrig(text) VALUES (@@global.lc_time_names); + INSERT INTO ttrig(text) VALUES (@@local.lc_time_names); + SET @@global.lc_time_names = 'ar_TN'; + SET @@local.lc_time_names = 'ar_IQ'; + INSERT INTO ttrig(text) VALUES (@@global.lc_time_names); + INSERT INTO ttrig(text) VALUES (@@local.lc_time_names); + + # enum + SET @@global.sql_mode = ''; + SET @@local.sql_mode = 'IGNORE_SPACE,NO_AUTO_CREATE_USER'; + INSERT INTO ttrig(text) VALUES (@@global.sql_mode); + INSERT INTO ttrig(text) VALUES (@@local.sql_mode); + SET @@global.sql_mode = 'NO_AUTO_VALUE_ON_ZERO,NO_BACKSLASH_ESCAPES,NO_DIR_IN_CREATE,NO_ENGINE_SUBSTITUTION'; + SET @@local.sql_mode = 'NO_FIELD_OPTIONS,NO_KEY_OPTIONS,NO_TABLE_OPTIONS'; + INSERT INTO ttrig(text) VALUES (@@global.sql_mode); + INSERT INTO ttrig(text) VALUES (@@local.sql_mode); + + # USER + + # numeric + SET @user_num = 20; + INSERT INTO ttrig(num) VALUES (@user_num); + SET @user_num = 30; + INSERT INTO ttrig(num) VALUES (@user_num); + + # string + SET @user_text = 'Bergsbrunna'; + INSERT INTO ttrig(text) VALUES (@user_text); + SET @user_text = 'Centrum'; + INSERT INTO ttrig(text) VALUES (@user_text); +END| +DELIMITER ;| + +INSERT INTO trigger_table VALUES ('bye.'); + + +--echo ==== Insert variables from a prepared statement ==== + +# GLOBAL + +# boolean +PREPARE p1 FROM 'SET @@global.relay_log_purge = ON'; +PREPARE p2 FROM 'INSERT INTO tprep(truth) VALUES (@@global.relay_log_purge)'; +PREPARE p3 FROM 'SET @@global.relay_log_purge = OFF'; +PREPARE p4 FROM 'INSERT INTO tprep(truth) VALUES (@@global.relay_log_purge)'; + +# numeric +PREPARE p5 FROM 'SET @@global.sync_binlog = 2000000'; +PREPARE p6 FROM 'INSERT INTO tprep(num) VALUES (@@global.sync_binlog)'; +PREPARE p7 FROM 'SET @@global.sync_binlog = 3000000'; +PREPARE p8 FROM 'INSERT INTO tprep(num) VALUES (@@global.sync_binlog)'; + +# string +PREPARE p9 FROM 'SET @@global.init_slave = \'SELECT 2\''; +PREPARE p10 FROM 'INSERT INTO tprep(text) VALUES (@@global.init_slave)'; +PREPARE p11 FROM 'SET @@global.init_slave = \'SELECT 3\''; +PREPARE p12 FROM 'INSERT INTO tprep(text) VALUES (@@global.init_slave)'; + +# enumeration +PREPARE p13 FROM 'SET @@global.slave_exec_mode = \'IDEMPOTENT\''; +PREPARE p14 FROM 'INSERT INTO tprep(text) VALUES (@@global.slave_exec_mode)'; +PREPARE p15 FROM 'SET @@global.slave_exec_mode = \'STRICT\''; +PREPARE p16 FROM 'INSERT INTO tprep(text) VALUES (@@global.slave_exec_mode)'; + +# SESSION + +# boolean +PREPARE p17 FROM 'SET @@sql_big_selects = ON'; +PREPARE p18 FROM 'INSERT INTO tprep(truth) VALUES (@@sql_big_selects)'; +PREPARE p19 FROM 'SET @@sql_big_selects = OFF'; +PREPARE p20 FROM 'INSERT INTO tprep(truth) VALUES (@@sql_big_selects)'; + +# numeric +PREPARE p21 FROM 'SET @@last_insert_id = 20'; +PREPARE p22 FROM 'INSERT INTO tprep(num) VALUES (@@last_insert_id)'; +PREPARE p23 FROM 'SET @@last_insert_id = 30'; +PREPARE p24 FROM 'INSERT INTO tprep(num) VALUES (@@last_insert_id)'; + +# BOTH + +# boolean +PREPARE p25 FROM 'SET @@global.low_priority_updates = ON'; +PREPARE p26 FROM 'SET @@local.low_priority_updates = OFF'; +PREPARE p27 FROM 'INSERT INTO tprep(truth) VALUES (@@global.low_priority_updates)'; +PREPARE p28 FROM 'INSERT INTO tprep(truth) VALUES (@@local.low_priority_updates)'; +PREPARE p29 FROM 'SET @@global.low_priority_updates = OFF'; +PREPARE p30 FROM 'SET @@local.low_priority_updates = ON'; +PREPARE p31 FROM 'INSERT INTO tprep(truth) VALUES (@@global.low_priority_updates)'; +PREPARE p32 FROM 'INSERT INTO tprep(truth) VALUES (@@local.low_priority_updates)'; + +# numeric +PREPARE p33 FROM 'SET @@global.default_week_format = 3'; +PREPARE p34 FROM 'SET @@local.default_week_format = 4'; +PREPARE p35 FROM 'INSERT INTO tprep(num) VALUES (@@global.default_week_format)'; +PREPARE p36 FROM 'INSERT INTO tprep(num) VALUES (@@local.default_week_format)'; +PREPARE p37 FROM 'SET @@global.default_week_format = 5'; +PREPARE p38 FROM 'SET @@local.default_week_format = 6'; +PREPARE p39 FROM 'INSERT INTO tprep(num) VALUES (@@global.default_week_format)'; +PREPARE p40 FROM 'INSERT INTO tprep(num) VALUES (@@local.default_week_format)'; + +# text +PREPARE p41 FROM 'SET @@global.lc_time_names = \'sv_SE\''; +PREPARE p42 FROM 'SET @@local.lc_time_names = \'sv_FI\''; +PREPARE p43 FROM 'INSERT INTO tprep(text) VALUES (@@global.lc_time_names)'; +PREPARE p44 FROM 'INSERT INTO tprep(text) VALUES (@@local.lc_time_names)'; +PREPARE p45 FROM 'SET @@global.lc_time_names = \'ar_TN\''; +PREPARE p46 FROM 'SET @@local.lc_time_names = \'ar_IQ\''; +PREPARE p47 FROM 'INSERT INTO tprep(text) VALUES (@@global.lc_time_names)'; +PREPARE p48 FROM 'INSERT INTO tprep(text) VALUES (@@local.lc_time_names)'; + +# enum +PREPARE p49 FROM 'SET @@global.sql_mode = \'\''; +PREPARE p50 FROM 'SET @@local.sql_mode = \'IGNORE_SPACE,NO_AUTO_CREATE_USER\''; +PREPARE p51 FROM 'INSERT INTO tprep(text) VALUES (@@global.sql_mode)'; +PREPARE p52 FROM 'INSERT INTO tprep(text) VALUES (@@local.sql_mode)'; +PREPARE p53 FROM 'SET @@global.sql_mode = \'NO_AUTO_VALUE_ON_ZERO,NO_BACKSLASH_ESCAPES,NO_DIR_IN_CREATE,NO_ENGINE_SUBSTITUTION\''; +PREPARE p54 FROM 'SET @@local.sql_mode = \'NO_FIELD_OPTIONS,NO_KEY_OPTIONS,NO_TABLE_OPTIONS\''; +PREPARE p55 FROM 'INSERT INTO tprep(text) VALUES (@@global.sql_mode)'; +PREPARE p56 FROM 'INSERT INTO tprep(text) VALUES (@@local.sql_mode)'; + +# USER + +# numeric +PREPARE p57 FROM 'SET @user_num = 20'; +PREPARE p58 FROM 'INSERT INTO tprep(num) VALUES (@user_num)'; +PREPARE p59 FROM 'SET @user_num = 30'; +PREPARE p60 FROM 'INSERT INTO tprep(num) VALUES (@user_num)'; + +# string +PREPARE p61 FROM 'SET @user_text = \'Bergsbrunna\''; +PREPARE p62 FROM 'INSERT INTO tprep(text) VALUES (@user_text)'; +PREPARE p63 FROM 'SET @user_text = \'Centrum\''; +PREPARE p64 FROM 'INSERT INTO tprep(text) VALUES (@user_text)'; + +EXECUTE p1; EXECUTE p2; EXECUTE p3; EXECUTE p4; EXECUTE p5; EXECUTE p6; +EXECUTE p7; EXECUTE p8; EXECUTE p9; EXECUTE p10; EXECUTE p11; EXECUTE p12; +EXECUTE p13; EXECUTE p14; EXECUTE p15; EXECUTE p16; EXECUTE p17; EXECUTE p18; +EXECUTE p19; EXECUTE p20; EXECUTE p21; EXECUTE p22; EXECUTE p23; EXECUTE p24; +EXECUTE p25; EXECUTE p26; EXECUTE p27; EXECUTE p28; EXECUTE p29; EXECUTE p30; +EXECUTE p31; EXECUTE p32; EXECUTE p33; EXECUTE p34; EXECUTE p35; EXECUTE p36; +EXECUTE p37; EXECUTE p38; EXECUTE p39; EXECUTE p40; EXECUTE p41; EXECUTE p42; +EXECUTE p43; EXECUTE p44; EXECUTE p45; EXECUTE p46; EXECUTE p47; EXECUTE p48; +EXECUTE p49; EXECUTE p50; EXECUTE p51; EXECUTE p52; EXECUTE p53; EXECUTE p54; +EXECUTE p55; EXECUTE p56; EXECUTE p57; EXECUTE p58; EXECUTE p59; EXECUTE p60; +EXECUTE p61; EXECUTE p62; EXECUTE p63; EXECUTE p64; + +--sync_slave_with_master +--connection master + + +--echo ==== Results ==== + +# Show the result in table test.tstmt on master... +SELECT * FROM tstmt ORDER BY id; + +--sync_slave_with_master + +# ... then compare test.tstmt on master to the other tables on master and slave. +let $diff_tables= master:tstmt, master:tproc, master:tfunc, master:ttrig, master:tprep, slave:tstmt, slave:tproc, slave:tfunc, slave:ttrig, slave:tprep; +source include/diff_tables.inc; + + +--echo ==== Clean up ==== + +connection master; +DROP PROCEDURE proc; +DROP FUNCTION func; +DROP TRIGGER trig; +DROP TABLE tstmt, tproc, tfunc, ttrig, tprep, trigger_table; + +SET @@global.default_week_format= @m_default_week_format; +SET @@global.init_slave= @m_init_slave; +SET @@global.lc_time_names= @m_lc_time_names; +SET @@global.low_priority_updates= @m_low_priority_updates; +SET @@global.relay_log_purge= @m_relay_log_purge; +SET @@global.slave_exec_mode= @m_slave_exec_mode; +SET @@global.sql_mode= @m_sql_mode; +SET @@global.sync_binlog= @m_sync_binlog; + +connection slave; +SET @@global.default_week_format= @s_default_week_format; +SET @@global.init_slave= @s_init_slave; +SET @@global.lc_time_names= @s_lc_time_names; +SET @@global.low_priority_updates= @s_low_priority_updates; +SET @@global.relay_log_purge= @s_relay_log_purge; +SET @@global.slave_exec_mode= @s_slave_exec_mode; +SET @@global.sql_mode= @s_sql_mode; +SET @@global.sync_binlog= @s_sync_binlog; + +connection master; +sync_slave_with_master; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_variables_stm.test b/mysql-test/suite/rpl/t/rpl_variables_stm.test new file mode 100644 index 00000000..ffbb3e77 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_variables_stm.test @@ -0,0 +1,618 @@ +# ==== Purpose ==== +# +# In general, queries referencing @@system_variables are not +# considered safe to write to the binlog in statement-based logging +# mode. However, a few special cases are supported. +# +# This test verifies that queries referencing these specially +# supported variables are replicated correctly in statement mode. +# +# +# ==== Method ==== +# +# The test simply does a lot of "INSERT INTO t1 VALUES (@@variable)" +# and checks the result on the slave. +# +# Statements referencing a variable only replicate correctly in mixed +# and row mode: in row mode, the values inserted are replicated. In +# mixed mode, statements referencing a variable are marked as unsafe, +# meaning they will be replicated by row. In statement mode, the +# slave's value will be used and replication will break. (Except in a +# small number of special cases: random seeds, insert_id, and +# auto_increment are replicated). +# +# We test all replicated variables, from each of the following +# contexts: +# - directly +# - from a stored procedure +# - from a stored function +# - from a trigger +# - from a prepared statement +# +# For all variables where it is possible, we set the variable to one +# value on slave, and insert it on the master with two distinct +# values. +# +# The same insertions are made in four different tables using direct +# insert, stored procedure, stored function, or trigger. Then all +# eight resulting tables on master and slave are compared. +# +# +# ==== Related bugs ==== +# +# BUG#31168: @@hostname does not replicate +# +# +# ==== Related test cases ==== +# +# binlog.binlog_unsafe tests that a warning is issued if system +# variables are replicated in statement mode. +# +# rpl.rpl_variables verifies that variables which cannot be replicated +# safely in statement mode are replicated correctly in mixed or row +# mode. + +source include/have_binlog_format_mixed_or_statement.inc; +source include/master-slave.inc; + +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); + +--echo ==== Initialization ==== + +# Backup the values of global variables so that they can be restored +# later. + +connection master; +SET @m_auto_increment_increment= @@global.auto_increment_increment; +SET @m_auto_increment_offset= @@global.auto_increment_offset; +SET @m_character_set_client= @@global.character_set_client; +SET @m_collation_connection= @@global.collation_connection; +SET @m_collation_server= @@global.collation_server; +SET @m_time_zone= @@global.time_zone; +SET @m_lc_time_names= @@global.lc_time_names; +SET @m_collation_database= @@global.collation_database; + +connection slave; +SET @s_auto_increment_increment= @@global.auto_increment_increment; +SET @s_auto_increment_offset= @@global.auto_increment_offset; +SET @s_character_set_client= @@global.character_set_client; +SET @s_collation_connection= @@global.collation_connection; +SET @s_collation_server= @@global.collation_server; +SET @s_time_zone= @@global.time_zone; +SET @s_lc_time_names= @@global.lc_time_names; +SET @s_collation_database= @@global.collation_database; + +SET @@global.auto_increment_increment=19; +SET @@global.auto_increment_offset=4; +SET @@global.character_set_client='latin2'; +SET @@global.collation_connection='latin2_bin'; +SET @@global.collation_server='geostd8_general_ci'; +SET @@global.time_zone='Japan'; +SET @@global.lc_time_names='sv_SE'; +SET @@global.collation_database='geostd8_bin'; + +connection master; + +# Tables where everything happens. +CREATE TABLE tstmt (id INT AUTO_INCREMENT PRIMARY KEY, + num INT, + text VARCHAR(100)); +CREATE TABLE tproc LIKE tstmt; +CREATE TABLE tfunc LIKE tstmt; +CREATE TABLE ttrig LIKE tstmt; +CREATE TABLE tprep LIKE tstmt; + +# Table on which we put a trigger. +CREATE TABLE trigger_table (text CHAR(4)); + + +--echo ==== Insert variables directly ==== + +SET @@pseudo_thread_id= 4712; +INSERT INTO tstmt(num) VALUES (@@session.pseudo_thread_id); +SET @@pseudo_thread_id= 4713; +INSERT INTO tstmt(num) VALUES (@@session.pseudo_thread_id); + +SET @@foreign_key_checks= 0; +INSERT INTO tstmt(num) VALUES (@@session.foreign_key_checks); +SET @@foreign_key_checks= 1; +INSERT INTO tstmt(num) VALUES (@@session.foreign_key_checks); + +SET @@sql_auto_is_null= 0; +INSERT INTO tstmt(num) VALUES (@@session.sql_auto_is_null); +SET @@sql_auto_is_null= 1; +INSERT INTO tstmt(num) VALUES (@@session.sql_auto_is_null); + +SET @@unique_checks= 0; +INSERT INTO tstmt(num) VALUES (@@session.unique_checks); +SET @@unique_checks= 1; +INSERT INTO tstmt(num) VALUES (@@session.unique_checks); + +SET @@auto_increment_increment= 11; +INSERT INTO tstmt(num) VALUES (@@session.auto_increment_increment); +SET @@auto_increment_increment= 19; +INSERT INTO tstmt(num) VALUES (@@session.auto_increment_increment); + +SET @@auto_increment_offset= 13; +INSERT INTO tstmt(num) VALUES (@@session.auto_increment_offset); +SET @@auto_increment_offset= 17; +INSERT INTO tstmt(num) VALUES (@@session.auto_increment_offset); + +# reset these as they affect the index column +SET @@auto_increment_increment= 1; +SET @@auto_increment_offset= 1; + +SET @@character_set_client= 'cp1257'; +INSERT INTO tstmt(text) VALUES (@@session.character_set_client); +SET @@character_set_client= 'cp1256'; +INSERT INTO tstmt(text) VALUES (@@session.character_set_client); + +SET @@collation_connection= 'cp1251_ukrainian_ci'; +INSERT INTO tstmt(text) VALUES (@@session.collation_connection); +INSERT INTO tstmt(text) VALUES (@@session.character_set_connection); +SET @@collation_connection= 'cp1251_bulgarian_ci'; +INSERT INTO tstmt(text) VALUES (@@session.collation_connection); +INSERT INTO tstmt(text) VALUES (@@session.character_set_connection); + +SET @@collation_server= 'latin7_bin'; +INSERT INTO tstmt(text) VALUES (@@session.collation_server); +INSERT INTO tstmt(text) VALUES (@@session.character_set_server); +SET @@collation_server= 'latin7_general_cs'; +INSERT INTO tstmt(text) VALUES (@@session.collation_server); +INSERT INTO tstmt(text) VALUES (@@session.character_set_server); + +SET @@time_zone= 'Europe/Moscow'; +INSERT INTO tstmt(text) VALUES (@@session.time_zone); +SET @@time_zone= 'Universal'; +INSERT INTO tstmt(text) VALUES (@@session.time_zone); + +SET @@lc_time_names= 'sv_FI'; +INSERT INTO tstmt(text) VALUES (@@session.lc_time_names); +SET @@lc_time_names= 'no_NO'; +INSERT INTO tstmt(text) VALUES (@@session.lc_time_names); + +SET @@collation_database= 'latin7_general_ci'; +INSERT INTO tstmt(text) VALUES (@@session.collation_database); +INSERT INTO tstmt(text) VALUES (@@session.character_set_database); +SET @@collation_database= 'latin7_estonian_cs'; +INSERT INTO tstmt(text) VALUES (@@session.collation_database); +INSERT INTO tstmt(text) VALUES (@@session.character_set_database); + +SET @@timestamp= 47114711; +INSERT INTO tstmt(text) VALUES (@@session.timestamp); +SET @@timestamp= 47124712; +INSERT INTO tstmt(text) VALUES (@@session.timestamp); + +SET @@last_insert_id= 1616; +INSERT INTO tstmt(text) VALUES (@@session.last_insert_id); +SET @@last_insert_id= 1717; +INSERT INTO tstmt(text) VALUES (@@session.last_insert_id); + + +--echo ==== Insert variables from a stored procedure ==== + +DELIMITER |; +CREATE PROCEDURE proc() +BEGIN + + SET @@pseudo_thread_id= 4712; + INSERT INTO tproc(num) VALUES (@@session.pseudo_thread_id); + SET @@pseudo_thread_id= 4713; + INSERT INTO tproc(num) VALUES (@@session.pseudo_thread_id); + + SET @@foreign_key_checks= 0; + INSERT INTO tproc(num) VALUES (@@session.foreign_key_checks); + SET @@foreign_key_checks= 1; + INSERT INTO tproc(num) VALUES (@@session.foreign_key_checks); + + SET @@sql_auto_is_null= 0; + INSERT INTO tproc(num) VALUES (@@session.sql_auto_is_null); + SET @@sql_auto_is_null= 1; + INSERT INTO tproc(num) VALUES (@@session.sql_auto_is_null); + + SET @@unique_checks= 0; + INSERT INTO tproc(num) VALUES (@@session.unique_checks); + SET @@unique_checks= 1; + INSERT INTO tproc(num) VALUES (@@session.unique_checks); + + SET @@auto_increment_increment= 11; + INSERT INTO tproc(num) VALUES (@@session.auto_increment_increment); + SET @@auto_increment_increment= 19; + INSERT INTO tproc(num) VALUES (@@session.auto_increment_increment); + + SET @@auto_increment_offset= 13; + INSERT INTO tproc(num) VALUES (@@session.auto_increment_offset); + SET @@auto_increment_offset= 17; + INSERT INTO tproc(num) VALUES (@@session.auto_increment_offset); + + # reset these as they affect the index column + SET @@auto_increment_increment= 1; + SET @@auto_increment_offset= 1; + + SET @@character_set_client= 'cp1257'; + INSERT INTO tproc(text) VALUES (@@session.character_set_client); + SET @@character_set_client= 'cp1256'; + INSERT INTO tproc(text) VALUES (@@session.character_set_client); + + SET @@collation_connection= 'cp1251_ukrainian_ci'; + INSERT INTO tproc(text) VALUES (@@session.collation_connection); + INSERT INTO tproc(text) VALUES (@@session.character_set_connection); + SET @@collation_connection= 'cp1251_bulgarian_ci'; + INSERT INTO tproc(text) VALUES (@@session.collation_connection); + INSERT INTO tproc(text) VALUES (@@session.character_set_connection); + + SET @@collation_server= 'latin7_bin'; + INSERT INTO tproc(text) VALUES (@@session.collation_server); + INSERT INTO tproc(text) VALUES (@@session.character_set_server); + SET @@collation_server= 'latin7_general_cs'; + INSERT INTO tproc(text) VALUES (@@session.collation_server); + INSERT INTO tproc(text) VALUES (@@session.character_set_server); + + SET @@time_zone= 'Europe/Moscow'; + INSERT INTO tproc(text) VALUES (@@session.time_zone); + SET @@time_zone= 'Universal'; + INSERT INTO tproc(text) VALUES (@@session.time_zone); + + SET @@lc_time_names= 'sv_FI'; + INSERT INTO tproc(text) VALUES (@@session.lc_time_names); + SET @@lc_time_names= 'no_NO'; + INSERT INTO tproc(text) VALUES (@@session.lc_time_names); + + SET @@collation_database= 'latin7_general_ci'; + INSERT INTO tproc(text) VALUES (@@session.collation_database); + INSERT INTO tproc(text) VALUES (@@session.character_set_database); + SET @@collation_database= 'latin7_estonian_cs'; + INSERT INTO tproc(text) VALUES (@@session.collation_database); + INSERT INTO tproc(text) VALUES (@@session.character_set_database); + + SET @@timestamp= 47114711; + INSERT INTO tproc(text) VALUES (@@session.timestamp); + SET @@timestamp= 47124712; + INSERT INTO tproc(text) VALUES (@@session.timestamp); + + SET @@last_insert_id= 1616; + INSERT INTO tproc(text) VALUES (@@session.last_insert_id); + SET @@last_insert_id= 1717; + INSERT INTO tproc(text) VALUES (@@session.last_insert_id); + +END| +DELIMITER ;| + +CALL proc(); + + +--echo ==== Insert variables from a stored function ==== + +DELIMITER |; +CREATE FUNCTION func() +RETURNS INT +BEGIN + + SET @@pseudo_thread_id= 4712; + INSERT INTO tfunc(num) VALUES (@@session.pseudo_thread_id); + SET @@pseudo_thread_id= 4713; + INSERT INTO tfunc(num) VALUES (@@session.pseudo_thread_id); + + SET @@foreign_key_checks= 0; + INSERT INTO tfunc(num) VALUES (@@session.foreign_key_checks); + SET @@foreign_key_checks= 1; + INSERT INTO tfunc(num) VALUES (@@session.foreign_key_checks); + + SET @@sql_auto_is_null= 0; + INSERT INTO tfunc(num) VALUES (@@session.sql_auto_is_null); + SET @@sql_auto_is_null= 1; + INSERT INTO tfunc(num) VALUES (@@session.sql_auto_is_null); + + SET @@unique_checks= 0; + INSERT INTO tfunc(num) VALUES (@@session.unique_checks); + SET @@unique_checks= 1; + INSERT INTO tfunc(num) VALUES (@@session.unique_checks); + + SET @@auto_increment_increment= 11; + INSERT INTO tfunc(num) VALUES (@@session.auto_increment_increment); + SET @@auto_increment_increment= 19; + INSERT INTO tfunc(num) VALUES (@@session.auto_increment_increment); + + SET @@auto_increment_offset= 13; + INSERT INTO tfunc(num) VALUES (@@session.auto_increment_offset); + SET @@auto_increment_offset= 17; + INSERT INTO tfunc(num) VALUES (@@session.auto_increment_offset); + + # reset these as they affect the index column + SET @@auto_increment_increment= 1; + SET @@auto_increment_offset= 1; + + SET @@character_set_client= 'cp1257'; + INSERT INTO tfunc(text) VALUES (@@session.character_set_client); + SET @@character_set_client= 'cp1256'; + INSERT INTO tfunc(text) VALUES (@@session.character_set_client); + + SET @@collation_connection= 'cp1251_ukrainian_ci'; + INSERT INTO tfunc(text) VALUES (@@session.collation_connection); + INSERT INTO tfunc(text) VALUES (@@session.character_set_connection); + SET @@collation_connection= 'cp1251_bulgarian_ci'; + INSERT INTO tfunc(text) VALUES (@@session.collation_connection); + INSERT INTO tfunc(text) VALUES (@@session.character_set_connection); + + SET @@collation_server= 'latin7_bin'; + INSERT INTO tfunc(text) VALUES (@@session.collation_server); + INSERT INTO tfunc(text) VALUES (@@session.character_set_server); + SET @@collation_server= 'latin7_general_cs'; + INSERT INTO tfunc(text) VALUES (@@session.collation_server); + INSERT INTO tfunc(text) VALUES (@@session.character_set_server); + + SET @@time_zone= 'Europe/Moscow'; + INSERT INTO tfunc(text) VALUES (@@session.time_zone); + SET @@time_zone= 'Universal'; + INSERT INTO tfunc(text) VALUES (@@session.time_zone); + + SET @@lc_time_names= 'sv_FI'; + INSERT INTO tfunc(text) VALUES (@@session.lc_time_names); + SET @@lc_time_names= 'no_NO'; + INSERT INTO tfunc(text) VALUES (@@session.lc_time_names); + + SET @@collation_database= 'latin7_general_ci'; + INSERT INTO tfunc(text) VALUES (@@session.collation_database); + INSERT INTO tfunc(text) VALUES (@@session.character_set_database); + SET @@collation_database= 'latin7_estonian_cs'; + INSERT INTO tfunc(text) VALUES (@@session.collation_database); + INSERT INTO tfunc(text) VALUES (@@session.character_set_database); + + SET @@timestamp= 47114711; + INSERT INTO tfunc(text) VALUES (@@session.timestamp); + SET @@timestamp= 47124712; + INSERT INTO tfunc(text) VALUES (@@session.timestamp); + + SET @@last_insert_id= 1616; + INSERT INTO tfunc(text) VALUES (@@session.last_insert_id); + SET @@last_insert_id= 1717; + INSERT INTO tfunc(text) VALUES (@@session.last_insert_id); + + RETURN 0; +END| +DELIMITER ;| + +--disable_ps2_protocol +--disable_warnings +SELECT func(); +--enable_warnings +--enable_ps2_protocol + +--echo ==== Insert variables from a trigger ==== + +DELIMITER |; +CREATE TRIGGER trig +BEFORE INSERT ON trigger_table +FOR EACH ROW +BEGIN + + SET @@pseudo_thread_id= 4712; + INSERT INTO ttrig(num) VALUES (@@session.pseudo_thread_id); + SET @@pseudo_thread_id= 4713; + INSERT INTO ttrig(num) VALUES (@@session.pseudo_thread_id); + + SET @@foreign_key_checks= 0; + INSERT INTO ttrig(num) VALUES (@@session.foreign_key_checks); + SET @@foreign_key_checks= 1; + INSERT INTO ttrig(num) VALUES (@@session.foreign_key_checks); + + SET @@sql_auto_is_null= 0; + INSERT INTO ttrig(num) VALUES (@@session.sql_auto_is_null); + SET @@sql_auto_is_null= 1; + INSERT INTO ttrig(num) VALUES (@@session.sql_auto_is_null); + + SET @@unique_checks= 0; + INSERT INTO ttrig(num) VALUES (@@session.unique_checks); + SET @@unique_checks= 1; + INSERT INTO ttrig(num) VALUES (@@session.unique_checks); + + SET @@auto_increment_increment= 11; + INSERT INTO ttrig(num) VALUES (@@session.auto_increment_increment); + SET @@auto_increment_increment= 19; + INSERT INTO ttrig(num) VALUES (@@session.auto_increment_increment); + + SET @@auto_increment_offset= 13; + INSERT INTO ttrig(num) VALUES (@@session.auto_increment_offset); + SET @@auto_increment_offset= 17; + INSERT INTO ttrig(num) VALUES (@@session.auto_increment_offset); + + # reset these as they affect the index column + SET @@auto_increment_increment= 1; + SET @@auto_increment_offset= 1; + + SET @@character_set_client= 'cp1257'; + INSERT INTO ttrig(text) VALUES (@@session.character_set_client); + SET @@character_set_client= 'cp1256'; + INSERT INTO ttrig(text) VALUES (@@session.character_set_client); + + SET @@collation_connection= 'cp1251_ukrainian_ci'; + INSERT INTO ttrig(text) VALUES (@@session.collation_connection); + INSERT INTO ttrig(text) VALUES (@@session.character_set_connection); + SET @@collation_connection= 'cp1251_bulgarian_ci'; + INSERT INTO ttrig(text) VALUES (@@session.collation_connection); + INSERT INTO ttrig(text) VALUES (@@session.character_set_connection); + + SET @@collation_server= 'latin7_bin'; + INSERT INTO ttrig(text) VALUES (@@session.collation_server); + INSERT INTO ttrig(text) VALUES (@@session.character_set_server); + SET @@collation_server= 'latin7_general_cs'; + INSERT INTO ttrig(text) VALUES (@@session.collation_server); + INSERT INTO ttrig(text) VALUES (@@session.character_set_server); + + SET @@time_zone= 'Europe/Moscow'; + INSERT INTO ttrig(text) VALUES (@@session.time_zone); + SET @@time_zone= 'Universal'; + INSERT INTO ttrig(text) VALUES (@@session.time_zone); + + SET @@lc_time_names= 'sv_FI'; + INSERT INTO ttrig(text) VALUES (@@session.lc_time_names); + SET @@lc_time_names= 'no_NO'; + INSERT INTO ttrig(text) VALUES (@@session.lc_time_names); + + SET @@collation_database= 'latin7_general_ci'; + INSERT INTO ttrig(text) VALUES (@@session.collation_database); + INSERT INTO ttrig(text) VALUES (@@session.character_set_database); + SET @@collation_database= 'latin7_estonian_cs'; + INSERT INTO ttrig(text) VALUES (@@session.collation_database); + INSERT INTO ttrig(text) VALUES (@@session.character_set_database); + + SET @@timestamp= 47114711; + INSERT INTO ttrig(text) VALUES (@@session.timestamp); + SET @@timestamp= 47124712; + INSERT INTO ttrig(text) VALUES (@@session.timestamp); + + SET @@last_insert_id= 1616; + INSERT INTO ttrig(text) VALUES (@@session.last_insert_id); + SET @@last_insert_id= 1717; + INSERT INTO ttrig(text) VALUES (@@session.last_insert_id); + +END| +DELIMITER ;| + +--disable_warnings +INSERT INTO trigger_table VALUES ('bye.'); +--enable_warnings + + +--echo ==== Insert variables from a prepared statement ==== + +# GLOBAL + +PREPARE p1 FROM 'SET @@pseudo_thread_id= 4712'; +PREPARE p2 FROM 'INSERT INTO tprep(num) VALUES (@@session.pseudo_thread_id)'; +PREPARE p3 FROM 'SET @@pseudo_thread_id= 4713'; +PREPARE p4 FROM 'INSERT INTO tprep(num) VALUES (@@session.pseudo_thread_id)'; + +PREPARE p5 FROM 'SET @@foreign_key_checks= 0'; +PREPARE p6 FROM 'INSERT INTO tprep(num) VALUES (@@session.foreign_key_checks)'; +PREPARE p7 FROM 'SET @@foreign_key_checks= 1'; +PREPARE p8 FROM 'INSERT INTO tprep(num) VALUES (@@session.foreign_key_checks)'; + +PREPARE p9 FROM 'SET @@sql_auto_is_null= 0'; +PREPARE p10 FROM 'INSERT INTO tprep(num) VALUES (@@session.sql_auto_is_null)'; +PREPARE p11 FROM 'SET @@sql_auto_is_null= 1'; +PREPARE p12 FROM 'INSERT INTO tprep(num) VALUES (@@session.sql_auto_is_null)'; + +PREPARE p13 FROM 'SET @@unique_checks= 0'; +PREPARE p14 FROM 'INSERT INTO tprep(num) VALUES (@@session.unique_checks)'; +PREPARE p15 FROM 'SET @@unique_checks= 1'; +PREPARE p16 FROM 'INSERT INTO tprep(num) VALUES (@@session.unique_checks)'; + +PREPARE p17 FROM 'SET @@auto_increment_increment= 11'; +PREPARE p18 FROM 'INSERT INTO tprep(num) VALUES (@@session.auto_increment_increment)'; +PREPARE p19 FROM 'SET @@auto_increment_increment= 19'; +PREPARE p20 FROM 'INSERT INTO tprep(num) VALUES (@@session.auto_increment_increment)'; + +PREPARE p21 FROM 'SET @@auto_increment_offset= 13'; +PREPARE p22 FROM 'INSERT INTO tprep(num) VALUES (@@session.auto_increment_offset)'; +PREPARE p23 FROM 'SET @@auto_increment_offset= 17'; +PREPARE p24 FROM 'INSERT INTO tprep(num) VALUES (@@session.auto_increment_offset)'; + +# reset these as they affect the index column +PREPARE p25 FROM 'SET @@auto_increment_increment= 1'; +PREPARE p26 FROM 'SET @@auto_increment_offset= 1'; + +PREPARE p27 FROM 'SET @@character_set_client= \'cp1257\''; +PREPARE p28 FROM 'INSERT INTO tprep(text) VALUES (@@session.character_set_client)'; +PREPARE p29 FROM 'SET @@character_set_client= \'cp1256\''; +PREPARE p30 FROM 'INSERT INTO tprep(text) VALUES (@@session.character_set_client)'; + +PREPARE p31 FROM 'SET @@collation_connection= \'cp1251_ukrainian_ci\''; +PREPARE p32 FROM 'INSERT INTO tprep(text) VALUES (@@session.collation_connection)'; +PREPARE p33 FROM 'INSERT INTO tprep(text) VALUES (@@session.character_set_connection)'; +PREPARE p34 FROM 'SET @@collation_connection= \'cp1251_bulgarian_ci\''; +PREPARE p35 FROM 'INSERT INTO tprep(text) VALUES (@@session.collation_connection)'; +PREPARE p36 FROM 'INSERT INTO tprep(text) VALUES (@@session.character_set_connection)'; + +PREPARE p37 FROM 'SET @@collation_server= \'latin7_bin\''; +PREPARE p38 FROM 'INSERT INTO tprep(text) VALUES (@@session.collation_server)'; +PREPARE p39 FROM 'INSERT INTO tprep(text) VALUES (@@session.character_set_server)'; +PREPARE p40 FROM 'SET @@collation_server= \'latin7_general_cs\''; +PREPARE p41 FROM 'INSERT INTO tprep(text) VALUES (@@session.collation_server)'; +PREPARE p42 FROM 'INSERT INTO tprep(text) VALUES (@@session.character_set_server)'; + +PREPARE p43 FROM 'SET @@time_zone= \'Europe/Moscow\''; +PREPARE p44 FROM 'INSERT INTO tprep(text) VALUES (@@session.time_zone)'; +PREPARE p45 FROM 'SET @@time_zone= \'Universal\''; +PREPARE p46 FROM 'INSERT INTO tprep(text) VALUES (@@session.time_zone)'; + +PREPARE p47 FROM 'SET @@lc_time_names= \'sv_FI\''; +PREPARE p48 FROM 'INSERT INTO tprep(text) VALUES (@@session.lc_time_names)'; +PREPARE p49 FROM 'SET @@lc_time_names= \'no_NO\''; +PREPARE p50 FROM 'INSERT INTO tprep(text) VALUES (@@session.lc_time_names)'; + +PREPARE p51 FROM 'SET @@collation_database= \'latin7_general_ci\''; +PREPARE p52 FROM 'INSERT INTO tprep(text) VALUES (@@session.collation_database)'; +PREPARE p53 FROM 'INSERT INTO tprep(text) VALUES (@@session.character_set_database)'; +PREPARE p54 FROM 'SET @@collation_database= \'latin7_estonian_cs\''; +PREPARE p55 FROM 'INSERT INTO tprep(text) VALUES (@@session.collation_database)'; +PREPARE p56 FROM 'INSERT INTO tprep(text) VALUES (@@session.character_set_database)'; + +PREPARE p57 FROM 'SET @@timestamp= 47114711'; +PREPARE p58 FROM 'INSERT INTO tprep(text) VALUES (@@session.timestamp)'; +PREPARE p59 FROM 'SET @@timestamp= 47124712'; +PREPARE p60 FROM 'INSERT INTO tprep(text) VALUES (@@session.timestamp)'; + +PREPARE p61 FROM 'SET @@last_insert_id= 1616'; +PREPARE p62 FROM 'INSERT INTO tprep(text) VALUES (@@session.last_insert_id)'; +PREPARE p63 FROM 'SET @@last_insert_id= 1717'; +PREPARE p64 FROM 'INSERT INTO tprep(text) VALUES (@@session.last_insert_id)'; + +EXECUTE p1; EXECUTE p2; EXECUTE p3; EXECUTE p4; EXECUTE p5; EXECUTE p6; +EXECUTE p7; EXECUTE p8; EXECUTE p9; EXECUTE p10; EXECUTE p11; EXECUTE p12; +EXECUTE p13; EXECUTE p14; EXECUTE p15; EXECUTE p16; EXECUTE p17; EXECUTE p18; +EXECUTE p19; EXECUTE p20; EXECUTE p21; EXECUTE p22; EXECUTE p23; EXECUTE p24; +EXECUTE p25; EXECUTE p26; EXECUTE p27; EXECUTE p28; EXECUTE p29; EXECUTE p30; +EXECUTE p31; EXECUTE p32; EXECUTE p33; EXECUTE p34; EXECUTE p35; EXECUTE p36; +EXECUTE p37; EXECUTE p38; EXECUTE p39; EXECUTE p40; EXECUTE p41; EXECUTE p42; +EXECUTE p43; EXECUTE p44; EXECUTE p45; EXECUTE p46; EXECUTE p47; EXECUTE p48; +EXECUTE p49; EXECUTE p50; EXECUTE p51; EXECUTE p52; EXECUTE p53; EXECUTE p54; +EXECUTE p55; EXECUTE p56; EXECUTE p57; EXECUTE p58; EXECUTE p59; EXECUTE p60; +EXECUTE p61; EXECUTE p62; EXECUTE p63; EXECUTE p64; + +--sync_slave_with_master +--connection master + + +--echo ==== Results ==== + +# Show the result in table test.tstmt on master... +SELECT * FROM tstmt ORDER BY id; + +--sync_slave_with_master + +# ... then compare test.tstmt on master to the other tables on master and slave. +let $diff_tables= master:tstmt, master:tproc, master:tfunc, master:ttrig, master:tprep, slave:tstmt, slave:tproc, slave:tfunc, slave:ttrig, slave:tprep; +source include/diff_tables.inc; + + +--echo ==== Clean up ==== + +connection master; +DROP PROCEDURE proc; +DROP FUNCTION func; +DROP TRIGGER trig; +DROP TABLE tstmt, tproc, tfunc, ttrig, tprep, trigger_table; + +SET @@global.auto_increment_increment= @m_auto_increment_increment; +SET @@global.auto_increment_offset= @m_auto_increment_offset; +SET @@global.character_set_client= @m_character_set_client; +SET @@global.collation_connection= @m_collation_connection; +SET @@global.collation_server= @m_collation_server; +SET @@global.time_zone= @m_time_zone; +SET @@global.lc_time_names= @m_lc_time_names; +SET @@global.collation_database= @m_collation_database; + +connection slave; +SET @@global.auto_increment_increment= @s_auto_increment_increment; +SET @@global.auto_increment_offset= @s_auto_increment_offset; +SET @@global.character_set_client= @s_character_set_client; +SET @@global.collation_connection= @s_collation_connection; +SET @@global.collation_server= @s_collation_server; +SET @@global.time_zone= @s_time_zone; +SET @@global.lc_time_names= @s_lc_time_names; +SET @@global.collation_database= @s_collation_database; + +connection master; +sync_slave_with_master; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_view.test b/mysql-test/suite/rpl/t/rpl_view.test new file mode 100644 index 00000000..987b93a1 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_view.test @@ -0,0 +1,171 @@ +# NYI - row-based cannot use CREATE ... SELECT + +source include/master-slave.inc; +--disable_warnings +drop table if exists t1,v1; +drop view if exists t1,v1; +sync_slave_with_master; +reset master; +--enable_warnings + +# +# Check that creation drop of view is replicated, also check replication of +# updating of view +# +connection master; +create table t1 (a int); +insert into t1 values (1); +create view v1 as select a from t1; +insert into v1 values (2); +select * from v1 order by a; +sync_slave_with_master; +# view already have to be on slave +select * from v1 order by a; +connection master; +update v1 set a=3 where a=1; +select * from v1 order by a; +sync_slave_with_master; +select * from v1 order by a; +connection master; +delete from v1 where a=2; +select * from v1 order by a; +sync_slave_with_master; +select * from v1 order by a; +connection master; +# 'alter view' internally maped to creation, but still check that it works +alter view v1 as select a as b from t1; +sync_slave_with_master; +select * from v1 order by 1; +connection master; +drop view v1; +sync_slave_with_master; +#error, because view have to be removed from slave +-- error 1146 +select * from v1 order by a; +connection master; +drop table t1; +sync_slave_with_master; +# Change Author: JBM +# Change Date: 2005-12-22 +# Change: Commented out binlog events to work with SBR and RBR +#--replace_column 2 # 5 # +# show binlog events limit 1,100; + +# +# BUG#20438: CREATE statements for views, stored routines and triggers can be +# not replicable. +# + +--echo +--echo ---> Test for BUG#20438 + +# Prepare environment. + +--echo +--echo ---> Preparing environment... +--connection master + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP VIEW IF EXISTS v1; +--enable_warnings + +--echo +--echo ---> Synchronizing slave with master... + +--sync_slave_with_master + +--echo +--connection master + +# Test. + +--echo +--echo ---> Creating objects... + +CREATE TABLE t1(c INT); + +/*!50003 CREATE VIEW v1 AS SELECT * FROM t1 */; + +--echo +--echo ---> Inserting value... + +INSERT INTO t1 VALUES(1); + +--echo +--echo ---> Checking on master... + +SELECT * FROM t1; + +--echo +--echo ---> Synchronizing slave with master... + +--sync_slave_with_master + +SELECT * FROM t1; + +# Cleanup. + +--connection master + +--echo +--echo ---> Cleaning up... + +DROP VIEW v1; +DROP TABLE t1; + +--sync_slave_with_master +--connection master + +# +# BUG#19419: "VIEW: View that the column name is different +# by master and slave is made". +# +connection master; +create table t1(a int, b int); +insert into t1 values (1, 1), (1, 2), (1, 3); +create view v1(a, b) as select a, sum(b) from t1 group by a; + +sync_slave_with_master; +explain v1; +show create table v1; +select * from v1; + +connection master; +drop table t1; +drop view v1; + +sync_slave_with_master; + +# +# BUG#28244 CREATE VIEW breaks replication when view exists +# +connection master; +CREATE TABLE t1(a INT); +CREATE VIEW v1 AS SELECT * FROM t1; +--error ER_TABLE_EXISTS_ERROR +CREATE VIEW v1 AS SELECT * FROM t1; +DROP VIEW v1; +DROP TABLE t1; +sync_slave_with_master; + +# +# Bug#32575 Parse error of stmt with extended comments on slave side +# Verify that 'CREATE VIEW' with comments is properly logged to binlog +connection master; +CREATE TABLE t1 (a INT); +--echo # create view as output from mysqldump 10.11 (5.0.62) +/*!50001 CREATE ALGORITHM=UNDEFINED */ +/*!50013 DEFINER=`root`@`localhost` SQL SECURITY DEFINER */ +/*!50001 VIEW `v1` AS select `t1`.`a` AS `a` from `t1` where (`t1`.`a` < 3) */ +/*!50002 WITH CASCADED CHECK OPTION */; +SHOW CREATE VIEW v1; +sync_slave_with_master; +SHOW CREATE VIEW v1; +connection master; +DROP VIEW v1; +DROP TABLE t1; +sync_slave_with_master; + +--echo End of 5.0 tests +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_view_debug.test b/mysql-test/suite/rpl/t/rpl_view_debug.test new file mode 100644 index 00000000..08036924 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_view_debug.test @@ -0,0 +1,35 @@ +--source include/have_debug.inc +--source include/master-slave.inc + +--echo # +--echo # MDEV-6409 CREATE VIEW replication problem if error occurs in mysql_register_view +--echo # +--echo # Check the bug where if an error occurs in mysql_register_view the view +--echo # is still replicated to the slave +--echo # +connection master; +create table t1 (a int); +insert into t1 values (1); +create view v1 as select a from t1; +insert into v1 values (2); +select * from v1 order by a; +sync_slave_with_master; + +# view already has to be on slave +show tables; +connection master; +SET @saved_dbug = @@SESSION.debug_dbug; +set @@debug_dbug="d,simulate_register_view_failure"; + +--error ER_OUT_OF_RESOURCES +CREATE VIEW v2 as SELECT * FROM t1; + +show tables; +sync_slave_with_master; +show tables; + +connection master; +DROP VIEW IF EXISTS v1; +DROP TABLE t1; +SET debug_dbug= @saved_dbug; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_view_multi.test b/mysql-test/suite/rpl/t/rpl_view_multi.test new file mode 100644 index 00000000..50b9c184 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_view_multi.test @@ -0,0 +1,133 @@ +# +# This file contains test cases for bugs which involve views, several +# concurren connections and manifest themselves as wrong binary log +# sequence which results in broken replication. In principle we are +# mostly interested in SBR here but this test will also work with RBR. +# +--source include/master-slave.inc + +--echo # +--echo # Bug #25144 "replication / binlog with view breaks". +--echo # Statements that used views didn't ensure that view were not modified +--echo # during their execution. Indeed this led to incorrect binary log with +--echo # statement based logging and as result to broken replication. +--echo # +# +# Suppress "unsafe" warnings. +# +disable_query_log; +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); +enable_query_log; + + +--disable_warnings +drop tables if exists t1, t2; +drop view if exists v1; +--enable_warnings +--echo # Syncing slave with master +--sync_slave_with_master + +--disable_ps2_protocol +connect (master2,127.0.0.1,root,,test,$MASTER_MYPORT,); + +connection master; +create table t1 (i int); +create table t2 (i int); +create view v1 as select * from t1; + +--echo # First we try to concurrently execute statement that uses view +--echo # and statement that drops it. We use "user" locks as means to +--echo # suspend execution of first statement once it opens our view. +select get_lock("lock_bg25144", 1); + +connection master1; +--send insert into v1 values (get_lock("lock_bg25144", 100)) + +connection master2; +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "User lock" and info like "insert into v1 %lock_bg25144%"; +--source include/wait_condition.inc +--send drop view v1 + +connection master; +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and info = "drop view v1"; +--source include/wait_condition.inc + +select release_lock("lock_bg25144"); + +connection master1; +--disable_warnings +--reap +--enable_warnings +select release_lock("lock_bg25144"); + +connection master2; +--reap + +connection master; +--echo # Check that insertion through view did happen. +select * from t1; +--echo # Syncing slave with master +--sync_slave_with_master +--echo # Check that slave was able to replicate this sequence +--echo # which means that we got correct binlog order. +select * from t1; + +connection master; +--echo # Now we will repeat the test by trying concurrently execute +--echo # statement that uses a view and statement that alters it. +create view v1 as select * from t1; + +select get_lock("lock_bg25144", 1); + +connection master1; +--send insert into v1 values (get_lock("lock_bg25144", 100)) + +connection master2; +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "User lock" and info like "insert into v1 %lock_bg25144%"; +--source include/wait_condition.inc +--send alter view v1 as select * from t2 + +connection master; +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "alter view v1 as select * from t2"; +--source include/wait_condition.inc + +select release_lock("lock_bg25144"); + +connection master1; +--disable_warnings +--reap +--enable_warnings +select release_lock("lock_bg25144"); + +connection master2; +--reap + +connection master; + +--echo # Second insertion should go to t1 as well. +select * from t1; +select * from t2; + +--echo # Syncing slave with master +--sync_slave_with_master +--echo # Now let us check that statements were logged in proper order +--echo # So we have same result on slave. +select * from t1; +select * from t2; +--enable_ps2_protocol + +connection master; +drop table t1, t2; +drop view v1; +--echo # Syncing slave with master +--sync_slave_with_master +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_xa-master.opt b/mysql-test/suite/rpl/t/rpl_xa-master.opt new file mode 100644 index 00000000..6794216d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_xa-master.opt @@ -0,0 +1 @@ +--binlog-ignore-db=test_ign diff --git a/mysql-test/suite/rpl/t/rpl_xa.inc b/mysql-test/suite/rpl/t/rpl_xa.inc new file mode 100644 index 00000000..d22d2d2e --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_xa.inc @@ -0,0 +1,433 @@ +# +# This "body" file checks general properties of XA transaction replication +# as of MDEV-742. +# Parameters: +# --let rpl_xa_check= SELECT ... +# +connection master; +create table t1 (a int, b int) engine=InnoDB; +insert into t1 values(0, 0); +xa start 't'; +insert into t1 values(1, 2); +xa end 't'; +xa prepare 't'; +xa commit 't'; + +sync_slave_with_master; +let $diff_tables= master:t1, slave:t1; +source include/diff_tables.inc; + +connection master; + +xa start 't'; +insert into t1 values(3, 4); +xa end 't'; +xa prepare 't'; +xa rollback 't'; + +sync_slave_with_master; +let $diff_tables= master:t1, slave:t1; +source include/diff_tables.inc; + +connection master; +--disable_warnings +SET pseudo_slave_mode=1; +--enable_warnings +create table t2 (a int) engine=InnoDB; +xa start 't'; +insert into t1 values (5, 6); +xa end 't'; +xa prepare 't'; +xa start 's'; +insert into t2 values (0); +xa end 's'; +xa prepare 's'; +--source include/save_master_gtid.inc + +connection slave; +source include/sync_with_master_gtid.inc; +if ($rpl_xa_check) +{ + --eval $rpl_xa_check + if ($rpl_xa_verbose) + { + --eval SELECT $rpl_xa_check_lhs + --eval SELECT $rpl_xa_check_rhs + } +} +sorted_result; +xa recover; + +connection master; +xa commit 't'; +xa commit 's'; +--disable_warnings +SET pseudo_slave_mode=0; +--enable_warnings +sync_slave_with_master; +let $diff_tables= master:t1, slave:t1; +source include/diff_tables.inc; +let $diff_tables= master:t2, slave:t2; +source include/diff_tables.inc; + +# +# Read-only XA remains prepared after disconnect and must rollback at XA-complete +# after recoonect. To the read-only also belongs non-transactional engine XA. +# +--connection master + +--echo *** At the start of read-only section gtid list is: +flush logs; +--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1) +--source include/show_gtid_list.inc + + +set @query1="select 1"; +set @query2="select count(*) into @s2 from t1"; +--let $ro_cases=2 +--let $db=test + +# No disconnect +--let $p_trx=$ro_cases +while ($p_trx) +{ +--connection master + --let $xid=ro_$p_trx + --let $query=`SELECT @query$p_trx` + --source rpl_create_xa_prepared.inc + --let $complete=`select if(floor(rand()*10)%2,'COMMIT','ROLLBACK')` + --error 0 + --disable_query_log + --disable_result_log + --eval xa $complete '$xid' + --enable_result_log + --enable_query_log + + --disconnect master_$xid + --source include/wait_until_disconnected.inc + + --dec $p_trx +} + + +--let $p_trx=$ro_cases +# With diconnect +while ($p_trx) +{ +--connection master + --let $xid=ro_$p_trx + --let $query=`SELECT @query$p_trx` + --source rpl_create_xa_prepared.inc + + --disconnect master_$xid + --source include/wait_until_disconnected.inc + + --dec $p_trx +} + +--echo *** $ro_cases prepared xa:s must be in the list: +--connection master +sorted_result; +xa recover; + +--let $p_trx=$ro_cases +while ($p_trx) +{ + --let $xid=ro_$p_trx + --let $complete=`select if(floor(rand()*10)%2,'COMMIT','ROLLBACK')` + --disable_query_log + --disable_result_log + --error ER_XA_RBROLLBACK + --eval xa $complete '$xid' + --enable_result_log + --enable_query_log + + --dec $p_trx +} +--echo *** Zero prepared xa:s must be in the list: +xa recover; + +--echo *** At the end of read-only section gtid list has 0 more compare with previous check: +flush logs; +--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1) +--source include/show_gtid_list.inc + + +# +# XA logging cases while some of XA resources are read-only +# +# A1. Binlog filter + + +--let $db=test_ign +--eval create database $db +set @@sql_log_bin = 0; +--eval create table $db.t (a int) engine=InnoDB +set @@sql_log_bin = 1; + +--let $xid=rw_no_binlog +--let $query=insert into $db.t set a=1 +--source rpl_create_xa_prepared.inc +--disconnect master_$xid +--source include/wait_until_disconnected.inc + +--echo *** $xid must be in the list: +--connection master +xa recover; + +--let $complete=`select if(floor(rand()*10)%2,'COMMIT','ROLLBACK')` +--error 0 +--disable_query_log +--disable_result_log +--eval xa $complete '$xid' +--enable_result_log +--enable_query_log + +--echo *** Zero must be in the list: +--connection master +xa recover; +# restore for the following tests +--let $db=test + +--echo *** At the end of --binlog-ignore-db section gtid list has 2 more: +flush logs; +--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1) +--source include/show_gtid_list.inc + +# +# A2. Opposite to A1, ineffective execution in Engine may create a +# binlog transaction +# +connection master; +create table t3 (a int) engine=innodb; + +--echo *** the disconnected prepare case +--let $xid=rw_binlog_only +--let $query=delete from t3 +--connect (master_$xid, 127.0.0.1,root,,$db,$MASTER_MYPORT,) + set @@binlog_format=statement; + # --source rpl_create_xa_prepared.inc + --eval xa start '$xid' + --eval $query + --eval xa end '$xid' + --eval xa prepare '$xid' + + --disconnect master_$xid + --source include/wait_until_disconnected.inc + +connection master; +--echo *** $xid must be in the list: +xa recover; + + --let $complete=`select if(floor(rand()*10)%2,'COMMIT','ROLLBACK')` + --disable_query_log + --disable_result_log + --eval xa $complete '$xid' + --enable_result_log + --enable_query_log + +--echo *** Zero must be in the list: +xa recover; + +--echo *** the same connection complete case. +connection master; + --let $xid=rw_binlog_only + --let $query=delete from t3 +--connect (master_$xid, 127.0.0.1,root,,$db,$MASTER_MYPORT,) + set @@binlog_format=statement; + # --source rpl_create_xa_prepared.inc + --eval xa start '$xid' + --eval $query + --eval xa end '$xid' + --eval xa prepare '$xid' + +--echo *** $xid must be in the list: +xa recover; + +--disable_query_log + --disable_result_log + --eval xa $complete '$xid' + --enable_result_log + --enable_query_log +--disconnect master_$xid +--source include/wait_until_disconnected.inc + +--echo *** Zero must be in the list: +--connection master +xa recover; + +--echo *** At the end of ineffective in engine section gtid list has 5 more: +flush logs; +--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1) +--source include/show_gtid_list.inc + +# +# A3 MyISAM "xa" logs empty XA-prepare group, followed by +# an XA-complete event +create table tm (a int) engine=myisam; + +# No disconnect +--connection master + --let $xid=rw_myisam + --let $query=insert into tm set a=1 + --source rpl_create_xa_prepared.inc + --let $complete=`select if(floor(rand()*10)%2,'COMMIT','ROLLBACK')` + --error 0 + --disable_query_log + --disable_result_log + --eval xa $complete '$xid' + --enable_result_log + --enable_query_log + + --disconnect master_$xid + --source include/wait_until_disconnected.inc + +# With diconnect +--connection master + --source rpl_create_xa_prepared.inc + --disconnect master_$xid + --source include/wait_until_disconnected.inc + +--echo *** $xid prepared must be in the list: +--connection master +xa recover; + + --let $complete=`select if(floor(rand()*10)%2,'COMMIT','ROLLBACK')` + --disable_query_log + --disable_result_log + --eval xa $complete '$xid' + --enable_result_log + --enable_query_log + +--echo *** Zero prepared xa:s must be in the list: +xa recover; + +--echo *** At the end of MyISAM "xa" section gtid list has 7 more compare with previous check: +flush logs; +--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1) +--source include/show_gtid_list.inc + + +# B. Session binlog disable does not log even empty XA-prepare +# Therefore XA-complete should be also run in sql_log_bin-OFF environment. + +--let $db=test +--let $xid=skip_binlog +--let $query=insert into t2 values(1) +--connect (master_$xid, 127.0.0.1,root,,$db,$MASTER_MYPORT,) +set @@session.sql_log_bin = OFF; +--eval xa start '$xid' + --eval $query +--eval xa end '$xid' +--eval xa prepare '$xid' + +--disconnect master_$xid +--source include/wait_until_disconnected.inc + +--echo *** $xid must be in the list: +--connection master +xa recover; + +# now commit it carefully to avoid binlogging as the prepare part did +set @@session.sql_log_bin = OFF; +--eval xa rollback '$xid' +set @@session.sql_log_bin = ON; +--source include/save_master_gtid.inc + +--echo *** Zero must be in the list: +--connection master +xa recover; + +--echo *** At the end of skip_log_binb section gtid list has 0 more: +flush logs; +--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1) +--source include/show_gtid_list.inc + +# +# sync slave successfully to prove its consistency +# +--connection slave +source include/sync_with_master_gtid.inc; + + +connection master; +--eval drop database test_ign +drop table t1, t2, t3, tm; + +--echo # +--echo # MDEV-26682 slave lock timeout with XA and gap locks +--echo # +create table t1 (a int primary key, b int unique) engine=innodb; +insert t1 values (1,1),(3,3),(5,5); +sync_slave_with_master; + +# set a strong isolation level to keep the read view below. +# alternatively a long-running select can do that too even in read-committed +set session tx_isolation='repeatable-read'; +start transaction; +# opens a read view to disable purge on the slave +select * from t1; + +connect m2, localhost, root; +# now, delete a value, purge it on the master, but not on the slave +delete from t1 where a=3; +xa start 'x1'; +# this sets a gap lock on <3>, when it exists (so, on the slave) +update t1 set b=3 where a=5; +xa end 'x1'; +xa prepare 'x1'; + +connect m3, localhost, root; +# and this tries to insert straight into the locked gap +insert t1 values (2, 2); + +echo -->slave; +sync_slave_with_master; +commit; +select * from t1; + +connection m2; +xa rollback 'x1'; +disconnect m2; +disconnect m3; + +connection master; + +drop table t1; + +create table t1 (id int auto_increment primary key, c1 int not null unique) +engine=innodb; + +create table t2 (id int auto_increment primary key, c1 int not null, +foreign key(c1) references t1(c1), unique key(c1)) engine=innodb; + +insert t1 values (869,1), (871,3), (873,4), (872,5), (870,6), (877,7); +insert t2 values (795,6), (800,7); + +xa start '1'; +update t2 set id = 9, c1 = 5 where c1 in (null, null, null, null, null, 7, 3); + +connect con1, localhost,root; +xa start '2'; +delete from t1 where c1 like '3%'; +xa end '2'; +xa prepare '2'; + +connection master; +xa end '1'; +xa prepare '1'; + +echo ->slave; + +sync_slave_with_master; + +connection slave; +source include/sync_with_master_gtid.inc; + +connection con1; +xa commit '2'; +disconnect con1; + +connection master; +xa commit '1'; +drop table t2, t1; diff --git a/mysql-test/suite/rpl/t/rpl_xa.test b/mysql-test/suite/rpl/t/rpl_xa.test new file mode 100644 index 00000000..05a1abe5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_xa.test @@ -0,0 +1,5 @@ +source include/have_innodb.inc; +source include/master-slave.inc; + +source rpl_xa.inc; +source include/rpl_end.inc; diff --git a/mysql-test/suite/rpl/t/rpl_xa_empty_transaction.cnf b/mysql-test/suite/rpl/t/rpl_xa_empty_transaction.cnf new file mode 100644 index 00000000..92acd0c7 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_xa_empty_transaction.cnf @@ -0,0 +1,18 @@ +!include include/default_mysqld.cnf + +[mysqld.1] +log-slave-updates +innodb + +[mysqld.2] +log-slave-updates +innodb + +[mysqld.3] +log-slave-updates +innodb + +[ENV] +SERVER_MYPORT_1= @mysqld.1.port +SERVER_MYPORT_2= @mysqld.2.port +SERVER_MYPORT_3= @mysqld.3.port diff --git a/mysql-test/suite/rpl/t/rpl_xa_empty_transaction.test b/mysql-test/suite/rpl/t/rpl_xa_empty_transaction.test new file mode 100644 index 00000000..61cc0621 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_xa_empty_transaction.test @@ -0,0 +1,175 @@ +# +# Purpose: +# This test ensures consistency in binlogging behavior for XA transactions +# that have all statements error and rollback, effectively leaving an "empty" +# transaction. In such cases, an empty XA transaction should be binlogged. The +# bug reported by MDEV-25616 revealed that an "empty" XA transaction would +# binlog an XA ROLLBACK or XA COMMIT event without a preceding setup, i.e. +# XA START through XA PREPARE. The bug presented differently for XA +# transactions consisting of transactional and non-transactional statements. +# Therefore, this test validates that an entire XA transaction is binlogged +# for different combinations of transactional or non-transactional statements. +# Note that the behavior changes when binlogging empty XA transactions +# depending on the binlog_row_format variables. That is, when the content of +# the transaction consists of errored transactional statements, in row format, +# an empty XA transaction will be binlogged; however, in mixed and statement +# formats, nothing will be written into the binary log. +# +# Methodology: +# Create XA transactions with various combinations of erroring transactional +# or non-transactional statements. The binary log is examined to ensure all +# XA components are written. Chain replication is used, i.e. +# (primary->replica->replica), to ensure replica binlogging is consistent with +# manual execution. The transactional and non-transactional tables use InnoDB +# and MyISAM, respectively. +# +# Parameters +# $expect_transactional_xa_binlog : Boolean indicating whether or not an +# errored transactional statement should result in XA statements written +# into the binary log. +# +# References: +# MDEV-25616: Binlog event for XA COMMIT is generated without matching +# XA START, replication aborts +# +--source include/have_log_bin.inc + +--let $rpl_server_count= 3 +--let $rpl_topology= 1->2->3 +--source include/rpl_init.inc + +--connection server_1 +-- source include/have_innodb.inc +--connection server_2 +-- source include/have_innodb.inc +--connection server_3 +-- source include/have_innodb.inc +--connection server_1 + +--echo # +--echo # Test Case 1: An XA transaction without any statements should not be +--echo # binlogged +--let $trx_statements= + +--let $xa_completion_action= COMMIT +--source include/rpl_xa_empty_transaction.inc + +--let $xa_completion_action= ROLLBACK +--source include/rpl_xa_empty_transaction.inc + + +--echo # +--echo # Test Case 2: An XA transaction consisting of a successfully rolled back +--echo # statement should not be binlogged +--let $trx_statements= T + +--let $xa_completion_action= COMMIT +--source include/rpl_xa_empty_transaction.inc + +--let $xa_completion_action= ROLLBACK +--source include/rpl_xa_empty_transaction.inc + + +--echo # +--echo # Test Case 3: An XA transaction with a statement that cannot be rolled +--echo # back should be binlogged + +# TODO: remove work-around MDEV-24654 when fixed. +--connection server_1 +set @sav_binlog_format = @@binlog_format; +set @@binlog_format = row; +set @@global.binlog_format = row; +--let $trx_statements= N + +--let $xa_completion_action= COMMIT +--source include/rpl_xa_empty_transaction.inc + +--let $xa_completion_action= ROLLBACK +--source include/rpl_xa_empty_transaction.inc + +--connection server_1 +set @@binlog_format = @sav_binlog_format; +set @@global.binlog_format = @sav_binlog_format; + + +--echo # +--echo # Test Case 4: An XA transaction with multiple statements that can all +--echo # be rolled back should not be binlogged +--let $trx_statements= T,T + +--let $xa_completion_action= COMMIT +--source include/rpl_xa_empty_transaction.inc + +--let $xa_completion_action= ROLLBACK +--source include/rpl_xa_empty_transaction.inc + + +--echo # +--echo # Test Case 5: A mixed XA transaction consisting of one statement that +--echo # can successfully be rolled back (first statement), and another that +--echo # can not (second statement) should be binlogged + +--connection server_1 +set @sav_binlog_format = @@binlog_format; +set @@binlog_format = row; +set @@global.binlog_format = row; +--let $trx_statements= T,N + +--let $xa_completion_action= COMMIT +--source include/rpl_xa_empty_transaction.inc + +--let $xa_completion_action= ROLLBACK +--source include/rpl_xa_empty_transaction.inc + +--connection server_1 +set @@binlog_format = @sav_binlog_format; +set @@global.binlog_format = @sav_binlog_format; + + +--echo # +--echo # Test Case 6: A mixed XA transaction consisting of one statement that +--echo # cannot successfully be rolled back (first statement), and another that +--echo # can (second statement) should be binlogged + +--connection server_1 +set @sav_binlog_format = @@binlog_format; +set @@binlog_format = row; +set @@global.binlog_format = row; +--let $trx_statements= N,T + +--let $xa_completion_action= COMMIT +--source include/rpl_xa_empty_transaction.inc + +--let $xa_completion_action= ROLLBACK +--source include/rpl_xa_empty_transaction.inc + +--connection server_1 +set @@binlog_format = @sav_binlog_format; +set @@global.binlog_format = @sav_binlog_format; + +--echo # +--echo # Test Case 7: An XA transaction consisting of two failed +--echo # non-transactional statements should be binlogged + +--connection server_1 +set @sav_binlog_format = @@binlog_format; +set @@binlog_format = row; +set @@global.binlog_format = row; +--let $trx_statements= N,N + +--let $xa_completion_action= COMMIT +--source include/rpl_xa_empty_transaction.inc + +--let $xa_completion_action= ROLLBACK +--source include/rpl_xa_empty_transaction.inc + +--connection server_1 +set @@binlog_format = @sav_binlog_format; +set @@global.binlog_format = @sav_binlog_format; + +# +# Cleanup +--connection server_1 +--source include/rpl_end.inc + +--echo # End of rpl_xa_empty_transaction.test diff --git a/mysql-test/suite/rpl/t/rpl_xa_gap_lock-slave.opt b/mysql-test/suite/rpl/t/rpl_xa_gap_lock-slave.opt new file mode 100644 index 00000000..4602a43c --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_xa_gap_lock-slave.opt @@ -0,0 +1 @@ +--transaction-isolation=READ-COMMITTED diff --git a/mysql-test/suite/rpl/t/rpl_xa_gap_lock.test b/mysql-test/suite/rpl/t/rpl_xa_gap_lock.test new file mode 100644 index 00000000..29e883a1 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_xa_gap_lock.test @@ -0,0 +1,137 @@ +# ==== Purpose ==== +# +# This test will generate two XA transactions on the master in a way that +# they will block each other on the slave if the transaction isolation level +# used by the slave applier is more restrictive than the READ COMMITTED one. +# +# Consider: +# E=execute, P=prepare, C=commit; +# 1=first transaction, 2=second transaction; +# +# Master does: E1, E2, P2, P1, C1, C2 +# Slave does: E2, P2, E1, P1, C1, C2 +# +# The transactions are designed so that, if the applier transaction isolation +# level is more restrictive than the READ COMMITTED, E1 will be blocked on +# the slave waiting for gap locks to be released. +# +# Step 1 +# +# The test will verify that the transactions don't block each other because +# the applier thread automatically changed the isolation level. +# +# Step 2 +# +# The test will verify that applying master's binary log dump in slave doesn't +# block because mysqlbinlog is informing the isolation level to be used. +# +# ==== Related Bugs and Worklogs ==== +# +# BUG#25040331: INTERLEAVED XA TRANSACTIONS MAY DEADLOCK SLAVE APPLIER WITH +# REPEATABLE READ +# +--source include/have_debug.inc +--source include/have_innodb.inc +# The test case only make sense for RBR +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +--connection slave +# To hit the issue, we need to split the data in two pages. +# This global variable will help us. +SET @saved_innodb_limit_optimistic_insert_debug = @@GLOBAL.innodb_limit_optimistic_insert_debug; +SET @@GLOBAL.innodb_limit_optimistic_insert_debug = 2; + +# +# Step 1 - Using async replication +# + +# Let's generate the workload on the master +--connection master +CREATE TABLE t1 ( + c1 INT NOT NULL, + KEY(c1) +) ENGINE=InnoDB; + +CREATE TABLE t2 ( + c1 INT NOT NULL, + FOREIGN KEY(c1) REFERENCES t1(c1) +) ENGINE=InnoDB; + +INSERT INTO t1 VALUES (1), (3), (4); + +--connection master1 +XA START 'XA1'; +INSERT INTO t1 values(2); +XA END 'XA1'; + +# This transaction will reference the gap where XA1 +# was inserted, and will be prepared and committed +# before XA1, so the slave will prepare it (but will +# not commit it) before preparing XA1. +--connection master +XA START 'XA2'; +INSERT INTO t2 values(3); +XA END 'XA2'; + +# The XA2 prepare should be binary logged first +XA PREPARE 'XA2'; + +# The XA1 prepare should be binary logged +# after XA2 prepare and before XA2 commit. +--connection master1 +XA PREPARE 'XA1'; + +# The commit order doesn't matter much for the issue being tested. +XA COMMIT 'XA1'; +--connection master +XA COMMIT 'XA2'; + +# Everything is fine if the slave can sync with the master. +--source include/sync_slave_sql_with_master.inc + +# +# Step 2 - Using mysqlbinlog dump to restore the salve +# +--source include/stop_slave.inc +DROP TABLE t2, t1; +RESET SLAVE; +RESET MASTER; + +--connection master +--let $master_data_dir= `SELECT @@datadir` +--let $master_log_file= query_get_value(SHOW MASTER STATUS, File, 1) +--let $mysql_server= $MYSQL --defaults-group-suffix=.2 +--echo Restore binary log from the master into the slave +--exec $MYSQL_BINLOG --force-if-open $master_data_dir/$master_log_file | $mysql_server + +--let $diff_tables= master:test.t1, slave:test.t1 +--source include/diff_tables.inc +--let $diff_tables= master:test.t2, slave:test.t2 +--source include/diff_tables.inc + +# +# Cleanup +# +--let $master_file= query_get_value(SHOW MASTER STATUS, File, 1) +--let $master_pos= query_get_value(SHOW MASTER STATUS, Position, 1) +DROP TABLE t2, t1; + +## When GTID_MODE=OFF, we need to skip already applied transactions +--connection slave +#--let $gtid_mode= `SELECT @@GTID_MODE` +#if ($gtid_mode == OFF) +#{ +# --disable_query_log +# --disable_result_log +# --eval CHANGE MASTER TO MASTER_LOG_FILE='$master_file', MASTER_LOG_POS=$master_pos +# --enable_result_log +# --enable_query_log +#} +--replace_result $master_file LOG_FILE $master_pos LOG_POS +--eval CHANGE MASTER TO MASTER_LOG_FILE='$master_file', MASTER_LOG_POS=$master_pos, MASTER_USE_GTID=NO + +SET @@GLOBAL.innodb_limit_optimistic_insert_debug = @saved_innodb_limit_optimistic_insert_debug; +--source include/start_slave.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_xa_gtid_pos_auto_engine-master.opt b/mysql-test/suite/rpl/t/rpl_xa_gtid_pos_auto_engine-master.opt new file mode 100644 index 00000000..6794216d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_xa_gtid_pos_auto_engine-master.opt @@ -0,0 +1 @@ +--binlog-ignore-db=test_ign diff --git a/mysql-test/suite/rpl/t/rpl_xa_gtid_pos_auto_engine.test b/mysql-test/suite/rpl/t/rpl_xa_gtid_pos_auto_engine.test new file mode 100644 index 00000000..b8349376 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_xa_gtid_pos_auto_engine.test @@ -0,0 +1,29 @@ +--source include/have_innodb.inc +--source include/master-slave.inc + +--connection slave +call mtr.add_suppression("The automatically created table.*name may not be entirely in lowercase"); + +--source include/stop_slave.inc +CHANGE MASTER TO master_use_gtid=slave_pos; + +SET @@global.gtid_pos_auto_engines="innodb"; +--source include/start_slave.inc +--let $rpl_xa_check_lhs= @@global.gtid_slave_pos +--let $rpl_xa_check_rhs= CONCAT(domain_id,"-",server_id,"-",seq_no) FROM mysql.gtid_slave_pos WHERE seq_no = (SELECT DISTINCT max(seq_no) FROM mysql.gtid_slave_pos) +--let $rpl_xa_check=SELECT $rpl_xa_check_lhs = $rpl_xa_check_rhs +--source rpl_xa.inc + +--connection slave +--source include/stop_slave.inc +SET @@global.gtid_pos_auto_engines=""; +SET @@session.sql_log_bin=0; +DROP TABLE mysql.gtid_slave_pos_InnoDB; +if (`SHOW COUNT(*) WARNINGS`) +{ + show tables in mysql like 'gtid_slave_pos%'; +} +SET @@session.sql_log_bin=1; +--source include/start_slave.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_xa_prepare_gtid_fail.test b/mysql-test/suite/rpl/t/rpl_xa_prepare_gtid_fail.test new file mode 100644 index 00000000..aa1b088e --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_xa_prepare_gtid_fail.test @@ -0,0 +1,102 @@ +# +# When handling the replication of an XA PREPARE, the commit phase is +# bifurcated. First, the prepare is handled by the relevant storage engines. +# Then second,the GTID slave state is updated as a separate autocommit +# transaction. If the second stage fails, i.e. we are unable to update the +# GTID slave state, then the slave should immediately quit in error, without +# retry. +# +# This tests validates the above behavior by forcing a lock-wait timeout on +# the GTID slave state table during the second part of XA PREPARE's commit, to +# ensure that the appropriate error is reported and the transaction was never +# retried. +# +# +# References +# MDEV-31038: Parallel Replication Breaks if XA PREPARE Fails Updating Slave +# GTID State +# +source include/master-slave.inc; +source include/have_binlog_format_row.inc; +source include/have_innodb.inc; + +--connection slave +--source include/stop_slave.inc + +set @save_par_thds= @@global.slave_parallel_threads; +set @save_strict_mode= @@global.gtid_strict_mode; +set @save_innodb_lock_wait_timeout= @@global.innodb_lock_wait_timeout; + +change master to master_use_gtid=slave_pos; +set @@global.slave_parallel_threads= 4; +set @@global.slave_parallel_mode= optimistic; +set @@global.gtid_strict_mode=ON; + +set statement sql_log_bin=0 for alter table mysql.gtid_slave_pos engine=innodb; +--source include/start_slave.inc + +--connection master +create table t1 (a int primary key, b int) engine=innodb; +insert t1 values (1,1); +--source include/save_master_gtid.inc + +--connection slave +--source include/sync_with_master_gtid.inc +--source include/stop_slave.inc +set @@global.innodb_lock_wait_timeout= 1; + +--let $retried_tx_initial= query_get_value(SHOW ALL SLAVES STATUS, Retried_transactions, 1) + +--connection master +--let $gtid_domain_id=`SELECT @@GLOBAL.gtid_domain_id` +--let $gtid_server_id=`SELECT @@GLOBAL.server_id` +--let $xap_seq_no=100 +--eval set @@session.gtid_seq_no=$xap_seq_no +xa start '1'; +update t1 set b=b+10 where a=1; +xa end '1'; +xa prepare '1'; +--let $new_gtid= `SELECT @@global.gtid_binlog_pos` +xa commit '1'; +--source include/save_master_gtid.inc + +--connection slave1 +BEGIN; +--eval SELECT * FROM mysql.gtid_slave_pos WHERE seq_no=$xap_seq_no FOR UPDATE + +--connection slave +--source include/start_slave.inc + +--let $slave_sql_errno= 1942 +--source include/wait_for_slave_sql_error.inc + +# TODO: Remove after fixing MDEV-21777 +# Stop the IO thread too, so the existing relay logs are force purged on slave +# restart, as to not re-execute the already-prepared transaction +--source include/stop_slave_io.inc + +--let $retried_tx_test= query_get_value(SHOW ALL SLAVES STATUS, Retried_transactions, 1) +if ($retried_tx_initial != $retried_tx_test) +{ + --echo Transaction was retried when a failed XA PREPARE slave GTID update should lead to immediate slave stop without retry + --die Transaction was retried when a failed XA PREPARE slave GTID update should lead to immediate slave stop without retry +} + +--connection slave1 +ROLLBACK; + +--echo # Cleanup + +--connection master +drop table t1; + +--connection slave +--echo # TODO: Remove after fixing MDEV-21777 +--eval set @@global.gtid_slave_pos= "$new_gtid" +set @@global.slave_parallel_threads= @save_par_thds; +set @@global.gtid_strict_mode= @save_strict_mode; +set @@global.innodb_lock_wait_timeout= @save_innodb_lock_wait_timeout; +--source include/start_slave.inc + +--source include/rpl_end.inc +--echo # End of rpl_xa_prepare_gtid_fail.test diff --git a/mysql-test/suite/rpl/t/rpl_xa_survive_disconnect.test b/mysql-test/suite/rpl/t/rpl_xa_survive_disconnect.test new file mode 100644 index 00000000..e4193a35 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_xa_survive_disconnect.test @@ -0,0 +1,301 @@ +# BUG #12161 Xa recovery and client disconnection +# the test verifies that +# a. disconnection does not lose a prepared transaction +# so it can be committed from another connection +# c. the prepared transaction is logged +# d. interleaved prepared transactions are correctly applied on the slave. + +# +# Both replication format are checked through explict +# set @@binlog_format in the test. +# +--source include/have_innodb.inc +--source include/have_binlog_format_mixed.inc +# +# Prepared XA can't get available to an external connection +# until a connection, that either leaves actively or is killed, +# has completed a necessary part of its cleanup. +# Selecting from P_S.threads provides a method to learn that. +# +--source include/have_perfschema.inc +--source include/master-slave.inc + +--connection master +call mtr.add_suppression("Found 2 prepared XA transactions"); +CREATE VIEW v_processlist as SELECT * FROM performance_schema.threads where type = 'FOREGROUND'; + +CREATE DATABASE d1; +CREATE DATABASE d2; + +CREATE TABLE d1.t (a INT) ENGINE=innodb; +CREATE TABLE d2.t (a INT) ENGINE=innodb; + +# MDEV-515 takes X-lock on the table for the first insert. +# So concurrent DML won't happen on the table +INSERT INTO d1.t VALUES(100); + +connect (master_conn1, 127.0.0.1,root,,test,$MASTER_MYPORT,); +--let $conn_id=`SELECT connection_id()` +SET @@session.binlog_format= statement; +XA START '1-stmt'; +INSERT INTO d1.t VALUES (1); +XA END '1-stmt'; +XA PREPARE '1-stmt'; + +--disconnect master_conn1 + +--connection master + +--let $wait_condition= SELECT count(*) = 0 FROM v_processlist WHERE PROCESSLIST_ID = $conn_id +--source include/wait_condition.inc + +connect (master_conn2, 127.0.0.1,root,,test,$MASTER_MYPORT,); +--let $conn_id=`SELECT connection_id()` +SET @@session.binlog_format= row; +XA START '1-row'; +INSERT INTO d2.t VALUES (1); +XA END '1-row'; +XA PREPARE '1-row'; + +--disconnect master_conn2 + +--connection master +--let $wait_condition= SELECT count(*) = 0 FROM v_processlist WHERE PROCESSLIST_ID = $conn_id +--source include/wait_condition.inc + +XA START '2'; +INSERT INTO d1.t VALUES (2); +XA END '2'; +XA PREPARE '2'; +XA COMMIT '2'; + +XA COMMIT '1-row'; +XA COMMIT '1-stmt'; +source include/show_binlog_events.inc; + +# the proof: slave is in sync with the table updated by the prepared transactions. +--source include/sync_slave_sql_with_master.inc + +--source include/stop_slave.inc + +# +# Recover with Master server restart +# +--connection master + +connect (master2, 127.0.0.1,root,,test,$MASTER_MYPORT,); +--connection master2 +SET @@session.binlog_format= statement; +XA START '3-stmt'; +INSERT INTO d1.t VALUES (3); +XA END '3-stmt'; +XA PREPARE '3-stmt'; +--disconnect master2 + +connect (master2, 127.0.0.1,root,,test,$MASTER_MYPORT,); +--connection master2 +SET @@session.binlog_format= row; +XA START '3-row'; +INSERT INTO d2.t VALUES (4); +XA END '3-row'; +XA PREPARE '3-row'; +--disconnect master2 + +--connection master + +# +# Testing read-only +# +connect (master2, 127.0.0.1,root,,test,$MASTER_MYPORT,); +--connection master2 +XA START '4'; +SELECT * FROM d1.t; +XA END '4'; +XA PREPARE '4'; +--disconnect master2 + +# +# Logging few disconnected XA:s for replication. +# +--let $bulk_trx_num=10 +--let $i = $bulk_trx_num + +while($i > 0) +{ + --connect (master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,) + --let $conn_id=`SELECT connection_id()` + + --eval XA START 'bulk_trx_$i' + --eval INSERT INTO d1.t VALUES ($i) + --eval INSERT INTO d2.t VALUES ($i) + --eval XA END 'bulk_trx_$i' + --eval XA PREPARE 'bulk_trx_$i' + + --disconnect master_bulk_conn$i + + --connection master + --let $wait_condition= SELECT count(*) = 0 FROM v_processlist WHERE PROCESSLIST_ID = $conn_id + --source include/wait_condition.inc + + --dec $i +} + +# +# Prove the slave applier is capable to resume the prepared XA:s +# upon its restart. +# +--connection slave +--source include/start_slave.inc +--connection master +--source include/sync_slave_sql_with_master.inc +--source include/stop_slave.inc + +--connection master +--let $i = $bulk_trx_num +while($i > 0) +{ + --let $command=COMMIT + if (`SELECT $i % 2`) + { + --let $command=ROLLBACK + } + --eval XA $command 'bulk_trx_$i' + --dec $i +} + +--let $rpl_server_number= 1 +--source include/rpl_restart_server.inc + +--connection slave +--source include/start_slave.inc + +--connection master +--echo *** '3-stmt','3-row' xa-transactions must be in the list *** +XA RECOVER; +XA COMMIT '3-stmt'; +XA ROLLBACK '3-row'; + +--source include/sync_slave_sql_with_master.inc + +# +# Testing replication with marginal XID values and in two formats. +# + +--connection master +--let $wait_condition= SELECT count(*) = 0 FROM v_processlist WHERE PROCESSLIST_ID = $conn_id +--source include/wait_condition.inc + +# Max size XID incl max value of formatID +--let $formatid_range=`SELECT (1<<31)` +--let $max_formatid=`SELECT (1<<31) - 1` + +connect (master_conn2, 127.0.0.1,root,,test,$MASTER_MYPORT,); +--let $conn_id=`SELECT connection_id()` + +--let $gtrid=0123456789012345678901234567890123456789012345678901234567890124 +--let $bqual=0123456789012345678901234567890123456789012345678901234567890124 +--eval XA START '$gtrid','$bqual',$max_formatid + INSERT INTO d1.t VALUES (64); +--eval XA END '$gtrid','$bqual',$max_formatid +--eval XA PREPARE '$gtrid','$bqual',$max_formatid + +--disconnect master_conn2 + +--connection master +--let $wait_condition= SELECT count(*) = 0 FROM v_processlist WHERE PROCESSLIST_ID = $conn_id +--source include/wait_condition.inc + +# Max size XID with non-ascii chars +connect (master_conn3, 127.0.0.1,root,,test,$MASTER_MYPORT,); +--let $conn_id=`SELECT connection_id()` + +--let $gtrid_hex=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +--let $bqual_hex=00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +--eval XA START X'$gtrid_hex',X'$bqual_hex',0 + INSERT INTO d1.t VALUES (0); +--eval XA END X'$gtrid_hex',X'$bqual_hex',0 +--eval XA PREPARE X'$gtrid_hex',X'$bqual_hex',0 + +--disconnect master_conn3 + +--connection master +--let $wait_condition= SELECT count(*) = 0 FROM v_processlist WHERE PROCESSLIST_ID = $conn_id +--source include/wait_condition.inc + +# Random XID +--disable_query_log + +connect (master_conn4, 127.0.0.1,root,,test,$MASTER_MYPORT,); +--let $conn_id=`SELECT connection_id()` + +--let $gtridlen=`SELECT 2*(1 + round(rand()*100) % 31)` +--let $bquallen=`SELECT 2*(1 + round(rand()*100) % 31)` +--let $gtrid_rand=`SELECT substring(concat(MD5(rand()), MD5(rand())), 1, $gtridlen)` +--let $bqual_rand=`SELECT substring(concat(MD5(rand()), MD5(rand())), 1, $bquallen)` +--let $formt_rand=`SELECT floor((rand()*10000000000) % $formatid_range)` +--eval XA START X'$gtrid_rand',X'$bqual_rand',$formt_rand + INSERT INTO d1.t VALUES (0); +--eval XA END X'$gtrid_rand',X'$bqual_rand',$formt_rand +--eval XA PREPARE X'$gtrid_rand',X'$bqual_rand',$formt_rand + +--enable_query_log + +--disconnect master_conn4 + +--connection master +--let $wait_condition= SELECT count(*) = 0 FROM v_processlist WHERE PROCESSLIST_ID = $conn_id +--source include/wait_condition.inc + +--eval XA COMMIT '$gtrid','$bqual',$max_formatid +--eval XA COMMIT X'$gtrid_hex',X'$bqual_hex',0 +--disable_query_log +--echo XA COMMIT 'RANDOM XID' +--eval XA COMMIT X'$gtrid_rand',X'$bqual_rand',$formt_rand +--enable_query_log + +--source include/sync_slave_sql_with_master.inc + +# +# Testing ONE PHASE +# +--let $onephase_trx_num=10 +--let $i = $onephase_trx_num +while($i > 0) +{ + --connect (master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,) + + --connection master_bulk_conn$i + --eval XA START 'one_phase_$i' + --eval INSERT INTO d1.t VALUES ($i) + --eval INSERT INTO d2.t VALUES ($i) + --eval XA END 'one_phase_$i' + --eval XA COMMIT 'one_phase_$i' ONE PHASE + + --disconnect master_bulk_conn$i + --dec $i +} +--connection master +--source include/sync_slave_sql_with_master.inc + +# +# Overall consistency check +# +--let $diff_tables= master:d1.t, slave:d1.t +--source include/diff_tables.inc +--let $diff_tables= master:d2.t, slave:d2.t +--source include/diff_tables.inc +# +# cleanup +# +--connection master + +DELETE FROM d1.t; +DELETE FROM d2.t; +DROP TABLE d1.t, d2.t; +DROP DATABASE d1; +DROP DATABASE d2; +DROP VIEW v_processlist; + +--source include/sync_slave_sql_with_master.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_xa_survive_disconnect_lsu_off-slave.opt b/mysql-test/suite/rpl/t/rpl_xa_survive_disconnect_lsu_off-slave.opt new file mode 100644 index 00000000..94c36500 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_xa_survive_disconnect_lsu_off-slave.opt @@ -0,0 +1,2 @@ +--log-slave-updates=off + diff --git a/mysql-test/suite/rpl/t/rpl_xa_survive_disconnect_lsu_off.test b/mysql-test/suite/rpl/t/rpl_xa_survive_disconnect_lsu_off.test new file mode 100644 index 00000000..df3811df --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_xa_survive_disconnect_lsu_off.test @@ -0,0 +1,8 @@ +# ==== Purpose ==== +# 'rpl_xa_survive_disconnect_lsu_off' verifies the same properties as the sourced file +# in conditions of the slave does not log own updates +# (lsu in the name stands for log_slave_updates). +# Specifically this mode aims at proving correct operations on the slave +# mysql.gtid_executed. + +--source ./rpl_xa_survive_disconnect.test diff --git a/mysql-test/suite/rpl/t/rpl_xa_survive_disconnect_mixed_engines.test b/mysql-test/suite/rpl/t/rpl_xa_survive_disconnect_mixed_engines.test new file mode 100644 index 00000000..f52a9630 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_xa_survive_disconnect_mixed_engines.test @@ -0,0 +1,68 @@ +# BUG#12161 Xa recovery and client disconnection +# +# The test verifies correct XA transaction two phase logging and its applying +# in a case the transaction updates transactional and non-transactional tables. +# Transactions are terminated according to specfied parameters to +# a sourced inc-file. + +--source include/have_innodb.inc +--source include/master-slave.inc + +--connection master +CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); + +--let $command=setup +--source include/rpl_xa_mixed_engines.inc + +--echo === COMMIT === +--let $command=run +--let $xa_terminate=XA COMMIT +--let $xa_prepare_opt=1 +--source include/rpl_xa_mixed_engines.inc + +--source include/sync_slave_sql_with_master.inc +--connection master + +--echo === COMMIT ONE PHASE === + +--let $command=run +--let $xa_terminate=XA COMMIT +--let $one_phase=ONE PHASE +--let $xa_prepare_opt= +--source include/rpl_xa_mixed_engines.inc +--let $one_phase= +--source include/sync_slave_sql_with_master.inc +--connection master + +--echo === ROLLBACK with PREPARE === + +--let $command=run +--let $xa_terminate=xa rollback +--let $xa_prepare_opt=1 +--source include/rpl_xa_mixed_engines.inc + +--source include/sync_slave_sql_with_master.inc +--connection master + +--echo === ROLLBACK with no PREPARE === + +--let $command=run +--let $xa_terminate=xa rollback +--let $xa_prepare_opt= +--source include/rpl_xa_mixed_engines.inc +--let $xa_rollback_only= + +--source include/sync_slave_sql_with_master.inc + +--let $diff_tables= master:tm, slave:tm +--source include/diff_tables.inc + +# Cleanup + +--connection master +--let $command=cleanup +--source include/rpl_xa_mixed_engines.inc + +--source include/sync_slave_sql_with_master.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/sec_behind_master-5114.test b/mysql-test/suite/rpl/t/sec_behind_master-5114.test new file mode 100644 index 00000000..d1d21bfa --- /dev/null +++ b/mysql-test/suite/rpl/t/sec_behind_master-5114.test @@ -0,0 +1,63 @@ +source include/have_binlog_format_statement.inc; +source include/master-slave.inc; + +call mtr.add_suppression("Unsafe statement written to the binary log"); + + +# Make sure that the start time of the first event is certainly different +# from the next event +--let $timestamp= `SELECT @@timestamp` +--disable_query_log +eval SET TIMESTAMP= $timestamp-100; +--enable_query_log +CREATE TABLE t1 (a int); + +# Make sure that the slave is done with the first event, and all checks +# that we'll perform later will be really against the second event +sync_slave_with_master; + +connection master; + +# Restore the timestamp now. It doesn't matter that it's not precise, +# it just needs to be very different from the earlier event +--disable_query_log +eval SET TIMESTAMP= $timestamp; +--enable_query_log + +send INSERT INTO t1 VALUES(SLEEP(2)); + +connection slave; + +# When the slave starts executing the event, Seconds_Behind_Master +# should start growing steadilly. The bugfix ensures that they are +# calculated based on the start time of the current event, rather +# than the start time of the previous event. To check it, we only need +# the first non-zero value + +let $run = 20; +while ($run) +{ + dec $run; + let $sbm=query_get_value(SHOW SLAVE STATUS, Seconds_Behind_Master, 1); + # for debugging uncomment echo and remove the if() +# echo Seconds_Behind_Master: $sbm; + if ($sbm) + { + let $run = 0; + } + sleep 0.5; +} + +# Normally the first non-zero value should be 1. However, due to race +# conditions on slow servers, sometimes the check might miss the value 1, +# and only catch a higher one. It does not matter, we just need to make +# sure it didn't start with 100+, as it would have with bug MDEV-5114 + +--disable_query_log +eval SELECT $sbm > 0 and $sbm < 99 AS Seconds_Behind_Master_is_less_than_100; +--enable_query_log + +connection master; +reap; +drop table t1; +source include/rpl_end.inc; diff --git a/mysql-test/suite/rpl/t/semisync_future-7591.test b/mysql-test/suite/rpl/t/semisync_future-7591.test new file mode 100644 index 00000000..793d8bcc --- /dev/null +++ b/mysql-test/suite/rpl/t/semisync_future-7591.test @@ -0,0 +1,33 @@ +--source include/master-slave.inc + +call mtr.add_suppression("Timeout waiting for reply of binlog*"); +create table t1 (i int); + +set global rpl_semi_sync_master_enabled = ON; + +--connection slave +--source include/stop_slave.inc +set global rpl_semi_sync_slave_enabled = ON; +change master to master_log_file='master-bin.000002', master_log_pos = 320, master_use_gtid=no; + +start slave; +--let $slave_io_errno=1236 +--source include/wait_for_slave_io_error.inc + +--connection master +insert into t1 values (1); +reset master; + +--connection slave +--source include/stop_slave.inc +--let $master_use_gtid_option= No +--source include/reset_slave.inc +--source include/start_slave.inc + +set global rpl_semi_sync_slave_enabled = OFF; +--connection master +drop table t1; +--sync_slave_with_master +--connection master +set global rpl_semi_sync_master_enabled = OFF; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/semisync_memleak_4066.test b/mysql-test/suite/rpl/t/semisync_memleak_4066.test new file mode 100644 index 00000000..e88e2335 --- /dev/null +++ b/mysql-test/suite/rpl/t/semisync_memleak_4066.test @@ -0,0 +1,14 @@ +# +# MDEV-4066 semisync_master + temporary tables causes memory leaks +# +source include/have_binlog_format_row.inc; +source include/master-slave.inc; + +connection master; + +--connect (con1,localhost,root,,) +CREATE TEMPORARY TABLE tmp (i INT); +--disconnect con1 + +source include/rpl_end.inc; + diff --git a/mysql-test/suite/rpl/t/sequence.cnf b/mysql-test/suite/rpl/t/sequence.cnf new file mode 100644 index 00000000..58b605ad --- /dev/null +++ b/mysql-test/suite/rpl/t/sequence.cnf @@ -0,0 +1,8 @@ +!include ../my.cnf + +[mysqld.3] +log-slave-updates + +[ENV] +SERVER_MYPORT_3= @mysqld.3.port +SERVER_MYSOCK_3= @mysqld.3.socket diff --git a/mysql-test/suite/rpl/t/sequence.test b/mysql-test/suite/rpl/t/sequence.test new file mode 100644 index 00000000..5c6a8e1e --- /dev/null +++ b/mysql-test/suite/rpl/t/sequence.test @@ -0,0 +1,54 @@ +# +# Testing sequences with replication +# + +--source include/have_binlog_format_row.inc +--source include/have_aria.inc +--source include/have_sequence.inc + +--let $rpl_topology= 1->2->3 +--source include/rpl_init.inc + +--let $rpl_connection_name= master +--let $rpl_server_number= 1 +--source include/rpl_connect.inc + +--let $rpl_connection_name= slave +--let $rpl_server_number= 2 +--source include/rpl_connect.inc + +--let $rpl_connection_name= slave2 +--let $rpl_server_number= 3 +--source include/rpl_connect.inc + +--connection master + +set @@default_storage_engine="aria"; + +CREATE SEQUENCE s1 cache=10; +create table t1 select * from s1; +--disable_ps2_protocol +select NEXT VALUE for s1,seq from seq_1_to_20; +--enable_ps2_protocol +insert into t1 select * from s1; +do setval(s1,5, 1, 0); +insert into t1 select * from s1; +do setval(s1, 5000, 1 ,0); +insert into t1 select * from s1; +alter sequence s1 minvalue=-1 start=-1 restart=-1; +insert into t1 select * from s1; +insert into s1 values(-100,-1000,9223372036854775806,1,1,1000,0,0); +insert into t1 select * from s1; +select * from t1; +--sync_slave_with_master +select * from t1; +--sync_slave_with_master slave2 +select * from t1; + +--let $binlog_file = LAST +source include/show_binlog_events.inc; + +connection master; +drop table s1,t1; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/show_status_stop_slave_race-7126.test b/mysql-test/suite/rpl/t/show_status_stop_slave_race-7126.test new file mode 100644 index 00000000..12794dbd --- /dev/null +++ b/mysql-test/suite/rpl/t/show_status_stop_slave_race-7126.test @@ -0,0 +1,22 @@ +# +# MDEV-7126 replication slave - deadlock in terminate_slave_thread with stop slave and show variables of replication filters and show global status +# +--source include/master-slave.inc + +call mtr.add_suppression("Master is configured to log replication events"); + +--connection slave + + +# If everything is okay, the test will end in several seconds; maybe a minute. +# If the problem shows up, it will hang until testcase timeout is exceeded. +--exec $MYSQL_SLAP --silent --host=127.0.0.1 -P $SLAVE_MYPORT -q "START SLAVE; STOP SLAVE; SHOW GLOBAL STATUS" -c 2 --number-of-queries=100 --create-schema=test + +# All done. + +--connection slave +--source include/wait_for_slave_to_stop.inc +start slave; + +--connection master +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/temporal_row-9560-master.opt b/mysql-test/suite/rpl/t/temporal_row-9560-master.opt new file mode 100644 index 00000000..07c4494e --- /dev/null +++ b/mysql-test/suite/rpl/t/temporal_row-9560-master.opt @@ -0,0 +1 @@ +--disable-mysql56-temporal-format diff --git a/mysql-test/suite/rpl/t/temporal_row-9560.combinations b/mysql-test/suite/rpl/t/temporal_row-9560.combinations new file mode 100644 index 00000000..b1c360f8 --- /dev/null +++ b/mysql-test/suite/rpl/t/temporal_row-9560.combinations @@ -0,0 +1,6 @@ +[old2old] +--disable-mysql56-temporal-format + +[old2new] +--enable-mysql56-temporal-format + diff --git a/mysql-test/suite/rpl/t/temporal_row-9560.test b/mysql-test/suite/rpl/t/temporal_row-9560.test new file mode 100644 index 00000000..00fb59bc --- /dev/null +++ b/mysql-test/suite/rpl/t/temporal_row-9560.test @@ -0,0 +1,20 @@ +# +# MDEV-9560 Mariadb 10.1 Crashes when replicating from 10.0 +# +source include/have_binlog_format_row.inc; +source include/master-slave.inc; + +select @@mysql56_temporal_format; +create table t1 (ts timestamp(3), t time(3), dt datetime(3)); +insert into t1 values ('2016-02-15 12:50:06.123', '12:50:06.123', '2016-02-15 12:50:06.123'); + +sync_slave_with_master; + +select @@mysql56_temporal_format; +select * from t1; + +connection master; +drop table t1; + +source include/rpl_end.inc; + |