#At file:///home/lsoares/Workspace/mysql-server/bugfix/42829/mysql-5.1-bug39934/ based on revid:luis.soares@stripped
3028 Luis Soares 2009-07-23
BUG#42829: binlogging enabled for all schemas regardless of
binlog-db-db / binlog-ignore-db
InnoDB will return an error if statement based replication is
used along with transaction isolation level READ-COMMITTED (or
weaker), even if the statement in question is filtered out
according to the binlog-do-db rules set. In this case, an error
should not be raised.
This patch addresses this issue by extending the existing check
in external_lock to take into account binlog filtering rules
before deciding to print an error. After BUG 39934 is fixed,
decide_logging_format takes into account filtering rules for
SBL. Thence, there is no need to change decide_logging_format as
part of this bugfix.
@ mysql-test/suite/binlog/r/binlog_stm_do_db.result
Result file.
@ mysql-test/suite/binlog/t/binlog_stm_do_db-master.opt
Server option to filter all databases except the one with the
name 'b42829'.
@ mysql-test/suite/binlog/t/binlog_stm_do_db.test
Test case for statement based logging. This format triggered
the bug reported.
@ sql/sql_class.cc
Added the thd_binlog_filter_ok to INNODB_COMPATIBILITY_HOOKS set.
@ storage/innobase/handler/ha_innodb.cc
Extended check in external_lock to take into consideration the
filtering when deciding to throw an error.
@ storage/innobase/handler/ha_innodb.h
Added declaration of new hook.
added:
mysql-test/suite/binlog/r/binlog_stm_do_db.result
mysql-test/suite/binlog/t/binlog_stm_do_db-master.opt
mysql-test/suite/binlog/t/binlog_stm_do_db.test
modified:
sql/sql_class.cc
storage/innobase/handler/ha_innodb.cc
storage/innobase/handler/ha_innodb.h
=== added file 'mysql-test/suite/binlog/r/binlog_stm_do_db.result'
--- a/mysql-test/suite/binlog/r/binlog_stm_do_db.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/binlog/r/binlog_stm_do_db.result 2009-07-23 12:59:25 +0000
@@ -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: Cannot execute statement: binlogging impossible since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-logging. InnoDB is limited to row-logging when transaction isolation level is READ COMMITTED or READ UNCOMMITTED.
+UPDATE b42829_filtered.t1 ft1, b42829.t1 nft1 SET ft1.x=1, nft1.x=2;
+ERROR HY000: Cannot execute statement: binlogging impossible since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-logging. InnoDB is limited to row-logging when transaction isolation level is READ COMMITTED or READ UNCOMMITTED.
+INSERT INTO t1 SELECT * FROM t2;
+ERROR HY000: Cannot execute statement: binlogging impossible since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-logging. InnoDB is limited to row-logging when transaction isolation level is READ COMMITTED or READ UNCOMMITTED.
+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;
=== added file 'mysql-test/suite/binlog/t/binlog_stm_do_db-master.opt'
--- a/mysql-test/suite/binlog/t/binlog_stm_do_db-master.opt 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/binlog/t/binlog_stm_do_db-master.opt 2009-07-23 12:59:25 +0000
@@ -0,0 +1 @@
+--binlog-do-db=b42829
=== added file 'mysql-test/suite/binlog/t/binlog_stm_do_db.test'
--- a/mysql-test/suite/binlog/t/binlog_stm_do_db.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/binlog/t/binlog_stm_do_db.test 2009-07-23 12:59:25 +0000
@@ -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_STMT_MODE_AND_ROW_ENGINE
+INSERT INTO t2 VALUES (1,2), (1,3), (1,4);
+-- error ER_BINLOG_STMT_MODE_AND_ROW_ENGINE
+-- eval UPDATE $filtered.t1 ft1, $not_filtered.t1 nft1 SET ft1.x=1, nft1.x=2
+-- error ER_BINLOG_STMT_MODE_AND_ROW_ENGINE
+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;
\ No newline at end of file
=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc 2009-07-23 10:38:03 +0000
+++ b/sql/sql_class.cc 2009-07-23 12:59:25 +0000
@@ -43,6 +43,7 @@
#include "sp_rcontext.h"
#include "sp_cache.h"
+#include "rpl_filter.h"
/*
The following is used to initialise Table_ident with a internal
@@ -2915,6 +2916,11 @@ extern "C" void thd_mark_transaction_to_
{
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 */
/****************************************************************************
=== modified file 'storage/innobase/handler/ha_innodb.cc'
--- a/storage/innobase/handler/ha_innodb.cc 2009-07-23 10:38:03 +0000
+++ b/storage/innobase/handler/ha_innodb.cc 2009-07-23 12:59:25 +0000
@@ -6860,7 +6860,8 @@ ha_innobase::external_lock(
*/
if (lock_type == F_WRLCK &&
!(table_flags() & HA_BINLOG_STMT_CAPABLE) &&
- thd_binlog_format(thd) == BINLOG_FORMAT_STMT) {
+ thd_binlog_format(thd) == BINLOG_FORMAT_STMT &&
+ thd_binlog_filter_ok(thd) != 0) {
/* The error may be suppressed by test cases, by setting
the no_innodb_binlog_errors debug symbol. */
if (DBUG_EVALUATE_IF("no_innodb_binlog_errors", 0, 1)) {
=== modified file 'storage/innobase/handler/ha_innodb.h'
--- a/storage/innobase/handler/ha_innodb.h 2009-04-24 11:28:46 +0000
+++ b/storage/innobase/handler/ha_innodb.h 2009-07-23 12:59:25 +0000
@@ -252,4 +252,11 @@ int thd_binlog_format(const MYSQL_THD th
@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);
}
Attachment: [text/bzr-bundle] bzr/luis.soares@sun.com-20090723125925-vkn1cti1ptlxd0mp.bundle