Bug #23333 stored function + non-transac table + transac table = breaks stmt-based binlog

Binlogging of the statement with a side effect like a modified non-trans table did not happen.
The artifact involved all binloggable dml queries.

Fixed with changing the binlogging conditions all over the code to exploit thd->transaction.stmt.modified_non_trans_table
introduced by the patch for bug@27417.

Multi-delete case has own specific addressed by another bug@29136. Multi-update case has been addressed by bug#27716 and
patch and will need merging.
parent 04981779
Loading
Loading
Loading
Loading
+71 −2
Original line number Diff line number Diff line
@@ -365,7 +365,7 @@ insert into t2 values (bug27417(2));
ERROR 23000: Duplicate entry '2' for key 1
show master status;
File	Position	Binlog_Do_DB	Binlog_Ignore_DB
master-bin.000001	98		
master-bin.000001	196		
/* only (!) with fixes for #23333 will show there is the query */;
select count(*) from t1 /* must be 3 */;
count(*)
@@ -390,6 +390,75 @@ affected rows: 0
select count(*) from t1 /* must be 7 */;
count(*)
7
drop function bug27417;
drop table t1,t2;
CREATE TABLE t1 (a int  NOT NULL auto_increment primary key) ENGINE=MyISAM;
CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB;
CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique);
insert into t2 values (1);
reset master;
insert into t2 values (bug27417(1));
ERROR 23000: Duplicate entry '1' for key 1
show master status /* the offset must denote there is the query */;
File	Position	Binlog_Do_DB	Binlog_Ignore_DB
master-bin.000001	267		
select count(*) from t1 /* must be 1 */;
count(*)
1
delete from t1;
delete from t2;
insert into t2 values (2);
reset master;
insert into t2 select bug27417(1) union select bug27417(2);
ERROR 23000: Duplicate entry '2' for key 1
show master status /* the offset must denote there is the query */;
File	Position	Binlog_Do_DB	Binlog_Ignore_DB
master-bin.000001	290		
select count(*) from t1 /* must be 2 */;
count(*)
2
delete from t1;
insert into t3 values (1,1),(2,3),(3,4);
reset master;
update t3 set b=b+bug27417(1);
ERROR 23000: Duplicate entry '4' for key 2
show master status /* the offset must denote there is the query */;
File	Position	Binlog_Do_DB	Binlog_Ignore_DB
master-bin.000001	190		
select count(*) from t1 /* must be 2 */;
count(*)
2
delete from t1;
delete from t2;
delete from t3;
insert into t2 values (1);
insert into t3 values (1,1);
create trigger trg_del before delete on t2 for each row 
insert into t3 values (bug27417(1), 2);
reset master;
delete from t2;
ERROR 23000: Duplicate entry '1' for key 1
show master status /* the offset must denote there is the query */;
File	Position	Binlog_Do_DB	Binlog_Ignore_DB
master-bin.000001	246		
select count(*) from t1 /* must be 1 */;
count(*)
1
delete from t1;
create table t4 (a int default 0, b int primary key) engine=innodb;
insert into t4 values (0, 17);
reset master;
load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2);
ERROR 23000: Duplicate entry '17' for key 1
select * from t4;
a	b
0	17
select count(*) from t1 /* must be 2 */;
count(*)
2
show master status /* the offset must denote there is the query */;
File	Position	Binlog_Do_DB	Binlog_Ignore_DB
master-bin.000001	376		
drop trigger trg_del;
drop table t1,t2,t3;
drop function bug27417;
end of tests
+3 −2
Original line number Diff line number Diff line
@@ -12,8 +12,9 @@ end|
reset master|
insert into t2 values (bug23333(),1)|
ERROR 23000: Duplicate entry '1' for key 1
show binlog events from 98 /* with fixes for #23333 will show there is the query */|
Log_name	Pos	Event_type	Server_id	End_log_pos	Info
show master status /* the offset must denote there is the query */|
File	Position	Binlog_Do_DB	Binlog_Ignore_DB
master-bin.000001	284		
select count(*),@a from t1 /* must be 1,1 */|
count(*)	@a
1	1
+119 −1
Original line number Diff line number Diff line
@@ -380,8 +380,126 @@ delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */;
--disable_info
select count(*) from t1 /* must be 7 */;

drop function bug27417;
# function bug27417 remains for the following testing of bug#23333
drop table t1,t2;

#
# Bug#23333 using the patch (and the test) for bug#27471
# throughout the bug tests 
# t1 - non-trans side effects gatherer;
# t2 - transactional table;
#
CREATE TABLE t1 (a int  NOT NULL auto_increment primary key) ENGINE=MyISAM;
CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB;
CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique);


#
# INSERT
#

# prepare
  
 insert into t2 values (1);
 reset master;

# execute

 --error ER_DUP_ENTRY
 insert into t2 values (bug27417(1)); 
  
# check

 show master status /* the offset must denote there is the query */;
 select count(*) from t1 /* must be 1 */;

#
# INSERT SELECT
#

# prepare
 delete from t1;
 delete from t2;
 insert into t2 values (2);
 reset master;

# execute

 --error ER_DUP_ENTRY
 insert into t2 select bug27417(1) union select bug27417(2); 
  
# check

 show master status /* the offset must denote there is the query */;
 select count(*) from t1 /* must be 2 */;

#
# UPDATE (multi-update see bug#27716)
#

# prepare
 delete from t1;
 insert into t3 values (1,1),(2,3),(3,4);
 reset master;

# execute
 --error ER_DUP_ENTRY
 update t3 set b=b+bug27417(1);

# check
 show master status /* the offset must denote there is the query */;
 select count(*) from t1 /* must be 2 */;


#
# DELETE (for multi-delete see Bug #29136)
#

# prepare
 delete from t1;
 delete from t2;
 delete from t3;
 insert into t2 values (1);
 insert into t3 values (1,1);
 create trigger trg_del before delete on t2 for each row 
   insert into t3 values (bug27417(1), 2);
 reset master;

# execute
 --error ER_DUP_ENTRY
 delete from t2;
# check
 show master status /* the offset must denote there is the query */;
 select count(*) from t1 /* must be 1 */;


#
# LOAD DATA
#

# prepare
 delete from t1;
 create table t4 (a int default 0, b int primary key) engine=innodb;
 insert into t4 values (0, 17);
 reset master;

# execute
 --error ER_DUP_ENTRY
 load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2);
# check
 select * from t4;
 select count(*) from t1 /* must be 2 */;
 show master status /* the offset must denote there is the query */;

#
# bug#23333 cleanup
#


drop trigger trg_del;
drop table t1,t2,t3;
drop function bug27417;


--echo end of tests
+1 −2
Original line number Diff line number Diff line
@@ -26,8 +26,7 @@ end|
reset master|
--error ER_DUP_ENTRY
insert into t2 values (bug23333(),1)| 
--replace_column 2 # 5 # 6 #
show binlog events from 98 /* with fixes for #23333 will show there is the query */|
show master status /* the offset must denote there is the query */|
select count(*),@a from t1 /* must be 1,1 */|
drop table t1, t2|
+3 −3
Original line number Diff line number Diff line
@@ -319,7 +319,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
    thd->transaction.stmt.modified_non_trans_table= TRUE;
  
  /* See similar binlogging code in sql_update.cc, for comments */
  if ((error < 0) || (deleted && !transactional_table))
  if ((error < 0) || thd->transaction.stmt.modified_non_trans_table)
  {
    if (mysql_bin_log.is_open())
    {
@@ -817,7 +817,8 @@ bool multi_delete::send_eof()
  {
    query_cache_invalidate3(thd, delete_tables, 1);
  }
  if ((local_error == 0) || (deleted && normal_tables))
  DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table);
  if ((local_error == 0) || thd->transaction.stmt.modified_non_trans_table)
  {
    if (mysql_bin_log.is_open())
    {
@@ -831,7 +832,6 @@ bool multi_delete::send_eof()
    if (thd->transaction.stmt.modified_non_trans_table)
      thd->transaction.all.modified_non_trans_table= TRUE;
  }
  DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table);

  /* Commit or rollback the current SQL statement */
  if (transactional_tables)
Loading