Skip to content

Commit 9f4ba62

Browse files
mariadb-SachinSetiyaandrelkin
authored andcommitted
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.
1 parent 174f173 commit 9f4ba62

File tree

5 files changed

+97
-3
lines changed

5 files changed

+97
-3
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
include/rpl_init.inc [topology=1->2->3]
2+
call mtr.add_suppression('Unsafe statement written to the binary log using ');
3+
connection server_1;
4+
set binlog_format=statement;
5+
#first bug
6+
create table t1 (a int);
7+
create temporary table tmp like t1;
8+
load data local infile 'MYSQLTEST_VARDIR/load_data' INTO TABLE tmp;
9+
insert into t1 select * from tmp;
10+
#second bug
11+
create table t2 (a int);
12+
create temporary table tmp2 like t2;
13+
insert into tmp2 values(10);
14+
update tmp2 set a = 20 limit 1;
15+
Warnings:
16+
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
17+
insert into t2 select * from tmp2;
18+
connection server_2;
19+
connection server_3;
20+
#t1 should have 2 rows
21+
select count(*) = 2 from t1;
22+
count(*) = 2
23+
1
24+
#t2 should have 1 rows with a = 20
25+
select * from t2;
26+
a
27+
20
28+
connection server_1;
29+
drop table t1, t2, tmp, tmp2;
30+
include/rpl_end.inc

mysql-test/suite/rpl/t/mdev_24667.cnf

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
!include ../my.cnf
2+
3+
[mysqld.3]
4+
log-slave-updates
5+
6+
[ENV]
7+
SERVER_MYPORT_3= @mysqld.3.port
8+
SERVER_MYSOCK_3= @mysqld.3.socket
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#
2+
# MDEV-24667 LOAD DATA INFILE/inserted rows not written to binlog
3+
#
4+
# In this test we will have a replication configuration like 1->2->3
5+
# 1 will have statement format
6+
# 2 and 3 will have mixed format
7+
# We will make some updates on temporary table which are unsafe , So 2 must
8+
# Log these queries in row format, Since it is on tmp table , It wont be logged
9+
# So the next query which copies the data from tmp table to normal must be logged
10+
# into the row format. Instead of checking for the binlog We will compare the
11+
# results on the 3, If no binlog is lost(ie it is logged into row format), There
12+
# should not be any data loss.
13+
--let $rpl_topology=1->2->3
14+
--source include/rpl_init.inc
15+
--source include/have_binlog_format_mixed.inc
16+
call mtr.add_suppression('Unsafe statement written to the binary log using ');
17+
--connection server_1
18+
19+
set binlog_format=statement;
20+
--echo #first bug
21+
create table t1 (a int);
22+
create temporary table tmp like t1;
23+
--write_file $MYSQLTEST_VARDIR/load_data
24+
1
25+
2
26+
EOF
27+
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
28+
eval load data local infile '$MYSQLTEST_VARDIR/load_data' INTO TABLE tmp;
29+
insert into t1 select * from tmp;
30+
31+
--echo #second bug
32+
create table t2 (a int);
33+
#insert into t2 values(10);
34+
create temporary table tmp2 like t2;
35+
insert into tmp2 values(10);
36+
update tmp2 set a = 20 limit 1;
37+
insert into t2 select * from tmp2;
38+
--save_master_pos
39+
40+
--connection server_2
41+
--sync_with_master
42+
--save_master_pos
43+
44+
--connection server_3
45+
--sync_with_master
46+
--echo #t1 should have 2 rows
47+
select count(*) = 2 from t1;
48+
--echo #t2 should have 1 rows with a = 20
49+
select * from t2;
50+
51+
52+
# cleanup
53+
--connection server_1
54+
drop table t1, t2, tmp, tmp2;
55+
--remove_file $MYSQLTEST_VARDIR/load_data
56+
--source include/rpl_end.inc

sql/sql_class.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3960,13 +3960,13 @@ class THD :public Statement,
39603960
*/
39613961
DBUG_PRINT("debug",
39623962
("temporary_tables: %s, in_sub_stmt: %s, system_thread: %s",
3963-
YESNO(has_thd_temporary_tables()), YESNO(in_sub_stmt),
3963+
YESNO(has_temporary_tables()), YESNO(in_sub_stmt),
39643964
show_system_thread(system_thread)));
39653965
if (in_sub_stmt == 0)
39663966
{
39673967
if (wsrep_binlog_format() == BINLOG_FORMAT_ROW)
39683968
set_current_stmt_binlog_format_row();
3969-
else if (!has_thd_temporary_tables())
3969+
else if (!has_temporary_tables())
39703970
set_current_stmt_binlog_format_stmt();
39713971
}
39723972
DBUG_VOID_RETURN;

sql/temporary_tables.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -866,7 +866,7 @@ void THD::restore_tmp_table_share(TMP_TABLE_SHARE *share)
866866
@return false Temporary tables exist
867867
true No temporary table exist
868868
*/
869-
inline bool THD::has_temporary_tables()
869+
bool THD::has_temporary_tables()
870870
{
871871
DBUG_ENTER("THD::has_temporary_tables");
872872
bool result= (rgi_slave

0 commit comments

Comments
 (0)