List:Commits« Previous MessageNext Message »
From:Alfranio Correia Date:July 2 2009 5:55pm
Subject:Re: bzr commit into mysql-5.1-bugteam branch (luis.soares:2950)
Bug#42829
View as plain text  
Luis, great work.

Comments on the test case:

0 - Please, make sure that the documentation will be properly changed.
1 - Please, make sure that someone in the Innodb Team reviews it.
2 - In the test case, replace the error number by the constant.
3 - After every assertion, print out the content that was inserted in
the binary log.
4 - Please, try to combine the core of the test case in one single file.

Find further comments in-line.

Cheers.


Luis Soares wrote:
> #At file:///home/lsoares/Workspace/mysql-server/bugfix/42829/5.1-bt/ based on
> revid:joro@stripped
>
>  2950 Luis Soares	2009-06-20
>       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 stricter),
>   
I would not use the word stricter. 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:
>       
>        1. adding a innodb compatibility hook that checks if statement is
>           filtered (to be used when logging in STATEMENT mode).
>       
>        2. extending the existing check in external_lock to verify binlog
>           filter hook before deciding to print an error.
>       
>        3. changing decide_logging_format, so that if statement is ignored,
>           then no error is printed. This change also makes
>           decide_logging_format to calculate capabilities for both, ROW and
>           STMT formats always. 
>       
>           Collecting STMT mode capabilities is done considering all engines
>           involved (this was the behavior before this patch).
>       
>           Collecting ROW mode capabilities considers binlog filtering
>           rules. So, for each engine involved in the statement, its
>           capabilities are conly considered if the table does not belong to
>           a filtered database.
>       
>           Decision on which capabilities to take (for checking if logging is
>           possible), depends on the logging format chosen.
>       
>        4. extending rpl_filter with a new method that checks for a list of
>           tables if at least one of them belongs to a non filtered
>           database. This is useful to find out if a statement logged in ROW
>           mode has its all changes (possibly involving different databases)
>           filtered. Consider the following:
>       
>             UPDATE db1.t1, db2.t2 SET db1.t1.a=1, db2.t2.a=2;
>       
>           if db1 and db2 are filtered and ROW mode is used, then statement
>           is completely filtered from binlog. On the other hand, if only db1
>           was to be filtered, then changes to db2 will make it into the
>           binlog. This new method is most useful in decide_logging_format.
>       
>          
>      @ mysql-test/extra/rpl_tests/rpl_innodb_rc_do_db_cleanup.test
>         Clean up shared part of the test.
>      @ mysql-test/extra/rpl_tests/rpl_innodb_rc_do_db_mix_row.test
>         Part of the test for mixed and row mode.
>      @ mysql-test/extra/rpl_tests/rpl_innodb_rc_do_db_prepare.test
>         Shared part of the test. (Prepare section)
>      @ mysql-test/extra/rpl_tests/rpl_innodb_rc_do_db_stm.test
>         Part of the test for statement mode.
>      @ mysql-test/suite/rpl/t/rpl_innodb_rc_do_db_mix_row-master.opt
>         Option file stating which database log.
>      @ mysql-test/suite/rpl/t/rpl_innodb_rc_do_db_mix_row.test
>         Mixed and Row mode logging test.
>      @ mysql-test/suite/rpl/t/rpl_innodb_rc_do_db_stm-master.opt
>         Option file stating which database log.
>      @ mysql-test/suite/rpl/t/rpl_innodb_rc_do_db_stm.test
>         Statement mode logging test.
>      @ sql/rpl_filter.cc
>         Added Rpl_filter::db_ok(TABLE_LIST* tables) which checks if at least 
>         one table in the list provided belongs to a database that is not
>         filtered out.
>      @ sql/rpl_filter.h
>         Added 'bool db_ok(TABLE_LIST *tables)' method declaration.
>      @ sql/sql_base.cc
>         Reworked decide_logging_format to take into account filtering rules.
>         
>         After this patch, it decides to skip error reporting if statement is
>         filtered out from binlog. Also, capabilities are calculated considering
>         filtering rules.
>      @ sql/sql_class.cc
>         Added 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/extra/rpl_tests/rpl_innodb_rc_do_db_cleanup.test
>       mysql-test/extra/rpl_tests/rpl_innodb_rc_do_db_mix_row.test
>       mysql-test/extra/rpl_tests/rpl_innodb_rc_do_db_prepare.test
>       mysql-test/extra/rpl_tests/rpl_innodb_rc_do_db_stm.test
>       mysql-test/suite/rpl/r/rpl_innodb_rc_do_db_mix_row.result
>       mysql-test/suite/rpl/r/rpl_innodb_rc_do_db_stm.result
>       mysql-test/suite/rpl/t/rpl_innodb_rc_do_db_mix_row-master.opt
>       mysql-test/suite/rpl/t/rpl_innodb_rc_do_db_mix_row.test
>       mysql-test/suite/rpl/t/rpl_innodb_rc_do_db_stm-master.opt
>       mysql-test/suite/rpl/t/rpl_innodb_rc_do_db_stm.test
>     modified:
>       sql/rpl_filter.cc
>       sql/rpl_filter.h
>       sql/sql_base.cc
>       sql/sql_class.cc
>       storage/innobase/handler/ha_innodb.cc
>       storage/innobase/handler/ha_innodb.h
> === added file 'mysql-test/extra/rpl_tests/rpl_innodb_rc_do_db_cleanup.test'
> --- a/mysql-test/extra/rpl_tests/rpl_innodb_rc_do_db_cleanup.test	1970-01-01 00:00:00
> +0000
> +++ b/mysql-test/extra/rpl_tests/rpl_innodb_rc_do_db_cleanup.test	2009-06-20 13:57:39
> +0000
> @@ -0,0 +1,10 @@
> +#
> +# BUG#42829
> +#   Shared part of the test for cleanup
> +#
> +
> +# cleanup
> +-- eval DROP DATABASE $not_filtered
> +-- eval DROP DATABASE $filtered
> +
> +SET @@tx_isolation= @old_isolation_level;
>
> === added file 'mysql-test/extra/rpl_tests/rpl_innodb_rc_do_db_mix_row.test'
> --- a/mysql-test/extra/rpl_tests/rpl_innodb_rc_do_db_mix_row.test	1970-01-01 00:00:00
> +0000
> +++ b/mysql-test/extra/rpl_tests/rpl_innodb_rc_do_db_mix_row.test	2009-06-20 13:57:39
> +0000
> @@ -0,0 +1,91 @@
> +# BUG#42829
> +
> +-- echo ### assertion: assert that filtered events no longer throw error
> +-- eval use $filtered
> +INSERT INTO t2 VALUES (1,2);
> +INSERT INTO t1 SELECT * FROM t2;
> +
> +-- echo ### assertion: assert that events not filtered make it into binlog
> +-- eval use $not_filtered
> +INSERT INTO t2 VALUES (1,2);
> +INSERT INTO t1 SELECT * FROM t2;
> +
> +-- sync_slave_with_master
> +
> +-- let $diff_table_1=slave:$not_filtered.t1
> +-- let $diff_table_2=master:$not_filtered.t1
> +-- source include/diff_tables.inc
> +
> +-- let $diff_table_1=slave:$not_filtered.t2
> +-- let $diff_table_2=master:$not_filtered.t2
> +-- source include/diff_tables.inc
> +
> +-- connection master
> +
> +-- echo ### assertion: assert that statements referencing filtered tables
> +-- echo ###            while using "not filtered database" don't throw error
> +
> +-- eval INSERT INTO $filtered.t1 VALUES (1, 2)
> +-- eval INSERT INTO $filtered.t3 VALUES (UUID())
> +
> +-- echo ### assertion: assert that multi-value multi-table update succeeds
> +-- echo ###            on not filtered database
> +
> +-- eval use $not_filtered
> +DELETE FROM t1;
> +INSERT INTO t1 VALUES (1,2);
> +INSERT INTO t1 VALUES (1,3);
> +
> +DELETE FROM t2;
> +INSERT INTO t2 VALUES (1,2);
> +INSERT INTO t2 VALUES (1,3);
> +
> +UPDATE t1, t2 SET t1.y=4, t2.y=3;
> +
> +-- sync_slave_with_master
> +
> +-- let $diff_table_1=slave:$not_filtered.t1
> +-- let $diff_table_2=master:$not_filtered.t1
> +-- source include/diff_tables.inc
> +
> +-- let $diff_table_1=slave:$not_filtered.t2
> +-- let $diff_table_2=master:$not_filtered.t2
> +-- source include/diff_tables.inc
> +
> +-- connection master
> +
> +-- echo ### assertion: assert that multi-value multi-table update succeeds
> +-- echo ###            while cross-referencing filtered and not filtered
> +-- echo ###            databases 
> +
> +
> +-- eval use $not_filtered
> +-- eval DELETE FROM t2;
> +
> +-- eval INSERT INTO $not_filtered.t2 VALUES (8,1);
> +-- eval INSERT INTO $not_filtered.t2 VALUES (8,1);
> +
> +-- eval use $filtered
> +DELETE FROM t1;
> +
> +INSERT INTO t1 VALUES (8,2);
> +INSERT INTO t1 VALUES (8,3);
> +
> +INSERT INTO t2 VALUES (8,3);
> +INSERT INTO t2 VALUES (8,3);
> +
> +-- eval UPDATE $filtered.t1 ft1, $not_filtered.t2 nft2 SET ft1.y=4, nft2.y=3;
> +
> +-- sync_slave_with_master
> +
> +-- eval SELECT * FROM $not_filtered.t2;
> +
> +-- connection master
> +
> +-- eval SELECT * FROM $not_filtered.t2;
> +
> +-- let $diff_table_1=slave:$not_filtered.t2
> +-- let $diff_table_2=master:$not_filtered.t2
> +-- source include/diff_tables.inc
> +
> +-- connection master
>
> === added file 'mysql-test/extra/rpl_tests/rpl_innodb_rc_do_db_prepare.test'
> --- a/mysql-test/extra/rpl_tests/rpl_innodb_rc_do_db_prepare.test	1970-01-01 00:00:00
> +0000
> +++ b/mysql-test/extra/rpl_tests/rpl_innodb_rc_do_db_prepare.test	2009-06-20 13:57:39
> +0000
> @@ -0,0 +1,19 @@
> +#
> +# BUG#42829
> +#   Shared part of the test for prepare.
> +#
> +
> +SET @old_isolation_level= @@tx_isolation;
> +SET tx_isolation= 'READ-COMMITTED';
> +
> +-- 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 TABLE t3 (x varchar(100)) 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
> +-- eval CREATE TABLE t3 (x varchar(100)) engine=$engine
>
> === added file 'mysql-test/extra/rpl_tests/rpl_innodb_rc_do_db_stm.test'
> --- a/mysql-test/extra/rpl_tests/rpl_innodb_rc_do_db_stm.test	1970-01-01 00:00:00
> +0000
> +++ b/mysql-test/extra/rpl_tests/rpl_innodb_rc_do_db_stm.test	2009-06-20 13:57:39
> +0000
> @@ -0,0 +1,91 @@
> +# BUG#42829
> +
> +-- echo ### assertion: assert that filtered events no longer throw error
> +-- eval use $filtered
> +INSERT INTO t2 VALUES (1,2);
> +INSERT INTO t1 SELECT * FROM t2;
> +
> +-- echo ### assertion: assert that events not filtered do throw error 
> +-- eval use $not_filtered
> +-- error 1598
> +INSERT INTO t2 VALUES (1,2);
> +-- error 1598
> +INSERT INTO t1 SELECT * FROM t2;
> +
> +-- echo ### comparing tables on master/slave. Should hold no values
> +-- sync_slave_with_master
> +-- eval use $not_filtered
> +SELECT * FROM t1;
> +SELECT * FROM t2;
> +
> +-- connection master
> +SELECT * FROM t1;
> +SELECT * FROM t2;
> +
> +-- echo ### assertion: assert that multi-values multi-table update fails
> +-- echo ###            on not filtered database
> +
> +-- eval use $not_filtered
> +SET SQL_LOG_BIN=0;
> +DELETE FROM t1;
> +DELETE FROM t2;
> +INSERT INTO t1 VALUES (9,2);
> +INSERT INTO t1 VALUES (9,3);
> +INSERT INTO t2 VALUES (9,2);
> +INSERT INTO t2 VALUES (9,3);
> +SET SQL_LOG_BIN=1;
> +
> +-- error 1598
> +UPDATE t1,t2 SET t1.y=4, t2.y=4 WHERE x=9;
> +
> +-- echo ### assertion: assert that multi-values multi-table update succeeds
> +-- echo ###            while cross-referencing filtered and not filtered
> +-- echo ###            databases but statement is filtered (master and slave
> +-- echo ###            become inconsistent because in STMT mode filtering is
> +-- echo ###            done based on used database - in this case is $filtered)
> +
> +-- eval use $filtered
> +-- eval DELETE FROM $filtered.t1;
> +-- eval DELETE FROM $not_filtered.t1;
> +
> +INSERT INTO t1 VALUES (8,2);
> +INSERT INTO t1 VALUES (8,3);
> +-- eval INSERT INTO $not_filtered.t1 VALUES (8,2);
> +-- eval INSERT INTO $not_filtered.t1 VALUES (8,2);
>   

> +
> +-- eval UPDATE $filtered.t1 ft1, $not_filtered.t1 nft1 SET ft1.y=1000, nft1.y=100;
>   
Show also the opposite: $not_filtered.t1, $filtered.t1 ft1
Although this not really important at this test, I think it would be good
as a documentation because there is a filter on the slave side that
takes this
into account.

> +
> +# compare not_filtered contents on slave and master
> +-- sync_slave_with_master
> +-- eval use $not_filtered
> +SELECT * FROM t1 WHERE y=100;
> +
> +-- connection master
> +-- eval use $not_filtered
> +SELECT * FROM t1 WHERE y=100;
> +
> +-- echo ### assertion: assert that multi-value multi-table update succeeds
> +-- echo ###            while cross-referencing filtered and not filtered
> +-- echo ###            databases  (statement is filterd because used database
> +-- echo ###            is filtered)
>   
What is the difference between this assertion and the one presented above?
> +
> +-- eval use $filtered
> +SET SQL_LOG_BIN=0;
>   
Do you need the SET SQL_LOG_BIN? Won't the statements be filtered due to
the "use $filtered"?
> +-- eval DELETE FROM $filtered.t1;
> +-- eval DELETE FROM $not_filtered.t2;
> +
> +INSERT INTO t1 VALUES (7,1);
> +INSERT INTO t1 VALUES (7,1);
> +-- eval INSERT INTO $not_filtered.t2 VALUES (7,1);
> +-- eval INSERT INTO $not_filtered.t2 VALUES (7,1);
> +SET SQL_LOG_BIN=1;
> +
> +-- eval UPDATE $filtered.t1 ft1, $not_filtered.t2 nft2 SET ft1.y=100, nft2.y=100;
> +
> +# compare not_filtered contents on slave and master
> +-- sync_slave_with_master
> +-- eval use $not_filtered
> +SELECT * FROM t1 WHERE y=100;
> +
> +-- connection master
> +SELECT * FROM t1 WHERE y=100;
>
> === added file 'mysql-test/suite/rpl/r/rpl_innodb_rc_do_db_mix_row.result'
> --- a/mysql-test/suite/rpl/r/rpl_innodb_rc_do_db_mix_row.result	1970-01-01 00:00:00
> +0000
> +++ b/mysql-test/suite/rpl/r/rpl_innodb_rc_do_db_mix_row.result	2009-06-20 13:57:39
> +0000
> @@ -0,0 +1,70 @@
> +stop slave;
> +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
> +reset master;
> +reset slave;
> +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
> +start slave;
> +SET @old_isolation_level= @@tx_isolation;
> +SET 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 TABLE t3 (x varchar(100)) 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;
> +CREATE TABLE t3 (x varchar(100)) engine=InnoDB;
> +### assertion: assert that filtered events no longer throw error
> +use b42829_filtered;
> +INSERT INTO t2 VALUES (1,2);
> +INSERT INTO t1 SELECT * FROM t2;
> +### assertion: assert that events not filtered make it into binlog
> +use b42829;
> +INSERT INTO t2 VALUES (1,2);
> +INSERT INTO t1 SELECT * FROM t2;
> +Comparing tables slave:b42829.t1 and master:b42829.t1
> +Comparing tables slave:b42829.t2 and master:b42829.t2
> +### assertion: assert that statements referencing filtered tables
> +###            while using "not filtered database" don't throw error
> +INSERT INTO b42829_filtered.t1 VALUES (1, 2);
> +INSERT INTO b42829_filtered.t3 VALUES (UUID());
> +### assertion: assert that multi-value multi-table update succeeds
> +###            on not filtered database
> +use b42829;
> +DELETE FROM t1;
> +INSERT INTO t1 VALUES (1,2);
> +INSERT INTO t1 VALUES (1,3);
> +DELETE FROM t2;
> +INSERT INTO t2 VALUES (1,2);
> +INSERT INTO t2 VALUES (1,3);
> +UPDATE t1, t2 SET t1.y=4, t2.y=3;
> +Comparing tables slave:b42829.t1 and master:b42829.t1
> +Comparing tables slave:b42829.t2 and master:b42829.t2
> +### assertion: assert that multi-value multi-table update succeeds
> +###            while cross-referencing filtered and not filtered
> +###            databases 
> +use b42829;
> +DELETE FROM t2;;
> +INSERT INTO b42829.t2 VALUES (8,1);;
> +INSERT INTO b42829.t2 VALUES (8,1);;
> +use b42829_filtered;
> +DELETE FROM t1;
> +INSERT INTO t1 VALUES (8,2);
> +INSERT INTO t1 VALUES (8,3);
> +INSERT INTO t2 VALUES (8,3);
> +INSERT INTO t2 VALUES (8,3);
> +UPDATE b42829_filtered.t1 ft1, b42829.t2 nft2 SET ft1.y=4, nft2.y=3;;
> +SELECT * FROM b42829.t2;;
> +x	y
> +8	3
> +8	3
> +SELECT * FROM b42829.t2;;
> +x	y
> +8	3
> +8	3
> +Comparing tables slave:b42829.t2 and master:b42829.t2
> +DROP DATABASE b42829;
> +DROP DATABASE b42829_filtered;
> +SET @@tx_isolation= @old_isolation_level;
>
> === added file 'mysql-test/suite/rpl/r/rpl_innodb_rc_do_db_stm.result'
> --- a/mysql-test/suite/rpl/r/rpl_innodb_rc_do_db_stm.result	1970-01-01 00:00:00
> +0000
> +++ b/mysql-test/suite/rpl/r/rpl_innodb_rc_do_db_stm.result	2009-06-20 13:57:39
> +0000
> @@ -0,0 +1,96 @@
> +stop slave;
> +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
> +reset master;
> +reset slave;
> +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
> +start slave;
> +SET @old_isolation_level= @@tx_isolation;
> +SET 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 TABLE t3 (x varchar(100)) 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;
> +CREATE TABLE t3 (x varchar(100)) engine=InnoDB;
> +### assertion: assert that filtered events no longer throw error
> +use b42829_filtered;
> +INSERT INTO t2 VALUES (1,2);
> +INSERT INTO t1 SELECT * FROM t2;
> +### assertion: assert that events not filtered do throw error 
> +use b42829;
> +INSERT INTO t2 VALUES (1,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'
> +### comparing tables on master/slave. Should hold no values
> +use b42829;
> +SELECT * FROM t1;
> +x	y
> +SELECT * FROM t2;
> +x	y
> +SELECT * FROM t1;
> +x	y
> +SELECT * FROM t2;
> +x	y
> +### assertion: assert that multi-values multi-table update fails
> +###            on not filtered database
> +use b42829;
> +SET SQL_LOG_BIN=0;
> +DELETE FROM t1;
> +DELETE FROM t2;
> +INSERT INTO t1 VALUES (9,2);
> +INSERT INTO t1 VALUES (9,3);
> +INSERT INTO t2 VALUES (9,2);
> +INSERT INTO t2 VALUES (9,3);
> +SET SQL_LOG_BIN=1;
> +UPDATE t1,t2 SET t1.y=4, t2.y=4 WHERE x=9;
> +ERROR HY000: Binary logging not possible. Message: Transaction level
> 'READ-COMMITTED' in InnoDB is not safe for binlog mode 'STATEMENT'
> +### assertion: assert that multi-values multi-table update succeeds
> +###            while cross-referencing filtered and not filtered
> +###            databases but statement is filtered (master and slave
> +###            become inconsistent because in STMT mode filtering is
> +###            done based on used database - in this case is b42829_filtered)
> +use b42829_filtered;
> +DELETE FROM b42829_filtered.t1;;
> +DELETE FROM b42829.t1;;
> +INSERT INTO t1 VALUES (8,2);
> +INSERT INTO t1 VALUES (8,3);
> +INSERT INTO b42829.t1 VALUES (8,2);;
> +INSERT INTO b42829.t1 VALUES (8,2);;
> +UPDATE b42829_filtered.t1 ft1, b42829.t1 nft1 SET ft1.y=1000, nft1.y=100;;
> +use b42829;
> +SELECT * FROM t1 WHERE y=100;
> +x	y
> +use b42829;
> +SELECT * FROM t1 WHERE y=100;
> +x	y
> +8	100
> +8	100
> +### assertion: assert that multi-value multi-table update succeeds
> +###            while cross-referencing filtered and not filtered
> +###            databases  (statement is filterd because used database
> +###            is filtered)
> +use b42829_filtered;
> +SET SQL_LOG_BIN=0;
> +DELETE FROM b42829_filtered.t1;;
> +DELETE FROM b42829.t2;;
> +INSERT INTO t1 VALUES (7,1);
> +INSERT INTO t1 VALUES (7,1);
> +INSERT INTO b42829.t2 VALUES (7,1);;
> +INSERT INTO b42829.t2 VALUES (7,1);;
> +SET SQL_LOG_BIN=1;
> +UPDATE b42829_filtered.t1 ft1, b42829.t2 nft2 SET ft1.y=100, nft2.y=100;;
> +use b42829;
> +SELECT * FROM t1 WHERE y=100;
> +x	y
> +SELECT * FROM t1 WHERE y=100;
> +x	y
> +7	100
> +7	100
> +DROP DATABASE b42829;
> +DROP DATABASE b42829_filtered;
> +SET @@tx_isolation= @old_isolation_level;
>
> === added file 'mysql-test/suite/rpl/t/rpl_innodb_rc_do_db_mix_row-master.opt'
> --- a/mysql-test/suite/rpl/t/rpl_innodb_rc_do_db_mix_row-master.opt	1970-01-01
> 00:00:00 +0000
> +++ b/mysql-test/suite/rpl/t/rpl_innodb_rc_do_db_mix_row-master.opt	2009-06-20
> 13:57:39 +0000
> @@ -0,0 +1 @@
> +--binlog-do-db=b42829
>
> === added file 'mysql-test/suite/rpl/t/rpl_innodb_rc_do_db_mix_row.test'
> --- a/mysql-test/suite/rpl/t/rpl_innodb_rc_do_db_mix_row.test	1970-01-01 00:00:00
> +0000
> +++ b/mysql-test/suite/rpl/t/rpl_innodb_rc_do_db_mix_row.test	2009-06-20 13:57:39
> +0000
> @@ -0,0 +1,28 @@
> +#
> +# BUG#42829: binlogging enabled for all schemas regardless of binlog-db-db /
> +# binlog-ignore-db
> +#
> +# DESCRIPTION
> +# ===========
> +#
> +#   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 the patch an error would be thrown.
> +#    iv) Do some other combinations of statements and filtered/not filtered
> +#        databases and check expected result. See
> +#        extra/rpl_tests/rpl_innodb_rc_do_db_mixed_or_row.test for details.
> +
> +-- source include/master-slave.inc
> +-- source include/have_innodb.inc
> +-- source include/have_binlog_format_mixed_or_row.inc
> +
> +-- let $engine= InnoDB
> +-- let $filtered= b42829_filtered
> +-- let $not_filtered= b42829
> +
> +-- source extra/rpl_tests/rpl_innodb_rc_do_db_prepare.test
> +-- source extra/rpl_tests/rpl_innodb_rc_do_db_mix_row.test
> +-- source extra/rpl_tests/rpl_innodb_rc_do_db_cleanup.test
>
> === added file 'mysql-test/suite/rpl/t/rpl_innodb_rc_do_db_stm-master.opt'
> --- a/mysql-test/suite/rpl/t/rpl_innodb_rc_do_db_stm-master.opt	1970-01-01 00:00:00
> +0000
> +++ b/mysql-test/suite/rpl/t/rpl_innodb_rc_do_db_stm-master.opt	2009-06-20 13:57:39
> +0000
> @@ -0,0 +1 @@
> +--binlog-do-db=b42829
>
> === added file 'mysql-test/suite/rpl/t/rpl_innodb_rc_do_db_stm.test'
> --- a/mysql-test/suite/rpl/t/rpl_innodb_rc_do_db_stm.test	1970-01-01 00:00:00 +0000
> +++ b/mysql-test/suite/rpl/t/rpl_innodb_rc_do_db_stm.test	2009-06-20 13:57:39 +0000
> @@ -0,0 +1,28 @@
> +#
> +# BUG#42829: binlogging enabled for all schemas regardless of binlog-db-db /
> +# binlog-ignore-db
> +#
> +# DESCRIPTION
> +# ===========
> +#
> +#   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 the patch an error would be thrown.
> +#    iv) Do some other combinations of statements and filtered/not filtered
> +#        databases and check expected result. See
> +#        extra/rpl_tests/rpl_innodb_rc_do_db_stm.test for details.
> +
> +-- source include/master-slave.inc
> +-- source include/have_innodb.inc
> +-- source include/have_binlog_format_statement.inc
> +
> +-- let $engine= InnoDB
> +-- let $filtered= b42829_filtered
> +-- let $not_filtered= b42829
> +
> +-- source extra/rpl_tests/rpl_innodb_rc_do_db_prepare.test
> +-- source extra/rpl_tests/rpl_innodb_rc_do_db_stm.test
> +-- source extra/rpl_tests/rpl_innodb_rc_do_db_cleanup.test
>
> === modified file 'sql/rpl_filter.cc'
> --- a/sql/rpl_filter.cc	2009-04-29 02:59:10 +0000
> +++ b/sql/rpl_filter.cc	2009-06-20 13:57:39 +0000
> @@ -129,6 +129,30 @@ Rpl_filter::tables_ok(const char* db, TA
>                !do_table_inited && !wild_do_table_inited);
>  }
>  
> +/*
> +  Checks if at least one table in the list belongs to a database that is not
> +  filtered out.
> +
> +  SYNOPSIS
> +    db_ok()
> +    tables          list of tables accessed
> +
> +  RETURN VALUES
> +    0           no table belongs to database not filtered out
> +    1           some table(s) belong(s) to database(s) not filtered out
> +*/
> +
> +bool
> +Rpl_filter::db_ok(TABLE_LIST* tables)
> +{
> +  bool res= FALSE;
> +  for (; tables; tables= tables->next_global)
> +  {
> +    res= res || this->db_ok(tables->db);
> +  }
> +
> +  return res;
> +} 
>  
>  /*
>    Checks whether a db matches some do_db and ignore_db rules
>
> === modified file 'sql/rpl_filter.h'
> --- a/sql/rpl_filter.h	2007-05-10 09:59:39 +0000
> +++ b/sql/rpl_filter.h	2009-06-20 13:57:39 +0000
> @@ -44,6 +44,7 @@ public:
>  
>    bool tables_ok(const char* db, TABLE_LIST* tables);
>    bool db_ok(const char* db);
> +  bool db_ok(TABLE_LIST *tables);
>    bool db_ok_with_wild_table(const char *db);
>  
>    bool is_on();
>
> === modified file 'sql/sql_base.cc'
> --- a/sql/sql_base.cc	2009-05-30 13:32:28 +0000
> +++ b/sql/sql_base.cc	2009-06-20 13:57:39 +0000
>   

You are missing an include in here.
#include "rpl_filter.h"

> @@ -5050,7 +5050,6 @@ static void mark_real_tables_as_free_for
>        table->table->query_id= 0;
>  }
>  
> -
>  /**
>     Decide on logging format to use for the statement.
>  
> @@ -5097,12 +5096,17 @@ int decide_logging_format(THD *thd, TABL
>        set with all the capabilities bits set and one with no
>        capabilities bits set.
>       */
> +    handler::Table_flags flags_some_set_row= 0;
>      handler::Table_flags flags_some_set= 0;
>      handler::Table_flags flags_all_set=
>        HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE;
> +    handler::Table_flags flags_all_set_row=
> +      HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE;
>  
> +    my_bool log_as_row= FALSE;
>      my_bool multi_engine= FALSE;
>      void* prev_ht= NULL;
> +    int error= 0;
>      for (TABLE_LIST *table= tables; table; table= table->next_global)
>      {
>        if (table->placeholder())
> @@ -5119,8 +5123,22 @@ int decide_logging_format(THD *thd, TABL
>          if (prev_ht && prev_ht != table->table->file->ht)
>            multi_engine= TRUE;
>          prev_ht= table->table->file->ht;
> +        /*
> +          Collect capabilities for engines involved in the
> +          statement. These are the capabilities to check when logging
> +          in statement mode.
> +        */
>          flags_all_set &= flags;
>          flags_some_set |= flags;
> +        /*
> +          Collect capabilities for tables in databases that would not
> +          be filtered when logging in row mode.
> +        */
> +        if (binlog_filter->db_ok(table->db))
> +        {
> +          flags_all_set_row &= flags;
> +          flags_some_set_row |= flags;
> +        }
>        }
>      }
>  
> @@ -5135,23 +5153,98 @@ int decide_logging_format(THD *thd, TABL
>      DBUG_PRINT("info", ("multi_engine: %s",
>                          multi_engine ? "TRUE" : "FALSE"));
>  
> -    int error= 0;
> +    /**
> +      Flag stating whether this statement should be logged as row or
> +      not.
> +    */
> +    log_as_row= (thd->variables.binlog_format==BINLOG_FORMAT_ROW ||
> +		 (thd->variables.binlog_format==BINLOG_FORMAT_MIXED && 
> +		  (thd->lex->is_stmt_unsafe() || 
> +		   (flags_all_set & HA_BINLOG_STMT_CAPABLE) ==0)));
> +
>   
Is there any reason to keep the if/else?
If there isn't, please, change this part of the logic.

> +    /**
> +      Check whether statement is filtered from binlog or not.
> +    */
> +    if ((log_as_row && !binlog_filter->db_ok(tables)) || 
> +	(!log_as_row && !binlog_filter->db_ok(thd->db)))
> +    {
> +
> +      /*	
> +	We are filtering this statement from log. As such, we skip
> +	error checking.
> +
> +	Still, we mark statement to be logged as ROW if in MIXED and
> +	switch should happen. This way, the statement is subject to
> +	the same filtering rules when the time comes to log it, that
> +	were considered here.
> +      */
> +      goto end;
> +    }
> +    else
> +    {
> +      /*        
> +	Choose which capabilities to take based on the filtering
> +	analysis and the binlog format that one is to choose.
> +        
> +	So, if using RBR or MIXED+switch_to_row, the capabilities
> +	considered are the ones collected for events on *not* filtered
> +	tables (databases).
> +
> +	For STMT or MIXED+not_switch_to_row, the capabilities to
> +	consider are the ones collected from all the engines involved.
> +
> +	Q. What is this trying to solve?
> +        A. Some cases involving filtered and not filtered out
> +           databases, in the same statement and when using row mode
> +           logging. Consider scenario description and questions below.
> +
> +        Scenario:
> +          1. MIXED mode
> +          2. filtered: db2; !filtered: db1
> +          3. capabilities: db1 => ROW, db2 => STMT
> +          4. UPDATE db1.t1 A, db2.t1 B SET A.x=1, B.x=2;
> +
> +	Q. Which is the value of flags_all_set_row?
> +	A. HA_BINLOG_ROW_CAPABLE, because, db2 is filtered (MIXED
> +           should switch to row because flags_all_set would not have STMT
> +	   capability).
> +
> +	Q. Which is the value of flags_all_set?
> +	A. 0
> +
> +	Q. This statement should log the update on db1.t1 when using
> +           ROW and MIXED mode. As such, errors should not be thrown
> +           for this statement. In this case, which capabilities flags
> +           should one use to conduct error checking?
> +	A. flags_all_set_row
> +
> +	Basically, when one finds that is indeed logging in ROW mode,
> +	then the vector of capabilities should just hold the
> +	capabilities for the engines which are referenced by tables in
> +	databases not filtered out from binlog.
> +      */
> +      if (log_as_row)
> +      {
> +        flags_all_set= flags_all_set_row;
> +	flags_some_set= flags_some_set_row;
> +      }
> +    }
> +
>      if (flags_all_set == 0)
>      {
>        my_error((error= ER_BINLOG_LOGGING_IMPOSSIBLE), MYF(0),
>                 "Statement cannot be logged to the binary log in"
>                 " row-based nor statement-based format");
>      }
> -    else if (thd->variables.binlog_format == BINLOG_FORMAT_STMT &&
> +    else if (!log_as_row &&
>               (flags_all_set & HA_BINLOG_STMT_CAPABLE) == 0)
>      {
>        my_error((error= ER_BINLOG_LOGGING_IMPOSSIBLE), MYF(0),
>                  "Statement-based format required for this statement,"
>                  " but not allowed by this combination of engines");
>      }
> -    else if ((thd->variables.binlog_format == BINLOG_FORMAT_ROW ||
> -              thd->lex->is_stmt_unsafe()) &&
> -             (flags_all_set & HA_BINLOG_ROW_CAPABLE) == 0)
> +    else if (log_as_row && 
> +	     (flags_all_set & HA_BINLOG_ROW_CAPABLE) == 0)
>      {
>        my_error((error= ER_BINLOG_LOGGING_IMPOSSIBLE), MYF(0),
>                  "Row-based format required for this statement,"
> @@ -5179,6 +5272,7 @@ int decide_logging_format(THD *thd, TABL
>      if (error)
>        return -1;
>  
> +end:
>      /*
>        We switch to row-based format if we are in mixed mode and one of
>        the following are true:
> @@ -5191,8 +5285,7 @@ int decide_logging_format(THD *thd, TABL
>        this code in reset_current_stmt_binlog_row_based(), it has to be
>        here.
>      */
>   
> -    if (thd->lex->is_stmt_unsafe() ||
> -        (flags_all_set & HA_BINLOG_STMT_CAPABLE) == 0)
> +    if (log_as_row)
>      {
>        thd->set_current_stmt_binlog_row_based_if_mixed();
>      }
>
> === modified file 'sql/sql_class.cc'
> --- a/sql/sql_class.cc	2009-06-15 15:53:45 +0000
> +++ b/sql/sql_class.cc	2009-06-20 13:57:39 +0000
> @@ -41,6 +41,7 @@
>  
>  #include "sp_rcontext.h"
>  #include "sp_cache.h"
> +#include "rpl_filter.h"
>  
>  /*
>    The following is used to initialise Table_ident with a internal
> @@ -2912,6 +2913,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-05-19 08:20:28 +0000
> +++ b/storage/innobase/handler/ha_innodb.cc	2009-06-20 13:57:39 +0000
> @@ -6843,8 +6843,10 @@ ha_innobase::external_lock(
>  	{
>  		ulong const binlog_format= thd_binlog_format(thd);
>  		ulong const tx_isolation = thd_tx_isolation(current_thd);
> +                bool const is_binlog_filter_ok= thd_binlog_filter_ok(thd);
>  		if (tx_isolation <= ISO_READ_COMMITTED &&
> -		    binlog_format == BINLOG_FORMAT_STMT)
> +		    binlog_format == BINLOG_FORMAT_STMT &&
> +                    is_binlog_filter_ok)
>  		{
>  			char buf[256];
>  			my_snprintf(buf, sizeof(buf),
>
> === 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-06-20 13:57:39 +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);
>  }
>   
> ------------------------------------------------------------------------
>
> This body part will be downloaded on demand.

Thread
bzr commit into mysql-5.1-bugteam branch (luis.soares:2950) Bug#42829Luis Soares20 Jun
  • Re: bzr commit into mysql-5.1-bugteam branch (luis.soares:2950)Bug#42829Andrei Elkin24 Jun
    • Re: bzr commit into mysql-5.1-bugteam branch (luis.soares:2950)Bug#42829Alfranio Correia24 Jun
  • Re: bzr commit into mysql-5.1-bugteam branch (luis.soares:2950)Bug#42829He Zhenxing24 Jun
  • Re: bzr commit into mysql-5.1-bugteam branch (luis.soares:2950)Bug#42829Alfranio Correia2 Jul