diff --git a/mysql-test/suite/binlog/r/binlog_commit_fail.result b/mysql-test/suite/binlog/r/binlog_commit_fail.result new file mode 100644 index 00000000000..dd9e62be638 --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_commit_fail.result @@ -0,0 +1,116 @@ +set @@session.gtid_domain_id=1; +set @save_gtid_stric_mode=@@global.gtid_strict_mode; +create table ta (a int) engine=aria; +create table ti (a int) engine=innodb; +create table ti_pk (a int primary key) engine=innodb; +create table t (a int) engine=innodb; +create function f_i() +returns integer +begin +insert into ti set a=1; +return 1; +end | +create function f_ia(arg int) +returns integer +begin +insert into ti_pk set a=1; +insert into ta set a=1; +insert into ti_pk set a=arg; +return 1; +end | +call mtr.add_suppression("Error writing file"); +select count(*) as zero from t; +zero +0 +select count(*) as zero from ta; +zero +0 +select count(*) as zero from ti; +zero +0 +# 1. simple Innodb test +set @@global.gtid_strict_mode=0; +set @@session.gtid_seq_no=1; +set @@global.gtid_strict_mode=1; +insert into t set a=1; +ERROR HY000: An attempt was made to binlog GTID VALUE which would create an out-of-order sequence number with existing GTID VALUE, and gtid strict mode is enabled +# observe effective rollback +select count(*) as zero from t; +zero +0 +# 2. simple Aira test +set @@global.gtid_strict_mode=0; +set @@session.gtid_seq_no=1; +set @@global.gtid_strict_mode=1; +insert into ta values (1),(2); +ERROR HY000: An attempt was made to binlog GTID VALUE which would create an out-of-order sequence number with existing GTID VALUE, and gtid strict mode is enabled +# note no rollback +select count(*) as '*NON-zero*' from ta; +*NON-zero* +2 +delete from ta; +# 3. multi-engine test +set @@global.gtid_strict_mode=0; +set @@session.gtid_seq_no=1; +set @@global.gtid_strict_mode=1; +insert into ta set a=f_i(); +ERROR HY000: An attempt was made to binlog GTID VALUE which would create an out-of-order sequence number with existing GTID VALUE, and gtid strict mode is enabled +# note no rollback.. +select count(*) as one from ta; +one +1 +# ..except transactional engine +select count(*) as zero from ti; +zero +0 +delete from ta; +set @@global.gtid_strict_mode=0; +set @@session.gtid_seq_no=1; +set @@global.gtid_strict_mode=1; +insert into t set a=f_ia(0); +ERROR HY000: An attempt was made to binlog GTID VALUE which would create an out-of-order sequence number with existing GTID VALUE, and gtid strict mode is enabled +# note no rollback.. +select count(*) as one from ta; +one +1 +# ..except transactional engine +select count(*) as zero from t; +zero +0 +select count(*) as zero from ti_pk; +zero +0 +delete from ta; +# 4. create-table-select-f() +set @@global.gtid_strict_mode=0; +set @@session.gtid_seq_no=1; +set @@global.gtid_strict_mode=1; +create table f_x (a int) select f_i() as a; +ERROR HY000: An attempt was made to binlog GTID VALUE which would create an out-of-order sequence number with existing GTID VALUE, and gtid strict mode is enabled +# rollback indeed takes place in the pure transactional case +select count(*) as zero from ti; +zero +0 +set @@global.gtid_strict_mode=0; +set @@session.gtid_seq_no=1; +set @@global.gtid_strict_mode=1; +create table t_x (a int) engine=aria select f_ia(0) as a; +ERROR HY000: An attempt was made to binlog GTID VALUE which would create an out-of-order sequence number with existing GTID VALUE, and gtid strict mode is enabled +select * from t_x; +ERROR 42S02: Table 'test.t_x' doesn't exist +# **TODO**: fix MDEV-36027 +# **TODO**: the empty binlog is buggy .. +include/show_binlog_events.inc +# .. as non-transactional `ta` (and `t_x` sic!) are modified +select count(*) as one from ta; +one +1 +select count(*) as zero from ti; +zero +0 +delete from ta; +#. +set @@global.gtid_strict_mode=@save_gtid_stric_mode; +drop function f_i; +drop function f_ia; +drop table t, ta, ti, ti_pk; diff --git a/mysql-test/suite/binlog/t/binlog_commit_fail.test b/mysql-test/suite/binlog/t/binlog_commit_fail.test new file mode 100644 index 00000000000..d88ad552b07 --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_commit_fail.test @@ -0,0 +1,135 @@ +# Tests of commit time failures. +# At committing of an auto-commit statement a failure to commit in its +# binlog branch should rollback at least the transactional part of the statement. +# +# References: +# MDEV-35506 commit policy of one-phase-commit even at errored-out binlogging leads to assert +# MDEV-36027 Errored-out CREATE-SELECT does not binlog results of non-transactional table modification + +source include/have_innodb.inc; +source include/have_binlog_format_row.inc; + +set @@session.gtid_domain_id=1; +set @save_gtid_stric_mode=@@global.gtid_strict_mode; + +create table ta (a int) engine=aria; +create table ti (a int) engine=innodb; +create table ti_pk (a int primary key) engine=innodb; +create table t (a int) engine=innodb; +delimiter |; +create function f_i() +returns integer +begin + insert into ti set a=1; +return 1; +end | +create function f_ia(arg int) +returns integer +begin + insert into ti_pk set a=1; + insert into ta set a=1; + insert into ti_pk set a=arg; + return 1; +end | +delimiter ;| + +call mtr.add_suppression("Error writing file"); + +# Naturally all empty now +select count(*) as zero from t; +select count(*) as zero from ta; +select count(*) as zero from ti; + +# Force manual value assignement to gtid::seq_no while in the strict mode +# so that the value is rejected. Despite the errorred out statement +# being at its commit phase it will eventually be rolled back. +# Side effects of non-transactional engines, like Aria, are displayed. +--echo # 1. simple Innodb test +set @@global.gtid_strict_mode=0; set @@session.gtid_seq_no=1; +set @@global.gtid_strict_mode=1; +# mask possible allowed seq_no shift +--replace_regex /GTID 1-1-[0-9]+/GTID VALUE/ +--error ER_GTID_STRICT_OUT_OF_ORDER +insert into t set a=1; + +--echo # observe effective rollback +select count(*) as zero from t; + +--echo # 2. simple Aira test +set @@global.gtid_strict_mode=0; set @@session.gtid_seq_no=1; +set @@global.gtid_strict_mode=1; +--replace_regex /GTID 1-1-[0-9]+/GTID VALUE/ +--error ER_GTID_STRICT_OUT_OF_ORDER +insert into ta values (1),(2); + +--echo # note no rollback +select count(*) as '*NON-zero*' from ta; +# local cleanup +delete from ta; + +--echo # 3. multi-engine test +# A. non-transactional top-level +set @@global.gtid_strict_mode=0; set @@session.gtid_seq_no=1; +set @@global.gtid_strict_mode=1; +--replace_regex /GTID 1-1-[0-9]+/GTID VALUE/ +--error ER_GTID_STRICT_OUT_OF_ORDER +insert into ta set a=f_i(); +--echo # note no rollback.. +select count(*) as one from ta; +--echo # ..except transactional engine +select count(*) as zero from ti; +delete from ta; + +# B. non-transactional in the leaf +set @@global.gtid_strict_mode=0; set @@session.gtid_seq_no=1; +set @@global.gtid_strict_mode=1; +--replace_regex /GTID 1-1-[0-9]+/GTID VALUE/ +--error ER_GTID_STRICT_OUT_OF_ORDER +insert into t set a=f_ia(0); + +--echo # note no rollback.. +select count(*) as one from ta; +--echo # ..except transactional engine +select count(*) as zero from t; +select count(*) as zero from ti_pk; +delete from ta; + +--echo # 4. create-table-select-f() +--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1) +--let $binlog_start = query_get_value(SHOW MASTER STATUS, Position, 1) +# A. two phase commit branch +set @@global.gtid_strict_mode=0; set @@session.gtid_seq_no=1; +set @@global.gtid_strict_mode=1; +--replace_regex /GTID 1-1-[0-9]+/GTID VALUE/ +--error ER_GTID_STRICT_OUT_OF_ORDER +create table f_x (a int) select f_i() as a; +--echo # rollback indeed takes place in the pure transactional case +select count(*) as zero from ti; + +# B. one phase commit branch +--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1) +--let $binlog_start = query_get_value(SHOW MASTER STATUS, Position, 1) +set @@global.gtid_strict_mode=0; set @@session.gtid_seq_no=1; +set @@global.gtid_strict_mode=1; +--replace_regex /GTID 1-1-[0-9]+/GTID VALUE/ +--error ER_GTID_STRICT_OUT_OF_ORDER +create table t_x (a int) engine=aria select f_ia(0) as a; +--error ER_NO_SUCH_TABLE +select * from t_x; + +--echo # **TODO**: fix MDEV-36027 +--echo # **TODO**: the empty binlog is buggy .. +--source include/show_binlog_events.inc +--echo # .. as non-transactional `ta` (and `t_x` sic!) are modified +select count(*) as one from ta; +select count(*) as zero from ti; + +delete from ta; +--echo #. + +# cleanup + +set @@global.gtid_strict_mode=@save_gtid_stric_mode; +drop function f_i; +drop function f_ia; +drop table t, ta, ti, ti_pk; diff --git a/sql/handler.cc b/sql/handler.cc index 3d1415b3dec..0088b84a2ec 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1901,6 +1901,8 @@ int ha_commit_trans(THD *thd, bool all) } #endif /* WITH_WSREP */ error= ha_commit_one_phase(thd, all); + if (error) + goto err; #ifdef WITH_WSREP // Here in case of error we must return 2 for inconsistency if (run_wsrep_hooks && !error) @@ -2141,7 +2143,7 @@ commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans) if (ha_info) { - int err; + int err= 0; if (has_binlog_hton(ha_info) && (err= binlog_commit(thd, all, @@ -2149,6 +2151,8 @@ commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans) { my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); error= 1; + + goto err; } for (; ha_info; ha_info= ha_info_next) { @@ -2184,7 +2188,7 @@ commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans) if (count >= 2) statistic_increment(transactions_multi_engine, LOCK_status); } - + err: DBUG_RETURN(error); }