From 48596842bae0779149ce95bc13b6499e421c2f47 Mon Sep 17 00:00:00 2001 From: Mahmoud Khaled Date: Wed, 11 Mar 2026 06:31:36 +0200 Subject: [PATCH] #MDEV-26479 Add support for slave_skip_errors="ddl_exist_errors" Implement ddl_exist_errors alias option for slave_skip_errors which allows slave to skip DDL errors such as: ER_DB_CREATE_EXISTS ER_DB_DROP_EXISTS ER_TABLE_EXISTS_ERROR ER_BAD_TABLE_ERROR ER_BAD_FIELD_ERROR ER_DUP_FIELDNAME ER_DUP_KEYNAME ER_MULTIPLE_PRI_KEY ER_CANT_DROP_FIELD_OR_KEY ER_NO_SUCH_TABLE Test: Added rpl.rpl_skip_errors_ddl test to verify all errors are correctly skipped. --- .../rpl/r/rpl_slave_skip_errors_ddl.result | 207 ++++++++++++ .../suite/rpl/t/rpl_slave_skip_errors_ddl.opt | 1 + .../rpl/t/rpl_slave_skip_errors_ddl.test | 310 ++++++++++++++++++ sql/slave.cc | 26 ++ 4 files changed, 544 insertions(+) create mode 100644 mysql-test/suite/rpl/r/rpl_slave_skip_errors_ddl.result create mode 100644 mysql-test/suite/rpl/t/rpl_slave_skip_errors_ddl.opt create mode 100644 mysql-test/suite/rpl/t/rpl_slave_skip_errors_ddl.test diff --git a/mysql-test/suite/rpl/r/rpl_slave_skip_errors_ddl.result b/mysql-test/suite/rpl/r/rpl_slave_skip_errors_ddl.result new file mode 100644 index 0000000000000..7b4a870cf723a --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_slave_skip_errors_ddl.result @@ -0,0 +1,207 @@ +# MDEV-26479 Add support for slave_skip_errors="ddl_exist_errors" +include/master-slave.inc +[connection master] +# we just verfiy that codes is set correctly +connection slave; +SHOW VARIABLES LIKE 'slave_skip_errors'; +Variable_name Value +slave_skip_errors 1007,1008,1050,1051,1054,1060,1061,1068,1091,1146 +connection master; +CREATE TABLE t1 (a INT PRIMARY KEY); +# +# Test 1: ER_DB_CREATE_EXISTS ( 1007 ) +# +connection slave; +include/stop_slave.inc +CREATE DATABASE test_ddl1; +include/start_slave.inc +connection master; +CREATE DATABASE test_ddl1; +INSERT INTO t1 VALUES (1); +connection slave; +connection slave; +include/check_slave_param.inc [Slave_SQL_Running] +include/diff_tables.inc [master:t1, slave:t1] +# Error 1007 (ER_DB_CREATE_EXISTS) skipped successfully +# +# Test 2: ER_DB_DROP_EXISTS (1008) +# +connection master; +CREATE DATABASE test_ddl2; +connection slave; +connection slave; +include/stop_slave.inc +DROP DATABASE test_ddl2; +include/start_slave.inc +connection master; +DROP DATABASE test_ddl2; +INSERT INTO t1 VALUES (2); +connection slave; +connection slave; +include/check_slave_param.inc [Slave_SQL_Running] +include/diff_tables.inc [master:t1, slave:t1] +# Error 1008 (ER_DB_DROP_EXISTS) skipped successfully +# +# Test 3: ER_TABLE_EXISTS_ERROR (1050) +# +connection slave; +include/stop_slave.inc +CREATE TABLE t2 (c INT); +include/start_slave.inc +connection master; +CREATE TABLE t2 (b INT); +INSERT INTO t1 VALUES (3); +connection slave; +connection slave; +include/check_slave_param.inc [Slave_SQL_Running] +include/diff_tables.inc [master:t1, slave:t1] +# Error 1050 (ER_TABLE_EXISTS_ERROR) skipped successfully +# +# Test 4: ER_BAD_TABLE_ERROR (1051) +# +connection master; +CREATE TABLE t3 (d INT); +connection slave; +connection slave; +include/stop_slave.inc +DROP TABLE t3; +include/start_slave.inc +connection master; +DROP TABLE t3; +INSERT INTO t1 VALUES (4); +connection slave; +connection slave; +include/check_slave_param.inc [Slave_SQL_Running] +include/diff_tables.inc [master:t1, slave:t1] +# Error 1051 (ER_BAD_TABLE_ERROR) skipped successfully +# +# Test 5: ER_BAD_FIELD_ERROR (1054) +# +connection master; +CREATE TABLE t4 (id INT, name VARCHAR(50)); +connection slave; +connection slave; +include/stop_slave.inc +ALTER TABLE t4 DROP COLUMN name; +include/start_slave.inc +connection master; +ALTER TABLE t4 DROP COLUMN name; +INSERT INTO t1 VALUES (5); +connection slave; +connection slave; +include/check_slave_param.inc [Slave_SQL_Running] +include/diff_tables.inc [master:t1, slave:t1] +# Error 1054 (ER_BAD_FIELD_ERROR) skipped successfully +# +# Test 6: ER_DUP_FIELDNAME (1060) +# +connection master; +CREATE TABLE t5 (id INT); +connection slave; +connection slave; +include/stop_slave.inc +ALTER TABLE t5 ADD COLUMN name VARCHAR(100); +include/start_slave.inc +connection master; +ALTER TABLE t5 ADD COLUMN name VARCHAR(100); +INSERT INTO t1 VALUES (6); +connection slave; +connection slave; +include/check_slave_param.inc [Slave_SQL_Running] +include/diff_tables.inc [master:t1, slave:t1] +# Error 1060 (ER_DUP_FIELDNAME) skipped successfully +# +# Test 7: ER_DUP_KEYNAME (1061) +# +connection master; +CREATE TABLE t6 (id INT, value VARCHAR(100)); +connection slave; +connection slave; +include/stop_slave.inc +ALTER TABLE t6 ADD INDEX idx_value (value); +include/start_slave.inc +connection master; +ALTER TABLE t6 ADD INDEX idx_value (value); +INSERT INTO t1 VALUES (7); +connection slave; +connection slave; +include/check_slave_param.inc [Slave_SQL_Running] +include/diff_tables.inc [master:t1, slave:t1] +# Error 1061 (ER_DUP_KEYNAME) skipped successfully +# +# Test 8: ER_MULTIPLE_PRI_KEY (1068) +# +connection master; +CREATE TABLE t7 (id INT); +connection slave; +connection slave; +include/stop_slave.inc +ALTER TABLE t7 ADD PRIMARY KEY (id); +include/start_slave.inc +connection master; +ALTER TABLE t7 ADD PRIMARY KEY (id); +INSERT INTO t1 VALUES (8); +connection slave; +connection slave; +include/check_slave_param.inc [Slave_SQL_Running] +include/diff_tables.inc [master:t1, slave:t1] +# Error 1068 (ER_MULTIPLE_PRI_KEY) skipped successfully +# +# Test 9: ER_CANT_DROP_FIELD_OR_KEY (1091) +# +connection master; +CREATE TABLE t8 (id INT, col1 VARCHAR(50), col2 INT); +connection slave; +connection slave; +include/stop_slave.inc +ALTER TABLE t8 DROP COLUMN col2; +include/start_slave.inc +connection master; +ALTER TABLE t8 DROP COLUMN col2; +INSERT INTO t1 VALUES (9); +connection slave; +connection slave; +include/check_slave_param.inc [Slave_SQL_Running] +include/diff_tables.inc [master:t1, slave:t1] +# Error 1091 (ER_CANT_DROP_FIELD_OR_KEY) skipped successfully +# +# Test 10: ER_NO_SUCH_TABLE (1146) +# +connection master; +CREATE TABLE t9 (e INT); +connection slave; +connection slave; +include/stop_slave.inc +DROP TABLE t9; +include/start_slave.inc +connection master; +ALTER TABLE t9 ADD COLUMN col1 INT; +INSERT INTO t1 VALUES (10); +connection slave; +connection slave; +include/check_slave_param.inc [Slave_SQL_Running] +include/diff_tables.inc [master:t1, slave:t1] +# Error 1146 (ER_NO_SUCH_TABLE) skipped successfully +# +# all errors skipped successfully +# +connection slave; +SELECT COUNT(*) as total_rows FROM t1; +total_rows +10 +Slave_IO_Running: Yes +Slave_SQL_Running: Yes +# +# Cleanup +# +connection master; +connection master; +DROP DATABASE IF EXISTS test_ddl1; +DROP DATABASE IF EXISTS test_ddl2; +Warnings: +Note 1008 Can't drop database 'test_ddl2'; database doesn't exist +DROP TABLE IF EXISTS t1, t2, t3, t4, t5, t6, t7, t8, t9; +Warnings: +Note 1051 Unknown table 'test.t3' +connection slave; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_slave_skip_errors_ddl.opt b/mysql-test/suite/rpl/t/rpl_slave_skip_errors_ddl.opt new file mode 100644 index 0000000000000..b76d2c4e460ab --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_slave_skip_errors_ddl.opt @@ -0,0 +1 @@ +--slave-skip-errors=ddl_exist_errors \ No newline at end of file diff --git a/mysql-test/suite/rpl/t/rpl_slave_skip_errors_ddl.test b/mysql-test/suite/rpl/t/rpl_slave_skip_errors_ddl.test new file mode 100644 index 0000000000000..827a12220d651 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_slave_skip_errors_ddl.test @@ -0,0 +1,310 @@ +--echo # MDEV-26479 Add support for slave_skip_errors="ddl_exist_errors" + +--source include/have_binlog_format_mixed.inc +--source include/master-slave.inc + +--echo # we just verfiy that codes is set correctly +--connection slave +SHOW VARIABLES LIKE 'slave_skip_errors'; + +--connection master +CREATE TABLE t1 (a INT PRIMARY KEY); + +--echo # +--echo # Test 1: ER_DB_CREATE_EXISTS ( 1007 ) +--echo # + +--connection slave +--source include/stop_slave.inc +CREATE DATABASE test_ddl1; +--source include/start_slave.inc + +--connection master +CREATE DATABASE test_ddl1; +INSERT INTO t1 VALUES (1); +--sync_slave_with_master + +--connection slave +--let $slave_param= Slave_SQL_Running +--let $slave_param_value= Yes +--source include/check_slave_param.inc + +--let $diff_tables= master:t1, slave:t1 +--source include/diff_tables.inc + +--echo # Error 1007 (ER_DB_CREATE_EXISTS) skipped successfully + +--echo # +--echo # Test 2: ER_DB_DROP_EXISTS (1008) +--echo # + +--connection master +CREATE DATABASE test_ddl2; +--sync_slave_with_master + +--connection slave +--source include/stop_slave.inc +DROP DATABASE test_ddl2; +--source include/start_slave.inc + +--connection master +DROP DATABASE test_ddl2; +INSERT INTO t1 VALUES (2); +--sync_slave_with_master + +--connection slave +--let $slave_param= Slave_SQL_Running +--let $slave_param_value= Yes +--source include/check_slave_param.inc + +--let $diff_tables= master:t1, slave:t1 +--source include/diff_tables.inc + +--echo # Error 1008 (ER_DB_DROP_EXISTS) skipped successfully + +--echo # +--echo # Test 3: ER_TABLE_EXISTS_ERROR (1050) +--echo # + +--connection slave +--source include/stop_slave.inc +CREATE TABLE t2 (c INT); +--source include/start_slave.inc + +--connection master +CREATE TABLE t2 (b INT); +INSERT INTO t1 VALUES (3); +--sync_slave_with_master + +--connection slave +--let $slave_param= Slave_SQL_Running +--let $slave_param_value= Yes +--source include/check_slave_param.inc + +--let $diff_tables= master:t1, slave:t1 +--source include/diff_tables.inc + +--echo # Error 1050 (ER_TABLE_EXISTS_ERROR) skipped successfully + +--echo # +--echo # Test 4: ER_BAD_TABLE_ERROR (1051) +--echo # + +--connection master +CREATE TABLE t3 (d INT); +--sync_slave_with_master + +--connection slave +--source include/stop_slave.inc +DROP TABLE t3; +--source include/start_slave.inc + +--connection master +DROP TABLE t3; +INSERT INTO t1 VALUES (4); +--sync_slave_with_master + +--connection slave +--let $slave_param= Slave_SQL_Running +--let $slave_param_value= Yes +--source include/check_slave_param.inc + +--let $diff_tables= master:t1, slave:t1 +--source include/diff_tables.inc + +--echo # Error 1051 (ER_BAD_TABLE_ERROR) skipped successfully + +--echo # +--echo # Test 5: ER_BAD_FIELD_ERROR (1054) +--echo # + +--connection master +CREATE TABLE t4 (id INT, name VARCHAR(50)); +--sync_slave_with_master + +--connection slave +--source include/stop_slave.inc +ALTER TABLE t4 DROP COLUMN name; +--source include/start_slave.inc + +--connection master +ALTER TABLE t4 DROP COLUMN name; +INSERT INTO t1 VALUES (5); +--sync_slave_with_master + +--connection slave +--let $slave_param= Slave_SQL_Running +--let $slave_param_value= Yes +--source include/check_slave_param.inc + +--let $diff_tables= master:t1, slave:t1 +--source include/diff_tables.inc + +--echo # Error 1054 (ER_BAD_FIELD_ERROR) skipped successfully + +--echo # +--echo # Test 6: ER_DUP_FIELDNAME (1060) +--echo # + +--connection master +CREATE TABLE t5 (id INT); +--sync_slave_with_master + +--connection slave +--source include/stop_slave.inc +ALTER TABLE t5 ADD COLUMN name VARCHAR(100); +--source include/start_slave.inc + +--connection master +ALTER TABLE t5 ADD COLUMN name VARCHAR(100); +INSERT INTO t1 VALUES (6); +--sync_slave_with_master + +--connection slave +--let $slave_param= Slave_SQL_Running +--let $slave_param_value= Yes +--source include/check_slave_param.inc + +--let $diff_tables= master:t1, slave:t1 +--source include/diff_tables.inc + +--echo # Error 1060 (ER_DUP_FIELDNAME) skipped successfully + +--echo # +--echo # Test 7: ER_DUP_KEYNAME (1061) +--echo # + +--connection master +CREATE TABLE t6 (id INT, value VARCHAR(100)); +--sync_slave_with_master + +--connection slave +--source include/stop_slave.inc +ALTER TABLE t6 ADD INDEX idx_value (value); +--source include/start_slave.inc + +--connection master +ALTER TABLE t6 ADD INDEX idx_value (value); +INSERT INTO t1 VALUES (7); +--sync_slave_with_master + +--connection slave +--let $slave_param= Slave_SQL_Running +--let $slave_param_value= Yes +--source include/check_slave_param.inc + +--let $diff_tables= master:t1, slave:t1 +--source include/diff_tables.inc + +--echo # Error 1061 (ER_DUP_KEYNAME) skipped successfully + +--echo # +--echo # Test 8: ER_MULTIPLE_PRI_KEY (1068) +--echo # + + +--connection master +CREATE TABLE t7 (id INT); +--sync_slave_with_master + +--connection slave +--source include/stop_slave.inc +ALTER TABLE t7 ADD PRIMARY KEY (id); +--source include/start_slave.inc + +--connection master +ALTER TABLE t7 ADD PRIMARY KEY (id); +INSERT INTO t1 VALUES (8); +--sync_slave_with_master + +--connection slave +--let $slave_param= Slave_SQL_Running +--let $slave_param_value= Yes +--source include/check_slave_param.inc + +--let $diff_tables= master:t1, slave:t1 +--source include/diff_tables.inc + +--echo # Error 1068 (ER_MULTIPLE_PRI_KEY) skipped successfully + +--echo # +--echo # Test 9: ER_CANT_DROP_FIELD_OR_KEY (1091) +--echo # + +--connection master +CREATE TABLE t8 (id INT, col1 VARCHAR(50), col2 INT); +--sync_slave_with_master + +--connection slave +--source include/stop_slave.inc +ALTER TABLE t8 DROP COLUMN col2; +--source include/start_slave.inc + +--connection master +ALTER TABLE t8 DROP COLUMN col2; +INSERT INTO t1 VALUES (9); +--sync_slave_with_master + +--connection slave +--let $slave_param= Slave_SQL_Running +--let $slave_param_value= Yes +--source include/check_slave_param.inc + +--let $diff_tables= master:t1, slave:t1 +--source include/diff_tables.inc + +--echo # Error 1091 (ER_CANT_DROP_FIELD_OR_KEY) skipped successfully + +--echo # +--echo # Test 10: ER_NO_SUCH_TABLE (1146) +--echo # + +--connection master +CREATE TABLE t9 (e INT); +--sync_slave_with_master + +--connection slave +--source include/stop_slave.inc +DROP TABLE t9; +--source include/start_slave.inc + +--connection master +ALTER TABLE t9 ADD COLUMN col1 INT; +INSERT INTO t1 VALUES (10); +--sync_slave_with_master + +--connection slave +--let $slave_param= Slave_SQL_Running +--let $slave_param_value= Yes +--source include/check_slave_param.inc + +--let $diff_tables= master:t1, slave:t1 +--source include/diff_tables.inc + +--echo # Error 1146 (ER_NO_SUCH_TABLE) skipped successfully + +--echo # +--echo # all errors skipped successfully +--echo # + +--connection slave +SELECT COUNT(*) as total_rows FROM t1; + +--let $slave_io_running= query_get_value(SHOW SLAVE STATUS, Slave_IO_Running, 1) +--let $slave_sql_running= query_get_value(SHOW SLAVE STATUS, Slave_SQL_Running, 1) + +--echo Slave_IO_Running: $slave_io_running +--echo Slave_SQL_Running: $slave_sql_running + +--echo # +--echo # Cleanup +--echo # + +--connection master +--connection master +DROP DATABASE IF EXISTS test_ddl1; +DROP DATABASE IF EXISTS test_ddl2; +DROP TABLE IF EXISTS t1, t2, t3, t4, t5, t6, t7, t8, t9; +--sync_slave_with_master + +--source include/rpl_end.inc diff --git a/sql/slave.cc b/sql/slave.cc index c96c93a598ac9..a36aaa045036b 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -785,6 +785,32 @@ bool init_slave_skip_errors(const char* arg) bitmap_set_all(&slave_error_mask); goto end; } + + if (!system_charset_info->strnncoll((uchar*)arg,sizeof("ddl_exist_errors")-1, + (const uchar*)STRING_WITH_LEN("ddl_exist_errors"))) + { + static const uint ddl_errors[]= { + ER_DB_CREATE_EXISTS, + ER_DB_DROP_EXISTS, + ER_TABLE_EXISTS_ERROR, + ER_BAD_TABLE_ERROR, + ER_BAD_FIELD_ERROR, + ER_DUP_FIELDNAME, + ER_DUP_KEYNAME, + ER_MULTIPLE_PRI_KEY, + ER_CANT_DROP_FIELD_OR_KEY, + ER_NO_SUCH_TABLE + }; + for (uint i= 0; i < array_elements(ddl_errors); i++) + { + bitmap_set_bit(&slave_error_mask, ddl_errors[i]); + } + if (strlen(arg) > strlen("ddl_exist_errors")) + { + arg+= strlen("ddl_exist_errors") + 1; + } + } + for (p= arg ; *p; ) { long err_code;