Commit 9f4ba624 authored by Sachin Kumar's avatar Sachin Kumar Committed by Andrei

MDEV-24667 LOAD DATA INFILE on temporary table not written to slave binlog

Problem: In regular replication, when master binlogged using statement format
slave might not have written an event to its binary log when the Query
event aimed at a temporary table.
Specifically this was observed with LOAD DATA INFILE.

This effect was possible because unlike master slave holds temporary
tables in its pool and the master side check of existence of a
temporary table at the format bin-logging decision did not apply.

Solution: replace THD::has_thd_temporary_tables() with
THD::has_temporary_tables which allows to identify temporary table
presence on either side.

--
Reviewed by Andrei Elkin.
parent 174f1734
include/rpl_init.inc [topology=1->2->3]
call mtr.add_suppression('Unsafe statement written to the binary log using ');
connection server_1;
set binlog_format=statement;
#first bug
create table t1 (a int);
create temporary table tmp like t1;
load data local infile 'MYSQLTEST_VARDIR/load_data' INTO TABLE tmp;
insert into t1 select * from tmp;
#second bug
create table t2 (a int);
create temporary table tmp2 like t2;
insert into tmp2 values(10);
update tmp2 set a = 20 limit 1;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. The statement is unsafe because it uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted
insert into t2 select * from tmp2;
connection server_2;
connection server_3;
#t1 should have 2 rows
select count(*) = 2 from t1;
count(*) = 2
1
#t2 should have 1 rows with a = 20
select * from t2;
a
20
connection server_1;
drop table t1, t2, tmp, tmp2;
include/rpl_end.inc
!include ../my.cnf
[mysqld.3]
log-slave-updates
[ENV]
SERVER_MYPORT_3= @mysqld.3.port
SERVER_MYSOCK_3= @mysqld.3.socket
#
# MDEV-24667 LOAD DATA INFILE/inserted rows not written to binlog
#
# In this test we will have a replication configuration like 1->2->3
# 1 will have statement format
# 2 and 3 will have mixed format
# We will make some updates on temporary table which are unsafe , So 2 must
# Log these queries in row format, Since it is on tmp table , It wont be logged
# So the next query which copies the data from tmp table to normal must be logged
# into the row format. Instead of checking for the binlog We will compare the
# results on the 3, If no binlog is lost(ie it is logged into row format), There
# should not be any data loss.
--let $rpl_topology=1->2->3
--source include/rpl_init.inc
--source include/have_binlog_format_mixed.inc
call mtr.add_suppression('Unsafe statement written to the binary log using ');
--connection server_1
set binlog_format=statement;
--echo #first bug
create table t1 (a int);
create temporary table tmp like t1;
--write_file $MYSQLTEST_VARDIR/load_data
1
2
EOF
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
eval load data local infile '$MYSQLTEST_VARDIR/load_data' INTO TABLE tmp;
insert into t1 select * from tmp;
--echo #second bug
create table t2 (a int);
#insert into t2 values(10);
create temporary table tmp2 like t2;
insert into tmp2 values(10);
update tmp2 set a = 20 limit 1;
insert into t2 select * from tmp2;
--save_master_pos
--connection server_2
--sync_with_master
--save_master_pos
--connection server_3
--sync_with_master
--echo #t1 should have 2 rows
select count(*) = 2 from t1;
--echo #t2 should have 1 rows with a = 20
select * from t2;
# cleanup
--connection server_1
drop table t1, t2, tmp, tmp2;
--remove_file $MYSQLTEST_VARDIR/load_data
--source include/rpl_end.inc
...@@ -3960,13 +3960,13 @@ class THD :public Statement, ...@@ -3960,13 +3960,13 @@ class THD :public Statement,
*/ */
DBUG_PRINT("debug", DBUG_PRINT("debug",
("temporary_tables: %s, in_sub_stmt: %s, system_thread: %s", ("temporary_tables: %s, in_sub_stmt: %s, system_thread: %s",
YESNO(has_thd_temporary_tables()), YESNO(in_sub_stmt), YESNO(has_temporary_tables()), YESNO(in_sub_stmt),
show_system_thread(system_thread))); show_system_thread(system_thread)));
if (in_sub_stmt == 0) if (in_sub_stmt == 0)
{ {
if (wsrep_binlog_format() == BINLOG_FORMAT_ROW) if (wsrep_binlog_format() == BINLOG_FORMAT_ROW)
set_current_stmt_binlog_format_row(); set_current_stmt_binlog_format_row();
else if (!has_thd_temporary_tables()) else if (!has_temporary_tables())
set_current_stmt_binlog_format_stmt(); set_current_stmt_binlog_format_stmt();
} }
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
......
...@@ -866,7 +866,7 @@ void THD::restore_tmp_table_share(TMP_TABLE_SHARE *share) ...@@ -866,7 +866,7 @@ void THD::restore_tmp_table_share(TMP_TABLE_SHARE *share)
@return false Temporary tables exist @return false Temporary tables exist
true No temporary table exist true No temporary table exist
*/ */
inline bool THD::has_temporary_tables() bool THD::has_temporary_tables()
{ {
DBUG_ENTER("THD::has_temporary_tables"); DBUG_ENTER("THD::has_temporary_tables");
bool result= (rgi_slave bool result= (rgi_slave
......
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