# ==== 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);
  --echo Last_SQL_Error = $err (expected "duplicate key" error)
  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 ----
  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);
  --echo Last_SQL_Error = $err (expected "can't find record" error)
  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;
