summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.cmake1
-rw-r--r--mysql-test/suite/rpl/r/rpl_filter_dbs_dynamic.result40
-rw-r--r--mysql-test/suite/rpl/r/rpl_filter_tables_dynamic.result127
-rw-r--r--mysql-test/suite/rpl/r/rpl_filter_wild_tables_dynamic.result26
-rw-r--r--mysql-test/suite/rpl/t/rpl_filter_dbs_dynamic.test65
-rw-r--r--mysql-test/suite/rpl/t/rpl_filter_tables_dynamic.test218
-rw-r--r--mysql-test/suite/rpl/t/rpl_filter_wild_tables_dynamic.test50
-rw-r--r--mysql-test/suite/sys_vars/r/replicate_do_db_basic.result37
-rw-r--r--mysql-test/suite/sys_vars/r/replicate_do_table_basic.result44
-rw-r--r--mysql-test/suite/sys_vars/r/replicate_ignore_db_basic.result37
-rw-r--r--mysql-test/suite/sys_vars/r/replicate_ignore_table_basic.result44
-rw-r--r--mysql-test/suite/sys_vars/r/replicate_wild_do_table_basic.result44
-rw-r--r--mysql-test/suite/sys_vars/r/replicate_wild_ignore_table_basic.result44
-rw-r--r--mysql-test/suite/sys_vars/t/replicate_do_db_basic.test39
-rw-r--r--mysql-test/suite/sys_vars/t/replicate_do_table_basic.test48
-rw-r--r--mysql-test/suite/sys_vars/t/replicate_ignore_db_basic.test39
-rw-r--r--mysql-test/suite/sys_vars/t/replicate_ignore_table_basic.test48
-rw-r--r--mysql-test/suite/sys_vars/t/replicate_wild_do_table_basic.test48
-rw-r--r--mysql-test/suite/sys_vars/t/replicate_wild_ignore_table_basic.test48
-rw-r--r--sql/rpl_filter.cc236
-rw-r--r--sql/rpl_filter.h24
-rw-r--r--sql/sys_vars.cc144
-rw-r--r--sql/sys_vars.h50
23 files changed, 1483 insertions, 18 deletions
diff --git a/configure.cmake b/configure.cmake
index 66ee73ddc03..88ae46cbcb6 100644
--- a/configure.cmake
+++ b/configure.cmake
@@ -435,7 +435,6 @@ CHECK_FUNCTION_EXISTS (strlcat HAVE_STRLCAT)
CHECK_FUNCTION_EXISTS (strsignal HAVE_STRSIGNAL)
CHECK_FUNCTION_EXISTS (fgetln HAVE_FGETLN)
CHECK_FUNCTION_EXISTS (strpbrk HAVE_STRPBRK)
-CHECK_FUNCTION_EXISTS (strsep HAVE_STRSEP)
CHECK_FUNCTION_EXISTS (strstr HAVE_STRSTR)
CHECK_FUNCTION_EXISTS (strtok_r HAVE_STRTOK_R)
CHECK_FUNCTION_EXISTS (strtol HAVE_STRTOL)
diff --git a/mysql-test/suite/rpl/r/rpl_filter_dbs_dynamic.result b/mysql-test/suite/rpl/r/rpl_filter_dbs_dynamic.result
new file mode 100644
index 00000000000..321b8d912e6
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_filter_dbs_dynamic.result
@@ -0,0 +1,40 @@
+include/master-slave.inc
+[connection master]
+SET @@GLOBAL.replicate_do_db="db1";
+ERROR HY000: This operation cannot be performed with a running slave; run STOP SLAVE first
+SET @@GLOBAL.replicate_ignore_db="db2";
+ERROR HY000: This operation cannot be performed with a running slave; run STOP SLAVE first
+include/stop_slave.inc
+SET @@GLOBAL.replicate_do_db="db1";
+SET @@GLOBAL.replicate_ignore_db="db2";
+include/start_slave.inc
+CREATE DATABASE db1;
+CREATE DATABASE db2;
+CREATE DATABASE db3;
+USE db1;
+CREATE TABLE t1 (a INT);
+USE db2;
+CREATE TABLE t2 (a INT);
+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);
+[on slave]
+SHOW DATABASES LIKE 'db%';
+Database (db%)
+db1
+SHOW TABLES IN db1 LIKE 't%';
+Tables_in_db1 (t%)
+t1
+[on master]
+[on master]
+DROP DATABASE IF EXISTS db1;
+DROP DATABASE IF EXISTS db2;
+DROP DATABASE IF EXISTS db3;
+include/rpl_end.inc
+SET @@GLOBAL.replicate_do_db="";
+SET @@GLOBAL.replicate_ignore_db="";
diff --git a/mysql-test/suite/rpl/r/rpl_filter_tables_dynamic.result b/mysql-test/suite/rpl/r/rpl_filter_tables_dynamic.result
new file mode 100644
index 00000000000..9eb803d17ea
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_filter_tables_dynamic.result
@@ -0,0 +1,127 @@
+include/master-slave.inc
+[connection master]
+SET @@GLOBAL.replicate_do_table="test.t1,test.t2,test.t3";
+ERROR HY000: This operation cannot be performed with a running slave; run STOP SLAVE first
+SET @@GLOBAL.replicate_ignore_table="test.t4,test.t5,test.t6";
+ERROR HY000: This operation cannot be performed with a running slave; run STOP SLAVE first
+include/stop_slave.inc
+SET @@GLOBAL.replicate_do_table="test.t1,test.t2,test.t3";
+SET @@GLOBAL.replicate_ignore_table="test.t4,test.t5,test.t6";
+include/start_slave.inc
+CREATE TABLE t1 (id int, a int);
+CREATE TABLE t2 (id int, b int);
+CREATE TABLE t3 (id int, c int);
+CREATE TABLE t4 (id int, d int);
+CREATE TABLE t5 (id int, e int);
+CREATE TABLE t6 (id int, f int);
+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);
+[on slave]
+SHOW TABLES LIKE 't%';
+Tables_in_test (t%)
+t1
+t2
+t3
+[on master]
+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;
+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;
+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;
+call mtr.add_suppression("Slave SQL.*Error .Table .test.t[47]. doesn.t exist. on query.* Error_code: 1146");
+UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET a=0 where t1.id=1;
+include/wait_for_slave_sql_error_and_skip.inc [errno=1146]
+Last_SQL_Error = 'Error 'Table 'test.t4' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET a=0 where t1.id=1''
+UPDATE t1 LEFT JOIN (t4, t7) ON (t1.id=t4.id and t1.id=t7.id) SET a=0 where t1.id=1;
+include/wait_for_slave_sql_error_and_skip.inc [errno=1146]
+Last_SQL_Error = 'Error 'Table 'test.t4' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t1 LEFT JOIN (t4, t7) ON (t1.id=t4.id and t1.id=t7.id) SET a=0 where t1.id=1''
+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;
+include/wait_for_slave_sql_error_and_skip.inc [errno=1146]
+Last_SQL_Error = 'Error 'Table 'test.t4' doesn't exist' on query. Default database: 'test'. Query: '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''
+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;
+include/wait_for_slave_sql_error_and_skip.inc [errno=1146]
+Last_SQL_Error = 'Error 'Table 'test.t7' doesn't exist' on query. Default database: 'test'. Query: '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''
+UPDATE t1 LEFT JOIN t7 ON (t1.id=t7.id) SET a=0, g=0 where t1.id=1;
+include/wait_for_slave_sql_error_and_skip.inc [errno=1146]
+Last_SQL_Error = 'Error 'Table 'test.t7' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t1 LEFT JOIN t7 ON (t1.id=t7.id) SET a=0, g=0 where t1.id=1''
+UPDATE t7 LEFT JOIN t1 ON (t1.id=t7.id) SET a=0, g=0 where t7.id=1;
+include/wait_for_slave_sql_error_and_skip.inc [errno=1146]
+Last_SQL_Error = 'Error 'Table 'test.t7' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t7 LEFT JOIN t1 ON (t1.id=t7.id) SET a=0, g=0 where t7.id=1''
+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;
+include/wait_for_slave_sql_error_and_skip.inc [errno=1146]
+Last_SQL_Error = 'Error 'Table 'test.t4' doesn't exist' on query. Default database: 'test'. Query: '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''
+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;
+include/wait_for_slave_sql_error_and_skip.inc [errno=1146]
+Last_SQL_Error = 'Error 'Table 'test.t4' doesn't exist' on query. Default database: 'test'. Query: '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''
+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;
+include/wait_for_slave_sql_error_and_skip.inc [errno=1146]
+Last_SQL_Error = 'Error 'Table 'test.t7' doesn't exist' on query. Default database: 'test'. Query: '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''
+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;
+include/wait_for_slave_sql_error_and_skip.inc [errno=1146]
+Last_SQL_Error = 'Error 'Table 'test.t7' doesn't exist' on query. Default database: 'test'. Query: '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''
+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;
+include/wait_for_slave_sql_error_and_skip.inc [errno=1146]
+Last_SQL_Error = 'Error 'Table 'test.t7' doesn't exist' on query. Default database: 'test'. Query: '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''
+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;
+include/wait_for_slave_sql_error_and_skip.inc [errno=1146]
+Last_SQL_Error = 'Error 'Table 'test.t7' doesn't exist' on query. Default database: 'test'. Query: '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''
+UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET a=0, d=0 where t1.id=1;
+include/wait_for_slave_sql_error_and_skip.inc [errno=1146]
+Last_SQL_Error = 'Error 'Table 'test.t4' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET a=0, d=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 a=0, d=0, e=0, f=0 where t1.id=1;
+include/wait_for_slave_sql_error_and_skip.inc [errno=1146]
+Last_SQL_Error = 'Error 'Table 'test.t4' doesn't exist' on query. Default database: 'test'. Query: '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''
+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;
+include/wait_for_slave_sql_error_and_skip.inc [errno=1146]
+Last_SQL_Error = 'Error 'Table 'test.t4' doesn't exist' on query. Default database: 'test'. Query: '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''
+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;
+include/wait_for_slave_sql_error_and_skip.inc [errno=1146]
+Last_SQL_Error = 'Error 'Table 'test.t7' doesn't exist' on query. Default database: 'test'. Query: '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''
+[on slave]
+show tables like 't%';
+Tables_in_test (t%)
+t1
+t2
+t3
+SELECT * FROM t1;
+id a
+1 1
+2 2
+3 3
+SELECT * FROM t2;
+id b
+1 1
+2 2
+3 3
+SELECT * FROM t3;
+id c
+1 1
+2 2
+3 3
+[on master]
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+include/rpl_end.inc
+SET @@GLOBAL.replicate_do_table="";
+SET @@GLOBAL.replicate_ignore_table="";
diff --git a/mysql-test/suite/rpl/r/rpl_filter_wild_tables_dynamic.result b/mysql-test/suite/rpl/r/rpl_filter_wild_tables_dynamic.result
new file mode 100644
index 00000000000..6858181234e
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_filter_wild_tables_dynamic.result
@@ -0,0 +1,26 @@
+include/master-slave.inc
+[connection master]
+SET @@GLOBAL.replicate_wild_do_table="test.a%";
+ERROR HY000: This operation cannot be performed with a running slave; run STOP SLAVE first
+SET @@GLOBAL.replicate_wild_ignore_table="test.b%";
+ERROR HY000: This operation cannot be performed with a running slave; run STOP SLAVE first
+include/stop_slave.inc
+SET @@GLOBAL.replicate_wild_do_table="test.a%";
+SET @@GLOBAL.replicate_wild_ignore_table="test.b%";
+include/start_slave.inc
+CREATE TABLE a1 (a INT);
+CREATE TABLE b1 (a INT);
+CREATE TABLE c1 (a INT);
+INSERT INTO a1 VALUES (1);
+INSERT INTO b1 VALUES (2);
+INSERT INTO c1 VALUES (3);
+[on slave]
+SHOW TABLES LIKE '%1';
+Tables_in_test (%1)
+a1
+[on master]
+[on master]
+DROP TABLE IF EXISTS a1,b1,c1;
+include/rpl_end.inc
+SET @@GLOBAL.replicate_wild_do_table="";
+SET @@GLOBAL.replicate_wild_ignore_table="";
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 00000000000..9439ee32a42
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_filter_dbs_dynamic.test
@@ -0,0 +1,65 @@
+#
+# 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;
+echo [on master];
+
+# Clean up
+connection master;
+echo [on 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_tables_dynamic.test b/mysql-test/suite/rpl/t/rpl_filter_tables_dynamic.test
new file mode 100644
index 00000000000..5cc9e8e0789
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_filter_tables_dynamic.test
@@ -0,0 +1,218 @@
+# 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="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;
+echo [on slave];
+SHOW TABLES LIKE 't%';
+
+connection master;
+echo [on 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_code: 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;
+echo [on 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_wild_tables_dynamic.test b/mysql-test/suite/rpl/t/rpl_filter_wild_tables_dynamic.test
new file mode 100644
index 00000000000..c822c81f270
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_filter_wild_tables_dynamic.test
@@ -0,0 +1,50 @@
+#
+# 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="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;
+echo [on slave];
+SHOW TABLES LIKE '%1';
+
+connection master;
+echo [on master];
+
+# Clean up
+connection master;
+echo [on 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/sys_vars/r/replicate_do_db_basic.result b/mysql-test/suite/sys_vars/r/replicate_do_db_basic.result
new file mode 100644
index 00000000000..b964d3d14a1
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/replicate_do_db_basic.result
@@ -0,0 +1,37 @@
+#
+# Basic testing of replicate_do_db.
+#
+SET @save_replicate_do_db = @@GLOBAL.replicate_do_db;
+SELECT @save_replicate_do_db;
+@save_replicate_do_db
+
+# Scope.
+SET @@SESSION.replicate_do_db = "";
+ERROR HY000: Variable 'replicate_do_db' is a GLOBAL variable and should be set with SET GLOBAL
+SELECT @@SESSION.replicate_do_db;
+ERROR HY000: Variable 'replicate_do_db' is a GLOBAL variable
+# Incorrect type.
+SET @@GLOBAL.replicate_do_db=1;
+ERROR 42000: Incorrect argument type to variable 'replicate_do_db'
+SET @@GLOBAL.replicate_do_db=1.1;
+ERROR 42000: Incorrect argument type to variable 'replicate_do_db'
+SET @@GLOBAL.replicate_do_db=1e1;
+ERROR 42000: Incorrect argument type to variable 'replicate_do_db'
+# Argument syntax.
+SET @@GLOBAL.replicate_do_db="db1,,,,,db3";
+SELECT @@GLOBAL.replicate_do_db;
+@@GLOBAL.replicate_do_db
+db1,db3
+SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='replicate_do_db';
+VARIABLE_NAME VARIABLE_VALUE
+REPLICATE_DO_DB db1,db3
+SET @@GLOBAL.replicate_do_db="db1,,,db2,,,db3";
+SELECT @@GLOBAL.replicate_do_db;
+@@GLOBAL.replicate_do_db
+db1,db2,db3
+SET @@GLOBAL.replicate_do_db="";
+SELECT @@GLOBAL.replicate_do_db;
+@@GLOBAL.replicate_do_db
+
+# Cleanup.
+SET @@GLOBAL.replicate_do_db = @save_replicate_do_db;
diff --git a/mysql-test/suite/sys_vars/r/replicate_do_table_basic.result b/mysql-test/suite/sys_vars/r/replicate_do_table_basic.result
new file mode 100644
index 00000000000..fac237228ac
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/replicate_do_table_basic.result
@@ -0,0 +1,44 @@
+#
+# Basic testing of replicate_do_table.
+#
+SET @save_replicate_do_table = @@GLOBAL.replicate_do_table;
+SELECT @save_replicate_do_table;
+@save_replicate_do_table
+
+# Scope.
+SET @@SESSION.replicate_do_table = "";
+ERROR HY000: Variable 'replicate_do_table' is a GLOBAL variable and should be set with SET GLOBAL
+SELECT @@SESSION.replicate_do_table;
+ERROR HY000: Variable 'replicate_do_table' is a GLOBAL variable
+# Incorrect type.
+SET @@GLOBAL.replicate_do_table=1;
+ERROR 42000: Incorrect argument type to variable 'replicate_do_table'
+SET @@GLOBAL.replicate_do_table=1.1;
+ERROR 42000: Incorrect argument type to variable 'replicate_do_table'
+SET @@GLOBAL.replicate_do_table=1e1;
+ERROR 42000: Incorrect argument type to variable 'replicate_do_table'
+# Incorrect arguments.
+SET @@GLOBAL.replicate_do_table="t1";
+ERROR HY000: Incorrect arguments to SET
+SET @@GLOBAL.replicate_do_table="test.t1, t2";
+ERROR HY000: Incorrect arguments to SET
+SET @@GLOBAL.replicate_do_table="test.,t1";
+ERROR HY000: Incorrect arguments to SET
+# Argument syntax.
+SET @@GLOBAL.replicate_do_table="test.t1,,,,,test.t3";
+SELECT @@GLOBAL.replicate_do_table;
+@@GLOBAL.replicate_do_table
+test.t3,test.t1
+SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='replicate_do_table';
+VARIABLE_NAME VARIABLE_VALUE
+REPLICATE_DO_TABLE test.t3,test.t1
+SET @@GLOBAL.replicate_do_table="test.t1,,,test2.t2,,,test.t3";
+SELECT @@GLOBAL.replicate_do_table;
+@@GLOBAL.replicate_do_table
+test.t3,test.t1,test2.t2
+SET @@GLOBAL.replicate_do_table="";
+SELECT @@GLOBAL.replicate_do_table;
+@@GLOBAL.replicate_do_table
+
+# Cleanup.
+SET @@GLOBAL.replicate_do_table = @save_replicate_do_table;
diff --git a/mysql-test/suite/sys_vars/r/replicate_ignore_db_basic.result b/mysql-test/suite/sys_vars/r/replicate_ignore_db_basic.result
new file mode 100644
index 00000000000..c4d7a37321e
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/replicate_ignore_db_basic.result
@@ -0,0 +1,37 @@
+#
+# Basic testing of replicate_ignore_db.
+#
+SET @save_replicate_ignore_db = @@GLOBAL.replicate_ignore_db;
+SELECT @save_replicate_ignore_db;
+@save_replicate_ignore_db
+
+# Scope.
+SET @@SESSION.replicate_ignore_db = "";
+ERROR HY000: Variable 'replicate_ignore_db' is a GLOBAL variable and should be set with SET GLOBAL
+SELECT @@SESSION.replicate_ignore_db;
+ERROR HY000: Variable 'replicate_ignore_db' is a GLOBAL variable
+# Incorrect type.
+SET @@GLOBAL.replicate_ignore_db=1;
+ERROR 42000: Incorrect argument type to variable 'replicate_ignore_db'
+SET @@GLOBAL.replicate_ignore_db=1.1;
+ERROR 42000: Incorrect argument type to variable 'replicate_ignore_db'
+SET @@GLOBAL.replicate_ignore_db=1e1;
+ERROR 42000: Incorrect argument type to variable 'replicate_ignore_db'
+# Argument syntax.
+SET @@GLOBAL.replicate_ignore_db="db1,,,,,db3";
+SELECT @@GLOBAL.replicate_ignore_db;
+@@GLOBAL.replicate_ignore_db
+db1,db3
+SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='replicate_ignore_db';
+VARIABLE_NAME VARIABLE_VALUE
+REPLICATE_IGNORE_DB db1,db3
+SET @@GLOBAL.replicate_ignore_db="db1,,,db2,,,db3";
+SELECT @@GLOBAL.replicate_ignore_db;
+@@GLOBAL.replicate_ignore_db
+db1,db2,db3
+SET @@GLOBAL.replicate_ignore_db="";
+SELECT @@GLOBAL.replicate_ignore_db;
+@@GLOBAL.replicate_ignore_db
+
+# Cleanup.
+SET @@GLOBAL.replicate_ignore_db = @save_replicate_ignore_db;
diff --git a/mysql-test/suite/sys_vars/r/replicate_ignore_table_basic.result b/mysql-test/suite/sys_vars/r/replicate_ignore_table_basic.result
new file mode 100644
index 00000000000..bc463d07319
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/replicate_ignore_table_basic.result
@@ -0,0 +1,44 @@
+#
+# Basic testing of replicate_ignore_table.
+#
+SET @save_replicate_ignore_table = @@GLOBAL.replicate_ignore_table;
+SELECT @save_replicate_ignore_table;
+@save_replicate_ignore_table
+
+# Scope.
+SET @@SESSION.replicate_ignore_table = "";
+ERROR HY000: Variable 'replicate_ignore_table' is a GLOBAL variable and should be set with SET GLOBAL
+SELECT @@SESSION.replicate_ignore_table;
+ERROR HY000: Variable 'replicate_ignore_table' is a GLOBAL variable
+# Incorrect type.
+SET @@GLOBAL.replicate_ignore_table=1;
+ERROR 42000: Incorrect argument type to variable 'replicate_ignore_table'
+SET @@GLOBAL.replicate_ignore_table=1.1;
+ERROR 42000: Incorrect argument type to variable 'replicate_ignore_table'
+SET @@GLOBAL.replicate_ignore_table=1e1;
+ERROR 42000: Incorrect argument type to variable 'replicate_ignore_table'
+# Incorrect arguments.
+SET @@GLOBAL.replicate_ignore_table="t1";
+ERROR HY000: Incorrect arguments to SET
+SET @@GLOBAL.replicate_ignore_table="test.t1, t2";
+ERROR HY000: Incorrect arguments to SET
+SET @@GLOBAL.replicate_ignore_table="test.,t1";
+ERROR HY000: Incorrect arguments to SET
+# Argument syntax.
+SET @@GLOBAL.replicate_ignore_table="test.t1,,,,,test.t3";
+SELECT @@GLOBAL.replicate_ignore_table;
+@@GLOBAL.replicate_ignore_table
+test.t3,test.t1
+SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='replicate_ignore_table';
+VARIABLE_NAME VARIABLE_VALUE
+REPLICATE_IGNORE_TABLE test.t3,test.t1
+SET @@GLOBAL.replicate_ignore_table="test.t1,,,test2.t2,,,test.t3";
+SELECT @@GLOBAL.replicate_ignore_table;
+@@GLOBAL.replicate_ignore_table
+test.t3,test.t1,test2.t2
+SET @@GLOBAL.replicate_ignore_table="";
+SELECT @@GLOBAL.replicate_ignore_table;
+@@GLOBAL.replicate_ignore_table
+
+# Cleanup.
+SET @@GLOBAL.replicate_ignore_table = @save_replicate_ignore_table;
diff --git a/mysql-test/suite/sys_vars/r/replicate_wild_do_table_basic.result b/mysql-test/suite/sys_vars/r/replicate_wild_do_table_basic.result
new file mode 100644
index 00000000000..5647cc964fb
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/replicate_wild_do_table_basic.result
@@ -0,0 +1,44 @@
+#
+# Basic testing of replicate_wild_do_table.
+#
+SET @save_replicate_wild_do_table = @@GLOBAL.replicate_wild_do_table;
+SELECT @save_replicate_wild_do_table;
+@save_replicate_wild_do_table
+
+# Scope.
+SET @@SESSION.replicate_wild_do_table = "";
+ERROR HY000: Variable 'replicate_wild_do_table' is a GLOBAL variable and should be set with SET GLOBAL
+SELECT @@SESSION.replicate_wild_do_table;
+ERROR HY000: Variable 'replicate_wild_do_table' is a GLOBAL variable
+# Incorrect type.
+SET @@GLOBAL.replicate_wild_do_table=1;
+ERROR 42000: Incorrect argument type to variable 'replicate_wild_do_table'
+SET @@GLOBAL.replicate_wild_do_table=1.1;
+ERROR 42000: Incorrect argument type to variable 'replicate_wild_do_table'
+SET @@GLOBAL.replicate_wild_do_table=1e1;
+ERROR 42000: Incorrect argument type to variable 'replicate_wild_do_table'
+# Incorrect arguments.
+SET @@GLOBAL.replicate_wild_do_table="t1";
+ERROR HY000: Incorrect arguments to SET
+SET @@GLOBAL.replicate_wild_do_table="test.t, t2";
+ERROR HY000: Incorrect arguments to SET
+SET @@GLOBAL.replicate_wild_do_table="test.,t1";
+ERROR HY000: Incorrect arguments to SET
+# Argument syntax.
+SET @@GLOBAL.replicate_wild_do_table="test.%,,,,,test.t3";
+SELECT @@GLOBAL.replicate_wild_do_table;
+@@GLOBAL.replicate_wild_do_table
+test.%,test.t3
+SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='replicate_wild_do_table';
+VARIABLE_NAME VARIABLE_VALUE
+REPLICATE_WILD_DO_TABLE test.%,test.t3
+SET @@GLOBAL.replicate_wild_do_table="test.t1,,,test2.%,,,test.t3";
+SELECT @@GLOBAL.replicate_wild_do_table;
+@@GLOBAL.replicate_wild_do_table
+test.t1,test2.%,test.t3
+SET @@GLOBAL.replicate_wild_do_table="";
+SELECT @@GLOBAL.replicate_wild_do_table;
+@@GLOBAL.replicate_wild_do_table
+
+# Cleanup.
+SET @@GLOBAL.replicate_wild_do_table = @save_replicate_wild_do_table;
diff --git a/mysql-test/suite/sys_vars/r/replicate_wild_ignore_table_basic.result b/mysql-test/suite/sys_vars/r/replicate_wild_ignore_table_basic.result
new file mode 100644
index 00000000000..c6829b792a4
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/replicate_wild_ignore_table_basic.result
@@ -0,0 +1,44 @@
+#
+# Basic testing of replicate_wild_ignore_table.
+#
+SET @save_replicate_wild_ignore_table = @@GLOBAL.replicate_wild_ignore_table;
+SELECT @save_replicate_wild_ignore_table;
+@save_replicate_wild_ignore_table
+
+# Scope.
+SET @@SESSION.replicate_wild_ignore_table = "";
+ERROR HY000: Variable 'replicate_wild_ignore_table' is a GLOBAL variable and should be set with SET GLOBAL
+SELECT @@SESSION.replicate_wild_ignore_table;
+ERROR HY000: Variable 'replicate_wild_ignore_table' is a GLOBAL variable
+# Incorrect type.
+SET @@GLOBAL.replicate_wild_ignore_table=1;
+ERROR 42000: Incorrect argument type to variable 'replicate_wild_ignore_table'
+SET @@GLOBAL.replicate_wild_ignore_table=1.1;
+ERROR 42000: Incorrect argument type to variable 'replicate_wild_ignore_table'
+SET @@GLOBAL.replicate_wild_ignore_table=1e1;
+ERROR 42000: Incorrect argument type to variable 'replicate_wild_ignore_table'
+# Incorrect arguments.
+SET @@GLOBAL.replicate_wild_ignore_table="t1";
+ERROR HY000: Incorrect arguments to SET
+SET @@GLOBAL.replicate_wild_ignore_table="test.t, t2";
+ERROR HY000: Incorrect arguments to SET
+SET @@GLOBAL.replicate_wild_ignore_table="test.,t1";
+ERROR HY000: Incorrect arguments to SET
+# Argument syntax.
+SET @@GLOBAL.replicate_wild_ignore_table="test.%,,,,,test.t3";
+SELECT @@GLOBAL.replicate_wild_ignore_table;
+@@GLOBAL.replicate_wild_ignore_table
+test.%,test.t3
+SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='replicate_wild_ignore_table';
+VARIABLE_NAME VARIABLE_VALUE
+REPLICATE_WILD_IGNORE_TABLE test.%,test.t3
+SET @@GLOBAL.replicate_wild_ignore_table="test.t1,,,test2.%,,,test.t3";
+SELECT @@GLOBAL.replicate_wild_ignore_table;
+@@GLOBAL.replicate_wild_ignore_table
+test.t1,test2.%,test.t3
+SET @@GLOBAL.replicate_wild_ignore_table="";
+SELECT @@GLOBAL.replicate_wild_ignore_table;
+@@GLOBAL.replicate_wild_ignore_table
+
+# Cleanup.
+SET @@GLOBAL.replicate_wild_ignore_table = @save_replicate_wild_ignore_table;
diff --git a/mysql-test/suite/sys_vars/t/replicate_do_db_basic.test b/mysql-test/suite/sys_vars/t/replicate_do_db_basic.test
new file mode 100644
index 00000000000..ccf50b1d6ab
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/replicate_do_db_basic.test
@@ -0,0 +1,39 @@
+--source include/not_embedded.inc
+
+--echo #
+--echo # Basic testing of replicate_do_db.
+--echo #
+
+SET @save_replicate_do_db = @@GLOBAL.replicate_do_db;
+SELECT @save_replicate_do_db;
+
+--echo # Scope.
+
+--error ER_GLOBAL_VARIABLE
+SET @@SESSION.replicate_do_db = "";
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@SESSION.replicate_do_db;
+
+--echo # Incorrect type.
+
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@GLOBAL.replicate_do_db=1;
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@GLOBAL.replicate_do_db=1.1;
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@GLOBAL.replicate_do_db=1e1;
+
+--echo # Argument syntax.
+
+SET @@GLOBAL.replicate_do_db="db1,,,,,db3";
+SELECT @@GLOBAL.replicate_do_db;
+SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='replicate_do_db';
+
+SET @@GLOBAL.replicate_do_db="db1,,,db2,,,db3";
+SELECT @@GLOBAL.replicate_do_db;
+
+SET @@GLOBAL.replicate_do_db="";
+SELECT @@GLOBAL.replicate_do_db;
+
+--echo # Cleanup.
+SET @@GLOBAL.replicate_do_db = @save_replicate_do_db;
diff --git a/mysql-test/suite/sys_vars/t/replicate_do_table_basic.test b/mysql-test/suite/sys_vars/t/replicate_do_table_basic.test
new file mode 100644
index 00000000000..f3b1585613e
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/replicate_do_table_basic.test
@@ -0,0 +1,48 @@
+--source include/not_embedded.inc
+
+--echo #
+--echo # Basic testing of replicate_do_table.
+--echo #
+
+SET @save_replicate_do_table = @@GLOBAL.replicate_do_table;
+SELECT @save_replicate_do_table;
+
+--echo # Scope.
+
+--error ER_GLOBAL_VARIABLE
+SET @@SESSION.replicate_do_table = "";
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@SESSION.replicate_do_table;
+
+--echo # Incorrect type.
+
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@GLOBAL.replicate_do_table=1;
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@GLOBAL.replicate_do_table=1.1;
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@GLOBAL.replicate_do_table=1e1;
+
+--echo # Incorrect arguments.
+
+--error ER_WRONG_ARGUMENTS
+SET @@GLOBAL.replicate_do_table="t1";
+--error ER_WRONG_ARGUMENTS
+SET @@GLOBAL.replicate_do_table="test.t1, t2";
+--error ER_WRONG_ARGUMENTS
+SET @@GLOBAL.replicate_do_table="test.,t1";
+
+--echo # Argument syntax.
+
+SET @@GLOBAL.replicate_do_table="test.t1,,,,,test.t3";
+SELECT @@GLOBAL.replicate_do_table;
+SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='replicate_do_table';
+
+SET @@GLOBAL.replicate_do_table="test.t1,,,test2.t2,,,test.t3";
+SELECT @@GLOBAL.replicate_do_table;
+
+SET @@GLOBAL.replicate_do_table="";
+SELECT @@GLOBAL.replicate_do_table;
+
+--echo # Cleanup.
+SET @@GLOBAL.replicate_do_table = @save_replicate_do_table;
diff --git a/mysql-test/suite/sys_vars/t/replicate_ignore_db_basic.test b/mysql-test/suite/sys_vars/t/replicate_ignore_db_basic.test
new file mode 100644
index 00000000000..3a0bc88109a
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/replicate_ignore_db_basic.test
@@ -0,0 +1,39 @@
+--source include/not_embedded.inc
+
+--echo #
+--echo # Basic testing of replicate_ignore_db.
+--echo #
+
+SET @save_replicate_ignore_db = @@GLOBAL.replicate_ignore_db;
+SELECT @save_replicate_ignore_db;
+
+--echo # Scope.
+
+--error ER_GLOBAL_VARIABLE
+SET @@SESSION.replicate_ignore_db = "";
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@SESSION.replicate_ignore_db;
+
+--echo # Incorrect type.
+
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@GLOBAL.replicate_ignore_db=1;
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@GLOBAL.replicate_ignore_db=1.1;
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@GLOBAL.replicate_ignore_db=1e1;
+
+--echo # Argument syntax.
+
+SET @@GLOBAL.replicate_ignore_db="db1,,,,,db3";
+SELECT @@GLOBAL.replicate_ignore_db;
+SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='replicate_ignore_db';
+
+SET @@GLOBAL.replicate_ignore_db="db1,,,db2,,,db3";
+SELECT @@GLOBAL.replicate_ignore_db;
+
+SET @@GLOBAL.replicate_ignore_db="";
+SELECT @@GLOBAL.replicate_ignore_db;
+
+--echo # Cleanup.
+SET @@GLOBAL.replicate_ignore_db = @save_replicate_ignore_db;
diff --git a/mysql-test/suite/sys_vars/t/replicate_ignore_table_basic.test b/mysql-test/suite/sys_vars/t/replicate_ignore_table_basic.test
new file mode 100644
index 00000000000..aebe90732d2
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/replicate_ignore_table_basic.test
@@ -0,0 +1,48 @@
+--source include/not_embedded.inc
+
+--echo #
+--echo # Basic testing of replicate_ignore_table.
+--echo #
+
+SET @save_replicate_ignore_table = @@GLOBAL.replicate_ignore_table;
+SELECT @save_replicate_ignore_table;
+
+--echo # Scope.
+
+--error ER_GLOBAL_VARIABLE
+SET @@SESSION.replicate_ignore_table = "";
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@SESSION.replicate_ignore_table;
+
+--echo # Incorrect type.
+
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@GLOBAL.replicate_ignore_table=1;
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@GLOBAL.replicate_ignore_table=1.1;
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@GLOBAL.replicate_ignore_table=1e1;
+
+--echo # Incorrect arguments.
+
+--error ER_WRONG_ARGUMENTS
+SET @@GLOBAL.replicate_ignore_table="t1";
+--error ER_WRONG_ARGUMENTS
+SET @@GLOBAL.replicate_ignore_table="test.t1, t2";
+--error ER_WRONG_ARGUMENTS
+SET @@GLOBAL.replicate_ignore_table="test.,t1";
+
+--echo # Argument syntax.
+
+SET @@GLOBAL.replicate_ignore_table="test.t1,,,,,test.t3";
+SELECT @@GLOBAL.replicate_ignore_table;
+SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='replicate_ignore_table';
+
+SET @@GLOBAL.replicate_ignore_table="test.t1,,,test2.t2,,,test.t3";
+SELECT @@GLOBAL.replicate_ignore_table;
+
+SET @@GLOBAL.replicate_ignore_table="";
+SELECT @@GLOBAL.replicate_ignore_table;
+
+--echo # Cleanup.
+SET @@GLOBAL.replicate_ignore_table = @save_replicate_ignore_table;
diff --git a/mysql-test/suite/sys_vars/t/replicate_wild_do_table_basic.test b/mysql-test/suite/sys_vars/t/replicate_wild_do_table_basic.test
new file mode 100644
index 00000000000..b96a62f8dd1
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/replicate_wild_do_table_basic.test
@@ -0,0 +1,48 @@
+--source include/not_embedded.inc
+
+--echo #
+--echo # Basic testing of replicate_wild_do_table.
+--echo #
+
+SET @save_replicate_wild_do_table = @@GLOBAL.replicate_wild_do_table;
+SELECT @save_replicate_wild_do_table;
+
+--echo # Scope.
+
+--error ER_GLOBAL_VARIABLE
+SET @@SESSION.replicate_wild_do_table = "";
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@SESSION.replicate_wild_do_table;
+
+--echo # Incorrect type.
+
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@GLOBAL.replicate_wild_do_table=1;
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@GLOBAL.replicate_wild_do_table=1.1;
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@GLOBAL.replicate_wild_do_table=1e1;
+
+--echo # Incorrect arguments.
+
+--error ER_WRONG_ARGUMENTS
+SET @@GLOBAL.replicate_wild_do_table="t1";
+--error ER_WRONG_ARGUMENTS
+SET @@GLOBAL.replicate_wild_do_table="test.t, t2";
+--error ER_WRONG_ARGUMENTS
+SET @@GLOBAL.replicate_wild_do_table="test.,t1";
+
+--echo # Argument syntax.
+
+SET @@GLOBAL.replicate_wild_do_table="test.%,,,,,test.t3";
+SELECT @@GLOBAL.replicate_wild_do_table;
+SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='replicate_wild_do_table';
+
+SET @@GLOBAL.replicate_wild_do_table="test.t1,,,test2.%,,,test.t3";
+SELECT @@GLOBAL.replicate_wild_do_table;
+
+SET @@GLOBAL.replicate_wild_do_table="";
+SELECT @@GLOBAL.replicate_wild_do_table;
+
+--echo # Cleanup.
+SET @@GLOBAL.replicate_wild_do_table = @save_replicate_wild_do_table;
diff --git a/mysql-test/suite/sys_vars/t/replicate_wild_ignore_table_basic.test b/mysql-test/suite/sys_vars/t/replicate_wild_ignore_table_basic.test
new file mode 100644
index 00000000000..2900deab4d1
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/replicate_wild_ignore_table_basic.test
@@ -0,0 +1,48 @@
+--source include/not_embedded.inc
+
+--echo #
+--echo # Basic testing of replicate_wild_ignore_table.
+--echo #
+
+SET @save_replicate_wild_ignore_table = @@GLOBAL.replicate_wild_ignore_table;
+SELECT @save_replicate_wild_ignore_table;
+
+--echo # Scope.
+
+--error ER_GLOBAL_VARIABLE
+SET @@SESSION.replicate_wild_ignore_table = "";
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@SESSION.replicate_wild_ignore_table;
+
+--echo # Incorrect type.
+
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@GLOBAL.replicate_wild_ignore_table=1;
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@GLOBAL.replicate_wild_ignore_table=1.1;
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@GLOBAL.replicate_wild_ignore_table=1e1;
+
+--echo # Incorrect arguments.
+
+--error ER_WRONG_ARGUMENTS
+SET @@GLOBAL.replicate_wild_ignore_table="t1";
+--error ER_WRONG_ARGUMENTS
+SET @@GLOBAL.replicate_wild_ignore_table="test.t, t2";
+--error ER_WRONG_ARGUMENTS
+SET @@GLOBAL.replicate_wild_ignore_table="test.,t1";
+
+--echo # Argument syntax.
+
+SET @@GLOBAL.replicate_wild_ignore_table="test.%,,,,,test.t3";
+SELECT @@GLOBAL.replicate_wild_ignore_table;
+SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='replicate_wild_ignore_table';
+
+SET @@GLOBAL.replicate_wild_ignore_table="test.t1,,,test2.%,,,test.t3";
+SELECT @@GLOBAL.replicate_wild_ignore_table;
+
+SET @@GLOBAL.replicate_wild_ignore_table="";
+SELECT @@GLOBAL.replicate_wild_ignore_table;
+
+--echo # Cleanup.
+SET @@GLOBAL.replicate_wild_ignore_table = @save_replicate_wild_ignore_table;
diff --git a/sql/rpl_filter.cc b/sql/rpl_filter.cc
index 5f5473e09ab..0380bc323a3 100644
--- a/sql/rpl_filter.cc
+++ b/sql/rpl_filter.cc
@@ -42,8 +42,8 @@ Rpl_filter::~Rpl_filter()
free_string_array(&wild_do_table);
if (wild_ignore_table_inited)
free_string_array(&wild_ignore_table);
- free_list(&do_db);
- free_list(&ignore_db);
+ free_string_list(&do_db);
+ free_string_list(&ignore_db);
free_list(&rewrite_db);
}
@@ -263,6 +263,57 @@ Rpl_filter::is_on()
}
+/**
+ Parse and add the given comma-separated sequence of filter rules.
+
+ @param spec Comma-separated sequence of filter rules.
+ @param add Callback member function to add a filter rule.
+
+ @return true if error, false otherwise.
+*/
+
+int
+Rpl_filter::parse_filter_rule(const char* spec, Add_filter add)
+{
+ int status= 0;
+ char *arg, *ptr, *pstr;
+
+ if (! (ptr= my_strdup(spec, MYF(MY_WME))))
+ return true;
+
+ pstr= ptr;
+
+ while (pstr)
+ {
+ arg= pstr;
+
+ /* Parse token string. */
+ pstr= strpbrk(arg, ",");
+
+ /* NUL terminate the token string. */
+ if (pstr)
+ *pstr++= '\0';
+
+ /* Skip an empty token string. */
+ if (arg[0] == '\0')
+ continue;
+
+ /* Skip leading spaces. */
+ while (my_isspace(system_charset_info, *arg))
+ arg++;
+
+ status= (this->*add)(arg);
+
+ if (status)
+ break;
+ }
+
+ my_free(ptr);
+
+ return status;
+}
+
+
int
Rpl_filter::add_do_table(const char* table_spec)
{
@@ -285,6 +336,46 @@ Rpl_filter::add_ignore_table(const char* table_spec)
}
+int
+Rpl_filter::set_do_table(const char* table_spec)
+{
+ int status;
+
+ if (do_table_inited)
+ my_hash_reset(&do_table);
+
+ status= parse_filter_rule(table_spec, &Rpl_filter::add_do_table);
+
+ if (!do_table.records)
+ {
+ my_hash_free(&do_table);
+ do_table_inited= 0;
+ }
+
+ return status;
+}
+
+
+int
+Rpl_filter::set_ignore_table(const char* table_spec)
+{
+ int status;
+
+ if (ignore_table_inited)
+ my_hash_reset(&ignore_table);
+
+ status= parse_filter_rule(table_spec, &Rpl_filter::add_ignore_table);
+
+ if (!ignore_table.records)
+ {
+ my_hash_free(&ignore_table);
+ ignore_table_inited= 0;
+ }
+
+ return status;
+}
+
+
int
Rpl_filter::add_wild_do_table(const char* table_spec)
{
@@ -307,6 +398,46 @@ Rpl_filter::add_wild_ignore_table(const char* table_spec)
}
+int
+Rpl_filter::set_wild_do_table(const char* table_spec)
+{
+ int status;
+
+ if (wild_do_table_inited)
+ free_string_array(&wild_do_table);
+
+ status= parse_filter_rule(table_spec, &Rpl_filter::add_wild_do_table);
+
+ if (!wild_do_table.elements)
+ {
+ delete_dynamic(&wild_do_table);
+ wild_do_table_inited= 0;
+ }
+
+ return status;
+}
+
+
+int
+Rpl_filter::set_wild_ignore_table(const char* table_spec)
+{
+ int status;
+
+ if (wild_ignore_table_inited)
+ free_string_array(&wild_ignore_table);
+
+ status= parse_filter_rule(table_spec, &Rpl_filter::add_wild_ignore_table);
+
+ if (!wild_ignore_table.elements)
+ {
+ delete_dynamic(&wild_ignore_table);
+ wild_ignore_table_inited= 0;
+ }
+
+ return status;
+}
+
+
void
Rpl_filter::add_db_rewrite(const char* from_db, const char* to_db)
{
@@ -355,25 +486,59 @@ Rpl_filter::add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec)
}
-void
+int
+Rpl_filter::add_string_list(I_List<i_string> *list, const char* spec)
+{
+ char *str;
+ i_string *node;
+
+ if (! (str= my_strdup(spec, MYF(MY_WME))))
+ return true;
+
+ if (! (node= new i_string(str)))
+ {
+ my_free(str);
+ return true;
+ }
+
+ list->push_back(node);
+
+ return false;
+}
+
+
+int
Rpl_filter::add_do_db(const char* table_spec)
{
DBUG_ENTER("Rpl_filter::add_do_db");
- i_string *db = new i_string(table_spec);
- do_db.push_back(db);
- DBUG_VOID_RETURN;
+ DBUG_RETURN(add_string_list(&do_db, table_spec));
}
-void
+int
Rpl_filter::add_ignore_db(const char* table_spec)
{
DBUG_ENTER("Rpl_filter::add_ignore_db");
- i_string *db = new i_string(table_spec);
- ignore_db.push_back(db);
- DBUG_VOID_RETURN;
+ DBUG_RETURN(add_string_list(&ignore_db, table_spec));
}
+
+int
+Rpl_filter::set_do_db(const char* db_spec)
+{
+ free_string_list(&do_db);
+ return parse_filter_rule(db_spec, &Rpl_filter::add_do_db);
+}
+
+
+int
+Rpl_filter::set_ignore_db(const char* db_spec)
+{
+ free_string_list(&ignore_db);
+ return parse_filter_rule(db_spec, &Rpl_filter::add_ignore_db);
+}
+
+
extern "C" uchar *get_table_key(const uchar *, size_t *, my_bool);
extern "C" void free_table_ent(void* a);
@@ -448,6 +613,23 @@ Rpl_filter::free_string_array(DYNAMIC_ARRAY *a)
}
+void
+Rpl_filter::free_string_list(I_List<i_string> *l)
+{
+ void *ptr;
+ i_string *tmp;
+
+ while ((tmp= l->get()))
+ {
+ ptr= (void *) tmp->ptr;
+ my_free(ptr);
+ delete tmp;
+ }
+
+ l->empty();
+}
+
+
/*
Builds a String from a HASH of TABLE_RULE_ENT. Cannot be used for any other
hash, as it assumes that the hash entries are TABLE_RULE_ENT.
@@ -564,3 +746,37 @@ Rpl_filter::get_ignore_db()
{
return &ignore_db;
}
+
+
+void
+Rpl_filter::db_rule_ent_list_to_str(String* str, I_List<i_string>* list)
+{
+ I_List_iterator<i_string> it(*list);
+ i_string* s;
+
+ str->length(0);
+
+ while ((s= it++))
+ {
+ str->append(s->ptr);
+ str->append(',');
+ }
+
+ // Remove last ','
+ if (!str->is_empty())
+ str->chop();
+}
+
+
+void
+Rpl_filter::get_do_db(String* str)
+{
+ db_rule_ent_list_to_str(str, get_do_db());
+}
+
+
+void
+Rpl_filter::get_ignore_db(String* str)
+{
+ db_rule_ent_list_to_str(str, get_ignore_db());
+}
diff --git a/sql/rpl_filter.h b/sql/rpl_filter.h
index d32fb36d6fb..2eb0340b714 100644
--- a/sql/rpl_filter.h
+++ b/sql/rpl_filter.h
@@ -61,11 +61,20 @@ public:
int add_do_table(const char* table_spec);
int add_ignore_table(const char* table_spec);
+ int set_do_table(const char* table_spec);
+ int set_ignore_table(const char* table_spec);
+
int add_wild_do_table(const char* table_spec);
int add_wild_ignore_table(const char* table_spec);
- void add_do_db(const char* db_spec);
- void add_ignore_db(const char* db_spec);
+ int set_wild_do_table(const char* table_spec);
+ int set_wild_ignore_table(const char* table_spec);
+
+ int add_do_db(const char* db_spec);
+ int add_ignore_db(const char* db_spec);
+
+ int set_do_db(const char* db_spec);
+ int set_ignore_db(const char* db_spec);
void add_db_rewrite(const char* from_db, const char* to_db);
@@ -83,6 +92,9 @@ public:
I_List<i_string>* get_do_db();
I_List<i_string>* get_ignore_db();
+ void get_do_db(String* str);
+ void get_ignore_db(String* str);
+
private:
bool table_rules_on;
@@ -92,13 +104,21 @@ private:
int add_table_rule(HASH* h, const char* table_spec);
int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec);
+ typedef int (Rpl_filter::*Add_filter)(char const*);
+
+ int parse_filter_rule(const char* spec, Add_filter func);
+
void free_string_array(DYNAMIC_ARRAY *a);
+ void free_string_list(I_List<i_string> *l);
void table_rule_ent_hash_to_str(String* s, HASH* h, bool inited);
void table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a,
bool inited);
+ void db_rule_ent_list_to_str(String* s, I_List<i_string>* l);
TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len);
+ int add_string_list(I_List<i_string> *list, const char* spec);
+
/*
Those 4 structures below are uninitialized memory unless the
corresponding *_inited variables are "true".
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 72e9525db72..a16769459b4 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -3255,6 +3255,150 @@ static Sys_var_mybool Sys_relay_log_recovery(
"processed",
GLOBAL_VAR(relay_log_recovery), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
+bool Sys_var_rpl_filter::do_check(THD *thd, set_var *var)
+{
+ bool status;
+
+ mysql_mutex_lock(&LOCK_active_mi);
+ mysql_mutex_lock(&active_mi->rli.run_lock);
+
+ status= active_mi->rli.slave_running;
+
+ mysql_mutex_unlock(&active_mi->rli.run_lock);
+ mysql_mutex_unlock(&LOCK_active_mi);
+
+ if (status)
+ my_error(ER_SLAVE_MUST_STOP, MYF(0));
+ else
+ status= Sys_var_charptr::do_string_check(thd, var, charset(thd));
+
+ return status;
+}
+
+bool Sys_var_rpl_filter::global_update(THD *thd, set_var *var)
+{
+ bool slave_running, status= false;
+
+ mysql_mutex_lock(&LOCK_active_mi);
+ mysql_mutex_lock(&active_mi->rli.run_lock);
+
+ if (! (slave_running= active_mi->rli.slave_running))
+ status= set_filter_value(var->save_result.string_value.str);
+
+ mysql_mutex_unlock(&active_mi->rli.run_lock);
+ mysql_mutex_unlock(&LOCK_active_mi);
+
+ if (slave_running)
+ my_error(ER_SLAVE_MUST_STOP, MYF(0));
+
+ return slave_running || status;
+}
+
+bool Sys_var_rpl_filter::set_filter_value(const char *value)
+{
+ bool status= true;
+
+ switch (opt_id) {
+ case OPT_REPLICATE_DO_DB:
+ status= rpl_filter->set_do_db(value);
+ break;
+ case OPT_REPLICATE_DO_TABLE:
+ status= rpl_filter->set_do_table(value);
+ break;
+ case OPT_REPLICATE_IGNORE_DB:
+ status= rpl_filter->set_ignore_db(value);
+ break;
+ case OPT_REPLICATE_IGNORE_TABLE:
+ status= rpl_filter->set_ignore_table(value);
+ break;
+ case OPT_REPLICATE_WILD_DO_TABLE:
+ status= rpl_filter->set_wild_do_table(value);
+ break;
+ case OPT_REPLICATE_WILD_IGNORE_TABLE:
+ status= rpl_filter->set_wild_ignore_table(value);
+ break;
+ }
+
+ return status;
+}
+
+uchar *Sys_var_rpl_filter::global_value_ptr(THD *thd, LEX_STRING *base)
+{
+ char buf[256];
+ String tmp(buf, sizeof(buf), &my_charset_bin);
+
+ tmp.length(0);
+
+ mysql_mutex_lock(&LOCK_active_mi);
+ mysql_mutex_lock(&active_mi->rli.run_lock);
+
+ switch (opt_id) {
+ case OPT_REPLICATE_DO_DB:
+ rpl_filter->get_do_db(&tmp);
+ break;
+ case OPT_REPLICATE_DO_TABLE:
+ rpl_filter->get_do_table(&tmp);
+ break;
+ case OPT_REPLICATE_IGNORE_DB:
+ rpl_filter->get_ignore_db(&tmp);
+ break;
+ case OPT_REPLICATE_IGNORE_TABLE:
+ rpl_filter->get_ignore_table(&tmp);
+ break;
+ case OPT_REPLICATE_WILD_DO_TABLE:
+ rpl_filter->get_wild_do_table(&tmp);
+ break;
+ case OPT_REPLICATE_WILD_IGNORE_TABLE:
+ rpl_filter->get_wild_ignore_table(&tmp);
+ break;
+ }
+
+ mysql_mutex_unlock(&active_mi->rli.run_lock);
+ mysql_mutex_unlock(&LOCK_active_mi);
+
+ return (uchar *) thd->strmake(tmp.ptr(), tmp.length());
+}
+
+static Sys_var_rpl_filter Sys_replicate_do_db(
+ "replicate_do_db", OPT_REPLICATE_DO_DB,
+ "Tell the slave to restrict replication to updates of tables "
+ "whose names appear in the comma-separated list. For "
+ "statement-based replication, only the default database (that "
+ "is, the one selected by USE) is considered, not any explicitly "
+ "mentioned tables in the query. For row-based replication, the "
+ "actual names of table(s) being updated are checked.");
+
+static Sys_var_rpl_filter Sys_replicate_do_table(
+ "replicate_do_table", OPT_REPLICATE_DO_TABLE,
+ "Tells the slave to restrict replication to tables in the "
+ "comma-separated list.");
+
+static Sys_var_rpl_filter Sys_replicate_ignore_db(
+ "replicate_ignore_db", OPT_REPLICATE_IGNORE_DB,
+ "Tell the slave to restrict replication to updates of tables "
+ "whose names do not appear in the comma-separated list. For "
+ "statement-based replication, only the default database (that "
+ "is, the one selected by USE) is considered, not any explicitly "
+ "mentioned tables in the query. For row-based replication, the "
+ "actual names of table(s) being updated are checked.");
+
+static Sys_var_rpl_filter Sys_replicate_ignore_table(
+ "replicate_ignore_table", OPT_REPLICATE_IGNORE_TABLE,
+ "Tells the slave thread not to replicate any statement that "
+ "updates the specified table, even if any other tables might be "
+ "updated by the same statement.");
+
+static Sys_var_rpl_filter Sys_replicate_wild_do_table(
+ "replicate_wild_do_table", OPT_REPLICATE_WILD_DO_TABLE,
+ "Tells the slave thread to restrict replication to statements "
+ "where any of the updated tables match the specified database "
+ "and table name patterns.");
+
+static Sys_var_rpl_filter Sys_replicate_wild_ignore_table(
+ "replicate_wild_ignore_table", OPT_REPLICATE_WILD_IGNORE_TABLE,
+ "Tells the slave thread to not replicate to the tables that "
+ "match the given wildcard pattern.");
+
static Sys_var_charptr Sys_slave_load_tmpdir(
"slave_load_tmpdir", "The location where the slave should put "
"its temporary files when replicating a LOAD DATA INFILE command",
diff --git a/sql/sys_vars.h b/sql/sys_vars.h
index f2a2966e6a2..647403a96e4 100644
--- a/sql/sys_vars.h
+++ b/sql/sys_vars.h
@@ -430,11 +430,11 @@ public:
my_free(global_var(char*));
flags&= ~ALLOCATED;
}
- bool do_check(THD *thd, set_var *var)
+ static bool do_string_check(THD *thd, set_var *var, CHARSET_INFO *charset)
{
char buff[STRING_BUFFER_USUAL_SIZE], buff2[STRING_BUFFER_USUAL_SIZE];
- String str(buff, sizeof(buff), charset(thd));
- String str2(buff2, sizeof(buff2), charset(thd)), *res;
+ String str(buff, sizeof(buff), charset);
+ String str2(buff2, sizeof(buff2), charset), *res;
if (!(res=var->value->val_str(&str)))
var->save_result.string_value.str= 0;
@@ -442,10 +442,10 @@ public:
{
uint32 unused;
if (String::needs_conversion(res->length(), res->charset(),
- charset(thd), &unused))
+ charset, &unused))
{
uint errors;
- str2.copy(res->ptr(), res->length(), res->charset(), charset(thd),
+ str2.copy(res->ptr(), res->length(), res->charset(), charset,
&errors);
res=&str2;
@@ -456,6 +456,8 @@ public:
return false;
}
+ bool do_check(THD *thd, set_var *var)
+ { return do_string_check(thd, var, charset(thd)); }
bool session_update(THD *thd, set_var *var)
{
DBUG_ASSERT(FALSE);
@@ -550,6 +552,44 @@ protected:
}
};
+class Sys_var_rpl_filter: public sys_var
+{
+private:
+ int opt_id;
+
+public:
+ Sys_var_rpl_filter(const char *name, int getopt_id, const char *comment)
+ : sys_var(&all_sys_vars, name, comment, sys_var::GLOBAL, 0, -1,
+ NO_ARG, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
+ NULL, NULL, 0, NULL), opt_id(getopt_id)
+ {
+ option.var_type= GET_STR;
+ }
+
+ bool check_update_type(Item_result type)
+ { return type != STRING_RESULT; }
+
+ bool do_check(THD *thd, set_var *var);
+
+ void session_save_default(THD *thd, set_var *var)
+ { DBUG_ASSERT(FALSE); }
+
+ void global_save_default(THD *thd, set_var *var)
+ { DBUG_ASSERT(FALSE); }
+
+ bool session_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(FALSE);
+ return true;
+ }
+
+ bool global_update(THD *thd, set_var *var);
+
+protected:
+ uchar *global_value_ptr(THD *thd, LEX_STRING *base);
+ bool set_filter_value(const char *value);
+};
+
/**
The class for string variables. Useful for strings that aren't necessarily
\0-terminated. Otherwise the same as Sys_var_charptr.