diff options
author | Alexander Nozdrin <alik@sun.com> | 2009-11-05 13:58:14 +0300 |
---|---|---|
committer | Alexander Nozdrin <alik@sun.com> | 2009-11-05 13:58:14 +0300 |
commit | 132c439a0b52d0841d8876757c1a8e5b13dfa8fe (patch) | |
tree | 813ba28abf700c366d7ff928bd20c29830083ff7 | |
parent | 89cfb564e3ac3d92c582052d59bd512c343a0944 (diff) | |
parent | 2ad0d6910cf7476c08e7a4fb77e30c959ffa0e80 (diff) | |
download | mariadb-git-132c439a0b52d0841d8876757c1a8e5b13dfa8fe.tar.gz |
Manual merge from mysql-5.1.
-rw-r--r-- | mysql-test/suite/binlog/r/binlog_stm_do_db.result | 42 | ||||
-rw-r--r-- | mysql-test/suite/binlog/t/binlog_stm_do_db-master.opt | 1 | ||||
-rw-r--r-- | mysql-test/suite/binlog/t/binlog_stm_do_db.test | 90 | ||||
-rw-r--r-- | sql/sql_base.cc | 12 | ||||
-rw-r--r-- | sql/sql_class.cc | 5 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 5 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.h | 7 |
7 files changed, 159 insertions, 3 deletions
diff --git a/mysql-test/suite/binlog/r/binlog_stm_do_db.result b/mysql-test/suite/binlog/r/binlog_stm_do_db.result new file mode 100644 index 00000000000..ab4ba7cdca1 --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_stm_do_db.result @@ -0,0 +1,42 @@ +SET @old_isolation_level= @@session.tx_isolation; +SET @@session.tx_isolation= 'READ-COMMITTED'; +CREATE DATABASE b42829; +use b42829; +CREATE TABLE t1 (x int, y int) engine=InnoDB; +CREATE TABLE t2 (x int, y int) engine=InnoDB; +CREATE DATABASE b42829_filtered; +use b42829_filtered; +CREATE TABLE t1 (x int, y int) engine=InnoDB; +CREATE TABLE t2 (x int, y int) engine=InnoDB; +SET @@session.sql_log_bin= 0; +INSERT INTO b42829_filtered.t1 VALUES (100,100); +INSERT INTO b42829.t1 VALUES (100,100); +SET @@session.sql_log_bin= 1; +### assertion: the inserts will not raise log error because +### binlog-do-db is filtering used database +INSERT INTO t2 VALUES (1,2), (1,3), (1,4); +INSERT INTO t1 SELECT * FROM t2; +### assertion: assert that despite updating a not filtered +### database this wont trigger an error as the +### used database is the filtered one. +UPDATE b42829_filtered.t1 ft1, b42829.t1 nft1 SET ft1.x=1, nft1.x=2; +use b42829; +### assertion: the statements *will* raise log error because +### binlog-do-db is not filtering used database +BEGIN; +INSERT INTO t2 VALUES (1,2), (1,3), (1,4); +ERROR HY000: Binary logging not possible. Message: Transaction level 'READ-COMMITTED' in InnoDB is not safe for binlog mode 'STATEMENT' +UPDATE b42829_filtered.t1 ft1, b42829.t1 nft1 SET ft1.x=1, nft1.x=2; +ERROR HY000: Binary logging not possible. Message: Transaction level 'READ-COMMITTED' in InnoDB is not safe for binlog mode 'STATEMENT' +INSERT INTO t1 SELECT * FROM t2; +ERROR HY000: Binary logging not possible. Message: Transaction level 'READ-COMMITTED' in InnoDB is not safe for binlog mode 'STATEMENT' +COMMIT; +### assertion: filtered events did not make into the binlog +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # CREATE DATABASE b42829 +master-bin.000001 # Query # # use `b42829`; CREATE TABLE t1 (x int, y int) engine=InnoDB +master-bin.000001 # Query # # use `b42829`; CREATE TABLE t2 (x int, y int) engine=InnoDB +DROP DATABASE b42829; +DROP DATABASE b42829_filtered; +SET @@session.tx_isolation= @old_isolation_level; diff --git a/mysql-test/suite/binlog/t/binlog_stm_do_db-master.opt b/mysql-test/suite/binlog/t/binlog_stm_do_db-master.opt new file mode 100644 index 00000000000..e2cfcb299cf --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_stm_do_db-master.opt @@ -0,0 +1 @@ +--binlog-do-db=b42829 diff --git a/mysql-test/suite/binlog/t/binlog_stm_do_db.test b/mysql-test/suite/binlog/t/binlog_stm_do_db.test new file mode 100644 index 00000000000..858bc8cc683 --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_stm_do_db.test @@ -0,0 +1,90 @@ +# BUG#42829: binlogging enabled for all schemas regardless of +# binlog-db-db / binlog-ignore-db +# +# WHAT +# ==== +# +# We want to test whether filtered events from binlog will cause +# raising an error mentioning that statement is unable to be logged or +# not, when: +# +# 1. isolation level READ-COMMITTED; AND +# +# 2. using InnoDB engine; AND +# +# 3. using SBL (in which case InnoDB will only allow RBL). +# +# HOW +# === +# +# The test is implemented as follows: +# +# i) set tx_isolation to read-committed. +# +# ii) create two databases (one filtered other not - using +# binlog-do-db) +# +# iii) Create statements that are to be filtered on filtered db +# +# - At this point, before fix, an error would be raised +# +# iv) do the same thing for not the filtered database and check +# that events throw an error: +# +# - Error: ER_BINLOG_STMT_MODE_AND_ROW_ENGINE +# + +-- source include/have_log_bin.inc +-- source include/have_innodb.inc +-- source include/have_binlog_format_statement.inc + +SET @old_isolation_level= @@session.tx_isolation; +SET @@session.tx_isolation= 'READ-COMMITTED'; + +-- let $engine= InnoDB +-- let $filtered= b42829_filtered +-- let $not_filtered= b42829 + +-- eval CREATE DATABASE $not_filtered +-- eval use $not_filtered +-- eval CREATE TABLE t1 (x int, y int) engine=$engine +-- eval CREATE TABLE t2 (x int, y int) engine=$engine + +-- eval CREATE DATABASE $filtered +-- eval use $filtered +-- eval CREATE TABLE t1 (x int, y int) engine=$engine +-- eval CREATE TABLE t2 (x int, y int) engine=$engine + +SET @@session.sql_log_bin= 0; +-- eval INSERT INTO $filtered.t1 VALUES (100,100) +-- eval INSERT INTO $not_filtered.t1 VALUES (100,100) +SET @@session.sql_log_bin= 1; + +-- echo ### assertion: the inserts will not raise log error because +-- echo ### binlog-do-db is filtering used database +INSERT INTO t2 VALUES (1,2), (1,3), (1,4); +INSERT INTO t1 SELECT * FROM t2; + +-- echo ### assertion: assert that despite updating a not filtered +-- echo ### database this wont trigger an error as the +-- echo ### used database is the filtered one. +-- eval UPDATE $filtered.t1 ft1, $not_filtered.t1 nft1 SET ft1.x=1, nft1.x=2 + +-- eval use $not_filtered +-- echo ### assertion: the statements *will* raise log error because +-- echo ### binlog-do-db is not filtering used database +BEGIN; +-- error ER_BINLOG_LOGGING_IMPOSSIBLE +INSERT INTO t2 VALUES (1,2), (1,3), (1,4); +-- error ER_BINLOG_LOGGING_IMPOSSIBLE +-- eval UPDATE $filtered.t1 ft1, $not_filtered.t1 nft1 SET ft1.x=1, nft1.x=2 +-- error ER_BINLOG_LOGGING_IMPOSSIBLE +INSERT INTO t1 SELECT * FROM t2; +COMMIT; + +-- echo ### assertion: filtered events did not make into the binlog +source include/show_binlog_events.inc; + +-- eval DROP DATABASE $not_filtered +-- eval DROP DATABASE $filtered +SET @@session.tx_isolation= @old_isolation_level; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index e706bd04ea6..af18660b9a5 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -25,6 +25,7 @@ #include <m_ctype.h> #include <my_dir.h> #include <hash.h> +#include "rpl_filter.h" #ifdef __WIN__ #include <io.h> #endif @@ -5098,7 +5099,16 @@ static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table) int decide_logging_format(THD *thd, TABLE_LIST *tables) { - if (mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG)) + /* + In SBR mode, we are only proceeding if we are binlogging this + statement, ie, the filtering rules won't later filter this out. + + This check here is needed to prevent some spurious error to be + raised in some cases (See BUG#42829). + */ + if (mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG) && + (thd->variables.binlog_format != BINLOG_FORMAT_STMT || + binlog_filter->db_ok(thd->db))) { /* Compute the starting vectors for the computations by creating a diff --git a/sql/sql_class.cc b/sql/sql_class.cc index ddcd1cee4e9..a12b0198c98 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3045,6 +3045,11 @@ extern "C" void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all) { mark_transaction_to_rollback(thd, all); } + +extern "C" bool thd_binlog_filter_ok(const MYSQL_THD thd) +{ + return binlog_filter->db_ok(thd->db); +} #endif // INNODB_COMPATIBILITY_HOOKS */ /**************************************************************************** diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 3b0b53fed74..55fc8b1307a 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -7891,8 +7891,9 @@ ha_innobase::external_lock( { ulong const binlog_format= thd_binlog_format(thd); ulong const tx_isolation = thd_tx_isolation(ha_thd()); - if (tx_isolation <= ISO_READ_COMMITTED && - binlog_format == BINLOG_FORMAT_STMT) + if (tx_isolation <= ISO_READ_COMMITTED + && binlog_format == BINLOG_FORMAT_STMT + && thd_binlog_filter_ok(thd)) { char buf[256]; my_snprintf(buf, sizeof(buf), diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index cc98003f8ff..9560fbdaa5e 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -257,6 +257,13 @@ int thd_binlog_format(const MYSQL_THD thd); @param all TRUE <=> rollback main transaction. */ void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all); + +/** + Check if binary logging is filtered for thread's current db. + @param thd Thread handle + @retval 1 the query is not filtered, 0 otherwise. +*/ +bool thd_binlog_filter_ok(const MYSQL_THD thd); } typedef struct trx_struct trx_t; |