summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSachin Kumar <sachin.setiya@mariadb.com>2021-05-24 11:23:03 +0100
committerSachin Kumar <sachin.setiya@mariadb.com>2021-05-27 06:35:37 +0100
commit6b79bd2b5081a61903f66bc21d079d0eb07227e3 (patch)
treec4f31e597ab4a26f47d94f186361c24bb2f2f3fc
parent5c75ba9cadc7877e91d6b712f157ff5623c09c60 (diff)
downloadmariadb-git-bb-10.2-24667.tar.gz
MDEV-24667 LOAD DATA INFILE/inserted rows not written to binlogbb-10.2-24667
Problem:- In master slave replication , when master is using statement format and slave is using mixed format, sometime we can have binlog which is not written. For example LOAD DATA INFILE is a unsafe statement , it is logged as a row format, and if it is on temporary table , it wont be logged. If the next statement is copy data from the tmp table to normal table, it is logged as a statement format on the slave , because it thinks this statement is unsafe. As we can see we did not log LOAD DATA INFILE and we simply logging insert into from * into statement format , we have effectively lost the tmp table data. Solution:- On master in mixed format if tmp table is created thd->temporary_tables is set to not null. This will make THD::reset_for_next_command to not change the binlog format back to stmt. So till the tmp table exist all the logs will be written in row format. On master THD::has_thd_temporary_tables() is used to determine whether we have temporary tables or not. But this does not work for the slave , slave shifts temporary tables from thd->temporary_tables to rgi_slave->rli->save_temporary_tables, so this will make has_thd_temporary_tables() check to return false on slave. So instead of this function I am calling has_temporary_tables() , which also checks slave thread tmp tables.
-rw-r--r--mysql-test/suite/rpl/r/mdev_24667.result30
-rw-r--r--mysql-test/suite/rpl/t/mdev_24667.cnf8
-rw-r--r--mysql-test/suite/rpl/t/mdev_24667.test56
-rw-r--r--sql/sql_class.h4
-rw-r--r--sql/temporary_tables.cc2
5 files changed, 97 insertions, 3 deletions
diff --git a/mysql-test/suite/rpl/r/mdev_24667.result b/mysql-test/suite/rpl/r/mdev_24667.result
new file mode 100644
index 00000000000..7c7342d63d6
--- /dev/null
+++ b/mysql-test/suite/rpl/r/mdev_24667.result
@@ -0,0 +1,30 @@
+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
diff --git a/mysql-test/suite/rpl/t/mdev_24667.cnf b/mysql-test/suite/rpl/t/mdev_24667.cnf
new file mode 100644
index 00000000000..58b605ad928
--- /dev/null
+++ b/mysql-test/suite/rpl/t/mdev_24667.cnf
@@ -0,0 +1,8 @@
+!include ../my.cnf
+
+[mysqld.3]
+log-slave-updates
+
+[ENV]
+SERVER_MYPORT_3= @mysqld.3.port
+SERVER_MYSOCK_3= @mysqld.3.socket
diff --git a/mysql-test/suite/rpl/t/mdev_24667.test b/mysql-test/suite/rpl/t/mdev_24667.test
new file mode 100644
index 00000000000..d8490b335db
--- /dev/null
+++ b/mysql-test/suite/rpl/t/mdev_24667.test
@@ -0,0 +1,56 @@
+#
+# 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
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 50ab3c56ca9..795e6a5e8b2 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -3899,13 +3899,13 @@ public:
*/
DBUG_PRINT("debug",
("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)));
if (in_sub_stmt == 0)
{
if (wsrep_binlog_format() == 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();
}
DBUG_VOID_RETURN;
diff --git a/sql/temporary_tables.cc b/sql/temporary_tables.cc
index 005a520ff64..fb28ac40aa6 100644
--- a/sql/temporary_tables.cc
+++ b/sql/temporary_tables.cc
@@ -866,7 +866,7 @@ void THD::restore_tmp_table_share(TMP_TABLE_SHARE *share)
@return false Temporary tables exist
true No temporary table exist
*/
-inline bool THD::has_temporary_tables()
+bool THD::has_temporary_tables()
{
DBUG_ENTER("THD::has_temporary_tables");
bool result= (rgi_slave