Commit 5e04d469 authored by Luis Soares's avatar Luis Soares

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 printed.
      
This patch addresses this issue by extending the existing check in
external_lock to take into account the filter rules before deciding to
print an error. Furthermore, it also changes decide_logging_format to
take into consideration whether the statement is filtered out from 
binlog before decision is made.
parent 600703e5
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;
# 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;
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <m_ctype.h> #include <m_ctype.h>
#include <my_dir.h> #include <my_dir.h>
#include <hash.h> #include <hash.h>
#include "rpl_filter.h"
#ifdef __WIN__ #ifdef __WIN__
#include <io.h> #include <io.h>
#endif #endif
...@@ -5094,7 +5095,16 @@ static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table) ...@@ -5094,7 +5095,16 @@ static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table)
int decide_logging_format(THD *thd, TABLE_LIST *tables) 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 Compute the starting vectors for the computations by creating a
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include "sp_rcontext.h" #include "sp_rcontext.h"
#include "sp_cache.h" #include "sp_cache.h"
#include "rpl_filter.h"
/* /*
The following is used to initialise Table_ident with a internal The following is used to initialise Table_ident with a internal
...@@ -2980,6 +2981,11 @@ extern "C" void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all) ...@@ -2980,6 +2981,11 @@ extern "C" void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all)
{ {
mark_transaction_to_rollback(thd, 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 */ #endif // INNODB_COMPATIBILITY_HOOKS */
/**************************************************************************** /****************************************************************************
......
...@@ -6944,8 +6944,9 @@ ha_innobase::external_lock( ...@@ -6944,8 +6944,9 @@ ha_innobase::external_lock(
{ {
ulong const binlog_format= thd_binlog_format(thd); ulong const binlog_format= thd_binlog_format(thd);
ulong const tx_isolation = thd_tx_isolation(current_thd); ulong const tx_isolation = thd_tx_isolation(current_thd);
if (tx_isolation <= ISO_READ_COMMITTED && if (tx_isolation <= ISO_READ_COMMITTED
binlog_format == BINLOG_FORMAT_STMT) && binlog_format == BINLOG_FORMAT_STMT
&& thd_binlog_filter_ok(thd))
{ {
char buf[256]; char buf[256];
my_snprintf(buf, sizeof(buf), my_snprintf(buf, sizeof(buf),
......
...@@ -252,4 +252,11 @@ int thd_binlog_format(const MYSQL_THD thd); ...@@ -252,4 +252,11 @@ int thd_binlog_format(const MYSQL_THD thd);
@param all TRUE <=> rollback main transaction. @param all TRUE <=> rollback main transaction.
*/ */
void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all); 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);
} }
...@@ -7797,8 +7797,9 @@ ha_innobase::external_lock( ...@@ -7797,8 +7797,9 @@ ha_innobase::external_lock(
{ {
ulong const binlog_format= thd_binlog_format(thd); ulong const binlog_format= thd_binlog_format(thd);
ulong const tx_isolation = thd_tx_isolation(ha_thd()); ulong const tx_isolation = thd_tx_isolation(ha_thd());
if (tx_isolation <= ISO_READ_COMMITTED && if (tx_isolation <= ISO_READ_COMMITTED
binlog_format == BINLOG_FORMAT_STMT) && binlog_format == BINLOG_FORMAT_STMT
&& thd_binlog_filter_ok(thd))
{ {
char buf[256]; char buf[256];
my_snprintf(buf, sizeof(buf), my_snprintf(buf, sizeof(buf),
......
...@@ -257,6 +257,13 @@ int thd_binlog_format(const MYSQL_THD thd); ...@@ -257,6 +257,13 @@ int thd_binlog_format(const MYSQL_THD thd);
@param all TRUE <=> rollback main transaction. @param all TRUE <=> rollback main transaction.
*/ */
void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all); 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; typedef struct trx_struct trx_t;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment