From 9584cbe7fcc4ea98598087848f96c5e28c15d1d8 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Mon, 19 Mar 2012 15:00:23 -0700 Subject: [PATCH] Make Replication filter settings dynamic. Make the slave options --replicate-* dynamic variables so that these options can be changed dynamically while the server is running, which enables users to modify replication filtering rules without having to stop and restart the server. This is accomplished by just requiring that the slave threads are stopped when these options are set dynamically. Since filtering rules are only used by the SQL slave thread, setting them while the thread is not running avoids the need for locking. --- configure.cmake | 1 - .../suite/rpl/r/rpl_filter_dbs_dynamic.result | 40 +++ .../rpl/r/rpl_filter_tables_dynamic.result | 127 ++++++++++ .../r/rpl_filter_wild_tables_dynamic.result | 26 ++ .../suite/rpl/t/rpl_filter_dbs_dynamic.test | 65 +++++ .../rpl/t/rpl_filter_tables_dynamic.test | 218 ++++++++++++++++ .../rpl/t/rpl_filter_wild_tables_dynamic.test | 50 ++++ .../sys_vars/r/replicate_do_db_basic.result | 37 +++ .../r/replicate_do_table_basic.result | 44 ++++ .../r/replicate_ignore_db_basic.result | 37 +++ .../r/replicate_ignore_table_basic.result | 44 ++++ .../r/replicate_wild_do_table_basic.result | 44 ++++ .../replicate_wild_ignore_table_basic.result | 44 ++++ .../sys_vars/t/replicate_do_db_basic.test | 39 +++ .../sys_vars/t/replicate_do_table_basic.test | 48 ++++ .../sys_vars/t/replicate_ignore_db_basic.test | 39 +++ .../t/replicate_ignore_table_basic.test | 48 ++++ .../t/replicate_wild_do_table_basic.test | 48 ++++ .../t/replicate_wild_ignore_table_basic.test | 48 ++++ sql/rpl_filter.cc | 236 +++++++++++++++++- sql/rpl_filter.h | 24 +- sql/sys_vars.cc | 144 +++++++++++ sql/sys_vars.h | 50 +++- 23 files changed, 1483 insertions(+), 18 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_filter_dbs_dynamic.result create mode 100644 mysql-test/suite/rpl/r/rpl_filter_tables_dynamic.result create mode 100644 mysql-test/suite/rpl/r/rpl_filter_wild_tables_dynamic.result create mode 100644 mysql-test/suite/rpl/t/rpl_filter_dbs_dynamic.test create mode 100644 mysql-test/suite/rpl/t/rpl_filter_tables_dynamic.test create mode 100644 mysql-test/suite/rpl/t/rpl_filter_wild_tables_dynamic.test create mode 100644 mysql-test/suite/sys_vars/r/replicate_do_db_basic.result create mode 100644 mysql-test/suite/sys_vars/r/replicate_do_table_basic.result create mode 100644 mysql-test/suite/sys_vars/r/replicate_ignore_db_basic.result create mode 100644 mysql-test/suite/sys_vars/r/replicate_ignore_table_basic.result create mode 100644 mysql-test/suite/sys_vars/r/replicate_wild_do_table_basic.result create mode 100644 mysql-test/suite/sys_vars/r/replicate_wild_ignore_table_basic.result create mode 100644 mysql-test/suite/sys_vars/t/replicate_do_db_basic.test create mode 100644 mysql-test/suite/sys_vars/t/replicate_do_table_basic.test create mode 100644 mysql-test/suite/sys_vars/t/replicate_ignore_db_basic.test create mode 100644 mysql-test/suite/sys_vars/t/replicate_ignore_table_basic.test create mode 100644 mysql-test/suite/sys_vars/t/replicate_wild_do_table_basic.test create mode 100644 mysql-test/suite/sys_vars/t/replicate_wild_ignore_table_basic.test 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 *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 *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* list) +{ + I_List_iterator 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* get_do_db(); I_List* 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 *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* l); TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len); + int add_string_list(I_List *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.