mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
BUG#39393 slave-skip-errors does not work when using ROW based replication
RBR was not considering the option --slave-skip-errors. To fix the problem, we are reporting the ignored ERROR(s) as warnings thus avoiding stopping the SQL Thread. Besides, it fixes the output of "SHOW VARIABLES LIKE 'slave_skip_errors'" which was showing nothing when the value "all" was assigned to --slave-skip-errors. @sql/log_event.cc skipped rbr errors when the option skip-slave-errors is set. @sql/slave.cc fixed the output of for SHOW VARIABLES LIKE 'slave_skip_errors'" @test-cases fixed the output of rpl.rpl_idempotency updated the test case rpl_skip_error
This commit is contained in:
@@ -141,9 +141,9 @@ select * from ti1 order by b /* must be (2),(3) */;
|
|||||||
b
|
b
|
||||||
2
|
2
|
||||||
3
|
3
|
||||||
*** slave must stop
|
*** slave must stop (Trying to delete a referenced foreing key)
|
||||||
Last_SQL_Error
|
Last_SQL_Error
|
||||||
0
|
1451
|
||||||
select * from ti1 order by b /* must be (1),(2),(3) - not deleted */;
|
select * from ti1 order by b /* must be (1),(2),(3) - not deleted */;
|
||||||
b
|
b
|
||||||
1
|
1
|
||||||
@@ -159,7 +159,7 @@ set global slave_exec_mode='STRICT';
|
|||||||
*** conspire future problem
|
*** conspire future problem
|
||||||
delete from ti1 where b=3;
|
delete from ti1 where b=3;
|
||||||
insert into ti2 set a=3, b=3 /* offending write event */;
|
insert into ti2 set a=3, b=3 /* offending write event */;
|
||||||
*** slave must stop
|
*** slave must stop (Trying to insert an invalid foreign key)
|
||||||
Last_SQL_Error
|
Last_SQL_Error
|
||||||
1452
|
1452
|
||||||
select * from ti2 order by b /* must be (2,2) */;
|
select * from ti2 order by b /* must be (2,2) */;
|
||||||
@@ -179,7 +179,7 @@ a b
|
|||||||
*** conspiring query
|
*** conspiring query
|
||||||
insert into ti1 set b=1;
|
insert into ti1 set b=1;
|
||||||
insert into ti1 set b=1 /* offending write event */;
|
insert into ti1 set b=1 /* offending write event */;
|
||||||
*** slave must stop
|
*** slave must stop (Trying to insert a dupliacte key)
|
||||||
Last_SQL_Error
|
Last_SQL_Error
|
||||||
1062
|
1062
|
||||||
set foreign_key_checks= 0;
|
set foreign_key_checks= 0;
|
||||||
@@ -195,32 +195,32 @@ INSERT INTO t2 VALUES (-1),(-2),(-3);
|
|||||||
DELETE FROM t1 WHERE a = -2;
|
DELETE FROM t1 WHERE a = -2;
|
||||||
DELETE FROM t2 WHERE a = -2;
|
DELETE FROM t2 WHERE a = -2;
|
||||||
DELETE FROM t1 WHERE a = -2;
|
DELETE FROM t1 WHERE a = -2;
|
||||||
*** slave must stop
|
*** slave must stop (Key was not found)
|
||||||
Last_SQL_Error
|
Last_SQL_Error
|
||||||
1032
|
1032
|
||||||
set global slave_exec_mode='IDEMPOTENT';
|
set global slave_exec_mode='IDEMPOTENT';
|
||||||
start slave sql_thread;
|
start slave sql_thread;
|
||||||
set global slave_exec_mode='STRICT';
|
set global slave_exec_mode='STRICT';
|
||||||
DELETE FROM t2 WHERE a = -2;
|
DELETE FROM t2 WHERE a = -2;
|
||||||
*** slave must stop
|
*** slave must stop (Key was not found)
|
||||||
Last_SQL_Error
|
Last_SQL_Error
|
||||||
0
|
1032
|
||||||
set global slave_exec_mode='IDEMPOTENT';
|
set global slave_exec_mode='IDEMPOTENT';
|
||||||
start slave sql_thread;
|
start slave sql_thread;
|
||||||
set global slave_exec_mode='STRICT';
|
set global slave_exec_mode='STRICT';
|
||||||
UPDATE t1 SET a = 1 WHERE a = -1;
|
UPDATE t1 SET a = 1 WHERE a = -1;
|
||||||
UPDATE t2 SET a = 1 WHERE a = -1;
|
UPDATE t2 SET a = 1 WHERE a = -1;
|
||||||
UPDATE t1 SET a = 1 WHERE a = -1;
|
UPDATE t1 SET a = 1 WHERE a = -1;
|
||||||
*** slave must stop
|
*** slave must stop (Key was not found)
|
||||||
Last_SQL_Error
|
Last_SQL_Error
|
||||||
1032
|
1032
|
||||||
set global slave_exec_mode='IDEMPOTENT';
|
set global slave_exec_mode='IDEMPOTENT';
|
||||||
start slave sql_thread;
|
start slave sql_thread;
|
||||||
set global slave_exec_mode='STRICT';
|
set global slave_exec_mode='STRICT';
|
||||||
UPDATE t2 SET a = 1 WHERE a = -1;
|
UPDATE t2 SET a = 1 WHERE a = -1;
|
||||||
*** slave must stop
|
*** slave must stop (Key was not found)
|
||||||
Last_SQL_Error
|
Last_SQL_Error
|
||||||
0
|
1032
|
||||||
set global slave_exec_mode='IDEMPOTENT';
|
set global slave_exec_mode='IDEMPOTENT';
|
||||||
start slave sql_thread;
|
start slave sql_thread;
|
||||||
SET @@global.slave_exec_mode= @old_slave_exec_mode;
|
SET @@global.slave_exec_mode= @old_slave_exec_mode;
|
||||||
|
@@ -74,19 +74,16 @@ Last_SQL_Error
|
|||||||
drop table t1;
|
drop table t1;
|
||||||
create table t1(a int primary key);
|
create table t1(a int primary key);
|
||||||
insert into t1 values (1),(2);
|
insert into t1 values (1),(2);
|
||||||
delete from t1 where @@server_id=1;
|
SET SQL_LOG_BIN=0;
|
||||||
Warnings:
|
delete from t1;
|
||||||
Warning 1592 Statement is not safe to log in statement format.
|
SET SQL_LOG_BIN=1;
|
||||||
set sql_mode=strict_trans_tables;
|
set sql_mode=strict_trans_tables;
|
||||||
insert into t1 values (7), (8), (9);
|
insert into t1 values (1), (2), (3);
|
||||||
[on slave]
|
[on slave]
|
||||||
select * from t1;
|
select * from t1;
|
||||||
a
|
a
|
||||||
1
|
1
|
||||||
2
|
2
|
||||||
7
|
|
||||||
8
|
|
||||||
9
|
|
||||||
SHOW SLAVE STATUS;
|
SHOW SLAVE STATUS;
|
||||||
Slave_IO_State #
|
Slave_IO_State #
|
||||||
Master_Host 127.0.0.1
|
Master_Host 127.0.0.1
|
||||||
@@ -128,3 +125,84 @@ Last_SQL_Errno 0
|
|||||||
Last_SQL_Error
|
Last_SQL_Error
|
||||||
==== Clean Up ====
|
==== Clean Up ====
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
==== Using Innodb ====
|
||||||
|
SET SQL_LOG_BIN=0;
|
||||||
|
CREATE TABLE t1(id INT NOT NULL PRIMARY KEY, data INT) Engine=InnoDB;
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
Table Create Table
|
||||||
|
t1 CREATE TABLE `t1` (
|
||||||
|
`id` int(11) NOT NULL,
|
||||||
|
`data` int(11) DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||||
|
SET SQL_LOG_BIN=1;
|
||||||
|
CREATE TABLE t1(id INT NOT NULL PRIMARY KEY, data INT) Engine=InnoDB;
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
Table Create Table
|
||||||
|
t1 CREATE TABLE `t1` (
|
||||||
|
`id` int(11) NOT NULL,
|
||||||
|
`data` int(11) DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||||
|
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;
|
||||||
|
|
||||||
|
SELECT *, "INNODB SET SLAVE DATA" FROM t1 ORDER BY id;
|
||||||
|
id data INNODB SET SLAVE DATA
|
||||||
|
1 1 INNODB SET SLAVE DATA
|
||||||
|
2 1 INNODB SET SLAVE DATA
|
||||||
|
3 1 INNODB SET SLAVE DATA
|
||||||
|
4 1 INNODB SET SLAVE DATA
|
||||||
|
SELECT *, "INNODB SET MASTER DATA" FROM t1 ORDER BY id;
|
||||||
|
id data INNODB SET MASTER DATA
|
||||||
|
4 2 INNODB SET MASTER DATA
|
||||||
|
5 2 INNODB SET MASTER DATA
|
||||||
|
6 2 INNODB SET MASTER DATA
|
||||||
|
==== Using MyIsam ====
|
||||||
|
SET SQL_LOG_BIN=0;
|
||||||
|
CREATE TABLE t2(id INT NOT NULL PRIMARY KEY, data INT) Engine=MyIsam;
|
||||||
|
SHOW CREATE TABLE t2;
|
||||||
|
Table Create Table
|
||||||
|
t2 CREATE TABLE `t2` (
|
||||||
|
`id` int(11) NOT NULL,
|
||||||
|
`data` int(11) DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||||
|
SET SQL_LOG_BIN=1;
|
||||||
|
CREATE TABLE t2(id INT NOT NULL PRIMARY KEY, data INT) Engine=MyIsam;
|
||||||
|
SHOW CREATE TABLE t2;
|
||||||
|
Table Create Table
|
||||||
|
t2 CREATE TABLE `t2` (
|
||||||
|
`id` int(11) NOT NULL,
|
||||||
|
`data` int(11) DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||||
|
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;
|
||||||
|
|
||||||
|
SELECT *, "MYISAM SET SLAVE DATA" FROM t2 ORDER BY id;
|
||||||
|
id data MYISAM SET SLAVE DATA
|
||||||
|
2 1 MYISAM SET SLAVE DATA
|
||||||
|
3 1 MYISAM SET SLAVE DATA
|
||||||
|
4 2 MYISAM SET SLAVE DATA
|
||||||
|
5 1 MYISAM SET SLAVE DATA
|
||||||
|
SELECT *, "MYISAM SET MASTER DATA" FROM t2 ORDER BY id;
|
||||||
|
id data MYISAM SET MASTER DATA
|
||||||
|
4 2 MYISAM SET MASTER DATA
|
||||||
|
5 2 MYISAM SET MASTER DATA
|
||||||
|
6 2 MYISAM SET MASTER DATA
|
||||||
|
==== Clean Up ====
|
||||||
|
DROP TABLE t1;
|
||||||
|
DROP TABLE t2;
|
||||||
|
@@ -208,7 +208,7 @@ select * from ti1 order by b /* must be (2),(3) */;
|
|||||||
|
|
||||||
# foreign key: row is referenced
|
# foreign key: row is referenced
|
||||||
|
|
||||||
--echo *** slave must stop
|
--echo *** slave must stop (Trying to delete a referenced foreing key)
|
||||||
connection slave;
|
connection slave;
|
||||||
source include/wait_for_slave_sql_to_stop.inc;
|
source include/wait_for_slave_sql_to_stop.inc;
|
||||||
|
|
||||||
@@ -242,7 +242,7 @@ delete from ti1 where b=3;
|
|||||||
connection master;
|
connection master;
|
||||||
insert into ti2 set a=3, b=3 /* offending write event */;
|
insert into ti2 set a=3, b=3 /* offending write event */;
|
||||||
|
|
||||||
--echo *** slave must stop
|
--echo *** slave must stop (Trying to insert an invalid foreign key)
|
||||||
connection slave;
|
connection slave;
|
||||||
source include/wait_for_slave_sql_to_stop.inc;
|
source include/wait_for_slave_sql_to_stop.inc;
|
||||||
|
|
||||||
@@ -281,7 +281,7 @@ insert into ti1 set b=1;
|
|||||||
connection master;
|
connection master;
|
||||||
insert into ti1 set b=1 /* offending write event */;
|
insert into ti1 set b=1 /* offending write event */;
|
||||||
|
|
||||||
--echo *** slave must stop
|
--echo *** slave must stop (Trying to insert a dupliacte key)
|
||||||
connection slave;
|
connection slave;
|
||||||
source include/wait_for_slave_sql_to_stop.inc;
|
source include/wait_for_slave_sql_to_stop.inc;
|
||||||
|
|
||||||
@@ -316,7 +316,7 @@ DELETE FROM t2 WHERE a = -2;
|
|||||||
connection master;
|
connection master;
|
||||||
DELETE FROM t1 WHERE a = -2;
|
DELETE FROM t1 WHERE a = -2;
|
||||||
|
|
||||||
--echo *** slave must stop
|
--echo *** slave must stop (Key was not found)
|
||||||
connection slave;
|
connection slave;
|
||||||
source include/wait_for_slave_sql_to_stop.inc;
|
source include/wait_for_slave_sql_to_stop.inc;
|
||||||
|
|
||||||
@@ -334,7 +334,7 @@ set global slave_exec_mode='STRICT';
|
|||||||
|
|
||||||
connection master;
|
connection master;
|
||||||
DELETE FROM t2 WHERE a = -2;
|
DELETE FROM t2 WHERE a = -2;
|
||||||
--echo *** slave must stop
|
--echo *** slave must stop (Key was not found)
|
||||||
connection slave;
|
connection slave;
|
||||||
source include/wait_for_slave_sql_to_stop.inc;
|
source include/wait_for_slave_sql_to_stop.inc;
|
||||||
|
|
||||||
@@ -356,7 +356,7 @@ UPDATE t2 SET a = 1 WHERE a = -1;
|
|||||||
connection master;
|
connection master;
|
||||||
UPDATE t1 SET a = 1 WHERE a = -1;
|
UPDATE t1 SET a = 1 WHERE a = -1;
|
||||||
|
|
||||||
--echo *** slave must stop
|
--echo *** slave must stop (Key was not found)
|
||||||
connection slave;
|
connection slave;
|
||||||
source include/wait_for_slave_sql_to_stop.inc;
|
source include/wait_for_slave_sql_to_stop.inc;
|
||||||
|
|
||||||
@@ -376,7 +376,7 @@ set global slave_exec_mode='STRICT';
|
|||||||
connection master;
|
connection master;
|
||||||
UPDATE t2 SET a = 1 WHERE a = -1;
|
UPDATE t2 SET a = 1 WHERE a = -1;
|
||||||
|
|
||||||
--echo *** slave must stop
|
--echo *** slave must stop (Key was not found)
|
||||||
connection slave;
|
connection slave;
|
||||||
source include/wait_for_slave_sql_to_stop.inc;
|
source include/wait_for_slave_sql_to_stop.inc;
|
||||||
|
|
||||||
|
@@ -8,18 +8,23 @@
|
|||||||
# ==== Method ====
|
# ==== Method ====
|
||||||
#
|
#
|
||||||
# We run the slave with --slave-skip-errors=1062 (the code for
|
# We run the slave with --slave-skip-errors=1062 (the code for
|
||||||
# duplicate key). On slave, we insert value 1 in a table, and then,
|
# duplicate key). Then we have two set of tests. In the first
|
||||||
# on master, we insert value 1 in the table. The error should be
|
# set, we insert value 1 in a table on the slave, and then, on
|
||||||
# ignored on slave.
|
# 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 ====
|
# ==== Related bugs ====
|
||||||
#
|
#
|
||||||
# BUG#28839: Errors in strict mode silently stop SQL thread if --slave-skip-errors exists
|
# 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 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/master-slave.inc;
|
source include/master-slave.inc;
|
||||||
source include/have_binlog_format_statement.inc;
|
source include/have_innodb.inc;
|
||||||
|
|
||||||
|
|
||||||
--echo ==== Test Without sql_mode=strict_trans_tables ====
|
--echo ==== Test Without sql_mode=strict_trans_tables ====
|
||||||
|
|
||||||
@@ -64,9 +69,11 @@ sync_slave_with_master;
|
|||||||
connection master;
|
connection master;
|
||||||
create table t1(a int primary key);
|
create table t1(a int primary key);
|
||||||
insert into t1 values (1),(2);
|
insert into t1 values (1),(2);
|
||||||
delete from t1 where @@server_id=1;
|
SET SQL_LOG_BIN=0;
|
||||||
|
delete from t1;
|
||||||
|
SET SQL_LOG_BIN=1;
|
||||||
set sql_mode=strict_trans_tables;
|
set sql_mode=strict_trans_tables;
|
||||||
insert into t1 values (7), (8), (9);
|
insert into t1 values (1), (2), (3);
|
||||||
|
|
||||||
--echo [on slave]
|
--echo [on slave]
|
||||||
sync_slave_with_master;
|
sync_slave_with_master;
|
||||||
@@ -80,3 +87,93 @@ connection master;
|
|||||||
drop table t1;
|
drop table t1;
|
||||||
sync_slave_with_master;
|
sync_slave_with_master;
|
||||||
# End of 5.0 tests
|
# 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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
connection slave;
|
||||||
|
|
||||||
|
SELECT *, "INNODB SET SLAVE DATA" FROM t1 ORDER BY id;
|
||||||
|
|
||||||
|
connection master;
|
||||||
|
|
||||||
|
SELECT *, "INNODB SET MASTER DATA" FROM t1 ORDER BY id;
|
||||||
|
|
||||||
|
--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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
connection slave;
|
||||||
|
|
||||||
|
SELECT *, "MYISAM SET SLAVE DATA" FROM t2 ORDER BY id;
|
||||||
|
|
||||||
|
connection master;
|
||||||
|
|
||||||
|
SELECT *, "MYISAM SET MASTER DATA" FROM t2 ORDER BY id;
|
||||||
|
|
||||||
|
--echo ==== Clean Up ====
|
||||||
|
|
||||||
|
connection master;
|
||||||
|
|
||||||
|
DROP TABLE t1;
|
||||||
|
DROP TABLE t2;
|
||||||
|
|
||||||
|
sync_slave_with_master;
|
||||||
|
165
sql/log_event.cc
165
sql/log_event.cc
@@ -277,6 +277,47 @@ static void clear_all_errors(THD *thd, Relay_log_info *rli)
|
|||||||
rli->clear_error();
|
rli->clear_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline int idempotent_error_code(int err_code)
|
||||||
|
{
|
||||||
|
int ret= 0;
|
||||||
|
|
||||||
|
switch (err_code)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
ret= 1;
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
The following list of "idempotent" errors
|
||||||
|
means that an error from the list might happen
|
||||||
|
because of idempotent (more than once)
|
||||||
|
applying of a binlog file.
|
||||||
|
Notice, that binlog has a ddl operation its
|
||||||
|
second applying may cause
|
||||||
|
|
||||||
|
case HA_ERR_TABLE_DEF_CHANGED:
|
||||||
|
case HA_ERR_CANNOT_ADD_FOREIGN:
|
||||||
|
|
||||||
|
which are not included into to the list.
|
||||||
|
|
||||||
|
Note that HA_ERR_RECORD_DELETED is not in the list since
|
||||||
|
do_exec_row() should not return that error code.
|
||||||
|
*/
|
||||||
|
case HA_ERR_RECORD_CHANGED:
|
||||||
|
case HA_ERR_KEY_NOT_FOUND:
|
||||||
|
case HA_ERR_END_OF_FILE:
|
||||||
|
case HA_ERR_FOUND_DUPP_KEY:
|
||||||
|
case HA_ERR_FOUND_DUPP_UNIQUE:
|
||||||
|
case HA_ERR_FOREIGN_DUPLICATE_KEY:
|
||||||
|
case HA_ERR_NO_REFERENCED_ROW:
|
||||||
|
case HA_ERR_ROW_IS_REFERENCED:
|
||||||
|
ret= 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret= 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Ignore error code specified on command line.
|
Ignore error code specified on command line.
|
||||||
@@ -301,14 +342,37 @@ inline int ignored_error_code(int err_code)
|
|||||||
return ((err_code == ER_SLAVE_IGNORED_TABLE) ||
|
return ((err_code == ER_SLAVE_IGNORED_TABLE) ||
|
||||||
(use_slave_mask && bitmap_is_set(&slave_error_mask, err_code)));
|
(use_slave_mask && bitmap_is_set(&slave_error_mask, err_code)));
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
This function converts an engine's error to a server error.
|
||||||
|
|
||||||
|
If the thread does not have an error already reported, it tries to
|
||||||
|
define it by calling the engine's method print_error. However, if a
|
||||||
|
mapping is not found, it uses the ER_UNKNOWN_ERROR and prints out a
|
||||||
|
warning message.
|
||||||
|
*/
|
||||||
|
int convert_handler_error(int error, THD* thd, TABLE *table)
|
||||||
|
{
|
||||||
|
uint actual_error= (thd->is_error() ? thd->main_da.sql_errno() :
|
||||||
|
0);
|
||||||
|
|
||||||
|
if (actual_error == 0)
|
||||||
|
{
|
||||||
|
table->file->print_error(error, MYF(0));
|
||||||
|
actual_error= (thd->is_error() ? thd->main_da.sql_errno() :
|
||||||
|
ER_UNKNOWN_ERROR);
|
||||||
|
if (actual_error == ER_UNKNOWN_ERROR)
|
||||||
|
if (global_system_variables.log_warnings)
|
||||||
|
sql_print_warning("Unknown error detected %d in handler", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (actual_error);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
pretty_print_str()
|
pretty_print_str()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
|
|
||||||
static char *pretty_print_str(char *packet, const char *str, int len)
|
static char *pretty_print_str(char *packet, const char *str, int len)
|
||||||
{
|
{
|
||||||
const char *end= str + len;
|
const char *end= str + len;
|
||||||
@@ -7158,7 +7222,9 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Error reporting borrowed from Query_log_event with many excessive
|
Error reporting borrowed from Query_log_event with many excessive
|
||||||
simplifications (we don't honour --slave-skip-errors)
|
simplifications.
|
||||||
|
We should not honour --slave-skip-errors at this point as we are
|
||||||
|
having severe errors which should not be skiped.
|
||||||
*/
|
*/
|
||||||
rli->report(ERROR_LEVEL, actual_error,
|
rli->report(ERROR_LEVEL, actual_error,
|
||||||
"Error '%s' on opening tables",
|
"Error '%s' on opening tables",
|
||||||
@@ -7184,6 +7250,10 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
|
|||||||
{
|
{
|
||||||
if (ptr->m_tabledef.compatible_with(rli, ptr->table))
|
if (ptr->m_tabledef.compatible_with(rli, ptr->table))
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
We should not honour --slave-skip-errors at this point as we are
|
||||||
|
having severe errors which should not be skiped.
|
||||||
|
*/
|
||||||
mysql_unlock_tables(thd, thd->lock);
|
mysql_unlock_tables(thd, thd->lock);
|
||||||
thd->lock= 0;
|
thd->lock= 0;
|
||||||
thd->is_slave_error= 1;
|
thd->is_slave_error= 1;
|
||||||
@@ -7275,7 +7345,6 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
|
|||||||
|
|
||||||
// Do event specific preparations
|
// Do event specific preparations
|
||||||
error= do_before_row_operations(rli);
|
error= do_before_row_operations(rli);
|
||||||
|
|
||||||
// row processing loop
|
// row processing loop
|
||||||
|
|
||||||
while (error == 0 && m_curr_row < m_rows_end)
|
while (error == 0 && m_curr_row < m_rows_end)
|
||||||
@@ -7291,48 +7360,27 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
|
|||||||
DBUG_ASSERT(error != HA_ERR_RECORD_DELETED);
|
DBUG_ASSERT(error != HA_ERR_RECORD_DELETED);
|
||||||
|
|
||||||
table->in_use = old_thd;
|
table->in_use = old_thd;
|
||||||
switch (error)
|
|
||||||
|
if (error)
|
||||||
{
|
{
|
||||||
case 0:
|
int actual_error= convert_handler_error(error, thd, table);
|
||||||
break;
|
bool idempotent_error= (idempotent_error_code(error) &&
|
||||||
/*
|
((bit_is_set(slave_exec_mode,
|
||||||
The following list of "idempotent" errors
|
SLAVE_EXEC_MODE_IDEMPOTENT)) == 1));
|
||||||
means that an error from the list might happen
|
bool ignored_error= (idempotent_error == 0 ?
|
||||||
because of idempotent (more than once)
|
ignored_error_code(actual_error) : 0);
|
||||||
applying of a binlog file.
|
|
||||||
Notice, that binlog has a ddl operation its
|
|
||||||
second applying may cause
|
|
||||||
|
|
||||||
case HA_ERR_TABLE_DEF_CHANGED:
|
if (idempotent_error || ignored_error)
|
||||||
case HA_ERR_CANNOT_ADD_FOREIGN:
|
|
||||||
|
|
||||||
which are not included into to the list.
|
|
||||||
|
|
||||||
Note that HA_ERR_RECORD_DELETED is not in the list since
|
|
||||||
do_exec_row() should not return that error code.
|
|
||||||
*/
|
|
||||||
case HA_ERR_RECORD_CHANGED:
|
|
||||||
case HA_ERR_KEY_NOT_FOUND:
|
|
||||||
case HA_ERR_END_OF_FILE:
|
|
||||||
case HA_ERR_FOUND_DUPP_KEY:
|
|
||||||
case HA_ERR_FOUND_DUPP_UNIQUE:
|
|
||||||
case HA_ERR_FOREIGN_DUPLICATE_KEY:
|
|
||||||
case HA_ERR_NO_REFERENCED_ROW:
|
|
||||||
case HA_ERR_ROW_IS_REFERENCED:
|
|
||||||
|
|
||||||
if (bit_is_set(slave_exec_mode, SLAVE_EXEC_MODE_IDEMPOTENT) == 1)
|
|
||||||
{
|
{
|
||||||
if (global_system_variables.log_warnings)
|
if (global_system_variables.log_warnings)
|
||||||
slave_rows_error_report(WARNING_LEVEL, error, rli, thd, table,
|
slave_rows_error_report(WARNING_LEVEL, error, rli, thd, table,
|
||||||
get_type_str(),
|
get_type_str(),
|
||||||
RPL_LOG_NAME, (ulong) log_pos);
|
RPL_LOG_NAME, (ulong) log_pos);
|
||||||
|
clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
|
||||||
error= 0;
|
error= 0;
|
||||||
|
if (idempotent_error == 0)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
thd->is_slave_error= 1;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -7346,7 +7394,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
|
|||||||
(ulong) m_curr_row, (ulong) m_curr_row_end, (ulong) m_rows_end));
|
(ulong) m_curr_row, (ulong) m_curr_row_end, (ulong) m_rows_end));
|
||||||
|
|
||||||
if (!m_curr_row_end && !error)
|
if (!m_curr_row_end && !error)
|
||||||
unpack_current_row(rli);
|
error= unpack_current_row(rli);
|
||||||
|
|
||||||
// at this moment m_curr_row_end should be set
|
// at this moment m_curr_row_end should be set
|
||||||
DBUG_ASSERT(error || m_curr_row_end != NULL);
|
DBUG_ASSERT(error || m_curr_row_end != NULL);
|
||||||
@@ -7359,7 +7407,19 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
|
|||||||
|
|
||||||
DBUG_EXECUTE_IF("STOP_SLAVE_after_first_Rows_event",
|
DBUG_EXECUTE_IF("STOP_SLAVE_after_first_Rows_event",
|
||||||
const_cast<Relay_log_info*>(rli)->abort_slave= 1;);
|
const_cast<Relay_log_info*>(rli)->abort_slave= 1;);
|
||||||
error= do_after_row_operations(rli, error);
|
|
||||||
|
if ((error= do_after_row_operations(rli, error)) &&
|
||||||
|
ignored_error_code(convert_handler_error(error, thd, table)))
|
||||||
|
{
|
||||||
|
|
||||||
|
if (global_system_variables.log_warnings)
|
||||||
|
slave_rows_error_report(WARNING_LEVEL, error, rli, thd, table,
|
||||||
|
get_type_str(),
|
||||||
|
RPL_LOG_NAME, (ulong) log_pos);
|
||||||
|
clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
|
||||||
|
error= 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!cache_stmt)
|
if (!cache_stmt)
|
||||||
{
|
{
|
||||||
DBUG_PRINT("info", ("Marked that we need to keep log"));
|
DBUG_PRINT("info", ("Marked that we need to keep log"));
|
||||||
@@ -7374,37 +7434,22 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
|
|||||||
if (rli->tables_to_lock && get_flags(STMT_END_F))
|
if (rli->tables_to_lock && get_flags(STMT_END_F))
|
||||||
const_cast<Relay_log_info*>(rli)->clear_tables_to_lock();
|
const_cast<Relay_log_info*>(rli)->clear_tables_to_lock();
|
||||||
|
|
||||||
if (error)
|
|
||||||
{ /* error has occured during the transaction */
|
|
||||||
slave_rows_error_report(ERROR_LEVEL, error, rli, thd, table,
|
|
||||||
get_type_str(), RPL_LOG_NAME, (ulong) log_pos);
|
|
||||||
}
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
/*
|
slave_rows_error_report(ERROR_LEVEL, error, rli, thd, table,
|
||||||
If one day we honour --skip-slave-errors in row-based replication, and
|
get_type_str(),
|
||||||
the error should be skipped, then we would clear mappings, rollback,
|
RPL_LOG_NAME, (ulong) log_pos);
|
||||||
close tables, but the slave SQL thread would not stop and then may
|
|
||||||
assume the mapping is still available, the tables are still open...
|
|
||||||
So then we should clear mappings/rollback/close here only if this is a
|
|
||||||
STMT_END_F.
|
|
||||||
For now we code, knowing that error is not skippable and so slave SQL
|
|
||||||
thread is certainly going to stop.
|
|
||||||
rollback at the caller along with sbr.
|
|
||||||
*/
|
|
||||||
thd->reset_current_stmt_binlog_row_based();
|
thd->reset_current_stmt_binlog_row_based();
|
||||||
const_cast<Relay_log_info*>(rli)->cleanup_context(thd, error);
|
const_cast<Relay_log_info*>(rli)->cleanup_context(thd, error);
|
||||||
thd->is_slave_error= 1;
|
thd->is_slave_error= 1;
|
||||||
DBUG_RETURN(error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This code would ideally be placed in do_update_pos() instead, but
|
This code would ideally be placed in do_update_pos() instead, but
|
||||||
since we have no access to table there, we do the setting of
|
since we have no access to table there, we do the setting of
|
||||||
last_event_start_time here instead.
|
last_event_start_time here instead.
|
||||||
*/
|
*/
|
||||||
if (table && (table->s->primary_key == MAX_KEY) &&
|
else if (table && (table->s->primary_key == MAX_KEY) &&
|
||||||
!cache_stmt && get_flags(STMT_END_F) == RLE_NO_FLAGS)
|
!cache_stmt && get_flags(STMT_END_F) == RLE_NO_FLAGS)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
------------ Temporary fix until WL#2975 is implemented ---------
|
------------ Temporary fix until WL#2975 is implemented ---------
|
||||||
@@ -7425,7 +7470,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
|
|||||||
const_cast<Relay_log_info*>(rli)->last_event_start_time= my_time(0);
|
const_cast<Relay_log_info*>(rli)->last_event_start_time= my_time(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
Log_event::enum_skip_reason
|
Log_event::enum_skip_reason
|
||||||
|
@@ -361,6 +361,7 @@ void init_slave_skip_errors(const char* arg)
|
|||||||
if (!my_strnncoll(system_charset_info,(uchar*)arg,4,(const uchar*)"all",4))
|
if (!my_strnncoll(system_charset_info,(uchar*)arg,4,(const uchar*)"all",4))
|
||||||
{
|
{
|
||||||
bitmap_set_all(&slave_error_mask);
|
bitmap_set_all(&slave_error_mask);
|
||||||
|
print_slave_skip_errors();
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
for (p= arg ; *p; )
|
for (p= arg ; *p; )
|
||||||
|
Reference in New Issue
Block a user