summaryrefslogtreecommitdiff
path: root/mysql-test/extra/rpl_tests/rpl_conflicts.test
blob: 2fbf3dba5dce76acb041ec02b7b17a50771d5277 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# ==== Purpose ====
#
# Test that slave behaves well in some conflict situations.  The
# following are tested:
#
# - The slave SQL thread sees an 'INSERT' of a row with a key that
#   already exists in the table;
#
# - The slave SQL thread sees a 'DELETE' of a row that does not
#   exist in the table.
#
# In statement-logging mode, the first conflict type causes the slave
# to stop with an error and the second conflict is ignored.
#
# In row-logging mode, the slave behavior depends the value of
# @@slave_exec_mode on the slave: if @@slave_exec_mode is IDEMPOTENT,
# the slave should ignore the conflicting statement and continue
# normally.  If @@slave_exec_mode is STRICT, the slave should stop
# with an error.
#
# This test was previously named rpl_stm_mystery22/rpl_row_mystery22.
#
#
# ==== Method ====
#
# Create a table on master and slave, insert a row on slave, and
# insert the same row on master.
#
# Create a table on master and slave, insert a row on master with
# binlogging turned off, and remove the row on master with binlogging
# turned on.
#
#
# ==== Related bugs ====
#
# BUG#31552: Replication breaks when deleting rows from out-of-sync table without PK
# BUG#31609: Not all RBR slave errors reported as errors
#
# Bug in this test case:
# BUG#37718: rpl.rpl_stm_mystery22 fails sporadically on pushbuild
#
#
# ==== Usage ====
#
# This file assumes the following:
#
# - The test language variable $slave_is_idempotent is set to 1 if the
#   slave is expected to stop on duplicate key errors (i.e., if the
#   binlog is in statement mode or
#   @@global.slave_exec_mode=STRICT). It is set to 0 otherwise.
#
# - Replication has been initialized by include/master-slave.inc
#
# - The test adds a suppression for the following warning:
#    Slave: Can't find record in 't1' Error_code: 1032


--echo ==== Initialize ====

--echo [on master]
connection master;
CREATE TABLE t1(a INT PRIMARY KEY);
--echo [on slave]
sync_slave_with_master;


--echo ==== Test: SQL thread sees 'INSERT' of existing key ====

--echo ---- Prepare slave so that it will get duplicate key error ----
# This row will be in the way of the row inserted by master.
INSERT INTO t1 VALUES (1);

--echo ---- Insert rows on master ----
--echo [on master]
connection master;
# Insert the same row on master
INSERT INTO t1 VALUES (1);
save_master_pos;
SELECT * FROM t1;

--echo [on slave]
connection slave;

# If we are statement-logging or if slave_exec_mode=STRICT, we now
# expect to see an error on the slave.  Otherwise (i.e., we are
# row-logging and slave_exec_mode=IDEMPOTENT), we expect that the
# duplicate row is ignored by the slave and replication continues.
if (`SELECT @@global.binlog_format != 'ROW' OR @@global.slave_exec_mode = 'STRICT'`) {
  --echo ---- Wait until slave stops with an error ----
  # Wait until the slave tries to run the query, fails with duplicate
  # key error, and stops the SQL thread.
  let $slave_sql_errno= 1062; # ER_DUP_ENTRY
  source include/wait_for_slave_sql_error.inc;

  --let $err= query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1)
  --replace_regex /end_log_pos [0-9]+/end_log_pos END_LOG_POS/
  --disable_query_log
  --eval SELECT "$err" as 'Last_SQL_Error (expected "duplicate key" error)'
  --enable_query_log
  call mtr.add_suppression("Slave SQL.*Duplicate entry .1. for key .PRIMARY.* Error_code: 1062");

  SELECT * FROM t1;

  --echo ---- Resolve the conflict on the slave and restart SQL thread ----
  DELETE FROM t1 WHERE a = 1;
  START SLAVE SQL_THREAD;
  source include/wait_for_slave_sql_to_start.inc;
}

--echo ---- Sync slave and verify that there is no error ----
sync_with_master;
let $err= query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1);
--echo Last_SQL_Error = '$err' (expected no error)
SELECT * FROM t1;


--echo ==== Test: SQL thread sees 'DELETE' of non-existing row ====

--echo ---- On master, insert two rows, the second with binlogging off ----
--echo [on master]
connection master;
DELETE FROM t1;
INSERT INTO t1 VALUES (1);

--echo [on slave]
sync_slave_with_master;
DELETE FROM t1 WHERE a = 1;

--echo ---- On master, remove the row that does not exist on slave ----
--echo [on master]
connection master;
DELETE FROM t1 WHERE a = 1;
SELECT * FROM t1;
save_master_pos;

--echo [on slave]
connection slave;

# If we are row-logging and slave_exec_mode is STRICT, we now expect
# an error since the row to delete does not exist on slave.  Otherwise
# (i.e., either we are statement-logging or slave_exec_mode is
# IDEMPOTENT), the absence of the row to delete is ignored and
# replication continues.
if (`SELECT @@global.binlog_format = 'ROW' AND @@global.slave_exec_mode = 'STRICT'`) {
  --echo ---- Wait until slave stops with an error ----
  call mtr.add_suppression("Slave SQL.*Can.t find record in .t1., Error_code: 1032");
  let $slave_sql_errno= 1032; # ER_KEY_NOT_FOUND
  source include/wait_for_slave_sql_error.inc;

  --let $err= query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1)
  --replace_regex /end_log_pos [0-9]+/end_log_pos END_LOG_POS/
  --disable_query_log
  --eval SELECT "$err" as 'Last_SQL_Error (expected "duplicate key" error)'
  --enable_query_log

  SELECT * FROM t1;

  --echo ---- Resolve the conflict on the slave and restart SQL thread ----
  INSERT INTO t1 VALUES (1);
  START SLAVE SQL_THREAD;
  source include/wait_for_slave_sql_to_start.inc;
}

--echo ---- Sync slave and verify that there is no error ----
# The slave should sync ok, and SHOW SLAVE STATUS should give no
# error.
sync_with_master;
let $err= query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1);
--echo Last_SQL_Error = $err (expected no error)
SELECT * FROM t1;


--echo ==== Clean up ====

--echo [on master]
connection master;
DROP TABLE t1;

--echo [on slave]
--sync_slave_with_master